Deploying Production Applications on Kubernetes
Complete guide to deploying production applications on Kubernetes including deployment strategies, resource management, health checks, and production readiness.
# Deploying Production Applications on Kubernetes
Introduction
Deploying production applications on Kubernetes requires careful planning around deployment strategies, resource management, health checks, scaling, and observability. This tutorial covers end-to-end production deployment patterns using Helm, deployment strategies, and production readiness checklists.
Learning Objectives
By the end of this tutorial, you will be able to:
- Package applications with Helm charts
- Deploy applications using rolling updates, blue-green, and canary strategies
- Configure resource requests, limits, and quality of service
- Implement health checks and readiness probes
- Configure horizontal pod autoscaling
- Manage secrets and configuration in production
- Validate production readiness
Technical Background
Deployment Strategies
flowchart TD
Deploy[Deployment] --> Rolling[Rolling Update]
Deploy --> BlueGreen[Blue-Green]
Deploy --> Canary[Canary]
Rolling -->|Gradual| New[New Version]
BlueGreen -->|Switch| Traffic[Traffic Switch]
Canary -->|Percentage| CanaryTraffic[Canary Traffic]Prerequisites
- Running Kubernetes cluster
- kubectl configured
- Helm installed
- Container images in registry
Hardware and Software Requirements
| Component | Requirement | |-----------|-------------| | Kubernetes Cluster | v1.25+ | | Helm | v3+ | | Container Registry | Docker Hub, ECR, ACR, or GCR |
Step-by-Step Implementation
Phase 1: Helm Chart Structure
myapp/
├── Chart.yaml
├── values.yaml
├── values-production.yaml
├── templates/
│ ├── deployment.yaml
│ ├── service.yaml
│ ├── ingress.yaml
│ ├── hpa.yaml
│ └── pdb.yaml
└── charts/#### Chart.yaml
apiVersion: v2
name: myapp
description: Production application
type: application
version: 1.0.0
appVersion: "1.2.3"#### values.yaml
replicaCount: 3
image:
repository: myregistry.com/myapp
pullPolicy: IfNotPresent
tag: "1.2.3"
service:
type: ClusterIP
port: 80
targetPort: 3000
ingress:
enabled: true
hosts:
- host: app.example.com
paths:
- path: /
pathType: Prefix
resources:
limits:
cpu: 500m
memory: 512Mi
requests:
cpu: 250m
memory: 256Mi
autoscaling:
enabled: true
minReplicas: 3
maxReplicas: 10
targetCPUUtilizationPercentage: 70#### Deployment Template
# templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "myapp.fullname" . }}
labels:
{{- include "myapp.labels" . | nindent 4 }}
spec:
replicas: {{ .Values.replicaCount }}
selector:
matchLabels:
{{- include "myapp.selectorLabels" . | nindent 6 }}
template:
metadata:
labels:
{{- include "myapp.selectorLabels" . | nindent 8 }}
spec:
containers:
- name: {{ .Chart.Name }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
ports:
- containerPort: {{ .Values.service.targetPort }}
env:
- name: ENVIRONMENT
value: "production"
resources:
{{- toYaml .Values.resources | nindent 10 }}
livenessProbe:
httpGet:
path: /healthz
port: {{ .Values.service.targetPort }}
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
httpGet:
path: /ready
port: {{ .Values.service.targetPort }}
initialDelaySeconds: 5
periodSeconds: 5Phase 2: Deploy with Helm
# Lint chart
helm lint ./myapp
# Dry run
helm install myapp ./myapp --dry-run --namespace production
# Install
helm install myapp ./myapp --namespace production --create-namespace \
-f values-production.yaml
# Upgrade
helm upgrade myapp ./myapp --namespace production \
-f values-production.yaml --set image.tag=1.2.4
# Rollback
helm rollback myapp 1 --namespace production
# Uninstall
helm uninstall myapp --namespace productionPhase 3: Deployment Strategies
#### Rolling Update (Default)
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 25%
maxUnavailable: 25%#### Blue-Green with Helm
# Deploy blue (current)
helm install myapp-blue ./myapp -n production -f values-blue.yaml
# Deploy green (new)
helm install myapp-green ./myapp -n production -f values-green.yaml
# Switch traffic via Ingress or Service selector
kubectl patch service myapp -n production \
-p '{"spec":{"selector":{"version":"green"}}}'#### Canary with Argo Rollouts
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
name: myapp-rollout
spec:
strategy:
canary:
steps:
- setWeight: 10
- pause: {duration: 5m}
- setWeight: 50
- pause: {duration: 5m}
- setWeight: 100Phase 4: Horizontal Pod Autoscaling
# hpa.yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: myapp-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: myapp
minReplicas: 3
maxReplicas: 20
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 80Phase 5: Production Readiness Checklist
| Check | Status | |-------|--------| | Resource requests and limits defined | | | Health probes (liveness, readiness, startup) | | | PDB configured | | | HPA configured | | | Secrets and ConfigMaps used | | | Network policies applied | | | Image pull secrets configured | | | Non-root user configured | | | Read-only root filesystem | | | Logging and monitoring enabled | | | Rollback tested | | | Disaster recovery plan documented | |
Expected Output
- Helm chart for production deployment
- Application deployed with proper resource management
- Autoscaling configured
- Health checks implemented
- Production readiness validated
Verification Procedures
| Check | Command | Expected Result | |-------|---------|-----------------| | Helm release | `helm list -n production` | Release listed | | Pods running | `kubectl get pods -n production` | All Running | | HPA | `kubectl get hpa -n production` | HPA active | | Service | `kubectl get svc -n production` | Service with endpoints | | Ingress | `kubectl get ingress -n production` | Ingress with address |
Troubleshooting Scenarios
| Issue | Diagnosis | Resolution | |-------|-----------|------------| | Helm install fails | Template error or value issue | Check `helm lint`; verify values | | Pods not scaling | HPA not configured or metrics missing | Install metrics-server; check HPA | | Deployment stuck | Probe failing | Check application logs; fix probe | | Rollback fails | Previous revision not available | Keep revision history |
Best Practices
- **Use Helm:** Package applications as Helm charts
- **Version images:** Never use `latest` tag in production
- **Set resource limits:** Prevent resource exhaustion
- **Use health probes:** Configure liveness, readiness, startup
- **Implement PDB:** Ensure availability during disruptions
- **Use HPA:** Auto-scale based on resource utilization
- **Manage secrets properly:** Use Kubernetes Secrets or external secret manager
- **Test rollbacks:** Verify rollback procedures work
Security Considerations
- **Non-root user:** Run containers as non-root
- **Read-only filesystem:** Where possible
- **Drop capabilities:** Remove unnecessary Linux capabilities
- **Network policies:** Control pod-to-pod communication
- **Image scanning:** Scan for vulnerabilities before deployment
- **Secrets management:** Use external secret managers for production
Conclusion
Deploying production applications on Kubernetes requires careful planning around packaging, deployment strategies, resource management, health checks, and observability. By using Helm, implementing proper deployment strategies, and following production readiness best practices, teams can run reliable, scalable applications on Kubernetes.
References
- Helm Documentation: https://helm.sh/docs/
- Kubernetes Deployments: https://kubernetes.io/docs/concepts/workloads/controllers/deployment/
- Horizontal Pod Autoscaler: https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/
- Argo Rollouts: https://argoproj.github.io/argo-rollouts/
- Production Best Practices: https://kubernetes.io/docs/setup/production-environment/