Skip to main content

App charts

An app chart is the top-level Helm chart a project deploys. It owns the main workload and lists the components it pulls in as dependencies in its Chart.yaml.

Common shape

Every app chart has roughly the same structure:

my-app-chart/
├── Chart.yaml ← name, version, dependencies on components/
├── values.yaml ← defaults
└── templates/
├── deployment-app.yaml ← the main workload (Deployment or StatefulSet)
└── service-app.yaml ← the matching Service

The CronJobs, worker Deployments, and manual jobs come from component-tasks, the ingress from component-traefik-ingress, secrets from component-external-secret, etc. App chart templates do not duplicate those resources.

Service and pod labels

service-app.yaml exposes the main workload as a ClusterIP Service. Its selector is two labels, not one:

selector:
app: <global.nameOverride>
component: web

The main workload's pod template carries both app and component: web. The Deployment/StatefulSet .spec.selector deliberately stays on app alone — that field is immutable, so the component: web discriminator lives only on the pod template (an additive label change is a normal rolling update; changing the selector would require recreating the workload).

Cron, worker, and manual job pods from component-tasks share the same app label but are not web servers and never get component: web. The two-label selector is what keeps the Service pointed only at web pods — a bare app: selector also matches queue workers, routing a share of HTTP requests to pods with nothing listening on the web port (intermittent 502s / half-loaded pages).

Available app charts

  • symfony — Symfony PHP applications, StatefulSet, expects /health + /ready
  • php-generic — Generic PHP apps, same workload shape as symfony, with toggleable probes
  • node-generic — Generic Node.js apps on port 3000
  • sveltekit — SvelteKit on port 3000, Deployment (not StatefulSet)