- If the service fits the generic shape (deployment/statefulset, service,
ingress, config, secrets — anything expressible as Kubernetes objects), use
app-chartwith a values file. Don't add a chart. - Only add a dedicated chart when a service has real chart logic the
generic chart can't express — a CRD, an operator, complex conditional wiring.
A new chart that just re-implements
app-chartis a maintenance trap.
Create one folder under charts/, same shape as app-chart:
charts/<name>/
├── Chart.yaml # apiVersion: v2, name: <name>, version: 0.1.0
├── values.yaml # documented (# -- comments feed the README)
├── README.md.gotmpl # helm-docs template (README.md is generated)
├── .helmignore # exclude tests/, ci/, *.gotmpl from the package
├── templates/ # your templates
├── tests/ # helm-unittest suites (required)
└── ci/
└── example-values.yaml # realistic values for lint / kubeconform / Trivy
Chart.yaml—apiVersion: v2, a uniquename,version: 0.1.0,type: application, and amaintainersentry.values.yaml— start empty/off-by-default; document each key with a# --comment (helm-docs turns these into the README table) and add a short commented example after each.templates/— write the templates. Keep secrets out of the chart; use ExternalSecrets or values.tests/— add helm-unittest suites asserting the rendered output. This is required: it's what locks behavior. Runmake unittest.ci/example-values.yaml— a realistic values file.ct lint,kubeconform, and Trivy all render the chart with it, so make it clean (resources set, hardenedsecurityContext, no HIGH/CRITICAL Trivy findings).README.md.gotmpl+.helmignore— copyapp-chart's, then runmake docsto generateREADME.md. Never hand-edit the generated README.- (Optional) CODEOWNERS — add a
/charts/<name>/ @teamline if a specific team owns it.
CI discovers the new chart automatically — no workflow edits:
ct lint(viact list-changed) lints it on PRs that touch it.helm-unittestruns itstests/.kubeconformvalidates itsci/render.- Trivy scans its
ci/render for misconfig + secrets. - On merge to
main,chart-releaserpublishes it onceversionis set.
make unittest
make lint
make kubeconform
make pre-commitSee chart-publishing.md for how the chart then gets versioned and published.