No description
Find a file
holzi1005 fd6fec6fce
All checks were successful
Build / release (push) Successful in 21s
Merge pull request 'update workflows' (#3) from dev into main
Reviewed-on: System-Design/deploy-tool#3
2026-04-02 09:36:12 +02:00
.forgejo/workflows update workflow dev 2026-04-02 09:35:12 +02:00
.gitignore add tests 2026-03-22 16:18:43 +01:00
go.mod add tests 2026-03-22 16:19:20 +01:00
main.go add namespace deplyoment 2026-04-02 09:25:57 +02:00
main_test.go add namespace deplyoment 2026-04-02 09:25:57 +02:00
README.md add namespace deplyoment 2026-04-02 09:25:57 +02:00

deploy

A Go CLI tool for deploying Helm charts and raw Kubernetes manifests via kapp and vals.
Supports multiple environments, namespace-scoped deployments, optional CRD deployment and a --dry-run mode that shows what would change without applying anything.


Requirements

Tool Purpose
helm Render Helm charts
vals Resolve secret references in YAML
kapp Apply / delete Kubernetes resources
kubectl Create namespaces

All four tools must be available in $PATH.


Build

go build -o deploy deploy.go

No external Go dependencies only the standard library is used.


Usage

./deploy [flags]
Flag Default Description
--env staging Environment folder to deploy
--namespace (all) Only process _deployment_<namespace>.json
--dry-run false Show what would change without applying anything

Examples

# Deploy staging (all deployment files)
./deploy

# Deploy a specific environment
./deploy --env production

# Deploy only the monitoring namespace in staging
./deploy --namespace monitoring

# Dry-run for production
./deploy --env production --dry-run

# Dry-run for a single namespace
./deploy --env production --namespace monitoring --dry-run

Directory structure

.
├── deploy.go
├── base/
│   ├── cluster.yml          # Global base values (all envs)
│   └── <name>.yml           # Per-chart base values
├── staging/
│   ├── _deployment.json             # Deployment config (all namespaces)
│   ├── _deployment_monitoring.json  # Deployment config (monitoring only)
│   ├── _deployment_storage.json     # Deployment config (storage only)
│   ├── cluster.yml                  # Staging-wide values override
│   └── <namespace>/
│       ├── <name>.yml       # Per-chart values override
│       └── <manifest>.yaml  # Optional raw manifest
└── production/
    ├── _deployment.json
    └── ...

Values files are loaded in this order (later files take precedence):

  1. ./base/cluster.yml
  2. ./<env>/cluster.yml
  3. ./base/<name>.yml (or ./base/<base>.yml if base is set)
  4. ./<env>/<namespace>/<name>.yml

Deployment files

When --namespace is not set, the tool processes all deployment files in the environment folder in this order:

  1. _deployment.json (if present)
  2. _deployment_<namespace>.json (all matches, alphabetically)

When --namespace is set, only _deployment_<namespace>.json is processed.


_deployment.json / _deployment_<namespace>.json

{
  "app_k8s_deploy_helm_charts": [
    {
      "namespace": "monitoring",
      "applications": [
        {
          "name": "kube-prometheus-stack",
          "chart_ref": "prometheus-community/kube-prometheus-stack",
          "state": "present",
          "version": "58.0.0",
          "deploy_crds": true
        },
        {
          "name": "alertmanager",
          "chart_ref": "prometheus-community/alertmanager",
          "base": "prometheus-common",
          "state": "present"
        },
        {
          "name": "my-configmap",
          "state": "present",
          "manifest": "my-configmap.yaml"
        },
        {
          "name": "old-app",
          "chart_ref": "my-repo/old-app",
          "state": "absent"
        }
      ]
    }
  ]
}

Application fields

Field Type Required Description
name string Release name and kapp app identifier
state string present to deploy, absent to delete
chart_ref string Helm chart reference. If omitted, Helm is skipped entirely
version string Helm chart version. Omit to use latest
manifest string Path to a raw YAML manifest relative to ./<env>/<namespace>/
deploy_crds bool Pass --include-crds to helm template (default: false)
base string Override base values filename. Loads ./base/<base>.yml instead of ./base/<name>.yml

base field

By default the tool looks for ./base/<name>.yml as the per-chart base values file.
Set base to load a different file from the base/ folder instead:

{ "name": "alertmanager", "base": "prometheus-common" }

This loads ./base/prometheus-common.yml instead of ./base/alertmanager.yml.
Useful when multiple charts share the same base values file.

Behaviour matrix

chart_ref manifest Result
Helm chart rendered and deployed via kapp
Helm chart + manifest merged into one kapp deploy
Only the raw manifest is processed via vals and deployed via kapp
Entry is skipped with a warning

kapp app naming

Each application is registered in kapp under the name:

<env>-<namespace>-<name>

Example: staging-monitoring-kube-prometheus-stack

The kapp app itself is always stored in the gitops namespace.


Dry-run mode

--dry-run has two layers:

  1. Local commands (helm template, vals eval, kubectl, cat) only printed, not executed. An empty temporary file is created so the pipeline does not break.
  2. kapp instead of kapp -y deploy, the tool runs:
   kapp deploy --diff-run --diff-changes

This connects to the real cluster and shows exactly which resources would be added, changed or deleted without applying anything.

kapp delete in dry-run is only printed, never executed.


vals secret resolution

All YAML passed to kapp runs through vals eval -f - first.
This resolves secret references such as:

password: ref+vault://secret/myapp#/password
token: ref+awssecrets://myapp/token

See the vals documentation for supported backends.


CRD deployment

Setting deploy_crds: true passes --include-crds to helm template.

Note: helm template --include-crds does not render CRDs that live in the crds/ directory of a chart. For reliable CRD deployment it is recommended to helm pull --untar the chart and apply the crds/ directory separately before the main deploy.