You have worked through all 12 articles in the Kubernetes series. Now it is time to go to production.
This checklist covers everything you need to verify before your application is ready for real traffic. Each item links back to the tutorial where it is covered in depth.
Going through this checklist before your first production deploy will save you from the most common production failures.
Reliability
Define resource requests and limits on every container
Without requests, the Kubernetes scheduler cannot place Pods correctly. Without limits, one runaway container can OOM-kill an entire node.
resources:
requests:
cpu: "100m"
memory: "128Mi"
limits:
cpu: "500m"
memory: "256Mi"
Status: Every container in every Deployment must have this.
Add readiness and liveness probes
Without probes, Kubernetes cannot tell if your app is ready or broken. Traffic goes to crashing Pods.
readinessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 5
periodSeconds: 10
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 15
periodSeconds: 20
failureThreshold: 3
- Readiness probe — controls when a Pod receives traffic. If it fails, the Pod is removed from the Service load balancer.
- Liveness probe — controls when Kubernetes restarts a Pod. If it fails repeatedly, the Pod is restarted.
Run at least 2 replicas for every stateless service
A single replica means one crash = full outage. Always run at least 2.
spec:
replicas: 2 # Never 1 for production
Set a rolling update strategy with zero downtime
spec:
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 0 # Never remove a Pod before its replacement is ready
maxSurge: 1
Add a Pod Disruption Budget
Prevent cluster operations (node drains, upgrades) from taking down too many Pods at once.
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: myapp-pdb
spec:
minAvailable: 1 # At least 1 Pod must be running at all times
selector:
matchLabels:
app: myapp
Spread Pods across nodes (anti-affinity)
If all 3 replicas are on the same node and that node fails, your app is down.
spec:
affinity:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchLabels:
app: myapp
topologyKey: kubernetes.io/hostname
Networking
Use Gateway API (not Ingress) for new projects
ingress-nginx moved to maintenance mode in March 2026. Use Gateway API for all new projects.
See Kubernetes Tutorial #6: Ingress and Gateway API for migration and setup.
Enable TLS on your Gateway
All external traffic should use HTTPS. Configure TLS on the Gateway level:
spec:
listeners:
- name: https
protocol: HTTPS
port: 443
tls:
mode: Terminate
certificateRefs:
- name: myapp-tls
Apply Network Policies (default deny)
All Pods can talk to all Pods by default. Lock this down before going live.
# Start with deny-all
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-all
namespace: production
spec:
podSelector: {}
policyTypes:
- Ingress
- Egress
Then add explicit allow rules for each service.
Security
Run as non-root
securityContext:
runAsNonRoot: true
runAsUser: 1000
Read-only root filesystem
securityContext:
readOnlyRootFilesystem: true
If your app needs to write files, mount a specific emptyDir volume for that path.
Drop all Linux capabilities
securityContext:
capabilities:
drop:
- ALL
Disable privilege escalation
securityContext:
allowPrivilegeEscalation: false
Enforce Pod Security Standards on namespaces
kubectl label namespace production \
pod-security.kubernetes.io/enforce=restricted
Disable auto-mount of service account tokens
spec:
automountServiceAccountToken: false
Apply RBAC with least privilege
Create dedicated ServiceAccounts with minimal permissions for each component. See Kubernetes Tutorial #10: Security.
Use External Secrets Operator for secrets
Never commit plain Secret YAML to git. Use External Secrets Operator to sync from AWS Secrets Manager, HashiCorp Vault, or Azure Key Vault.
Scan images before deploying
trivy image --exit-code 1 --severity HIGH,CRITICAL myapp:1.0
Run this in CI before pushing to the registry. See Kubernetes Tutorial #9: CI/CD.
Storage
Use StatefulSets for databases
Databases need stable Pod names, ordered scaling, and unique storage per replica. Deployments do not provide this.
See Kubernetes Tutorial #5: Persistent Volumes.
Set reclaim policy to Retain for important data
kind: StorageClass
spec:
reclaimPolicy: Retain
With Delete policy, removing a PVC deletes the data permanently.
Set up Velero for cluster backups
Velero backs up Kubernetes resources and PersistentVolume data.
helm install velero vmware-tanzu/velero \
--namespace velero \
--set configuration.backupStorageLocation.bucket=my-backup-bucket
Schedule nightly backups:
velero schedule create daily-backup --schedule="0 2 * * *"
Configuration
Use namespaces for isolation
Do not run everything in the default namespace. Create separate namespaces per environment:
kubectl create namespace production
kubectl create namespace staging
kubectl create namespace monitoring
Apply ResourceQuotas per namespace
Prevent one team or service from consuming all cluster resources:
apiVersion: v1
kind: ResourceQuota
metadata:
name: production-quota
namespace: production
spec:
hard:
pods: "50"
requests.cpu: "10"
requests.memory: 20Gi
limits.cpu: "20"
limits.memory: 40Gi
Use ConfigMaps and Secrets — never hardcode values
Application config should be injected at runtime, not baked into the image. See Kubernetes Tutorial #4: ConfigMaps and Secrets.
Observability
Install Prometheus and Grafana
helm install prometheus prometheus-community/kube-prometheus-stack \
--namespace monitoring
Import the Kubernetes cluster dashboard (ID: 315) in Grafana immediately.
See Kubernetes Tutorial #8: Monitoring.
Set Prometheus retention limits
helm upgrade prometheus prometheus-community/kube-prometheus-stack \
--set prometheus.prometheusSpec.retention=30d \
--set prometheus.prometheusSpec.retentionSize=50GB
Create alerts for critical conditions
Minimum alerts to configure:
| Alert | Condition |
|---|---|
| Pod CrashLoop | Container restarts > 5 in 1 hour |
| Node NotReady | Node condition Ready == false |
| High error rate | HTTP 5xx rate > 5% |
| Disk full | PV usage > 85% |
| OOMKilled | Container memory limit hit |
Add application-level metrics
Expose a /metrics endpoint from your app. Add a ServiceMonitor so Prometheus scrapes it.
Autoscaling
Configure HPA for all stateless services
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
spec:
minReplicas: 2
maxReplicas: 20
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 60
Use VPA to right-size resource requests
Start with updateMode: "Off" to collect recommendations, then tune your requests accordingly.
Install KEDA for event-driven scaling
If you have background workers or queue consumers, use KEDA to scale to zero when idle.
See Kubernetes Tutorial #11: Autoscaling.
CI/CD
Use commit SHA as the image tag
IMAGE_TAG=${{ github.sha }}
Never use latest in production. You need to know exactly which code is running.
Wait for rollout to complete in CI
kubectl rollout status deployment/myapp --timeout=5m
Configure automatic rollback on failure
if ! kubectl rollout status deployment/myapp --timeout=5m; then
kubectl rollout undo deployment/myapp
exit 1
fi
See Kubernetes Tutorial #9: CI/CD.
Kubernetes Version Management
Stay within N-2 supported versions
Kubernetes supports the 3 most recent minor versions. Running an older version means no security patches.
Check your version:
kubectl version
Test upgrades on staging first
Never upgrade production Kubernetes directly. Always test the upgrade on a staging cluster first.
The upgrade path is sequential: 1.33 → 1.34 → 1.35. You cannot skip versions.
Final Pre-Production Check
Run these commands before going live:
# Check all Pods are running
kubectl get pods -A | grep -v Running | grep -v Completed
# Check resource usage
kubectl top nodes
kubectl top pods -A
# Check no Pods are in Pending state
kubectl get pods -A | grep Pending
# Verify HPAs are working
kubectl get hpa -A
# Verify Prometheus is scraping your app
kubectl port-forward -n monitoring svc/prometheus-kube-prometheus-prometheus 9090:9090
# Open http://localhost:9090/targets — your app should show as UP
# Check for security policy violations
kubectl get events -A | grep Warning
# Verify backups are configured
velero backup get
If all checks pass, you are ready.
Common Mistakes That Cause Production Incidents
Running databases on Kubernetes without StatefulSets, PVCs, and proper backup
A Deployment with no PVC will lose all database data on Pod restart. A StatefulSet with reclaimPolicy: Delete will lose data if someone deletes the PVC. Always use StatefulSets, Retain reclaim policy, and Velero backups.
No liveness/readiness probes
Kubernetes marks a Pod as ready as soon as the container starts. Without a readiness probe, the Pod receives traffic before it has finished starting up. Without a liveness probe, a stuck or deadlocked app will never restart.
Missing resource limits
One Pod using too much memory causes the node to run out. Kubernetes starts killing other Pods on the same node (OOMKilled). Always set limits.memory on every container.
Congratulations
You have completed the full Docker & Kubernetes Tutorial series.
You now know:
- Docker fundamentals and production image building
- Docker Compose for multi-container development
- Kubernetes architecture and core objects
- Persistent storage and stateful workloads
- Gateway API for production routing
- Helm for application packaging
- Prometheus and Grafana for monitoring
- GitHub Actions CI/CD pipeline
- Security hardening at every layer
- Autoscaling with HPA, VPA, and KEDA
- What it takes to run Kubernetes in production