Kubernetes Pods, Deployments, and Services

Sanjeev SharmaSanjeev Sharma
5 min read

Advertisement

Kubernetes Pods, Deployments, and Services

Master the core workload resources in Kubernetes for reliable, scalable application deployment.

Introduction

Pods, Deployments, and Services form the foundation of Kubernetes applications. Understanding their interaction is essential for effective container orchestration.

Pods Deep Dive

Single Container Pod

apiVersion: v1
kind: Pod
metadata:
  name: web-pod
  namespace: default
spec:
  containers:
  - name: web
    image: nginx:1.21
    ports:
    - containerPort: 80
    resources:
      requests:
        cpu: 100m
        memory: 128Mi
      limits:
        cpu: 250m
        memory: 256Mi

Multi-Container Pod

apiVersion: v1
kind: Pod
metadata:
  name: web-app-pod
spec:
  containers:
  # Main application
  - name: app
    image: myapp:1.0
    ports:
    - containerPort: 3000

  # Logging sidecar
  - name: logging
    image: logging-agent:1.0
    volumeMounts:
    - name: app-logs
      mountPath: /var/log/app

  # Service mesh sidecar
  - name: envoy
    image: envoy:latest
    ports:
    - containerPort: 8001

  volumes:
  - name: app-logs
    emptyDir: {}

Init Containers

Run setup tasks before main container:

apiVersion: v1
kind: Pod
metadata:
  name: app-with-init
spec:
  initContainers:
  - name: init-db
    image: busybox
    command: ['sh', '-c', 'until nc -z db:5432; do echo waiting for db; sleep 2; done']

  containers:
  - name: app
    image: myapp:1.0
    ports:
    - containerPort: 3000

Deployments

Basic Deployment

apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-app
spec:
  replicas: 3
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 0

  selector:
    matchLabels:
      app: web-app

  template:
    metadata:
      labels:
        app: web-app
        version: v1
    spec:
      containers:
      - name: web
        image: myapp:1.0
        ports:
        - containerPort: 3000
        livenessProbe:
          httpGet:
            path: /health
            port: 3000
          initialDelaySeconds: 10
          periodSeconds: 10
        readinessProbe:
          httpGet:
            path: /ready
            port: 3000
          initialDelaySeconds: 5
          periodSeconds: 5

StatefulSet

For stateful applications like databases:

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: mysql
spec:
  serviceName: mysql
  replicas: 1
  selector:
    matchLabels:
      app: mysql
  template:
    metadata:
      labels:
        app: mysql
    spec:
      containers:
      - name: mysql
        image: mysql:8.0
        ports:
        - containerPort: 3306
        volumeMounts:
        - name: data
          mountPath: /var/lib/mysql

  volumeClaimTemplates:
  - metadata:
      name: data
    spec:
      accessModes: ["ReadWriteOnce"]
      resources:
        requests:
          storage: 10Gi

DaemonSet

Run pod on every node:

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: log-collector
spec:
  selector:
    matchLabels:
      name: log-collector
  template:
    metadata:
      labels:
        name: log-collector
    spec:
      containers:
      - name: logger
        image: fluent/fluent-bit:latest
        volumeMounts:
        - name: varlog
          mountPath: /var/log
      volumes:
      - name: varlog
        hostPath:
          path: /var/log

Services

ClusterIP Service (Default)

Internal only, accessible within cluster:

apiVersion: v1
kind: Service
metadata:
  name: web-service
spec:
  type: ClusterIP
  selector:
    app: web-app
  ports:
  - protocol: TCP
    port: 80
    targetPort: 3000

Access within cluster:

# From another pod in cluster
curl web-service
curl web-service.default.svc.cluster.local

NodePort Service

Accessible from outside cluster:

apiVersion: v1
kind: Service
metadata:
  name: web-nodeport
spec:
  type: NodePort
  selector:
    app: web-app
  ports:
  - protocol: TCP
    port: 80
    targetPort: 3000
    nodePort: 30080  # 30000-32767 range

Access from outside:

# Get node IP
kubectl get nodes -o wide

# Access on any node
curl node-ip:30080

LoadBalancer Service

External load balancer (requires cloud integration):

apiVersion: v1
kind: Service
metadata:
  name: web-lb
spec:
  type: LoadBalancer
  selector:
    app: web-app
  ports:
  - protocol: TCP
    port: 80
    targetPort: 3000

Get external IP:

kubectl get service web-lb
# Wait for EXTERNAL-IP to be assigned

ExternalName Service

Reference external service:

apiVersion: v1
kind: Service
metadata:
  name: external-db
spec:
  type: ExternalName
  externalName: db.example.com
  ports:
  - port: 5432

Traffic Policies

Affinity: Keeping Pods Together

apiVersion: apps/v1
kind: Deployment
metadata:
  name: distributed-app
spec:
  replicas: 3
  template:
    spec:
      affinity:
        podAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
          - labelSelector:
              matchExpressions:
              - key: app
                operator: In
                values:
                - cache
            topologyKey: kubernetes.io/hostname

      containers:
      - name: app
        image: myapp:1.0

Anti-Affinity: Spreading Pods

affinity:
  podAntiAffinity:
    preferredDuringSchedulingIgnoredDuringExecution:
    - weight: 100
      podAffinityTerm:
        labelSelector:
          matchExpressions:
          - key: app
            operator: In
            values:
            - app
        topologyKey: kubernetes.io/hostname

Managing Deployments

Rolling Updates

# Update image
kubectl set image deployment/web-app web=myapp:2.0

# Check rollout status
kubectl rollout status deployment/web-app

# View revision history
kubectl rollout history deployment/web-app

# Rollback to previous revision
kubectl rollout undo deployment/web-app

# Rollback to specific revision
kubectl rollout undo deployment/web-app --to-revision=2

Scaling

# Scale manually
kubectl scale deployment web-app --replicas=5

# Check current replicas
kubectl get deployment web-app

Probes

Liveness Probe

Restart pod if unhealthy:

livenessProbe:
  httpGet:
    path: /health
    port: 3000
  initialDelaySeconds: 30
  periodSeconds: 10
  failureThreshold: 3

Readiness Probe

Route traffic only to ready pods:

readinessProbe:
  httpGet:
    path: /ready
    port: 3000
  initialDelaySeconds: 5
  periodSeconds: 5

Startup Probe

Allow slow-starting apps:

startupProbe:
  httpGet:
    path: /health
    port: 3000
  failureThreshold: 30
  periodSeconds: 10

Production Checklist

  • Define resource requests and limits
  • Implement liveness and readiness probes
  • Use multiple replicas for availability
  • Set rolling update strategy
  • Configure pod disruption budgets
  • Use health checks
  • Implement graceful shutdown

FAQ

Q: What's the difference between StatefulSet and Deployment? A: Deployments are for stateless apps with interchangeable replicas. StatefulSets maintain identity and stable storage for stateful apps.

Q: How many containers should I put in a Pod? A: Usually one. Use multiple containers for sidecars (logging, monitoring) that tightly couple with the main container.

Q: When should I use NodePort vs LoadBalancer? A: NodePort for development/testing. LoadBalancer for production external access with proper load distribution.

Advertisement

Sanjeev Sharma

Written by

Sanjeev Sharma

Full Stack Engineer · E-mopro