TL;DR

A Deployment manages ReplicaSets, and ReplicaSets manage Pods. Kubernetes native Deployments support RollingUpdate and Recreate; blue/green and canary are usually built with labels, Services, Ingress/service mesh routing, Helm, Argo Rollouts, or CI/CD automation.

How Deployments Work

A Deployment is a controller-managed desired state for stateless workloads. You describe the Pod template, replica count, and rollout behavior. When the Pod template changes, the Deployment creates a new ReplicaSet and scales old/new ReplicaSets according to the strategy.

Deployment replicas + template ReplicaSet v1 old Pod template ReplicaSet v2 new Pod template Pod Pod Pod Pod Pod A rollout is the Deployment scaling ReplicaSets up/down while preserving availability constraints.

Deployment creates and manages ReplicaSets; ReplicaSets create and manage Pods.

Daily Commands

bashdeployment-ops.sh
# Replace <namespace> and <deployment> before running.
kubectl get deployments -n <namespace> -o wide
kubectl describe deployment <deployment> -n <namespace>

# Show rollout progress and history.
kubectl rollout status deployment/<deployment> -n <namespace>
kubectl rollout history deployment/<deployment> -n <namespace>

# See ReplicaSets owned by the Deployment.
kubectl get rs -n <namespace> -l app=<app-label> -o wide

# Pause a rollout before multiple changes, then resume.
kubectl rollout pause deployment/<deployment> -n <namespace>
kubectl rollout resume deployment/<deployment> -n <namespace>

# Roll back to the previous revision.
kubectl rollout undo deployment/<deployment> -n <namespace>

# Roll back to a specific revision from rollout history.
kubectl rollout undo deployment/<deployment> -n <namespace> --to-revision=<revision-number>

Production Deployment YAML

This is a practical baseline for stateless web services. In real client environments, image, resources, probes, labels, security context, and annotations are usually driven by Helm values or GitOps manifests.

yamldeployment-production-baseline.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-api
  namespace: app
  labels:
    app: web-api # Stable app label used by Services, dashboards, alerts, and selectors.
spec:
  replicas: 4 # Desired Pod count. HPA may manage this if autoscaling is enabled.
  revisionHistoryLimit: 5 # Keeps old ReplicaSets for rollback without storing unlimited history.
  progressDeadlineSeconds: 600 # Rollout is marked failed if progress stalls beyond this time.
  minReadySeconds: 10 # Pod must be ready for this long before counted as available.
  strategy:
    type: RollingUpdate # Default strategy; gradually replaces old Pods.
    rollingUpdate:
      maxUnavailable: 1 # At most one desired replica unavailable during rollout.
      maxSurge: 1 # At most one extra Pod above desired replicas during rollout.
  selector:
    matchLabels:
      app: web-api # Must match template labels; immutable after creation.
  template:
    metadata:
      labels:
        app: web-api # Service selectors match this label.
        version: v1 # Useful for canary/blue-green routing and observability.
    spec:
      serviceAccountName: web-api # Use a named ServiceAccount, not default, when API access is needed.
      terminationGracePeriodSeconds: 30 # Time for graceful shutdown after SIGTERM.
      containers:
        - name: web-api
          image: registry.example.com/platform/web-api:1.0.0 # Prefer immutable tags or digests.
          imagePullPolicy: IfNotPresent
          ports:
            - name: http
              containerPort: 8080
          envFrom:
            - configMapRef:
                name: web-api-config # Non-sensitive configuration.
            - secretRef:
                name: web-api-secrets # Sensitive values such as passwords or tokens.
          startupProbe:
            httpGet:
              path: /health/startup
              port: http
            failureThreshold: 30
            periodSeconds: 2
          readinessProbe:
            httpGet:
              path: /health/ready # Controls whether this Pod receives Service traffic.
              port: http
            periodSeconds: 10
            timeoutSeconds: 2
            failureThreshold: 3
          livenessProbe:
            httpGet:
              path: /health/live # Keep liveness lightweight to avoid unnecessary restarts.
              port: http
            initialDelaySeconds: 20
            periodSeconds: 10
            timeoutSeconds: 2
          resources:
            requests:
              cpu: 250m # Scheduler reserves this amount.
              memory: 256Mi
            limits:
              cpu: 1 # CPU limit may throttle; tune using real metrics.
              memory: 512Mi # Exceeding this can cause OOMKilled.

Native Strategies

StrategyHow It WorksUse WhenTradeoff
RollingUpdateGradually scales up new ReplicaSet and scales down old ReplicaSet.Most stateless services.Old and new versions run together briefly.
RecreateDeletes old Pods before creating new Pods.Apps cannot run two versions at once.Causes downtime unless another layer absorbs it.

RollingUpdate Example

yamlrolling-update.yaml
strategy:
  type: RollingUpdate
  rollingUpdate:
    maxUnavailable: 25% # Percent or integer. Lower value protects availability.
    maxSurge: 25% # Extra Pods allowed during rollout. Needs spare cluster capacity.

Recreate Example

yamlrecreate.yaml
strategy:
  type: Recreate # Old Pods are terminated before new Pods are created.

Deployment Models

Kubernetes Deployments provide the primitives. Higher-level models are usually achieved by combining Deployments, labels, Services, Ingress, service mesh, CI/CD, Helm, or progressive delivery controllers.

ModelTraffic PatternTypical ImplementationBest For
RollingGradual replacementDeployment RollingUpdateDefault stateless app releases.
Blue/GreenSwitch all traffic from old to newTwo Deployments, one Service selector flipFast rollback and clean version separation.
CanarySmall percent to new versionTwo Deployments plus weighted routing or replica splitRisk-reduced releases with metrics validation.
ShadowCopy traffic to new version, do not return responseService mesh/Ingress/controller supportTesting behavior under real traffic safely.
A/BRoute by header/user/segmentIngress/service mesh/application gatewayProduct experiments and targeted releases.

Blue/Green Pattern

Blue/green keeps two versions live as separate Deployments. The Service points to one version using labels. Rollback is usually a Service selector flip.

yamlblue-green-service-switch.yaml
apiVersion: v1
kind: Service
metadata:
  name: web-api
  namespace: app
spec:
  selector:
    app: web-api
    slot: blue # Change to green to switch traffic.
  ports:
    - name: http
      port: 80
      targetPort: http
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-api-blue
  namespace: app
spec:
  replicas: 4
  selector:
    matchLabels:
      app: web-api
      slot: blue
  template:
    metadata:
      labels:
        app: web-api
        slot: blue
        version: v1
    spec:
      containers:
        - name: web-api
          image: registry.example.com/platform/web-api:1.0.0
          ports:
            - name: http
              containerPort: 8080
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-api-green
  namespace: app
spec:
  replicas: 4
  selector:
    matchLabels:
      app: web-api
      slot: green
  template:
    metadata:
      labels:
        app: web-api
        slot: green
        version: v2
    spec:
      containers:
        - name: web-api
          image: registry.example.com/platform/web-api:2.0.0
          ports:
            - name: http
              containerPort: 8080
bashblue-green-switch.sh
# Preview current endpoints before switching.
kubectl get endpointslice -n app -l kubernetes.io/service-name=web-api -o wide

# Switch Service traffic from blue to green.
kubectl patch service web-api -n app -p '{"spec":{"selector":{"app":"web-api","slot":"green"}}}'

# Roll back by switching selector back to blue.
kubectl patch service web-api -n app -p '{"spec":{"selector":{"app":"web-api","slot":"blue"}}}'

Canary Pattern

Basic Kubernetes canary can be done by running two Deployments with the same Service selector and different replica counts. This is approximate weighting because kube-proxy balances across endpoints, not exact percentages. For precise weights, use Ingress/service mesh or Argo Rollouts.

yamlsimple-canary.yaml
apiVersion: v1
kind: Service
metadata:
  name: web-api
  namespace: app
spec:
  selector:
    app: web-api # Both stable and canary Pods share this label.
  ports:
    - name: http
      port: 80
      targetPort: http
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-api-stable
  namespace: app
spec:
  replicas: 9 # About 90% of endpoints if canary has 1 replica.
  selector:
    matchLabels:
      app: web-api
      track: stable
  template:
    metadata:
      labels:
        app: web-api
        track: stable
        version: v1
    spec:
      containers:
        - name: web-api
          image: registry.example.com/platform/web-api:1.0.0
          ports:
            - name: http
              containerPort: 8080
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-api-canary
  namespace: app
spec:
  replicas: 1 # About 10% of endpoints when stable has 9 replicas.
  selector:
    matchLabels:
      app: web-api
      track: canary
  template:
    metadata:
      labels:
        app: web-api
        track: canary
        version: v2
    spec:
      containers:
        - name: web-api
          image: registry.example.com/platform/web-api:2.0.0
          ports:
            - name: http
              containerPort: 8080

Rollout Failure Debugging

bashrollout-debug.sh
# Check if rollout is stuck.
kubectl rollout status deployment/<deployment> -n <namespace> --timeout=60s

# Describe Deployment for Progressing/Available conditions and events.
kubectl describe deployment <deployment> -n <namespace>

# Compare old and new ReplicaSets.
kubectl get rs -n <namespace> -l app=<app-label> -o wide

# Check new Pods for image, scheduling, probe, config, or crash problems.
kubectl get pods -n <namespace> -l app=<app-label> -o wide
kubectl describe pod <new-pod-name> -n <namespace>
kubectl logs <new-pod-name> -n <namespace> --previous --tail=100

# Stop a bad rollout quickly.
kubectl rollout undo deployment/<deployment> -n <namespace>

HPA And PDB

Deployments often interact with HorizontalPodAutoscalers and PodDisruptionBudgets. HPA changes replica count based on metrics. PDB protects minimum availability during voluntary disruptions such as node drains.

yamlhpa-pdb.yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: web-api
  namespace: app
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: web-api # HPA adjusts .spec.replicas on this Deployment.
  minReplicas: 4
  maxReplicas: 20
  metrics:
    - type: Resource
      resource:
        name: cpu
        target:
          type: Utilization
          averageUtilization: 60 # Target average CPU usage across Pods.
---
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
  name: web-api
  namespace: app
spec:
  minAvailable: 3 # At least 3 matching Pods must remain available during voluntary disruption.
  selector:
    matchLabels:
      app: web-api

GitOps And Helm Notes

  • In GitOps clusters, update the manifest, Helm values, or Kustomize overlay in Git; do not rely on long-lived manual kubectl set image changes.
  • Use kubectl diff -f, helm template, helm diff, or ArgoCD app diff before rollout when possible.
  • Keep selectors stable. Changing spec.selector on a Deployment is not allowed and usually indicates a label design problem.
  • Use immutable image tags or digests so rollback points are reliable.

Common Gotchas

  • !Selector mismatch: Deployment selector must match Pod template labels. Bad labels can create orphaned or unmanaged Pods.
  • !Readiness blocks rollout: new Pods may run but never become available, causing rollout progress to stall.
  • !maxUnavailable too high: can drop capacity during rollout. Lower it for critical services.
  • !HPA and manual scaling: manual replica changes may be overwritten by HPA.
  • !Blue/green selector flip: validate the target Deployment is Ready before switching Service selectors.