| name | helm-production-patterns |
| description | Implement production deployment strategies including secrets management, blue-green deployments, canary releases, and upgrade procedures. Use when deploying charts to production, implementing secrets management, setting up blue-green or canary deployments, configuring chart testing strategies, or planning upgrade and rollback procedures. |
| version | 1.0.0 |
| dependencies | helm>=3.0, kubectl>=1.19 |
Helm Production Deployment Patterns
Purpose
Provide production-proven patterns for deploying Helm charts safely and reliably, including secrets management, testing strategies, deployment patterns, and upgrade procedures.
Secrets Management
Using Helm Secrets Plugin
Installation:
helm plugin install https://github.com/jkroepke/helm-secrets
Usage:
helm secrets enc secrets.yaml
helm secrets install myrelease . -f secrets.yaml
helm secrets upgrade myrelease . -f secrets.yaml
helm secrets view secrets.yaml
Secrets file structure:
database:
password: supersecretpassword123
connectionString: postgresql://user:pass@host:5432/db
api:
apiKey: sk-abc123def456
webhookSecret: whsec_xyz789
External Secrets Operator
SecretStore configuration:
apiVersion: external-secrets.io/v1beta1
kind: SecretStore
metadata:
name: vault-backend
namespace: {{ .Release.Namespace }}
spec:
provider:
vault:
server: "https://vault.example.com"
path: "secret"
version: "v2"
auth:
kubernetes:
mountPath: "kubernetes"
role: "myapp-prod"
ExternalSecret definition:
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: {{ include "mychart.fullname" . }}-secrets
spec:
refreshInterval: 1h
secretStoreRef:
name: vault-backend
kind: SecretStore
target:
name: {{ include "mychart.fullname" . }}-secrets
creationPolicy: Owner
data:
- secretKey: database-password
remoteRef:
key: myapp/database
property: password
Testing Strategies
Unit Testing with helm-unittest
Installation:
helm plugin install https://github.com/helm-unittest/helm-unittest
Test file example:
suite: test deployment
templates:
- deployment.yaml
tests:
- it: should create deployment with correct replicas
set:
replicaCount: 3
asserts:
- equal:
path: spec.replicas
value: 3
- it: should have resource limits
asserts:
- exists:
path: spec.template.spec.containers[0].resources.limits
- equal:
path: spec.template.spec.containers[0].resources.limits.cpu
value: 500m
- it: should use specific image tag
set:
image.tag: "1.2.3"
asserts:
- equal:
Run tests:
helm unittest charts/myapp
helm unittest -f tests/deployment_test.yaml charts/myapp
Integration Testing with helm test
Test pod definition:
apiVersion: v1
kind: Pod
metadata:
name: "{{ include "mychart.fullname" . }}-test-connection"
annotations:
"helm.sh/hook": test
"helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded
spec:
restartPolicy: Never
containers:
- name: test
image: curlimages/curl:latest
command:
- sh
- -c
- |
echo "Testing service connectivity..."
curl -f http://{{ include "mychart.fullname" . }}:{{ .Values.service.port }}/healthz
echo "Service is healthy"
Run integration tests:
helm install myrelease ./charts/myapp --namespace test --create-namespace
helm test myrelease --namespace test
kubectl logs -n test myrelease-test-connection
Multi-Stage Deployment
Database Migration Pre-Upgrade Hook
apiVersion: batch/v1
kind: Job
metadata:
name: {{ include "mychart.fullname" . }}-migration
annotations:
"helm.sh/hook": pre-upgrade,pre-install
"helm.sh/hook-weight": "-5"
"helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded
spec:
template:
spec:
restartPolicy: Never
containers:
- name: migration
image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
command: ["./migrate"]
env:
- name: DATABASE_URL
valueFrom:
secretKeyRef:
name: {{ include "mychart.fullname" . }}-secrets
key: database-url
Backup Job Before Upgrade
apiVersion: batch/v1
kind: Job
metadata:
name: {{ include "mychart.fullname" . }}-backup
annotations:
"helm.sh/hook": pre-upgrade
"helm.sh/hook-weight": "-10"
"helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded
spec:
template:
spec:
restartPolicy: Never
containers:
- name: backup
image: postgres:14-alpine
command:
- sh
- -c
- |
pg_dump $DATABASE_URL > /backup/dump-$(date +%Y%m%d-%H%M%S).sql
echo "Backup completed"
Rolling Update Configuration
Deployment strategy:
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "mychart.fullname" . }}
spec:
replicas: {{ .Values.replicaCount }}
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: {{ .Values.rollingUpdate.maxSurge | default "25%" }}
maxUnavailable: {{ .Values.rollingUpdate.maxUnavailable | default "25%" }}
Conservative rolling update (Production):
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
replicaCount: 3
Aggressive rolling update (Development):
rollingUpdate:
maxSurge: "100%"
maxUnavailable: "50%"
replicaCount: 2
Pod Disruption Budget
{{- if .Values.podDisruptionBudget.enabled }}
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: {{ include "mychart.fullname" . }}
spec:
{{- if .Values.podDisruptionBudget.minAvailable }}
minAvailable: {{ .Values.podDisruptionBudget.minAvailable }}
{{- end }}
{{- if .Values.podDisruptionBudget.maxUnavailable }}
maxUnavailable: {{ .Values.podDisruptionBudget.maxUnavailable }}
{{- end }}
selector:
matchLabels:
{{- include "mychart.selectorLabels" . | nindent 6 }}
{{- end }}
Values:
podDisruptionBudget:
enabled: true
minAvailable: 1
Monitoring and Observability
ServiceMonitor for Prometheus:
{{- if .Values.monitoring.serviceMonitor.enabled }}
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: {{ include "mychart.fullname" . }}
spec:
selector:
matchLabels:
{{- include "mychart.selectorLabels" . | nindent 6 }}
endpoints:
- port: metrics
interval: {{ .Values.monitoring.serviceMonitor.interval }}
path: {{ .Values.monitoring.serviceMonitor.path }}
{{- end }}
Upgrade Procedures
Pre-Upgrade Checklist
helm diff upgrade myrelease ./charts/myapp
helm get values myrelease > myrelease-backup-values.yaml
helm get manifest myrelease > myrelease-backup-manifest.yaml
helm upgrade myrelease ./charts/myapp --dry-run --debug
helm upgrade myrelease ./charts/myapp \
--wait \
--timeout 10m \
--atomic
Safe Upgrade Pattern
helm upgrade myrelease ./charts/myapp \
--install \
--create-namespace \
--wait \
--wait-for-jobs \
--timeout 10m \
--atomic \
--cleanup-on-fail
Rollback Procedure
helm history myrelease
helm rollback myrelease
helm rollback myrelease 3
helm rollback myrelease 3 \
--wait \
--timeout 5m \
--cleanup-on-fail
Production Deployment Checklist
Pre-Deployment
During Deployment
Post-Deployment
Blue-Green Deployment Pattern
Service selector pattern:
{{- if .Values.blueGreen.enabled }}
apiVersion: v1
kind: Service
metadata:
name: {{ include "mychart.fullname" . }}
spec:
selector:
{{- include "mychart.selectorLabels" . | nindent 4 }}
slot: {{ .Values.blueGreen.activeSlot }}
ports:
- port: {{ .Values.service.port }}
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "mychart.fullname" . }}-blue
spec:
replicas: {{ if eq .Values.blueGreen.activeSlot "blue" }}{{ .Values.replicaCount }}{{ else }}0{{ end }}
selector:
matchLabels:
{{- include "mychart.selectorLabels" }}
{{ }}
{{ }}{{ }}{{ }}{{ }}
{{ }}
{{ }}
Switch traffic:
blueGreen:
enabled: true
activeSlot: blue
Canary Deployment with Flagger
Canary resource:
{{- if .Values.canary.enabled }}
apiVersion: flagger.app/v1beta1
kind: Canary
metadata:
name: {{ include "mychart.fullname" . }}
spec:
targetRef:
apiVersion: apps/v1
kind: Deployment
name: {{ include "mychart.fullname" . }}
service:
port: {{ .Values.service.port }}
analysis:
interval: {{ .Values.canary.analysis.interval }}
threshold: {{ .Values.canary.analysis.threshold }}
maxWeight: {{ .Values.canary.analysis.maxWeight }}
stepWeight: {{ .Values.canary.analysis.stepWeight }}
metrics:
- name: request-success-rate
thresholdRange:
min: {{ .Values.canary.successRate }}
interval: 1m
{{- end }}
Values:
canary:
enabled: false
analysis:
interval: 30s
threshold: 5
maxWeight: 50
stepWeight: 10
successRate: 99
Validation Commands
helm lint ./charts/myapp
helm template myapp ./charts/myapp --debug
helm install test ./charts/myapp --dry-run --debug
helm install myrelease ./charts/myapp
helm upgrade myrelease ./charts/myapp --wait --atomic
helm rollback myrelease
helm uninstall myrelease
Resources
Related Agent
For comprehensive Helm/Kubernetes guidance that coordinates this and other Helm skills, use the helm-kubernetes-expert agent.