4.3 KiB
Per AI Blitz Plan §claude. Layer: 1. Repo: devops-infra-helm-charts.
04 — Override hierarchy
How the per-cluster override file, the chart's default values, and any raw-manifest sidecars compose at deploy time.
The three layers
For a given Argo Application targeting <cluster> × <app>, the rendered manifests come from three sources:
- Chart defaults —
helm-templates/<chart>/values.yaml. The upstream values, possibly customized in an intentional fork. This is the lowest precedence. - Cluster override —
helm-overrides/<cluster>/<app>/custom-values.yaml. Helm-merged on top of (1). This is what the agent edits day-to-day. - Raw manifest sidecars —
helm-overrides/<cluster>/<app>/<extra>.yaml(and optionally subdirectories likecomputeclass/,external-dns-services/). These are NOT consumed by Helm. Argo applies them directly to the cluster, in the same Application.
The Argo Application in the sister repo declares which path: (the override directory) and which helm.valueFiles: to use. Conventionally the Application points at the override directory and lists custom-values.yaml; raw sidecars in the same directory are picked up by Argo's manifest discovery.
Helm merge semantics
Helm performs a deep merge of (2) over (1):
- Maps merge key-by-key.
- Lists are replaced wholesale, not merged. This is the most common surprise — to extend an upstream list (
tolerations,extraArgs,extraEnv), copy the upstream list into the override and edit there. Don't write a list expecting it to append. nullin the override deletes the key set in defaults.
If you need surgical list editing rather than wholesale replacement, you must fork the chart and rewrite the template — almost never the right call. See ../docs/platform/procedures/fork-upstream-chart.md.
Dry-running the merge
Always render before pushing. The command from the root CLAUDE.md Quick reference table:
helm template <release> helm-templates/<chart> \
-f helm-overrides/<cluster>/<app>/custom-values.yaml
For wrapper charts (Chart.yaml dependencies:), refresh subcharts first:
helm dependency update helm-templates/<chart>
For raw sidecars, validate separately:
kubectl apply --dry-run=client -f helm-overrides/<cluster>/<app>/<extra>.yaml
Where each piece of config belongs
| Config | Goes in | Why |
|---|---|---|
| Image tag pin (production registry) | custom-values.yaml |
Per-cluster pinning is the whole point of the override layer. |
replicaCount, resource requests |
custom-values.yaml |
Per-cluster capacity tuning. |
nodeSelector, tolerations, computeClass |
custom-values.yaml |
Per-cluster node-pool topology. Never copy-paste across clusters. |
fullnameOverride |
custom-values.yaml |
Pinned to keep Service DNS / PVC binding stable. Never change an existing one. |
| Helm-managed Service / Deployment / ConfigMap | chart's templates/ (don't touch) |
Owned by upstream chart. |
| External-DNS record bound to a Service the chart doesn't manage | external-dns-services/*.yaml raw sidecar |
Not part of the chart's surface. |
ComputeClass definition (Autopilot) |
computeclass/*-cc.yaml raw sidecar |
Cluster-scoped object the chart can't render. |
| StorageClass / PriorityClass | manifests/storageclass/, manifests/priorityclass/<cluster>/ |
Cluster-wide singleton, separate from any one Application. |
| Secret values | External Secrets Operator + GCP Secret Manager / Vault | Never in custom-values.yaml. See ./06-secrets-and-identity.md. |
Schema details
- Override schema:
../docs/platform/schemas/custom-values-schema.md - Raw-sidecar schema:
../docs/platform/schemas/raw-manifest-sidecar-schema.md - Singleton schema:
../docs/platform/schemas/storageclass-priorityclass-schema.md