05 — Helm & Configuration
Focus: Helm. How BitVault is packaged and configured: a shared library chart, thin per-service charts, per-environment values, and the templating-vs-rendered debate. Helm is also the self-host install artifact (ADR-0012).
1. Chart architecture: library chart + thin service charts
flowchart TB
classDef l fill:#fde68a,stroke:#b45309,color:#111827;
classDef s fill:#bbf7d0,stroke:#15803d,color:#111827;
classDef v fill:#fbcfe8,stroke:#be185d,color:#111827;
lib["bitvault-common (library chart)<br/>templates: Rollout/Deployment · Service · HPA ·<br/>NetworkPolicy · PDB · ServiceMonitor · ExternalSecret"]:::l
gw["chart: gateway"]:::s
api["chart: bitvaultd"]:::s
wk["chart: worker"]:::s
web["chart: web"]:::s
lib --> gw & api & wk & web
base["values.yaml (defaults)"]:::v --> gw & api & wk & web
over["values-{dev,staging,prod}.yaml (GitOps repo)"]:::v --> gw & api & wk & web
- A library chart (
bitvault-common) holds the boilerplate (labels, probes, security context, rollout, network policy, service monitor) once. Per-service charts are thin — just the service’s specifics. DRY, consistent, one place to fix a defaulting bug. - No giant umbrella chart that deploys everything as one release — that couples unrelated services into one blast radius. Composition is ArgoCD’s job (ApplicationSet over per-service charts, 06), not Helm’s.
2. Values: defaults + per-environment overlays
- Chart ships safe defaults (
values.yaml). - The GitOps repo holds
values-<env>.yamloverlays (03) — scale, tier, endpoints, flags — and the pinned image digest (01). - No secrets in values — only
ExternalSecretreferences (09).
3. Templating at sync vs rendered manifests (a real choice)
| Approach | How | Pro | Con |
|---|---|---|---|
| Helm rendered by ArgoCD at sync | ArgoCD runs helm template on sync |
simple, dynamic, less to store | the Git diff is values, not the resulting manifests (surprises possible) |
| Rendered-manifests pattern | CI runs helm template → commits plain YAML to GitOps repo; ArgoCD applies YAML |
the diff shows exactly what will change; no templating at deploy; auditable | extra CI step + more YAML in Git |
Decision: start with ArgoCD-renders-Helm (simplest, fewest moving parts); offer rendered-manifests for prod where reviewers want to see the literal manifest diff before approving (08). Both keep the chart as the single templating source.
4. Helm vs Kustomize
- Helm is primary: it is the packaging/distribution format, and self-host needs a chart anyway (ADR-0012) — one tool, SaaS↔self-host parity.
- Kustomize is optional for last-mile, declarative overlays/patches where Helm values are awkward (ArgoCD supports both, and Helm-then-Kustomize post-rendering).
- We avoid maintaining both a chart and parallel Kustomize bases for the same thing.
5. Chart quality gates (in CI, 07)
helm lint → schema validation (values.schema.json, kubeconform) → unit tests
(helm-unittest) → policy (conftest/OPA: e.g. “must set resource limits”, “no
:latest”, “must run non-root”) → render + diff in PRs. Charts are versioned
(chart version ≠ appVersion) and published to an OCI registry for self-host.
6. Tradeoffs / Alternatives / Scaling
Tradeoffs. A library chart adds indirection but eliminates copy-paste drift across services — the right trade once there are >2 services. ArgoCD-renders-Helm trades diff auditability for simplicity (mitigated by the rendered-manifests option for prod).
Alternatives considered.
- Umbrella chart for the whole app: one release, one blast radius, coupled upgrades. Rejected in favor of ArgoCD composition.
- Kustomize-only (no Helm): loses the distributable package self-host needs (ADR-0012). Rejected as primary.
- Raw manifests + ArgoCD: no templating reuse across envs; doesn’t scale past a couple services. Rejected.
Scaling concerns.
- Many services × envs → library chart + ApplicationSet generators keep it linear (06), not copy-per-combination.
- Chart/app version skew → CI enforces chart bumps on template changes; OCI registry versions are immutable.
- Values sprawl → schema-validated values + a documented, minimal override surface per env.
References
- Helm library charts: https://helm.sh/docs/topics/library_charts/
- Helm OCI registries: https://helm.sh/docs/topics/registries/
- Rendered manifests pattern: https://akuity.io/blog/the-rendered-manifests-pattern