Day 24: Kubernetes Basics and Docker Integration

Learning Objectives: By the end of this lesson, you will be able to:

  • Understand Kubernetes architecture and core concepts
  • Deploy Docker containers to Kubernetes clusters
  • Create and manage Kubernetes deployments, services, and pods
  • Configure networking and storage for containerized applications
  • Implement basic monitoring and troubleshooting in Kubernetes

1. Welcome and Introduction (5 minutes)

Icebreaker Activity

“Imagine you’re managing a massive online platform like Netflix or Google, serving millions of users across the globe with thousands of microservices. You need automatic scaling, self-healing, rolling updates, and the ability to manage this complexity across multiple data centers. Docker Swarm got us started, but now we need something more powerful. Today we’ll explore Kubernetes - the ‘operating system’ for containerized applications at massive scale.”

Lesson Overview

  • Duration: 90 minutes
  • Prerequisites: Docker fundamentals, container orchestration concepts, YAML basics
  • Materials Needed: Kubernetes cluster (local or cloud), kubectl CLI, Docker images

2. Learning Objectives and Session Outline (5 minutes)

What We’ll Cover Today:

  1. Kubernetes Architecture - Understanding the control plane and worker nodes
  2. Core Objects - Pods, Deployments, Services, and ConfigMaps
  3. Container Integration - Running Docker containers in Kubernetes
  4. Service Discovery - Networking and communication between services
  5. Basic Operations - Deployment, scaling, and troubleshooting

Success Criteria:

By the end of this session, you should be able to deploy containerized applications to Kubernetes, understand the relationship between Docker and Kubernetes, and perform basic cluster operations and troubleshooting.

3. Foundation Knowledge (15-20 minutes)

Core Concepts

What is Kubernetes?

Kubernetes (K8s) is an open-source container orchestration platform that automates deployment, scaling, and management of containerized applications. It was originally developed by Google and is now maintained by the Cloud Native Computing Foundation.

Real-World Analogy: Think of Kubernetes as the operating system for a data center. Just as your computer’s OS manages processes, memory, and hardware, Kubernetes manages containers, networking, and compute resources across multiple machines. Docker provides the “executable format” (containers), while Kubernetes provides the “execution environment” (orchestration).

Why This Matters: Kubernetes solves the challenges of running containers at scale - automatic scaling, self-healing, rolling updates, service discovery, and resource management across hundreds or thousands of nodes.

Kubernetes vs Docker Swarm

Feature Docker Swarm Kubernetes
Learning Curve Gentle Steep
Setup Complexity Simple Complex
Ecosystem Limited Extensive
Scalability Good Excellent
Feature Set Basic Comprehensive
Community Moderate Large

Kubernetes Architecture

Control Plane Components:

  • API Server: The front-end for the Kubernetes control plane
  • etcd: Distributed key-value store for cluster data
  • Scheduler: Assigns pods to nodes based on resource requirements
  • Controller Manager: Runs controller processes for cluster state

Node Components:

  • kubelet: Agent that communicates with the control plane
  • kube-proxy: Network proxy for service communication
  • Container Runtime: Docker, containerd, or other runtime

Core Kubernetes Objects

  • Pod: Smallest deployable unit (one or more containers)
  • Deployment: Manages replica sets and rolling updates
  • Service: Stable network endpoint for accessing pods
  • ConfigMap/Secret: Configuration and sensitive data management
  • Namespace: Virtual clusters for resource isolation

Key Terminology

  • Cluster: Set of nodes running Kubernetes
  • Node: Worker machine (physical or virtual) running pods
  • Pod: Group of one or more containers sharing network and storage
  • Label: Key-value pairs for organizing and selecting objects
  • Selector: Query mechanism for finding objects by labels

4. Detailed Explanation and Examples (25-30 minutes)

Understanding Kubernetes Architecture

Kubernetes follows a master-worker architecture where the control plane manages the cluster state and worker nodes run the actual workloads. The declarative model means you describe the desired state, and Kubernetes continuously works to maintain that state.

Pod Lifecycle and Management

Pods are ephemeral and designed to be replaceable. Higher-level objects like Deployments manage pods:

  1. Pending: Pod accepted but not yet scheduled
  2. Running: Pod bound to node and containers are running
  3. Succeeded: All containers terminated successfully
  4. Failed: All containers terminated with at least one failure
  5. Unknown: Pod state could not be determined

Service Discovery and Networking

Kubernetes provides several networking concepts:

  • Cluster IP: Internal cluster communication
  • NodePort: Exposes service on each node’s IP
  • LoadBalancer: Cloud provider load balancer
  • Ingress: HTTP/HTTPS routing to services

Storage in Kubernetes

Kubernetes abstracts storage through:

  • Volumes: Shared storage within a pod
  • Persistent Volumes (PV): Cluster-wide storage resources
  • Persistent Volume Claims (PVC): Storage requests by pods
  • Storage Classes: Dynamic provisioning of storage

Docker Container Integration

Kubernetes doesn’t directly run Docker containers but uses container runtimes that can execute OCI-compliant container images. Docker images work seamlessly in Kubernetes because they follow the OCI standard.

Container Lifecycle in Kubernetes

  1. Image Pull: kubelet pulls container images from registries
  2. Container Creation: Runtime creates containers from images
  3. Health Checks: Kubernetes monitors container health
  4. Restart Policy: Automatic restart based on failure conditions

Best Practices for Kubernetes Containers

  • Single Responsibility: One main process per container
  • Health Checks: Implement liveness and readiness probes
  • Resource Limits: Set CPU and memory limits
  • Security Context: Run containers with minimal privileges
  • Graceful Shutdown: Handle termination signals properly

Common Misconceptions

  1. Misconception: Kubernetes replaces Docker Reality: Kubernetes orchestrates containers; Docker can still be used to build images

  2. Misconception: Kubernetes is only for large enterprises Reality: Kubernetes can benefit organizations of all sizes, though it has complexity overhead

5. Live Coding Demonstration (20-25 minutes)

Example 1: Basic Pod and Deployment

# simple-pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: nginx-pod
  labels:
    app: nginx
spec:
  containers:
  - name: nginx
    image: nginx:1.21
    ports:
    - containerPort: 80
    resources:
      requests:
        memory: "64Mi"
        cpu: "250m"
      limits:
        memory: "128Mi"
        cpu: "500m"
    livenessProbe:
      httpGet:
        path: /
        port: 80
      initialDelaySeconds: 30
      periodSeconds: 10
    readinessProbe:
      httpGet:
        path: /
        port: 80
      initialDelaySeconds: 5
      periodSeconds: 5
# nginx-deployment.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.21
        ports:
        - containerPort: 80
        resources:
          requests:
            memory: "64Mi"
            cpu: "250m"
          limits:
            memory: "128Mi"
            cpu: "500m"
        env:
        - name: NGINX_PORT
          value: "80"
        volumeMounts:
        - name: nginx-config
          mountPath: /etc/nginx/conf.d
      volumes:
      - name: nginx-config
        configMap:
          name: nginx-config

Deploy and manage:

# Apply the deployment
kubectl apply -f nginx-deployment.yaml

# Check deployment status
kubectl get deployments
kubectl get pods
kubectl get replicasets

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

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

# View deployment details
kubectl describe deployment nginx-deployment

Example 2: Services and Service Discovery

# nginx-service.yaml
apiVersion: v1
kind: Service
metadata:
  name: nginx-service
  labels:
    app: nginx
spec:
  selector:
    app: nginx
  ports:
  - protocol: TCP
    port: 80
    targetPort: 80
  type: ClusterIP
---
apiVersion: v1
kind: Service
metadata:
  name: nginx-nodeport
  labels:
    app: nginx
spec:
  selector:
    app: nginx
  ports:
  - protocol: TCP
    port: 80
    targetPort: 80
    nodePort: 30080
  type: NodePort
# multi-tier-app.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: frontend
spec:
  replicas: 2
  selector:
    matchLabels:
      app: frontend
  template:
    metadata:
      labels:
        app: frontend
    spec:
      containers:
      - name: frontend
        image: nginx:alpine
        ports:
        - containerPort: 80
        env:
        - name: BACKEND_URL
          value: "http://backend-service:3000"
---
apiVersion: v1
kind: Service
metadata:
  name: frontend-service
spec:
  selector:
    app: frontend
  ports:
  - port: 80
    targetPort: 80
  type: LoadBalancer
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: backend
spec:
  replicas: 3
  selector:
    matchLabels:
      app: backend
  template:
    metadata:
      labels:
        app: backend
    spec:
      containers:
      - name: backend
        image: node:16-alpine
        command: ["node", "server.js"]
        ports:
        - containerPort: 3000
        env:
        - name: DATABASE_URL
          valueFrom:
            secretKeyRef:
              name: db-secret
              key: url
---
apiVersion: v1
kind: Service
metadata:
  name: backend-service
spec:
  selector:
    app: backend
  ports:
  - port: 3000
    targetPort: 3000
  type: ClusterIP

Service operations:

# Apply services
kubectl apply -f nginx-service.yaml
kubectl apply -f multi-tier-app.yaml

# Check services
kubectl get services
kubectl get endpoints

# Test service connectivity
kubectl run test-pod --image=alpine --rm -it -- sh
# Inside the pod:
# wget -qO- http://nginx-service
# nslookup nginx-service

# Port forwarding for local access
kubectl port-forward service/nginx-service 8080:80

# Check service details
kubectl describe service nginx-service

Example 3: ConfigMaps and Secrets

# app-config.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config
data:
  database_host: "postgres.example.com"
  database_port: "5432"
  log_level: "info"
  feature_flags: |
    feature_a=true
    feature_b=false
    feature_c=true
  nginx.conf: |
    server {
        listen 80;
        server_name localhost;
        
        location / {
            proxy_pass http://backend-service:3000;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
        }
        
        location /health {
            return 200 "healthy\n";
            add_header Content-Type text/plain;
        }
    }
---
apiVersion: v1
kind: Secret
metadata:
  name: app-secrets
type: Opaque
data:
  database_password: cGFzc3dvcmQxMjM=  # base64 encoded
  api_key: YWJjZGVmZ2hpams=  # base64 encoded
stringData:
  jwt_secret: "my-jwt-secret-key"  # will be base64 encoded automatically
# app-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:v1.0
        ports:
        - containerPort: 3000
        env:
        - name: DATABASE_HOST
          valueFrom:
            configMapKeyRef:
              name: app-config
              key: database_host
        - name: DATABASE_PORT
          valueFrom:
            configMapKeyRef:
              name: app-config
              key: database_port
        - name: DATABASE_PASSWORD
          valueFrom:
            secretKeyRef:
              name: app-secrets
              key: database_password
        - name: LOG_LEVEL
          valueFrom:
            configMapKeyRef:
              name: app-config
              key: log_level
        volumeMounts:
        - name: config-volume
          mountPath: /app/config
        - name: nginx-config
          mountPath: /etc/nginx/conf.d
      volumes:
      - name: config-volume
        configMap:
          name: app-config
          items:
          - key: feature_flags
            path: features.conf
      - name: nginx-config
        configMap:
          name: app-config
          items:
          - key: nginx.conf
            path: default.conf

Configuration management:

# Create configmap from file
kubectl create configmap nginx-config --from-file=nginx.conf

# Create secret from literal
kubectl create secret generic db-secret \
  --from-literal=username=admin \
  --from-literal=password=secretpassword

# Apply configuration
kubectl apply -f app-config.yaml
kubectl apply -f app-with-config.yaml

# Check configuration
kubectl get configmaps
kubectl get secrets
kubectl describe configmap app-config

# Update configmap and reload
kubectl patch configmap app-config -p '{"data":{"log_level":"debug"}}'
kubectl rollout restart deployment app-deployment

Example 4: Persistent Storage

# storage-example.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: app-storage
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi
  storageClassName: standard
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: database
spec:
  replicas: 1
  selector:
    matchLabels:
      app: database
  template:
    metadata:
      labels:
        app: database
    spec:
      containers:
      - name: postgres
        image: postgres:13
        env:
        - name: POSTGRES_DB
          value: myapp
        - name: POSTGRES_USER
          value: user
        - name: POSTGRES_PASSWORD
          valueFrom:
            secretKeyRef:
              name: db-secret
              key: password
        ports:
        - containerPort: 5432
        volumeMounts:
        - name: postgres-storage
          mountPath: /var/lib/postgresql/data
        resources:
          requests:
            memory: "256Mi"
            cpu: "250m"
          limits:
            memory: "512Mi"
            cpu: "500m"
      volumes:
      - name: postgres-storage
        persistentVolumeClaim:
          claimName: app-storage

Storage operations:

# Apply storage configuration
kubectl apply -f storage-example.yaml

# Check storage
kubectl get pvc
kubectl get pv
kubectl describe pvc app-storage

# Test data persistence
kubectl exec -it deployment/database -- psql -U user -d myapp
# Create some data, then delete and recreate the pod
kubectl delete pod -l app=database
# Verify data persists

Example 5: Monitoring and Troubleshooting

# Basic cluster information
kubectl cluster-info
kubectl get nodes -o wide
kubectl get namespaces

# Check resource usage
kubectl top nodes
kubectl top pods

# Troubleshooting pods
kubectl get pods --all-namespaces
kubectl describe pod pod-name
kubectl logs pod-name
kubectl logs -f deployment/nginx-deployment

# Exec into containers
kubectl exec -it pod-name -- /bin/bash
kubectl exec -it pod-name -c container-name -- /bin/sh

# Debug networking
kubectl run debug --image=alpine --rm -it -- sh
# Inside debug pod:
# nslookup kubernetes
# wget -qO- http://service-name

# Events and troubleshooting
kubectl get events --sort-by=.metadata.creationTimestamp
kubectl describe node node-name

# Resource quotas and limits
kubectl describe limitrange
kubectl describe resourcequota

# Port forwarding for debugging
kubectl port-forward pod/pod-name 8080:80
kubectl port-forward deployment/nginx-deployment 8080:80

6. Hands-On Practice (30-40 minutes)

Exercise 1: Deploy Multi-Tier Application (20 minutes)

Objective: Deploy a complete web application with frontend, backend, and database

Instructions:

  1. Create a namespace for your application
  2. Deploy a PostgreSQL database with persistent storage
  3. Deploy a backend API service that connects to the database
  4. Deploy a frontend web application
  5. Configure services for communication between tiers
  6. Test the complete application flow

Starter Template:

apiVersion: v1
kind: Namespace
metadata:
  name: myapp
---
# TODO: Add your database deployment and service
# TODO: Add your backend deployment and service  
# TODO: Add your frontend deployment and service
# TODO: Add ConfigMaps and Secrets as needed

Verification Steps:

# Check all resources
kubectl get all -n myapp

# Test connectivity between services
kubectl run test -n myapp --image=alpine --rm -it -- sh

# Check logs for each tier
kubectl logs -n myapp deployment/frontend
kubectl logs -n myapp deployment/backend
kubectl logs -n myapp deployment/database

Exercise 2: Rolling Updates and Rollbacks (15 minutes)

Objective: Practice zero-downtime deployments and rollback procedures

Requirements:

  • Deploy initial version of an application
  • Perform rolling update to new version
  • Monitor update progress
  • Simulate failed deployment and rollback

Commands to practice:

# Initial deployment
kubectl apply -f app-v1.yaml

# Rolling update
kubectl set image deployment/myapp container=myapp:v2

# Monitor rollout
kubectl rollout status deployment/myapp
kubectl rollout history deployment/myapp

# Rollback
kubectl rollout undo deployment/myapp

Exercise 3: Debugging Application Issues (5 minutes)

Objective: Diagnose and fix common Kubernetes application problems

Challenge Scenarios:

  • Pod stuck in Pending state
  • Service not accessible
  • ConfigMap changes not reflected
  • Persistent volume mounting issues

Extension Ideas:

  • Set up resource quotas and limits
  • Configure horizontal pod autoscaling
  • Implement ingress for external access

7. Common Pitfalls and Troubleshooting (10 minutes)

Frequent Kubernetes Issues

  1. Problem: Pods stuck in Pending state Cause: Insufficient cluster resources or scheduling constraints Solution: Check node resources and pod resource requests

  2. Problem: Services not accessible Cause: Incorrect label selectors or network policies Solution: Verify service selectors match pod labels

  3. Problem: Image pull failures Cause: Incorrect image names, registry authentication, or network issues Solution: Verify image exists and check imagePullSecrets

Debugging Techniques

# Pod troubleshooting workflow
kubectl get pods                          # Check pod status
kubectl describe pod pod-name             # Get detailed information
kubectl logs pod-name                     # Check application logs
kubectl logs pod-name --previous          # Check previous container logs
kubectl exec -it pod-name -- /bin/bash    # Interactive debugging

# Service troubleshooting
kubectl get endpoints service-name        # Check if pods are selected
kubectl describe service service-name     # Verify service configuration
kubectl port-forward service/service-name 8080:80  # Test locally

# Network debugging
kubectl run debug --image=nicolaka/netshoot --rm -it -- bash
# Use network tools: dig, nslookup, curl, ping

# Resource issues
kubectl describe node node-name           # Check node resources
kubectl get events --sort-by=.metadata.creationTimestamp  # Recent events

Performance Optimization

  • Resource Requests/Limits: Set appropriate CPU and memory values
  • Node Affinity: Schedule pods on appropriate nodes
  • Pod Disruption Budgets: Ensure availability during updates
  • Horizontal Pod Autoscaling: Automatic scaling based on metrics

8. Best Practices and Professional Tips (5 minutes)

Application Design

  • Twelve-Factor App: Follow cloud-native application principles
  • Health Checks: Implement liveness and readiness probes
  • Graceful Shutdown: Handle SIGTERM signals properly
  • Resource Efficiency: Set appropriate requests and limits

Security Best Practices

  • RBAC: Implement role-based access control
  • Security Context: Run containers with minimal privileges
  • Network Policies: Control pod-to-pod communication
  • Secret Management: Use Kubernetes secrets for sensitive data

Operational Excellence

  • Monitoring: Implement comprehensive observability
  • GitOps: Manage configurations through version control
  • Namespaces: Use namespaces for resource isolation
  • Labels and Annotations: Organize resources effectively

9. Summary and Review (5 minutes)

Key Takeaways

  1. Architecture Understanding: Kubernetes provides powerful orchestration for Docker containers
  2. Declarative Management: Define desired state and let Kubernetes maintain it
  3. Service Discovery: Built-in networking and service discovery capabilities
  4. Operational Benefits: Rolling updates, self-healing, and horizontal scaling

Quick Review Questions

  1. What’s the difference between a Pod and a Deployment in Kubernetes?
  2. How does service discovery work in Kubernetes?
  3. What are the key considerations when migrating from Docker Swarm to Kubernetes?

For Instructors

Teaching Tips

  • Use visual diagrams to explain Kubernetes architecture
  • Demonstrate the relationship between Docker containers and Kubernetes pods
  • Show both imperative commands and declarative YAML configurations
  • Emphasize hands-on practice with real cluster operations

Assessment Ideas

  • Deploy and manage multi-tier applications on Kubernetes
  • Troubleshoot common deployment and networking issues
  • Compare Kubernetes approaches with Docker Swarm equivalents

Adaptation Notes

  • Beginners: Focus on core concepts and basic operations before advanced features
  • Advanced: Cover topics like operators, custom resources, and cluster administration
  • Cloud Environment: Use managed Kubernetes services for easier setup
  • Local Development: Demonstrate tools like Minikube, Kind, or Docker Desktop Kubernetes