# Helm Chart Patterns Production Helm chart structure and patterns. ## Chart Structure ``` myapp/ ├── Chart.yaml ├── values.yaml ├── values-staging.yaml ├── values-production.yaml ├── templates/ │ ├── _helpers.tpl │ ├── deployment.yaml │ ├── service.yaml │ ├── ingress.yaml │ ├── configmap.yaml │ ├── secret.yaml │ ├── hpa.yaml │ ├── pdb.yaml │ └── NOTES.txt └── charts/ # Dependencies ``` ## Chart.yaml ```yaml apiVersion: v2 name: myapp description: My Application Helm Chart type: application version: 1.0.0 appVersion: "2.0.0" keywords: - web - api maintainers: - name: Team email: team@example.com dependencies: - name: postgresql version: "12.x.x" repository: https://charts.bitnami.com/bitnami condition: postgresql.enabled ``` ## values.yaml ```yaml # Default values for myapp replicaCount: 3 image: repository: myregistry/myapp pullPolicy: IfNotPresent tag: "" # Defaults to appVersion imagePullSecrets: [] nameOverride: "" fullnameOverride: "" serviceAccount: create: true annotations: {} name: "" podAnnotations: {} podSecurityContext: runAsNonRoot: true runAsUser: 1000 fsGroup: 1000 securityContext: allowPrivilegeEscalation: false readOnlyRootFilesystem: true capabilities: drop: - ALL service: type: ClusterIP port: 80 ingress: enabled: false className: nginx annotations: {} hosts: - host: app.example.com paths: - path: / pathType: Prefix tls: [] resources: limits: cpu: 500m memory: 512Mi requests: cpu: 100m memory: 128Mi autoscaling: enabled: true minReplicas: 3 maxReplicas: 10 targetCPUUtilizationPercentage: 70 targetMemoryUtilizationPercentage: 80 pdb: enabled: true minAvailable: 2 nodeSelector: {} tolerations: [] affinity: {} # Application config config: logLevel: info cacheTtl: 3600 # Secrets (use external secrets in production) secrets: databaseUrl: "" apiKey: "" # Database dependency postgresql: enabled: false auth: database: myapp ``` ## Helper Template (_helpers.tpl) ```yaml {{/* Expand the name of the chart. */}} {{- define "myapp.name" -}} {{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} {{- end }} {{/* Create a default fully qualified app name. */}} {{- define "myapp.fullname" -}} {{- if .Values.fullnameOverride }} {{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} {{- else }} {{- $name := default .Chart.Name .Values.nameOverride }} {{- if contains $name .Release.Name }} {{- .Release.Name | trunc 63 | trimSuffix "-" }} {{- else }} {{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} {{- end }} {{- end }} {{- end }} {{/* Create chart name and version as used by the chart label. */}} {{- define "myapp.chart" -}} {{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} {{- end }} {{/* Common labels */}} {{- define "myapp.labels" -}} helm.sh/chart: {{ include "myapp.chart" . }} {{ include "myapp.selectorLabels" . }} {{- if .Chart.AppVersion }} app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} {{- end }} app.kubernetes.io/managed-by: {{ .Release.Service }} {{- end }} {{/* Selector labels */}} {{- define "myapp.selectorLabels" -}} app.kubernetes.io/name: {{ include "myapp.name" . }} app.kubernetes.io/instance: {{ .Release.Name }} {{- end }} {{/* Create the name of the service account to use */}} {{- define "myapp.serviceAccountName" -}} {{- if .Values.serviceAccount.create }} {{- default (include "myapp.fullname" .) .Values.serviceAccount.name }} {{- else }} {{- default "default" .Values.serviceAccount.name }} {{- end }} {{- end }} ``` ## Deployment Template ```yaml apiVersion: apps/v1 kind: Deployment metadata: name: {{ include "myapp.fullname" . }} labels: {{- include "myapp.labels" . | nindent 4 }} spec: {{- if not .Values.autoscaling.enabled }} replicas: {{ .Values.replicaCount }} {{- end }} selector: matchLabels: {{- include "myapp.selectorLabels" . | nindent 6 }} template: metadata: annotations: checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }} {{- with .Values.podAnnotations }} {{- toYaml . | nindent 8 }} {{- end }} labels: {{- include "myapp.selectorLabels" . | nindent 8 }} spec: {{- with .Values.imagePullSecrets }} imagePullSecrets: {{- toYaml . | nindent 8 }} {{- end }} serviceAccountName: {{ include "myapp.serviceAccountName" . }} securityContext: {{- toYaml .Values.podSecurityContext | nindent 8 }} containers: - name: {{ .Chart.Name }} securityContext: {{- toYaml .Values.securityContext | nindent 12 }} image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" imagePullPolicy: {{ .Values.image.pullPolicy }} ports: - name: http containerPort: 8000 protocol: TCP livenessProbe: httpGet: path: /health port: http initialDelaySeconds: 10 periodSeconds: 30 readinessProbe: httpGet: path: /ready port: http initialDelaySeconds: 5 periodSeconds: 10 resources: {{- toYaml .Values.resources | nindent 12 }} envFrom: - configMapRef: name: {{ include "myapp.fullname" . }} - secretRef: name: {{ include "myapp.fullname" . }} volumeMounts: - name: tmp mountPath: /tmp volumes: - name: tmp emptyDir: {} {{- with .Values.nodeSelector }} nodeSelector: {{- toYaml . | nindent 8 }} {{- end }} {{- with .Values.affinity }} affinity: {{- toYaml . | nindent 8 }} {{- end }} {{- with .Values.tolerations }} tolerations: {{- toYaml . | nindent 8 }} {{- end }} ``` ## Helm Commands ```bash # Install helm install myapp ./myapp -f values-production.yaml # Upgrade helm upgrade myapp ./myapp -f values-production.yaml # Dry run helm install myapp ./myapp --dry-run --debug # Template output helm template myapp ./myapp -f values-production.yaml # Rollback helm rollback myapp 1 # History helm history myapp # Uninstall helm uninstall myapp ``` ## Environment-Specific Values ### values-staging.yaml ```yaml replicaCount: 2 ingress: enabled: true hosts: - host: staging.app.example.com paths: - path: / pathType: Prefix tls: - secretName: staging-tls hosts: - staging.app.example.com resources: limits: cpu: 250m memory: 256Mi requests: cpu: 50m memory: 64Mi autoscaling: enabled: false ``` ### values-production.yaml ```yaml replicaCount: 3 ingress: enabled: true annotations: nginx.ingress.kubernetes.io/ssl-redirect: "true" hosts: - host: app.example.com paths: - path: / pathType: Prefix tls: - secretName: production-tls hosts: - app.example.com resources: limits: cpu: 500m memory: 512Mi requests: cpu: 100m memory: 128Mi autoscaling: enabled: true minReplicas: 3 maxReplicas: 20 pdb: enabled: true minAvailable: 2 ```