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:
- Kubernetes Architecture - Understanding the control plane and worker nodes
- Core Objects - Pods, Deployments, Services, and ConfigMaps
- Container Integration - Running Docker containers in Kubernetes
- Service Discovery - Networking and communication between services
- 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:
- Pending: Pod accepted but not yet scheduled
- Running: Pod bound to node and containers are running
- Succeeded: All containers terminated successfully
- Failed: All containers terminated with at least one failure
- 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
- Image Pull: kubelet pulls container images from registries
- Container Creation: Runtime creates containers from images
- Health Checks: Kubernetes monitors container health
- 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
-
Misconception: Kubernetes replaces Docker Reality: Kubernetes orchestrates containers; Docker can still be used to build images
-
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:
- Create a namespace for your application
- Deploy a PostgreSQL database with persistent storage
- Deploy a backend API service that connects to the database
- Deploy a frontend web application
- Configure services for communication between tiers
- 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
-
Problem: Pods stuck in Pending state Cause: Insufficient cluster resources or scheduling constraints Solution: Check node resources and pod resource requests
-
Problem: Services not accessible Cause: Incorrect label selectors or network policies Solution: Verify service selectors match pod labels
-
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
- Architecture Understanding: Kubernetes provides powerful orchestration for Docker containers
- Declarative Management: Define desired state and let Kubernetes maintain it
- Service Discovery: Built-in networking and service discovery capabilities
- Operational Benefits: Rolling updates, self-healing, and horizontal scaling
Quick Review Questions
- What’s the difference between a Pod and a Deployment in Kubernetes?
- How does service discovery work in Kubernetes?
- 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