DEV Community

janak0ff
janak0ff

Posted on

KodeKloud Level 1 - Kubernetes - Deploy Applications with Kubernetes Deployments

The Nautilus DevOps team is delving into Kubernetes for app management. One team member needs to create a deployment following these details:

Create a deployment named nginx to deploy the application nginx using the image nginx:latest (ensure to specify the tag)

Note: The kubectl utility on the jump-host has been configured to work with the Kubernetes cluster.


Deploy Applications with Kubernetes Deployments: A Complete Guide

Introduction

Kubernetes has become the de facto standard for container orchestration, and Deployments are one of its most powerful and essential resources. In this comprehensive guide, we'll explore how to deploy applications using Kubernetes Deployments, covering everything from basic concepts to advanced strategies used in production environments.

Whether you're preparing for the CKA certification, managing applications in production, or just starting your Kubernetes journey, this guide will provide you with the knowledge and hands-on experience needed to master Kubernetes Deployments.


What are Kubernetes Deployments?

A Deployment is a Kubernetes resource that provides declarative updates for Pods and ReplicaSets. Think of it as a higher-level concept that manages the lifecycle of your application instances, ensuring that the desired state of your application matches the actual state in the cluster.

Key Features of Deployments:

  • Declarative Updates: Define the desired state, and Kubernetes handles the rest
  • Rolling Updates: Zero-downtime updates with controlled rollout strategies
  • Rollbacks: Easy revert to previous versions if something goes wrong
  • Scaling: Simple horizontal scaling with a single command
  • Self-Healing: Automatically replaces failed or unhealthy pods
  • History & Auditing: Track deployment revisions and changes

Understanding the Architecture

Deployment Components

┌─────────────────────────────────────────┐
│         Deployment (nginx)              │
│  - Desired Replicas: 3                  │
│  - Update Strategy: RollingUpdate       │
│  - Selector: app=nginx                  │
└──────────────┬──────────────────────────┘
               │
               ▼
┌─────────────────────────────────────────┐
│       ReplicaSet (nginx-7c5d8bf9f7)    │
│  - Current Replicas: 3                  │
│  - Ready Replicas: 3                    │
│  - Owner: Deployment                    │
└──────────────┬──────────────────────────┘
               │
     ┌─────────┼─────────┐
     │         │         │
     ▼         ▼         ▼
┌────────┐┌────────┐┌────────┐
│  Pod 1 ││  Pod 2 ││  Pod 3 │
│        ││        ││        │
│ nginx  ││ nginx  ││ nginx  │
└────────┘└────────┘└────────┘
Enter fullscreen mode Exit fullscreen mode

Relationship Between Resources

  1. Deployment → Manages ReplicaSets
  2. ReplicaSet → Manages Pods
  3. Pods → Run the actual container(s)

Creating Your First Deployment

Method 1: Imperative Command

The quickest way to create a deployment:

kubectl create deployment nginx --image=nginx:latest
Enter fullscreen mode Exit fullscreen mode

Method 2: Declarative YAML (Recommended)

Generate the YAML first:

kubectl create deployment nginx \
  --image=nginx:latest \
  --dry-run=client -o yaml > nginx-deployment.yaml
Enter fullscreen mode Exit fullscreen mode

Then apply it:

kubectl apply -f nginx-deployment.yaml
Enter fullscreen mode Exit fullscreen mode

Method 3: Complete YAML Manifest

Here's a complete deployment manifest with all configurations:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
  namespace: production
  labels:
    app: nginx
    environment: production
    version: "1.0"
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
      environment: production
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 0
  revisionHistoryLimit: 10
  paused: false
  progressDeadlineSeconds: 600
  template:
    metadata:
      labels:
        app: nginx
        environment: production
        version: "1.0"
    spec:
      containers:
      - name: nginx
        image: nginx:1.21.6
        ports:
        - containerPort: 80
          name: http
          protocol: TCP
        env:
        - name: ENVIRONMENT
          value: "production"
        - name: NGINX_VERSION
          value: "1.21.6"
        resources:
          requests:
            memory: "64Mi"
            cpu: "250m"
          limits:
            memory: "128Mi"
            cpu: "500m"
        livenessProbe:
          httpGet:
            path: /
            port: 80
          initialDelaySeconds: 30
          periodSeconds: 10
          timeoutSeconds: 5
          successThreshold: 1
          failureThreshold: 3
        readinessProbe:
          httpGet:
            path: /
            port: 80
          initialDelaySeconds: 10
          periodSeconds: 5
          timeoutSeconds: 3
          successThreshold: 1
          failureThreshold: 3
        startupProbe:
          httpGet:
            path: /
            port: 80
          initialDelaySeconds: 5
          periodSeconds: 5
          failureThreshold: 30
      imagePullSecrets:
      - name: registry-credentials
      restartPolicy: Always
      terminationGracePeriodSeconds: 30
Enter fullscreen mode Exit fullscreen mode

Understanding Each Section

1. API Version and Kind

apiVersion: apps/v1
kind: Deployment
Enter fullscreen mode Exit fullscreen mode
  • apps/v1 is the stable API version for Deployments
  • Kind defines the resource type

2. Metadata

metadata:
  name: nginx
  namespace: production
  labels:
    app: nginx
Enter fullscreen mode Exit fullscreen mode
  • name: Unique identifier for the deployment
  • namespace: Logical grouping (defaults to "default")
  • labels: Key-value pairs for organization and selection

3. Spec Section

spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
Enter fullscreen mode Exit fullscreen mode
  • replicas: Number of desired pod instances
  • selector: How the deployment finds its pods

4. Pod Template

template:
  metadata:
    labels:
      app: nginx
  spec:
    containers:
    - name: nginx
      image: nginx:1.21.6
Enter fullscreen mode Exit fullscreen mode
  • Defines the blueprint for pods
  • Contains container specifications

5. Update Strategy

strategy:
  type: RollingUpdate
  rollingUpdate:
    maxSurge: 1
    maxUnavailable: 0
Enter fullscreen mode Exit fullscreen mode
  • Recreate: Delete all pods, then recreate
  • RollingUpdate: Gradually replace pods

Common Operations

1. Viewing Deployments

# List all deployments
kubectl get deployments

# Get detailed info
kubectl describe deployment nginx

# Get deployment status
kubectl rollout status deployment nginx

# Show deployment YAML
kubectl get deployment nginx -o yaml

# Get deployment in JSON
kubectl get deployment nginx -o json

# Show deployment with additional information
kubectl get deployment nginx -o wide
Enter fullscreen mode Exit fullscreen mode

2. Scaling

# Scale to 5 replicas
kubectl scale deployment nginx --replicas=5

# Scale using YAML
kubectl patch deployment nginx -p '{"spec":{"replicas":5}}'

# Scale based on load (using HPA - Horizontal Pod Autoscaler)
kubectl autoscale deployment nginx --min=3 --max=10 --cpu-percent=80
Enter fullscreen mode Exit fullscreen mode

3. Updating Applications

# Update image
kubectl set image deployment/nginx nginx=nginx:1.22.0

# Update multiple images
kubectl set image deployment/nginx nginx=nginx:1.22.0 sidecar=sidecar:2.0

# Update environment variables
kubectl set env deployment/nginx ENVIRONMENT=staging

# Update resources
kubectl set resources deployment/nginx -c=nginx --limits=cpu=500m,memory=256Mi

# Update all containers at once
kubectl patch deployment nginx -p '{"spec":{"template":{"spec":{"containers":[{"name":"nginx","image":"nginx:1.22.0"}]}}}}'
Enter fullscreen mode Exit fullscreen mode

4. Rollbacks

# View rollout history
kubectl rollout history deployment nginx

# View specific revision
kubectl rollout history deployment nginx --revision=2

# Rollback to previous version
kubectl rollout undo deployment nginx

# Rollback to specific revision
kubectl rollout undo deployment nginx --to-revision=2

# Pause and resume rollout
kubectl rollout pause deployment nginx
kubectl rollout resume deployment nginx
Enter fullscreen mode Exit fullscreen mode

5. Deleting

# Delete deployment
kubectl delete deployment nginx

# Delete using YAML
kubectl delete -f nginx-deployment.yaml

# Delete with force
kubectl delete deployment nginx --force --grace-period=0
Enter fullscreen mode Exit fullscreen mode

Advanced Deployment Strategies

1. Rolling Update Strategy

The default strategy that provides zero-downtime updates:

strategy:
  type: RollingUpdate
  rollingUpdate:
    maxSurge: 25%          # Maximum extra pods allowed during update
    maxUnavailable: 25%    # Maximum unavailable pods during update
Enter fullscreen mode Exit fullscreen mode

How it works:

  • Gradually replaces old pods with new ones
  • Ensures application availability during updates
  • Configurable speed with maxSurge and maxUnavailable

2. Recreate Strategy

Simple strategy that replaces all pods at once:

strategy:
  type: Recreate
Enter fullscreen mode Exit fullscreen mode

When to use:

  • Applications that don't support multiple versions simultaneously
  • When downtime is acceptable
  • Stateful applications with database migrations

3. Blue-Green Deployment

Not native to Kubernetes but can be implemented with Deployments:

# Blue (current) deployment
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-blue
  labels:
    app: nginx
    version: blue
# ... rest of config

---
# Green (new) deployment
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-green
  labels:
    app: nginx
    version: green
# ... rest of config
Enter fullscreen mode Exit fullscreen mode

4. Canary Deployment

Gradually roll out to a subset of users:

# Main deployment
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
  labels:
    app: nginx
spec:
  replicas: 9
  # ... rest of config

---
# Canary deployment (10% of traffic)
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-canary
  labels:
    app: nginx
    version: canary
spec:
  replicas: 1
  # ... rest of config
Enter fullscreen mode Exit fullscreen mode

Health Checks and Probes

Types of Probes

  1. Liveness Probe: Checks if the container is still running
  2. Readiness Probe: Checks if the container is ready to serve traffic
  3. Startup Probe: Checks if the application has started (for slow-starting apps)

Probe Configuration Examples

# HTTP Get Probe
livenessProbe:
  httpGet:
    path: /health
    port: 8080
    httpHeaders:
    - name: Custom-Header
      value: Awesome
  initialDelaySeconds: 15
  periodSeconds: 20
  timeoutSeconds: 5
  successThreshold: 1
  failureThreshold: 3

# TCP Socket Probe
readinessProbe:
  tcpSocket:
    port: 8080
  initialDelaySeconds: 5
  periodSeconds: 10

# Command Probe
startupProbe:
  exec:
    command:
    - cat
    - /tmp/healthy
  initialDelaySeconds: 5
  periodSeconds: 5
  failureThreshold: 30
Enter fullscreen mode Exit fullscreen mode

Resource Management

CPU and Memory Limits

resources:
  requests:
    memory: "128Mi"
    cpu: "250m"
  limits:
    memory: "256Mi"
    cpu: "500m"
Enter fullscreen mode Exit fullscreen mode

Understanding:

  • requests: Minimum guaranteed resources
  • limits: Maximum resources allowed
  • cpu: Measured in millicores (1000m = 1 CPU core)
  • memory: Measured in Mi (Mebibytes) or Gi

Quality of Service (QoS) Classes

  1. Guaranteed: When requests = limits for all resources
  2. Burstable: When requests < limits
  3. BestEffort: No requests or limits set

Monitoring and Debugging

1. Viewing Logs

# Logs from a specific pod
kubectl logs nginx-7c5d8bf9f7-nb2sz

# Logs from all pods in deployment
kubectl logs deployment/nginx

# Follow logs
kubectl logs -f deployment/nginx

# Previous container logs (if crashed)
kubectl logs nginx-7c5d8bf9f7-nb2sz --previous
Enter fullscreen mode Exit fullscreen mode

2. Executing Commands

# Execute command in pod
kubectl exec -it nginx-7c5d8bf9f7-nb2sz -- /bin/bash

# Run a single command
kubectl exec nginx-7c5d8bf9f7-nb2sz -- ls -la /usr/share/nginx/html

# Copy files to/from pod
kubectl cp nginx-7c5d8bf9f7-nb2sz:/var/log/nginx/access.log access.log
Enter fullscreen mode Exit fullscreen mode

3. Checking Events

# All events
kubectl get events

# Events for specific deployment
kubectl get events --field-selector involvedObject.name=nginx

# Sort events by time
kubectl get events --sort-by='.lastTimestamp'
Enter fullscreen mode Exit fullscreen mode

4. Troubleshooting Pods

# Detailed pod description
kubectl describe pod nginx-7c5d8bf9f7-nb2sz

# Check pod status
kubectl get pod nginx-7c5d8bf9f7-nb2sz -o yaml

# Check pod logs
kubectl logs nginx-7c5d8bf9f7-nb2sz

# Check pod events
kubectl get events --field-selector involvedObject.name=nginx-7c5d8bf9f7-nb2sz
Enter fullscreen mode Exit fullscreen mode

Best Practices

✅ DO's

  1. Use Declarative Manifests

    • Version control your YAML files
    • Enable audit trail and rollback capability
  2. Pin Image Versions

    • Avoid :latest in production
    • Use semantic versioning or commit hashes
  3. Set Resource Limits

    • Prevent resource exhaustion
    • Ensure QoS class assignment
  4. Add Health Checks

    • Implement liveness and readiness probes
    • Use startup probes for slow-starting apps
  5. Use Multiple Replicas

    • Ensure high availability
    • Enable rolling updates
  6. Implement Monitoring

    • Set up logging and metrics
    • Use monitoring tools like Prometheus
  7. Use Namespaces

    • Organize deployments logically
    • Implement RBAC and resource quotas
  8. Implement Security

    • Use ServiceAccounts with minimal permissions
    • Set security contexts
    • Use image pull secrets for private registries

❌ DON'Ts

  1. Don't use :latest in production - Unpredictable updates
  2. Don't ignore resource limits - Can crash the cluster
  3. Don't skip health checks - Missing self-healing
  4. Don't use single replicas - Single point of failure
  5. Don't delete pods directly - Let the deployment manage them
  6. Don't make direct updates to pods - Use the deployment
  7. Don't store secrets in manifests - Use Kubernetes secrets
  8. Don't run as root - Use security contexts

Production-Ready Example

Here's a complete production-ready deployment:

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-app
  namespace: production
  labels:
    app: web-app
    environment: production
    tier: frontend
    version: v1.2.3
  annotations:
    kubernetes.io/change-cause: "Updated to v1.2.3 with security patches"
    prometheus.io/scrape: "true"
    prometheus.io/port: "8080"
spec:
  replicas: 5
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 0
  selector:
    matchLabels:
      app: web-app
  revisionHistoryLimit: 10
  progressDeadlineSeconds: 600
  template:
    metadata:
      labels:
        app: web-app
        environment: production
        tier: frontend
        version: v1.2.3
    spec:
      containers:
      - name: web-app
        image: registry.example.com/web-app:v1.2.3
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 8080
          name: http
          protocol: TCP
        env:
        - name: ENVIRONMENT
          value: "production"
        - name: LOG_LEVEL
          value: "info"
        - name: DATABASE_URL
          valueFrom:
            secretKeyRef:
              name: db-secrets
              key: url
        - name: REDIS_HOST
          valueFrom:
            configMapKeyRef:
              name: app-config
              key: redis_host
        resources:
          requests:
            memory: "128Mi"
            cpu: "250m"
          limits:
            memory: "512Mi"
            cpu: "1000m"
        livenessProbe:
          httpGet:
            path: /health/live
            port: 8080
          initialDelaySeconds: 30
          periodSeconds: 10
          timeoutSeconds: 5
          failureThreshold: 3
        readinessProbe:
          httpGet:
            path: /health/ready
            port: 8080
          initialDelaySeconds: 15
          periodSeconds: 5
          timeoutSeconds: 3
          successThreshold: 1
          failureThreshold: 3
        startupProbe:
          httpGet:
            path: /health/startup
            port: 8080
          initialDelaySeconds: 5
          periodSeconds: 5
          failureThreshold: 30
        volumeMounts:
        - name: app-data
          mountPath: /data
        - name: app-config
          mountPath: /etc/config
        securityContext:
          runAsUser: 1000
          runAsGroup: 1000
          capabilities:
            drop:
            - ALL
            add:
            - NET_BIND_SERVICE
      volumes:
      - name: app-data
        persistentVolumeClaim:
          claimName: app-data-pvc
      - name: app-config
        configMap:
          name: app-config
      imagePullSecrets:
      - name: registry-credentials
      restartPolicy: Always
      terminationGracePeriodSeconds: 60
      securityContext:
        fsGroup: 1000
        runAsNonRoot: true
      serviceAccountName: web-app-sa
      nodeSelector:
        node-type: application
      tolerations:
      - key: "critical"
        operator: "Equal"
        value: "true"
        effect: "NoSchedule"
      affinity:
        podAntiAffinity:
          preferredDuringSchedulingIgnoredDuringExecution:
          - weight: 100
            podAffinityTerm:
              labelSelector:
                matchExpressions:
                - key: app
                  operator: In
                  values:
                  - web-app
              topologyKey: kubernetes.io/hostname
Enter fullscreen mode Exit fullscreen mode

Common Error Scenarios and Solutions

1. ImagePullBackOff

Error: Pod stuck in ImagePullBackOff
Solution:

# Check image name and tag
kubectl describe pod -l app=nginx | grep Image

# Fix by updating image
kubectl set image deployment/nginx nginx=nginx:1.21.6
Enter fullscreen mode Exit fullscreen mode

2. CrashLoopBackOff

Error: Pod constantly crashing
Solution:

# Check logs
kubectl logs deployment/nginx --previous

# Check events
kubectl describe pod -l app=nginx | grep -A 10 Events
Enter fullscreen mode Exit fullscreen mode

3. Deployment Stuck

Error: Deployment progress is stuck
Solution:

# Check rollout status
kubectl rollout status deployment nginx

# Check events
kubectl get events --field-selector involvedObject.name=nginx

# Restart deployment
kubectl rollout restart deployment nginx
Enter fullscreen mode Exit fullscreen mode

4. Insufficient Resources

Error: Pods pending due to resource constraints
Solution:

# Check node resources
kubectl describe nodes

# Reduce resource requests
kubectl patch deployment nginx -p '{"spec":{"template":{"spec":{"containers":[{"name":"nginx","resources":{"requests":{"cpu":"100m","memory":"64Mi"}}}]}}}}'
Enter fullscreen mode Exit fullscreen mode

Integration with Other Kubernetes Resources

1. Service

apiVersion: v1
kind: Service
metadata:
  name: nginx-service
spec:
  selector:
    app: nginx
  ports:
  - port: 80
    targetPort: 80
  type: ClusterIP
Enter fullscreen mode Exit fullscreen mode

2. ConfigMap

apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-config
data:
  nginx.conf: |
    server {
      listen 80;
      server_name example.com;
      location / {
        root /usr/share/nginx/html;
        index index.html;
      }
    }
Enter fullscreen mode Exit fullscreen mode

3. Secret

apiVersion: v1
kind: Secret
metadata:
  name: nginx-secrets
type: Opaque
data:
  username: dXNlcm5hbWU=  # base64 encoded
  password: cGFzc3dvcmQ=  # base64 encoded
Enter fullscreen mode Exit fullscreen mode

4. Ingress

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: nginx-ingress
spec:
  rules:
  - host: nginx.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: nginx-service
            port:
              number: 80
Enter fullscreen mode Exit fullscreen mode

CI/CD Integration

Example GitLab CI Pipeline

stages:
  - build
  - deploy

variables:
  IMAGE_TAG: $CI_COMMIT_SHORT_SHA
  K8S_NAMESPACE: production

build:
  stage: build
  script:
    - docker build -t $CI_REGISTRY_IMAGE:$IMAGE_TAG .
    - docker push $CI_REGISTRY_IMAGE:$IMAGE_TAG

deploy:
  stage: deploy
  script:
    - kubectl set image deployment/web-app web-app=$CI_REGISTRY_IMAGE:$IMAGE_TAG
    - kubectl rollout status deployment/web-app
  only:
    - main
Enter fullscreen mode Exit fullscreen mode

Monitoring with Prometheus/Grafana

ServiceMonitor for Prometheus

apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  name: nginx-monitor
  namespace: production
spec:
  selector:
    matchLabels:
      app: nginx
  endpoints:
  - port: metrics
    path: /metrics
    interval: 30s
Enter fullscreen mode Exit fullscreen mode

Conclusion

Kubernetes Deployments are the backbone of modern application deployment strategies. They provide the control, flexibility, and reliability needed for production-grade applications. In this guide, we've covered:

  • ✅ Understanding Deployment architecture and components
  • ✅ Creating and managing Deployments
  • ✅ Implementing different update strategies
  • ✅ Configuring health checks and resource management
  • ✅ Best practices for production environments
  • ✅ Troubleshooting common issues
  • ✅ Integrating with other Kubernetes resources
  • ✅ CI/CD automation

Key Takeaways

  1. Always use declarative YAML manifests for reproducibility
  2. Implement health checks for self-healing applications
  3. Use rolling updates for zero-downtime deployments
  4. Set resource limits to prevent resource exhaustion
  5. Pin image versions for predictable deployments
  6. Monitor your deployments for proactive maintenance
  7. Implement proper security practices from the start

Next Steps

Now that you've mastered Kubernetes Deployments, consider exploring:

  1. Horizontal Pod Autoscaler (HPA) - Automatic scaling based on metrics
  2. Vertical Pod Autoscaler (VPA) - Automatic resource adjustment
  3. Helm Charts - Package management for Kubernetes
  4. Kustomize - Template-free configuration management
  5. GitOps - Git as the source of truth for infrastructure
  6. Service Mesh - Advanced networking and security features
  7. Pod Disruption Budgets - Ensuring application availability during maintenance

Resources


Top comments (0)