Learning Kubernetes - Episode 26 - Introduction and Explanation of Deployment

Learning Kubernetes - Episode 26 - Introduction and Explanation of Deployment

In this episode, we'll discuss Kubernetes Deployment for managing application rollouts. We'll learn about rolling updates, rollbacks, scaling strategies, and best practices for production deployments.

Arman Dwi Pangestu
Arman Dwi PangestuApril 1, 2026
0 views
8 min read

Introduction

Note

If you want to read the previous episode, you can click the Episode 25 thumbnail below

Episode 25Episode 25

In the previous episode, we learned about managing Kubernetes objects using imperative and declarative approaches. In episode 26, we'll discuss Deployment, one of the most important Kubernetes resources for managing application rollouts and updates.

Note: Here I'll be using a Kubernetes Cluster installed through K3s.

Deployment provides declarative updates for Pods and ReplicaSets. It manages the entire lifecycle of your application, from initial deployment to updates and rollbacks, ensuring zero-downtime deployments.

What Is a Deployment?

A Deployment is a Kubernetes resource that manages a set of identical Pods, ensuring the desired number of Pods are running and handling updates gracefully.

Think of Deployment like a production manager - it ensures the right number of workers (Pods) are always available, replaces workers when they fail, and coordinates smooth transitions when you need to update your workforce.

Key characteristics of Deployment:

  • Declarative updates - Describe desired state, Kubernetes handles the rest
  • Rolling updates - Update Pods gradually without downtime
  • Rollback capability - Revert to previous versions easily
  • Scaling - Adjust number of replicas up or down
  • Self-healing - Automatically replaces failed Pods
  • Version history - Maintains revision history
  • Health checks - Ensures Pods are ready before routing traffic

Why Use Deployment?

Deployment solves several critical challenges:

  • Zero-downtime updates - Update applications without service interruption
  • Easy rollbacks - Quickly revert problematic updates
  • Automated scaling - Adjust capacity based on demand
  • Self-healing - Replace failed Pods automatically
  • Version control - Track deployment history
  • Gradual rollouts - Control update pace and strategy
  • Production-ready - Battle-tested for production workloads

Without Deployment, you would manually manage Pods, handle updates carefully to avoid downtime, and implement your own rollback mechanisms.

Creating a Deployment

Let's create a basic Deployment.

Basic Deployment

Kubernetesnginx-deployment.yml
apiVersion: apps/v1
kind: Deployment
metadata:
    name: nginx-deployment
    labels:
        app: nginx
spec:
    replicas: 3
    selector:
        matchLabels:
            app: nginx
    template:
        metadata:
            labels:
                app: nginx
        spec:
            containers:
                - name: nginx
                  image: nginx:1.25
                  ports:
                      - containerPort: 80

Apply the Deployment:

Kubernetesbash
sudo kubectl apply -f nginx-deployment.yml

Check Deployment status:

Kubernetesbash
sudo kubectl get deployments

Output:

Kubernetesbash
NAME               READY   UP-TO-DATE   AVAILABLE   AGE
nginx-deployment   3/3     3            3           30s

Check Pods created by Deployment:

Kubernetesbash
sudo kubectl get pods -l app=nginx

Deployment with Resource Limits

Kubernetesapp-deployment.yml
apiVersion: apps/v1
kind: Deployment
metadata:
    name: app-deployment
    labels:
        app: myapp
spec:
    replicas: 5
    selector:
        matchLabels:
            app: myapp
    template:
        metadata:
            labels:
                app: myapp
                version: v1.0
        spec:
            containers:
                - name: app
                  image: myapp:1.0
                  ports:
                      - containerPort: 8080
                  resources:
                      requests:
                          memory: "256Mi"
                          cpu: "250m"
                      limits:
                          memory: "512Mi"
                          cpu: "500m"
                  livenessProbe:
                      httpGet:
                          path: /health
                          port: 8080
                      initialDelaySeconds: 30
                      periodSeconds: 10
                  readinessProbe:
                      httpGet:
                          path: /ready
                          port: 8080
                      initialDelaySeconds: 5
                      periodSeconds: 5

Scaling Deployments

Adjust the number of replicas.

Manual Scaling

Using kubectl scale:

Kubernetesbash
sudo kubectl scale deployment nginx-deployment --replicas=5

Using kubectl apply:

Kubernetesnginx-deployment.yml
spec:
    replicas: 5  # Changed from 3 to 5
Kubernetesbash
sudo kubectl apply -f nginx-deployment.yml

Autoscaling

Use HorizontalPodAutoscaler for automatic scaling:

Kuberneteshpa.yml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
    name: nginx-hpa
spec:
    scaleTargetRef:
        apiVersion: apps/v1
        kind: Deployment
        name: nginx-deployment
    minReplicas: 3
    maxReplicas: 10
    metrics:
        - type: Resource
          resource:
              name: cpu
              target:
                  type: Utilization
                  averageUtilization: 70

Apply HPA:

Kubernetesbash
sudo kubectl apply -f hpa.yml

Check HPA status:

Kubernetesbash
sudo kubectl get hpa

Rolling Updates

Update Deployments without downtime.

Update Strategy

Deployment supports two update strategies:

RollingUpdate (default):

  • Updates Pods gradually
  • Maintains availability during update
  • Configurable with maxSurge and maxUnavailable

Recreate:

  • Terminates all Pods before creating new ones
  • Causes downtime
  • Useful for applications that can't run multiple versions

Rolling Update Configuration

Kubernetesdeployment-strategy.yml
apiVersion: apps/v1
kind: Deployment
metadata:
    name: app-deployment
spec:
    replicas: 10
    strategy:
        type: RollingUpdate
        rollingUpdate:
            maxSurge: 2        # Max 2 extra Pods during update
            maxUnavailable: 1  # Max 1 Pod unavailable during update
    selector:
        matchLabels:
            app: myapp
    template:
        metadata:
            labels:
                app: myapp
        spec:
            containers:
                - name: app
                  image: myapp:1.0
                  ports:
                      - containerPort: 8080

maxSurge: Maximum number of Pods that can be created above desired replicas maxUnavailable: Maximum number of Pods that can be unavailable during update

Performing a Rolling Update

Update image using kubectl set:

Kubernetesbash
sudo kubectl set image deployment/nginx-deployment nginx=nginx:1.26

Update using kubectl apply:

Kubernetesnginx-deployment.yml
# Change image version
containers:
    - name: nginx
      image: nginx:1.26  # Updated from 1.25
Kubernetesbash
sudo kubectl apply -f nginx-deployment.yml

Watch rollout progress:

Kubernetesbash
sudo kubectl rollout status deployment/nginx-deployment

Output:

Kubernetesbash
Waiting for deployment "nginx-deployment" rollout to finish: 1 out of 3 new replicas have been updated...
Waiting for deployment "nginx-deployment" rollout to finish: 2 out of 3 new replicas have been updated...
Waiting for deployment "nginx-deployment" rollout to finish: 1 old replicas are pending termination...
deployment "nginx-deployment" successfully rolled out

Rollback

Revert to a previous version.

View Rollout History

Kubernetesbash
sudo kubectl rollout history deployment/nginx-deployment

Output:

Kubernetesbash
deployment.apps/nginx-deployment
REVISION  CHANGE-CAUSE
1         <none>
2         <none>
3         kubectl set image deployment/nginx-deployment nginx=nginx:1.26

View Specific Revision

Kubernetesbash
sudo kubectl rollout history deployment/nginx-deployment --revision=2

Rollback to Previous Version

Kubernetesbash
sudo kubectl rollout undo deployment/nginx-deployment

Rollback to Specific Revision

Kubernetesbash
sudo kubectl rollout undo deployment/nginx-deployment --to-revision=2

Pause and Resume Rollout

Pause rollout:

Kubernetesbash
sudo kubectl rollout pause deployment/nginx-deployment

Make multiple changes:

Kubernetesbash
sudo kubectl set image deployment/nginx-deployment nginx=nginx:1.26
sudo kubectl set resources deployment/nginx-deployment -c=nginx --limits=cpu=500m,memory=512Mi

Resume rollout:

Kubernetesbash
sudo kubectl rollout resume deployment/nginx-deployment

Deployment Strategies

Different approaches for updating applications.

Rolling Update (Default)

Gradually replace old Pods with new ones:

Kubernetesrolling-update.yml
spec:
    strategy:
        type: RollingUpdate
        rollingUpdate:
            maxSurge: 25%
            maxUnavailable: 25%

Advantages:

  • Zero downtime
  • Gradual rollout
  • Easy rollback

Disadvantages:

  • Both versions run simultaneously
  • Slower than Recreate

Recreate

Terminate all Pods before creating new ones:

Kubernetesrecreate-strategy.yml
spec:
    strategy:
        type: Recreate

Advantages:

  • Simple and fast
  • Only one version runs at a time

Disadvantages:

  • Causes downtime
  • Not suitable for production

Blue-Green Deployment

Run two identical environments, switch traffic:

Kubernetesblue-green.yml
# Blue deployment (current)
apiVersion: apps/v1
kind: Deployment
metadata:
    name: app-blue
spec:
    replicas: 3
    selector:
        matchLabels:
            app: myapp
            version: blue
    template:
        metadata:
            labels:
                app: myapp
                version: blue
        spec:
            containers:
                - name: app
                  image: myapp:1.0
---
# Green deployment (new)
apiVersion: apps/v1
kind: Deployment
metadata:
    name: app-green
spec:
    replicas: 3
    selector:
        matchLabels:
            app: myapp
            version: green
    template:
        metadata:
            labels:
                app: myapp
                version: green
        spec:
            containers:
                - name: app
                  image: myapp:2.0
---
# Service (switch between blue and green)
apiVersion: v1
kind: Service
metadata:
    name: app-service
spec:
    selector:
        app: myapp
        version: blue  # Change to 'green' to switch
    ports:
        - port: 80
          targetPort: 8080

Canary Deployment

Gradually shift traffic to new version:

Kubernetescanary.yml
# Stable deployment (90% traffic)
apiVersion: apps/v1
kind: Deployment
metadata:
    name: app-stable
spec:
    replicas: 9
    selector:
        matchLabels:
            app: myapp
            track: stable
    template:
        metadata:
            labels:
                app: myapp
                track: stable
        spec:
            containers:
                - name: app
                  image: myapp:1.0
---
# Canary deployment (10% traffic)
apiVersion: apps/v1
kind: Deployment
metadata:
    name: app-canary
spec:
    replicas: 1
    selector:
        matchLabels:
            app: myapp
            track: canary
    template:
        metadata:
            labels:
                app: myapp
                track: canary
        spec:
            containers:
                - name: app
                  image: myapp:2.0
---
# Service (routes to both)
apiVersion: v1
kind: Service
metadata:
    name: app-service
spec:
    selector:
        app: myapp  # Matches both stable and canary
    ports:
        - port: 80
          targetPort: 8080

Practical Examples

Example 1: Production Web Application

Kubernetesweb-app-deployment.yml
apiVersion: apps/v1
kind: Deployment
metadata:
    name: web-app
    labels:
        app: web
        tier: frontend
spec:
    replicas: 5
    strategy:
        type: RollingUpdate
        rollingUpdate:
            maxSurge: 2
            maxUnavailable: 1
    selector:
        matchLabels:
            app: web
    template:
        metadata:
            labels:
                app: web
                version: v1.0
        spec:
            containers:
                - name: nginx
                  image: nginx:1.25
                  ports:
                      - containerPort: 80
                        name: http
                  resources:
                      requests:
                          memory: "128Mi"
                          cpu: "100m"
                      limits:
                          memory: "256Mi"
                          cpu: "200m"
                  livenessProbe:
                      httpGet:
                          path: /health
                          port: 80
                      initialDelaySeconds: 30
                      periodSeconds: 10
                      timeoutSeconds: 5
                      failureThreshold: 3
                  readinessProbe:
                      httpGet:
                          path: /ready
                          port: 80
                      initialDelaySeconds: 5
                      periodSeconds: 5
                      timeoutSeconds: 3
                      failureThreshold: 3
            affinity:
                podAntiAffinity:
                    preferredDuringSchedulingIgnoredDuringExecution:
                        - weight: 100
                          podAffinityTerm:
                              labelSelector:
                                  matchExpressions:
                                      - key: app
                                        operator: In
                                        values:
                                            - web
                              topologyKey: kubernetes.io/hostname

Example 2: Microservice with ConfigMap and Secret

Kubernetesmicroservice-deployment.yml
apiVersion: v1
kind: ConfigMap
metadata:
    name: api-config
data:
    LOG_LEVEL: "info"
    API_TIMEOUT: "30"
---
apiVersion: v1
kind: Secret
metadata:
    name: api-secrets
type: Opaque
stringData:
    DATABASE_PASSWORD: "secretpassword"
    API_KEY: "abc123xyz789"
---
apiVersion: apps/v1
kind: Deployment
metadata:
    name: api-service
spec:
    replicas: 3
    selector:
        matchLabels:
            app: api
    template:
        metadata:
            labels:
                app: api
        spec:
            containers:
                - name: api
                  image: myapi:latest
                  ports:
                      - containerPort: 8080
                  envFrom:
                      - configMapRef:
                            name: api-config
                      - secretRef:
                            name: api-secrets
                  resources:
                      requests:
                          memory: "256Mi"
                          cpu: "250m"
                      limits:
                          memory: "512Mi"
                          cpu: "500m"

Example 3: Multi-Container Deployment

Kubernetesmulti-container-deployment.yml
apiVersion: apps/v1
kind: Deployment
metadata:
    name: app-with-sidecar
spec:
    replicas: 3
    selector:
        matchLabels:
            app: myapp
    template:
        metadata:
            labels:
                app: myapp
        spec:
            containers:
                # Main application
                - name: app
                  image: myapp:latest
                  ports:
                      - containerPort: 8080
                  volumeMounts:
                      - name: logs
                        mountPath: /var/log/app
                # Log shipper sidecar
                - name: log-shipper
                  image: fluent/fluentd:v1.16
                  volumeMounts:
                      - name: logs
                        mountPath: /var/log/app
                        readOnly: true
            volumes:
                - name: logs
                  emptyDir: {}

Viewing Deployment Details

Get Deployments

Kubernetesbash
sudo kubectl get deployments
sudo kubectl get deployments -o wide

Describe Deployment

Kubernetesbash
sudo kubectl describe deployment nginx-deployment

View Deployment YAML

Kubernetesbash
sudo kubectl get deployment nginx-deployment -o yaml

Watch Deployment

Kubernetesbash
sudo kubectl get deployments --watch

Get ReplicaSets

Kubernetesbash
sudo kubectl get replicasets

Get Pods by Deployment

Kubernetesbash
sudo kubectl get pods -l app=nginx

Common Mistakes and Pitfalls

Mistake 1: No Resource Limits

Problem: Pods can consume unlimited resources.

Solution: Always set resource limits:

Kubernetesyml
resources:
    requests:
        memory: "256Mi"
        cpu: "250m"
    limits:
        memory: "512Mi"
        cpu: "500m"

Mistake 2: Missing Health Checks

Problem: Kubernetes routes traffic to unhealthy Pods.

Solution: Add liveness and readiness probes:

Kubernetesyml
livenessProbe:
    httpGet:
        path: /health
        port: 8080
readinessProbe:
    httpGet:
        path: /ready
        port: 8080

Mistake 3: Too Aggressive Rolling Update

Problem: Update happens too fast, causing issues.

Solution: Configure appropriate maxSurge and maxUnavailable:

Kubernetesyml
rollingUpdate:
    maxSurge: 1
    maxUnavailable: 0  # Ensures no downtime

Mistake 4: Not Testing Updates

Problem: Deploying untested changes to production.

Solution: Test in staging first:

Kubernetesbash
# Test in staging
sudo kubectl apply -f deployment.yml --namespace=staging
 
# After validation, deploy to production
sudo kubectl apply -f deployment.yml --namespace=production

Mistake 5: Ignoring Rollout Status

Problem: Not monitoring deployment progress.

Solution: Always check rollout status:

Kubernetesbash
sudo kubectl rollout status deployment/nginx-deployment

Best Practices

Use Declarative Configuration

Always use YAML files:

Kubernetesbash
# Good: Declarative
sudo kubectl apply -f deployment.yml
 
# Avoid: Imperative
sudo kubectl create deployment nginx --image=nginx:1.25

Set Appropriate Replica Count

Choose based on load and availability requirements:

Kubernetesyml
# Development: 1-2 replicas
replicas: 1
 
# Production: 3+ replicas for high availability
replicas: 5

Use Labels Effectively

Organize and select resources:

Kubernetesyml
metadata:
    labels:
        app: myapp
        version: v1.0
        environment: production
        tier: backend

Configure Update Strategy

Control rollout behavior:

Kubernetesyml
strategy:
    type: RollingUpdate
    rollingUpdate:
        maxSurge: 25%
        maxUnavailable: 25%

Add Annotations

Document deployment details:

Kubernetesyml
metadata:
    annotations:
        kubernetes.io/change-cause: "Update to version 1.26"
        description: "Production web server"
        owner: "platform-team"

Use Namespaces

Isolate environments:

Kubernetesyml
metadata:
    name: app-deployment
    namespace: production

Monitor Deployments

Set up monitoring and alerts:

Kubernetesbash
sudo kubectl get deployments --watch
sudo kubectl rollout status deployment/app

Troubleshooting Deployments

Check Deployment Status

Kubernetesbash
sudo kubectl get deployment nginx-deployment
sudo kubectl describe deployment nginx-deployment

Check ReplicaSet

Kubernetesbash
sudo kubectl get replicasets
sudo kubectl describe replicaset <replicaset-name>

Check Pods

Kubernetesbash
sudo kubectl get pods -l app=nginx
sudo kubectl describe pod <pod-name>
sudo kubectl logs <pod-name>

Check Events

Kubernetesbash
sudo kubectl get events --sort-by='.lastTimestamp'

Rollback if Needed

Kubernetesbash
sudo kubectl rollout undo deployment/nginx-deployment

Conclusion

In episode 26, we've explored Deployment in Kubernetes in depth. We've learned how to create Deployments, perform rolling updates, rollback changes, and implement different deployment strategies.

Key takeaways:

  • Deployment manages Pods and ReplicaSets declaratively
  • Provides zero-downtime updates with rolling updates
  • Easy rollback to previous versions
  • Scaling adjusts replica count up or down
  • Self-healing replaces failed Pods automatically
  • Two update strategies: RollingUpdate and Recreate
  • maxSurge and maxUnavailable control update pace
  • Rollout history tracks deployment revisions
  • Health checks ensure Pods are ready
  • Resource limits prevent resource exhaustion
  • Blue-green and canary strategies for advanced deployments
  • Always use declarative configuration files
  • Monitor rollout status during updates
  • Test in staging before production
  • Use labels for organization and selection

Deployment is the cornerstone of application management in Kubernetes. By understanding Deployments, you can confidently deploy, update, and manage applications in production with zero downtime and easy rollback capabilities.

Are you getting a clearer understanding of Deployment in Kubernetes? Keep your learning momentum going and look forward to the next episode!

Note

If you want to continue to the next episode, you can click the Episode 27 thumbnail below

Episode 27Episode 27

Related Posts