Kubernetes Pods, Deployments, and Services 2025 — Deep Dive with Examples
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: AlwaysWhy 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.0Deployments — 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: apiDeployment 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 productionUpdate 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-downtimeRecreate
Terminates all old pods before starting new ones. Causes downtime — use only for development or when you need a complete restart.
strategy:
type: RecreateServices — 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: LoadBalancerService 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 productionProbes — 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 timeoutLiveness 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 failuresStartup 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: 10Common Mistakes
- Not setting readiness probes — traffic hits pods that are still warming up (database connections, cache loading)
- Setting
maxUnavailable: 1withoutmaxSurge— causes brief capacity reduction during rolling updates - Using
latestimage 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
selectorthat 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: Alwayswhen using mutable tags; use immutable tags (commit SHA) for reliable rollouts - Set
terminationGracePeriodSecondsto match your app's shutdown time — default 30 seconds may be too short - Use
topologySpreadConstraintsto 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: 0and 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 justservicename - Resource requests affect scheduling decisions; resource limits enforce runtime constraints (CPU throttle, memory OOM kill)
kubectl rollout undoreverts to the previous ReplicaSet — always annotate releases withkubernetes.io/change-causefor traceability
Advertisement