Kubernetes: Pods, Services, Deployments - Complete Guide

Understanding Pods, Services, and Deployments is fundamental to mastering Kubernetes. These core resources form the foundation of application deployment and management in Kubernetes clusters. This comprehensive guide covers concepts, practical examples, and production best practices.

Table of Contents

Introduction

Kubernetes orchestrates containerized applications using several key resources:

  • Pods: Smallest deployable units, encapsulating one or more containers
  • Services: Stable network endpoints for accessing Pods
  • Deployments: Declarative updates for Pods and ReplicaSets

Resource Hierarchy

Deployment
  └── ReplicaSet
        └── Pod(s)
              └── Container(s)

Prerequisites

  • Kubernetes cluster (kubeadm, minikube, or cloud provider)
  • kubectl installed and configured
  • Basic understanding of containers and Docker
  • Familiarity with YAML syntax

Verify setup:

kubectl version --client
kubectl cluster-info
kubectl get nodes

Pods

Pods are the atomic unit of deployment in Kubernetes, representing one or more tightly coupled containers that share resources.

Pod Characteristics

  • Ephemeral and disposable
  • Share network namespace (single IP)
  • Share storage volumes
  • Scheduled together on same node
  • Managed by higher-level controllers

Creating a Simple Pod

# simple-pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: nginx-pod
  labels:
    app: nginx
    environment: dev
spec:
  containers:
  - name: nginx
    image: nginx:1.25-alpine
    ports:
    - containerPort: 80
# Create pod
kubectl apply -f simple-pod.yaml

# Check pod status
kubectl get pods

# Describe pod
kubectl describe pod nginx-pod

# Delete pod
kubectl delete pod nginx-pod

Multi-Container Pod

# multi-container-pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: web-app
spec:
  containers:
  - name: app
    image: myapp:latest
    ports:
    - containerPort: 8080
    volumeMounts:
    - name: shared-data
      mountPath: /app/data

  - name: sidecar
    image: log-collector:latest
    volumeMounts:
    - name: shared-data
      mountPath: /logs

  volumes:
  - name: shared-data
    emptyDir: {}

Pod with Resource Limits

# pod-resources.yaml
apiVersion: v1
kind: Pod
metadata:
  name: resource-pod
spec:
  containers:
  - name: app
    image: nginx:alpine
    resources:
      requests:
        memory: "128Mi"
        cpu: "250m"
      limits:
        memory: "256Mi"
        cpu: "500m"

Pod with Environment Variables

# pod-env.yaml
apiVersion: v1
kind: Pod
metadata:
  name: env-pod
spec:
  containers:
  - name: app
    image: myapp:latest
    env:
    - name: DATABASE_HOST
      value: "postgres.default.svc.cluster.local"
    - name: DATABASE_PORT
      value: "5432"
    - name: API_KEY
      valueFrom:
        secretKeyRef:
          name: api-credentials
          key: api-key

Pod Lifecycle

# Check pod phases
kubectl get pods -w

# Pod phases:
# Pending - Waiting for scheduling
# Running - Pod scheduled, containers running
# Succeeded - All containers terminated successfully
# Failed - At least one container failed
# Unknown - Pod state cannot be determined

Services

Services provide stable networking for accessing Pods, offering load balancing and service discovery.

Service Types

  • ClusterIP: Internal cluster access only (default)
  • NodePort: Exposes on each node's IP at a static port
  • LoadBalancer: Cloud load balancer (requires cloud provider)
  • ExternalName: Maps to external DNS name

ClusterIP Service

# service-clusterip.yaml
apiVersion: v1
kind: Service
metadata:
  name: backend-service
spec:
  type: ClusterIP
  selector:
    app: backend
    tier: api
  ports:
  - port: 80
    targetPort: 8080
    protocol: TCP
    name: http
# Create service
kubectl apply -f service-clusterip.yaml

# Access from within cluster
kubectl run curl --image=curlimages/curl -it --rm -- sh
# curl http://backend-service

NodePort Service

# service-nodeport.yaml
apiVersion: v1
kind: Service
metadata:
  name: web-service
spec:
  type: NodePort
  selector:
    app: web
  ports:
  - port: 80
    targetPort: 8080
    nodePort: 30080  # Optional: 30000-32767
    protocol: TCP
# Create service
kubectl apply -f service-nodeport.yaml

# Access from outside cluster
curl http://<NODE_IP>:30080

LoadBalancer Service

# service-loadbalancer.yaml
apiVersion: v1
kind: Service
metadata:
  name: frontend-service
spec:
  type: LoadBalancer
  selector:
    app: frontend
  ports:
  - port: 80
    targetPort: 3000
    protocol: TCP
# Create service
kubectl apply -f service-loadbalancer.yaml

# Get external IP (may take time)
kubectl get service frontend-service

# Access via external IP
curl http://<EXTERNAL_IP>

Service with Session Affinity

# service-session.yaml
apiVersion: v1
kind: Service
metadata:
  name: sticky-service
spec:
  type: ClusterIP
  sessionAffinity: ClientIP
  sessionAffinityConfig:
    clientIP:
      timeoutSeconds: 10800
  selector:
    app: web
  ports:
  - port: 80
    targetPort: 8080

Headless Service

# service-headless.yaml
apiVersion: v1
kind: Service
metadata:
  name: database-service
spec:
  clusterIP: None  # Headless service
  selector:
    app: database
  ports:
  - port: 5432
    targetPort: 5432

Deployments

Deployments provide declarative updates for Pods and ReplicaSets, enabling scaling, rolling updates, and rollbacks.

Basic Deployment

# deployment-basic.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  labels:
    app: nginx
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.25-alpine
        ports:
        - containerPort: 80
# Create deployment
kubectl apply -f deployment-basic.yaml

# Check deployment
kubectl get deployments
kubectl get pods

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

# Delete deployment
kubectl delete deployment nginx-deployment

Production-Ready Deployment

# deployment-production.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-app
  labels:
    app: web
    environment: production
spec:
  replicas: 3
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 1
  selector:
    matchLabels:
      app: web
  template:
    metadata:
      labels:
        app: web
        version: v1.0.0
    spec:
      containers:
      - name: app
        image: myapp:1.0.0
        ports:
        - containerPort: 8080
          name: http
        env:
        - name: ENVIRONMENT
          value: "production"
        resources:
          requests:
            memory: "256Mi"
            cpu: "250m"
          limits:
            memory: "512Mi"
            cpu: "500m"
        livenessProbe:
          httpGet:
            path: /health
            port: 8080
          initialDelaySeconds: 30
          periodSeconds: 10
        readinessProbe:
          httpGet:
            path: /ready
            port: 8080
          initialDelaySeconds: 5
          periodSeconds: 5

Deployment with ConfigMap and Secret

# configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config
data:
  database_url: "postgres://db:5432"
  log_level: "info"

---
# secret.yaml
apiVersion: v1
kind: Secret
metadata:
  name: app-secrets
type: Opaque
data:
  db_password: cGFzc3dvcmQxMjM=  # base64 encoded

---
# deployment-with-config.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: app-deployment
spec:
  replicas: 2
  selector:
    matchLabels:
      app: myapp
  template:
    metadata:
      labels:
        app: myapp
    spec:
      containers:
      - name: app
        image: myapp:latest
        envFrom:
        - configMapRef:
            name: app-config
        env:
        - name: DB_PASSWORD
          valueFrom:
            secretKeyRef:
              name: app-secrets
              key: db_password

ReplicaSets

ReplicaSets ensure a specified number of Pod replicas are running. Typically managed by Deployments.

ReplicaSet Example

# replicaset.yaml
apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: frontend-replicaset
spec:
  replicas: 3
  selector:
    matchLabels:
      app: frontend
  template:
    metadata:
      labels:
        app: frontend
    spec:
      containers:
      - name: nginx
        image: nginx:alpine
# Create ReplicaSet
kubectl apply -f replicaset.yaml

# Check ReplicaSet
kubectl get replicasets
kubectl get pods

# Scale ReplicaSet
kubectl scale replicaset frontend-replicaset --replicas=5

Labels and Selectors

Labels organize and select Kubernetes objects. Selectors query objects by labels.

Using Labels

# pod-with-labels.yaml
apiVersion: v1
kind: Pod
metadata:
  name: labeled-pod
  labels:
    app: web
    environment: production
    tier: frontend
    version: v1.2.3
spec:
  containers:
  - name: nginx
    image: nginx:alpine

Label Selectors

# Equality-based
kubectl get pods -l app=web
kubectl get pods -l environment=production

# Set-based
kubectl get pods -l 'environment in (production, staging)'
kubectl get pods -l 'tier notin (database)'

# Multiple conditions
kubectl get pods -l app=web,environment=production

# Show labels
kubectl get pods --show-labels

Adding/Removing Labels

# Add label
kubectl label pods labeled-pod new-label=value

# Update label
kubectl label pods labeled-pod environment=staging --overwrite

# Remove label
kubectl label pods labeled-pod environment-

Rolling Updates and Rollbacks

Performing Rolling Update

# Update deployment image
kubectl set image deployment/nginx-deployment nginx=nginx:1.26-alpine

# Or update via edit
kubectl edit deployment nginx-deployment

# Watch rollout status
kubectl rollout status deployment/nginx-deployment

# Check rollout history
kubectl rollout history deployment/nginx-deployment

Update Strategy

spec:
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 25%        # Max pods above desired count
      maxUnavailable: 25%  # Max unavailable pods during update

Rollback Deployment

# Rollback to previous version
kubectl rollout undo deployment/nginx-deployment

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

# Pause rollout
kubectl rollout pause deployment/nginx-deployment

# Resume rollout
kubectl rollout resume deployment/nginx-deployment

Production Best Practices

Resource Requests and Limits

spec:
  containers:
  - name: app
    resources:
      requests:
        memory: "256Mi"
        cpu: "250m"
      limits:
        memory: "512Mi"
        cpu: "500m"

Health Checks

spec:
  containers:
  - name: app
    livenessProbe:
      httpGet:
        path: /health
        port: 8080
      initialDelaySeconds: 30
      periodSeconds: 10
      timeoutSeconds: 5
      failureThreshold: 3

    readinessProbe:
      httpGet:
        path: /ready
        port: 8080
      initialDelaySeconds: 5
      periodSeconds: 5
      timeoutSeconds: 3
      failureThreshold: 3

Pod Disruption Budgets

# pdb.yaml
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
  name: web-pdb
spec:
  minAvailable: 2
  selector:
    matchLabels:
      app: web

Anti-Affinity for High Availability

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

Security Context

spec:
  securityContext:
    runAsNonRoot: true
    runAsUser: 1000
    fsGroup: 2000
  containers:
  - name: app
    securityContext:
      allowPrivilegeEscalation: false
      readOnlyRootFilesystem: true
      capabilities:
        drop:
        - ALL

Troubleshooting

Pod Issues

# Get pod details
kubectl describe pod <pod-name>

# View logs
kubectl logs <pod-name>
kubectl logs <pod-name> --previous  # Previous container

# Execute in pod
kubectl exec -it <pod-name> -- sh

# Check events
kubectl get events --sort-by='.lastTimestamp'

Service Issues

# Check service endpoints
kubectl get endpoints <service-name>

# Test DNS resolution
kubectl run test --image=busybox:1.28 --rm -it -- nslookup <service-name>

# Check service connectivity
kubectl run curl --image=curlimages/curl --rm -it -- curl http://<service-name>

Deployment Issues

# Check deployment status
kubectl get deployment <deployment-name>
kubectl describe deployment <deployment-name>

# Check ReplicaSet
kubectl get rs
kubectl describe rs <replicaset-name>

# Check rollout status
kubectl rollout status deployment/<deployment-name>

Common Problems

# ImagePullBackOff
kubectl describe pod <pod-name>  # Check image name and credentials

# CrashLoopBackOff
kubectl logs <pod-name>  # Check application logs

# Pending pods
kubectl describe pod <pod-name>  # Check node resources and scheduling

# Service not accessible
kubectl get endpoints <service-name>  # Verify pods are selected

Conclusion

Pods, Services, and Deployments form the core of Kubernetes application management. Understanding these resources is essential for deploying scalable, resilient applications.

Key Takeaways

  • Pods: Smallest deployable unit, ephemeral
  • Services: Stable network endpoints, load balancing
  • Deployments: Declarative updates, scaling, rollbacks
  • Labels: Organize and select resources
  • Health Checks: Ensure application reliability
  • Resource Limits: Prevent resource exhaustion

Quick Reference

# Pods
kubectl get pods
kubectl describe pod <name>
kubectl logs <name>
kubectl exec -it <name> -- sh
kubectl delete pod <name>

# Services
kubectl get services
kubectl describe service <name>
kubectl get endpoints <name>

# Deployments
kubectl get deployments
kubectl describe deployment <name>
kubectl scale deployment <name> --replicas=5
kubectl set image deployment/<name> container=image:tag
kubectl rollout status deployment/<name>
kubectl rollout undo deployment/<name>

# Labels
kubectl get pods --show-labels
kubectl get pods -l app=web
kubectl label pods <name> key=value

Next Steps

  1. Practice: Deploy various applications
  2. Monitoring: Set up Prometheus and Grafana
  3. Logging: Implement centralized logging
  4. Security: Apply RBAC and pod security policies
  5. Networking: Configure Ingress controllers
  6. Storage: Implement persistent volumes
  7. CI/CD: Automate deployments

Master these fundamentals to build robust Kubernetes applications!