Deploying to Kubernetes

Deployment Workflow

Deploying applications to Kubernetes involves preparing container images, creating deployment manifests, and managing the deployment lifecycle. Understanding this process is crucial for reliable production deployments.

Why this matters: Improper deployment practices lead to downtime, data loss, or performance issues. Kubernetes provides mechanisms for rolling updates, canary deployments, and automatic rollbacks to prevent these problems.


Building and Pushing Images

graph LR A["Source Code"] -->B["Build Image
docker build"] B -->C["Tag Image
registry/app:v1.0"] C -->D["Push to Registry
docker push"] D -->E["Kubernetes
Pulls Image"] style D fill:#e1f5ff style E fill:#fff3e0
# Build image docker build -t myregistry.azurecr.io/myapp:v1.0 . # Push to registry docker push myregistry.azurecr.io/myapp:v1.0

Why private registries: Kubernetes pulls images from registries. Using private registries ensures only authorized images run in production and provides security scanning capabilities.


Creating Deployment Manifests

A complete deployment manifest defines the application, resources, networking, and policies.

apiVersion: apps/v1 kind: Deployment metadata: name: api-server labels: app: api version: v1 spec: replicas: 3 strategy: type: RollingUpdate rollingUpdate: maxSurge: 1 maxUnavailable: 0 selector: matchLabels: app: api template: metadata: labels: app: api spec: containers: - name: api image: myregistry.azurecr.io/api:v1.0 imagePullPolicy: IfNotPresent ports: - containerPort: 5000 name: http resources: requests: memory: "256Mi" cpu: "250m" limits: memory: "512Mi" cpu: "500m" livenessProbe: httpGet: path: /health port: 5000 initialDelaySeconds: 10 periodSeconds: 10 readinessProbe: httpGet: path: /ready port: 5000 initialDelaySeconds: 5 periodSeconds: 5

Key fields:


Rolling Updates

Why rolling updates matter: Updating all pods simultaneously causes downtime. Rolling updates gradually replace old pods with new versions, maintaining availability.

# Update image version kubectl set image deployment/api-server api=myregistry.azurecr.io/api:v1.1 # Monitor rollout progress kubectl rollout status deployment/api-server # View rollout history kubectl rollout history deployment/api-server # Rollback if issues detected kubectl rollout undo deployment/api-server

Control update behavior:

strategy: type: RollingUpdate rollingUpdate: maxSurge: 1 # One extra pod during update maxUnavailable: 0 # Never remove pods (maintain availability)

Canary Deployments

Deploy new version to small subset of traffic first, gradually increasing if stable.

# Version 1 (current production) apiVersion: apps/v1 kind: Deployment metadata: name: api-v1 spec: replicas: 9 template: metadata: labels: app: api version: v1 spec: containers: - name: api image: myregistry.azurecr.io/api:v1.0 --- # Version 2 (canary - 10% of traffic) apiVersion: apps/v1 kind: Deployment metadata: name: api-v2 spec: replicas: 1 template: metadata: labels: app: api version: v2 spec: containers: - name: api image: myregistry.azurecr.io/api:v2.0

Both deployments use the same service selector app: api, so the service load balances between both versions. Monitor v2 for errors. If stable, increase v2 replicas and decrease v1.

Why canary deployments: Limit blast radius of bugs. If new version has issues, only small user subset is affected.


Environment Configuration

Use ConfigMaps and Secrets for different environments without changing images.

# ConfigMap for development apiVersion: v1 kind: ConfigMap metadata: name: app-config namespace: development data: LOG_LEVEL: "DEBUG" DATABASE_URL: "postgres://dev-db:5432/myapp" --- # ConfigMap for production apiVersion: v1 kind: ConfigMap metadata: name: app-config namespace: production data: LOG_LEVEL: "INFO" DATABASE_URL: "postgres://prod-db:5432/myapp"

Use in deployment:

envFrom: - configMapRef: name: app-config

Why ConfigMaps: Build once, deploy anywhere. Same image runs in dev, staging, and production with different configurations.


Blue-Green Deployments

Run two complete production versions simultaneously. Switch traffic between them instantly.

# Deploy new version (green) kubectl apply -f deployment-green.yaml # Both versions running kubectl get deployment # blue-deployment 3/3 # green-deployment 3/3 # Test green version kubectl port-forward svc/green-service 8080:80 # Switch traffic kubectl patch service api-service -p '{"spec":{"selector":{"version":"green"}}}' # or shorter: kubectl patch svc api-service -p '{"spec":{"selector":{"version":"green"}}}' # Keep blue for instant rollback if needed # Switch back: kubectl patch service api-service -p '{"spec":{"selector":{"version":"blue"}}}'

Why blue-green: Zero-downtime deployments with instant rollback capability.


Deployment Checklist

# 1. Build and test image locally docker build -t myapp:v1.0 . docker run myapp:v1.0 # 2. Push to registry docker push myregistry.azurecr.io/myapp:v1.0 # 3. Update deployment manifest # - Update image tag # - Verify resource limits # - Check health probes # 4. Deploy to staging first kubectl apply -f deployment.yaml -n staging # 5. Verify staging deployment kubectl rollout status deployment/myapp -n staging # or shorter: kubectl rollout status deploy/myapp -n staging # 6. Test staging version thoroughly # 7. Deploy to production kubectl apply -f deployment.yaml -n production # 8. Monitor rollout kubectl rollout status deployment/myapp -n production # or shorter: kubectl rollout status deploy/myapp -n production # 9. Monitor metrics and logs kubectl logs -f deployment/myapp -n production # or shorter: kubectl logs -f deploy/myapp -n production

Common Pitfalls


Key Takeaways

Next Steps: Create deployment manifests for applications, practice rolling updates on test cluster, implement canary deployments for safer production changes.