Kubernetes Explained


Kubernetes (K8s) is the industry-standard platform for container orchestration. It automates deployment, scaling, and management of containerized applications across clusters of machines.

What is Kubernetes?

Kubernetes is an open-source container orchestration platform originally developed by Google. It solves several critical problems:

  1. Automated deployment: Deploy containers across multiple machines automatically
  2. Self-healing: Restart failed containers and replace unhealthy instances
  3. Scaling: Scale applications up or down based on demand
  4. Load balancing: Distribute network traffic efficiently
  5. Rolling updates: Update applications without downtime
  6. Resource management: Optimize CPU and memory usage across clusters

Think of Kubernetes as an operating system for your datacenter or cloud infrastructure.

Kubernetes Architecture

Kubernetes follows a master-worker architecture with two main components:

Control Plane (Master Node)

The control plane manages the entire cluster and makes decisions about scheduling, scaling, and maintaining desired state.

Key components:

  1. API Server: Frontend for Kubernetes control plane; all communications go through this
  2. etcd: Distributed key-value store; stores all cluster data
  3. Scheduler: Assigns pods to nodes based on resource requirements
  4. Controller Manager: Runs controllers that handle routine tasks (replication, endpoints, service accounts)
  5. Cloud Controller Manager: Integrates with cloud provider APIs (AWS, Azure, GCP)

Worker Nodes

Worker nodes run your application containers.

Key components:

  1. kubelet: Agent that ensures containers are running as expected
  2. kube-proxy: Maintains network rules for pod communication
  3. Container Runtime: Software that runs containers (Docker, containerd, CRI-O)

Core Kubernetes Objects

1. Pods

A Pod is the smallest deployable unit in Kubernetes. It represents one or more containers that share storage and network resources.

apiVersion: v1
kind: Pod
metadata:
  name: nginx-pod
  labels:
    app: nginx
spec:
  containers:
  - name: nginx
    image: nginx:1.25
    ports:
    - containerPort: 80

Key characteristics:

  • Pods are ephemeral (temporary)
  • Each pod gets its own IP address
  • Containers in a pod share the same network namespace
  • Usually you don’t create pods directly (use Deployments instead)

2. Deployments

Deployments manage ReplicaSets and provide declarative updates for Pods.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.25
        ports:
        - containerPort: 80
        resources:
          requests:
            memory: "64Mi"
            cpu: "250m"
          limits:
            memory: "128Mi"
            cpu: "500m"

Deployments handle:

  • Rolling updates and rollbacks
  • Scaling (manual and automatic)
  • Self-healing (restart failed pods)
  • Version management

3. Services

Services provide stable networking endpoints for Pods. Since Pod IPs change when pods restart, Services act as a stable abstraction layer.

ClusterIP (default)

Internal-only service, accessible within the cluster.

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

NodePort

Exposes service on each node’s IP at a static port.

apiVersion: v1
kind: Service
metadata:
  name: nginx-nodeport
spec:
  type: NodePort
  selector:
    app: nginx
  ports:
  - protocol: TCP
    port: 80
    targetPort: 80
    nodePort: 30080

LoadBalancer

Exposes service externally using cloud provider’s load balancer.

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

4. ConfigMaps and Secrets

ConfigMaps store non-sensitive configuration data.

apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config
data:
  database_url: "postgres://db.example.com:5432/mydb"
  log_level: "info"

Secrets store sensitive information (base64 encoded).

apiVersion: v1
kind: Secret
metadata:
  name: db-secret
type: Opaque
data:
  username: YWRtaW4=  # base64 encoded "admin"
  password: cGFzc3dvcmQ=  # base64 encoded "password"

Using ConfigMap and Secret in a Pod:

apiVersion: v1
kind: Pod
metadata:
  name: app-pod
spec:
  containers:
  - name: app
    image: myapp:1.0
    env:
    - name: DATABASE_URL
      valueFrom:
        configMapKeyRef:
          name: app-config
          key: database_url
    - name: DB_PASSWORD
      valueFrom:
        secretKeyRef:
          name: db-secret
          key: password

5. Namespaces

Namespaces provide logical isolation within a cluster. They’re useful for multi-tenancy and environment separation.

apiVersion: v1
kind: Namespace
metadata:
  name: production

Common namespace pattern:

kubectl create namespace development
kubectl create namespace staging
kubectl create namespace production

Deploy to specific namespace:

kubectl apply -f deployment.yaml -n production

6. Persistent Volumes and Claims

PersistentVolume (PV): Cluster-level storage resource.

apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv-data
spec:
  capacity:
    storage: 10Gi
  accessModes:
  - ReadWriteOnce
  persistentVolumeReclaimPolicy: Retain
  hostPath:
    path: /mnt/data

PersistentVolumeClaim (PVC): Request for storage by a user.

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: pvc-data
spec:
  accessModes:
  - ReadWriteOnce
  resources:
    requests:
      storage: 5Gi

Using PVC in a Pod:

apiVersion: v1
kind: Pod
metadata:
  name: app-with-storage
spec:
  containers:
  - name: app
    image: myapp:1.0
    volumeMounts:
    - mountPath: /data
      name: app-data
  volumes:
  - name: app-data
    persistentVolumeClaim:
      claimName: pvc-data

7. Ingress

Ingress manages external HTTP/HTTPS access to services in the cluster.

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: app-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  rules:
  - host: myapp.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: nginx-service
            port:
              number: 80

Ingress provides:

  • SSL/TLS termination
  • Name-based virtual hosting
  • Path-based routing
  • Load balancing

Kubernetes Networking

Pod-to-Pod Communication

All pods can communicate with each other without NAT, regardless of which node they’re on. Kubernetes assigns a unique IP to each pod.

# From one pod, ping another pod
kubectl exec -it pod1 -- ping <pod2-ip>

Service Discovery

Kubernetes provides DNS-based service discovery. Services are automatically registered in cluster DNS.

Format: <service-name>.<namespace>.svc.cluster.local

Example:

# From any pod in the same namespace
curl http://nginx-service:80

# From pod in different namespace
curl http://nginx-service.production.svc.cluster.local:80

Network Policies

Control traffic flow between pods using Network Policies.

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-frontend
spec:
  podSelector:
    matchLabels:
      app: backend
  ingress:
  - from:
    - podSelector:
        matchLabels:
          app: frontend
    ports:
    - protocol: TCP
      port: 8080

This policy allows only pods with label app: frontend to access pods with label app: backend on port 8080.

Resource Management

Resource Requests and Limits

resources:
  requests:
    memory: "256Mi"
    cpu: "500m"
  limits:
    memory: "512Mi"
    cpu: "1000m"
  • Requests: Minimum guaranteed resources
  • Limits: Maximum allowed resources

Quality of Service (QoS) Classes

Based on requests and limits, pods are assigned QoS classes:

  1. Guaranteed: requests = limits for all containers
  2. Burstable: requests < limits
  3. BestEffort: no requests or limits set

Horizontal Pod Autoscaling (HPA)

Automatically scale pods based on metrics.

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: nginx-hpa
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: nginx-deployment
  minReplicas: 2
  maxReplicas: 10
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 70

Practical kubectl Commands

Cluster Information

# Cluster info
kubectl cluster-info

# Node information
kubectl get nodes
kubectl describe node <node-name>

Working with Pods

# List pods
kubectl get pods
kubectl get pods -n production
kubectl get pods --all-namespaces

# Detailed pod info
kubectl describe pod <pod-name>

# Pod logs
kubectl logs <pod-name>
kubectl logs -f <pod-name>  # follow logs
kubectl logs <pod-name> -c <container-name>  # specific container

# Execute command in pod
kubectl exec -it <pod-name> -- /bin/bash
kubectl exec <pod-name> -- ls /app

Working with Deployments

# List deployments
kubectl get deployments

# Create/update deployment
kubectl apply -f deployment.yaml

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

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

# Rollout status
kubectl rollout status deployment/nginx-deployment

# Rollout history
kubectl rollout history deployment/nginx-deployment

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

Working with Services

# List services
kubectl get services
kubectl get svc

# Describe service
kubectl describe svc nginx-service

# Port forwarding (for testing)
kubectl port-forward svc/nginx-service 8080:80

Debugging

# Get events
kubectl get events --sort-by=.metadata.creationTimestamp

# Debug with ephemeral container (K8s 1.23+)
kubectl debug -it <pod-name> --image=busybox --target=<container-name>

# Copy files from pod
kubectl cp <pod-name>:/path/to/file /local/path

# Get resource usage
kubectl top nodes
kubectl top pods

Common Deployment Patterns

1. Multi-Container Pod Pattern (Sidecar)

apiVersion: v1
kind: Pod
metadata:
  name: app-with-sidecar
spec:
  containers:
  - name: main-app
    image: myapp:1.0
    ports:
    - containerPort: 8080
  - name: log-shipper
    image: fluent-bit:2.0
    volumeMounts:
    - name: logs
      mountPath: /var/log
  volumes:
  - name: logs
    emptyDir: {}

2. Init Containers

Run before main containers start, useful for setup tasks.

apiVersion: v1
kind: Pod
metadata:
  name: app-with-init
spec:
  initContainers:
  - name: db-migration
    image: myapp-migration:1.0
    command: ['sh', '-c', 'run-migrations.sh']
  containers:
  - name: app
    image: myapp:1.0

3. Blue-Green Deployment

Maintain two identical environments and switch traffic between them.

# Blue deployment
apiVersion: apps/v1
kind: Deployment
metadata:
  name: app-blue
spec:
  replicas: 3
  selector:
    matchLabels:
      app: myapp
      version: blue
  template:
    metadata:
      labels:
        app: myapp
        version: blue
    spec:
      containers:
      - name: app
        image: myapp:1.0
---
# Service pointing to blue
apiVersion: v1
kind: Service
metadata:
  name: app-service
spec:
  selector:
    app: myapp
    version: blue  # Switch to green when ready
  ports:
  - port: 80

4. Canary Deployment

Gradually roll out new version to a small subset of users.

# Stable deployment (90%)
apiVersion: apps/v1
kind: Deployment
metadata:
  name: app-stable
spec:
  replicas: 9
  selector:
    matchLabels:
      app: myapp
      track: stable
  template:
    metadata:
      labels:
        app: myapp
        track: stable
    spec:
      containers:
      - name: app
        image: myapp:1.0
---
# Canary deployment (10%)
apiVersion: apps/v1
kind: Deployment
metadata:
  name: app-canary
spec:
  replicas: 1
  selector:
    matchLabels:
      app: myapp
      track: canary
  template:
    metadata:
      labels:
        app: myapp
        track: canary
    spec:
      containers:
      - name: app
        image: myapp:2.0
---
# Service routes to both
apiVersion: v1
kind: Service
metadata:
  name: app-service
spec:
  selector:
    app: myapp  # Matches both stable and canary
  ports:
  - port: 80

Health Checks

Liveness Probe

Checks if container is running. Kubernetes restarts unhealthy containers.

livenessProbe:
  httpGet:
    path: /healthz
    port: 8080
  initialDelaySeconds: 15
  periodSeconds: 10
  timeoutSeconds: 2
  failureThreshold: 3

Readiness Probe

Checks if container is ready to accept traffic.

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

Startup Probe

Checks if application has started (useful for slow-starting containers).

startupProbe:
  httpGet:
    path: /startup
    port: 8080
  initialDelaySeconds: 0
  periodSeconds: 10
  timeoutSeconds: 2
  failureThreshold: 30

Best Practices

Security

  1. Use specific image tags, not latest
  2. Run containers as non-root
  3. Use read-only root filesystems when possible
  4. Set resource limits to prevent resource exhaustion
  5. Use Network Policies to restrict traffic
  6. Enable RBAC (Role-Based Access Control)
  7. Scan images for vulnerabilities
  8. Use Secrets for sensitive data, not ConfigMaps
securityContext:
  runAsNonRoot: true
  runAsUser: 1000
  readOnlyRootFilesystem: true
  allowPrivilegeEscalation: false
  capabilities:
    drop:
    - ALL

Resource Management

  1. Always set resource requests and limits
  2. Use Horizontal Pod Autoscaler for variable workloads
  3. Use PodDisruptionBudgets for high availability
  4. Configure appropriate QoS classes
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
  name: app-pdb
spec:
  minAvailable: 2
  selector:
    matchLabels:
      app: myapp

Configuration Management

  1. Use ConfigMaps for environment-specific configuration
  2. Use Secrets for sensitive data
  3. Version your manifests in Git
  4. Use Helm or Kustomize for templating
  5. Separate concerns: one manifest per resource type

Monitoring and Logging

  1. Implement health checks (liveness, readiness, startup)
  2. Collect logs centrally (ELK, Loki, etc.)
  3. Use Prometheus for metrics
  4. Set up alerts for critical conditions
  5. Monitor resource usage (kubectl top, metrics-server)

Deployment Strategy

  1. Use rolling updates as default
  2. Implement proper health checks before declaring pod ready
  3. Use appropriate update strategy (RollingUpdate vs Recreate)
  4. Test in lower environments first
  5. Have rollback plan ready
strategy:
  type: RollingUpdate
  rollingUpdate:
    maxSurge: 1
    maxUnavailable: 0

Namespace Organization

  1. Use namespaces to separate environments
  2. Apply resource quotas per namespace
  3. Use labels consistently
  4. Implement network policies per namespace
apiVersion: v1
kind: ResourceQuota
metadata:
  name: compute-quota
  namespace: production
spec:
  hard:
    requests.cpu: "50"
    requests.memory: "100Gi"
    limits.cpu: "100"
    limits.memory: "200Gi"
    persistentvolumeclaims: "10"

Troubleshooting Common Issues

Pod Not Starting

# Check pod status
kubectl get pods
kubectl describe pod <pod-name>

# Common reasons:
# - Image pull errors (check image name/tag)
# - Insufficient resources
# - Volume mount issues
# - Init container failures

Service Not Reachable

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

# Test service from another pod
kubectl run test-pod --rm -it --image=busybox -- sh
wget -qO- http://<service-name>:<port>

# Check selector labels match
kubectl get pods --show-labels

High Memory/CPU Usage

# Check resource usage
kubectl top pods
kubectl top nodes

# Check if HPA is configured
kubectl get hpa

# Scale manually if needed
kubectl scale deployment <name> --replicas=<number>

CrashLoopBackOff

# Check logs from crashed container
kubectl logs <pod-name> --previous

# Common causes:
# - Application errors
# - Missing dependencies
# - Failed health checks
# - Configuration issues

Production Checklist

Before deploying to production:

  • Resource requests and limits defined
  • Health checks configured (liveness, readiness)
  • Secrets used for sensitive data
  • Images use specific tags (not latest)
  • Security context configured (non-root user)
  • Network policies in place
  • PodDisruptionBudget configured for HA
  • Monitoring and logging enabled
  • Backup strategy for persistent data
  • Resource quotas set for namespace
  • RBAC rules configured
  • Ingress/LoadBalancer configured properly
  • SSL/TLS certificates managed
  • Update strategy tested
  • Rollback procedure documented

References

See also