Kubernetes Pods, Deployments, and Services 2025 — Deep Dive with Examples

Sanjeev SharmaSanjeev Sharma
7 min read

Advertisement

Introduction

Why This Matters

Pods, Deployments, and Services are the three most fundamental Kubernetes resources. Every production workload you run on Kubernetes — whether it is a REST API, a background worker, or a batch job — is built on top of these primitives. Engineers who understand exactly how these objects relate to each other, how rolling updates work, and how service discovery resolves container addresses debug production issues in minutes rather than hours.

Most Kubernetes tutorials show you how to create a Pod. Production Kubernetes requires knowing why bare Pods are dangerous, how Deployment rollout strategies prevent downtime, and why readiness probes are not optional.

Pods — The Atomic Unit

A Pod is a group of one or more containers that always run on the same node and share network and storage namespaces. Containers in the same Pod communicate over localhost.

apiVersion: v1
kind: Pod
metadata:
  name: api-pod
  namespace: production
  labels:
    app: api
    tier: backend
    version: "1.3.0"
spec:
  containers:
  - name: api
    image: myrepo/api:1.3.0
    ports:
    - name: http
      containerPort: 3000
    env:
    - name: NODE_ENV
      value: production
    - name: PORT
      value: "3000"
    resources:
      requests:
        cpu: 100m      # 0.1 CPU core reserved
        memory: 128Mi  # 128 MB reserved for scheduling
      limits:
        cpu: 500m      # hard cap: 0.5 CPU core
        memory: 512Mi  # hard cap: container OOM-killed if exceeded
    readinessProbe:
      httpGet:
        path: /health/ready
        port: 3000
      initialDelaySeconds: 15
      periodSeconds: 5
      failureThreshold: 3
    livenessProbe:
      httpGet:
        path: /health/live
        port: 3000
      initialDelaySeconds: 30
      periodSeconds: 10
      failureThreshold: 5
  restartPolicy: Always

Why not use bare Pods in production? If the node running a bare Pod fails, Kubernetes does not reschedule it. You need a controller (Deployment, StatefulSet, DaemonSet) to ensure Pods are always running.

ReplicaSets — Maintaining Pod Count

A ReplicaSet ensures a specified number of identical Pods are running at all times. If a Pod is deleted or crashes, the ReplicaSet creates a replacement.

You almost never create ReplicaSets directly — Deployments manage them for you. But understanding ReplicaSets explains how Deployments implement rolling updates.

apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: api-rs
spec:
  replicas: 3
  selector:
    matchLabels:
      app: api
      version: "1.3.0"
  template:
    metadata:
      labels:
        app: api
        version: "1.3.0"
    spec:
      containers:
      - name: api
        image: myrepo/api:1.3.0

Deployments — Production-Grade Pod Management

A Deployment manages ReplicaSets and provides declarative updates, rolling upgrade strategies, and rollback capability.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: api
  namespace: production
  annotations:
    deployment.kubernetes.io/revision: "3"
spec:
  replicas: 3
  selector:
    matchLabels:
      app: api
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1          # allow 1 extra pod during update
      maxUnavailable: 0    # never take a pod down before a new one is ready
  template:
    metadata:
      labels:
        app: api
    spec:
      containers:
      - name: api
        image: myrepo/api:1.3.0
        ports:
        - containerPort: 3000
        resources:
          requests:
            cpu: 100m
            memory: 128Mi
          limits:
            cpu: 500m
            memory: 512Mi
        readinessProbe:
          httpGet:
            path: /health
            port: 3000
          initialDelaySeconds: 10
          periodSeconds: 5
        livenessProbe:
          httpGet:
            path: /health
            port: 3000
          initialDelaySeconds: 30
          periodSeconds: 10
      # Spread pods across nodes to avoid single point of failure
      topologySpreadConstraints:
      - maxSkew: 1
        topologyKey: kubernetes.io/hostname
        whenUnsatisfiable: DoNotSchedule
        labelSelector:
          matchLabels:
            app: api

Deployment Operations

# Apply
kubectl apply -f deployment.yaml
 
# Watch rollout progress
kubectl rollout status deployment/api -n production
 
# Update image (triggers rolling update)
kubectl set image deployment/api api=myrepo/api:1.4.0 -n production
 
# Annotate for audit trail
kubectl annotate deployment api \
  kubernetes.io/change-cause="Release 1.4.0: adds payment service" \
  -n production
 
# View rollout history
kubectl rollout history deployment/api -n production
 
# Rollback to previous version
kubectl rollout undo deployment/api -n production
 
# Rollback to a specific revision
kubectl rollout undo deployment/api --to-revision=2 -n production
 
# Pause a rollout (useful for canary analysis)
kubectl rollout pause deployment/api -n production
kubectl rollout resume deployment/api -n production
 
# Scale manually
kubectl scale deployment api --replicas=10 -n production

Update Strategies

RollingUpdate (default)

Gradually replaces old pods with new ones. Zero downtime when combined with readiness probes and maxUnavailable: 0.

strategy:
  type: RollingUpdate
  rollingUpdate:
    maxSurge: 25%        # or absolute number like 1
    maxUnavailable: 25%  # or 0 for zero-downtime

Recreate

Terminates all old pods before starting new ones. Causes downtime — use only for development or when you need a complete restart.

strategy:
  type: Recreate

Services — Stable Network Endpoints

Services provide a stable IP address and DNS name for a set of Pods. Even as Pods are replaced during rolling updates, the Service IP and DNS remain constant.

# ClusterIP service (default) — internal cluster traffic only
apiVersion: v1
kind: Service
metadata:
  name: api-service
  namespace: production
spec:
  selector:
    app: api          # selects pods with this label
  ports:
  - name: http
    port: 80          # service port (what clients call)
    targetPort: 3000  # pod port (where traffic goes)
  type: ClusterIP
# LoadBalancer service — provisions cloud load balancer
apiVersion: v1
kind: Service
metadata:
  name: api-lb
  namespace: production
  annotations:
    service.beta.kubernetes.io/aws-load-balancer-type: nlb
spec:
  selector:
    app: api
  ports:
  - port: 443
    targetPort: 3000
  type: LoadBalancer

Service DNS

Kubernetes creates DNS records for every Service. Format:

<service-name>.<namespace>.svc.cluster.local
# From any pod in the same namespace:
curl http://api-service/api/v1/users
 
# From a pod in a different namespace:
curl http://api-service.production.svc.cluster.local/api/v1/users
 
# Check service endpoints (shows which pod IPs are ready)
kubectl get endpoints api-service -n production

Probes — Health Checking Pods

Readiness Probe

Determines whether a Pod should receive traffic. If readiness fails, the Pod is removed from Service endpoints — no traffic is sent but the Pod keeps running.

readinessProbe:
  httpGet:
    path: /health/ready
    port: 3000
  initialDelaySeconds: 10  # wait before first check
  periodSeconds: 5         # check every 5 seconds
  successThreshold: 1      # 1 success = ready
  failureThreshold: 3      # 3 failures = not ready
  timeoutSeconds: 3        # request timeout

Liveness Probe

Determines whether a Pod is alive. If liveness fails repeatedly, Kubernetes restarts the container.

livenessProbe:
  httpGet:
    path: /health/live
    port: 3000
  initialDelaySeconds: 30  # longer delay — let the app fully start
  periodSeconds: 10
  failureThreshold: 5      # restart after 5 consecutive failures

Startup Probe

For slow-starting applications, prevents liveness from killing the container during initialization:

startupProbe:
  httpGet:
    path: /health/startup
    port: 3000
  failureThreshold: 30    # 30 * 10s = 5 minutes allowed to start
  periodSeconds: 10

Common Mistakes

  • Not setting readiness probes — traffic hits pods that are still warming up (database connections, cache loading)
  • Setting maxUnavailable: 1 without maxSurge — causes brief capacity reduction during rolling updates
  • Using latest image tags in Deployments — Kubernetes may not pull new images if the tag exists in local cache
  • Not setting resource requests — pods get scheduled onto overloaded nodes; OOM kills are unpredictable
  • Using a Service selector that matches more pods than intended — routes traffic to the wrong pods

Best Practices

  • Always use Deployments (or StatefulSets for stateful apps) — never bare Pods in production
  • Set imagePullPolicy: Always when using mutable tags; use immutable tags (commit SHA) for reliable rollouts
  • Set terminationGracePeriodSeconds to match your app's shutdown time — default 30 seconds may be too short
  • Use topologySpreadConstraints to distribute pods across availability zones and nodes
  • Set a Deployment revisionHistoryLimit (default: 10) — older ReplicaSets consume resources

Key Takeaways

  • A Pod is the smallest Kubernetes unit; it wraps containers that share a network namespace and communicate via localhost
  • ReplicaSets maintain a desired number of Pod replicas; Deployments manage ReplicaSets and add rolling update capabilities
  • Rolling updates with maxUnavailable: 0 and readiness probes guarantee zero-downtime deployments
  • Services provide a stable ClusterIP and DNS name that load-balance across all Ready pods matching the selector
  • Readiness probes gate traffic routing; liveness probes trigger container restarts; startup probes protect slow-starting apps
  • Service DNS format is servicename.namespace.svc.cluster.local — pods in the same namespace can use just servicename
  • Resource requests affect scheduling decisions; resource limits enforce runtime constraints (CPU throttle, memory OOM kill)
  • kubectl rollout undo reverts to the previous ReplicaSet — always annotate releases with kubernetes.io/change-cause for traceability

Advertisement

Sanjeev Sharma

Written by

Sanjeev Sharma

Full Stack Engineer · E-mopro

Related reading