Chapter 3: Workload Controllers
Haiyue
25min
Chapter 3: Workload Controllers
Learning Objectives
- Master the use of Deployments and rolling update strategies
- Understand the role and working principles of ReplicaSet
- Learn to use StatefulSet to deploy stateful applications
- Proficiently use DaemonSet and Job/CronJob
Controller Overview
What is a Controller
Controllers are a core concept in Kubernetes, continuously monitoring cluster state through a control loop pattern to ensure the actual state matches the desired state.
🔄 正在渲染 Mermaid 图表...
Controller Types Overview
🔄 正在渲染 Mermaid 图表...
| Controller | Purpose | Pod Name | Storage | Network Identity |
|---|---|---|---|---|
| Deployment | Stateless apps | Random suffix | Can share | No fixed identity |
| StatefulSet | Stateful apps | Ordered number | Independent PVC | Fixed DNS name |
| DaemonSet | One per node | Node-related | Local storage | Node-related |
| Job | One-time task | Random suffix | Temporary | None |
| CronJob | Scheduled task | Time-related | Temporary | None |
Deployment Deep Dive
Deployment Architecture
🔄 正在渲染 Mermaid 图表...
Creating a Deployment
# 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.24
ports:
- containerPort: 80
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 200m
memory: 256Mi
# Create Deployment
kubectl apply -f nginx-deployment.yaml
# View Deployment status
kubectl get deployment nginx-deployment
# View detailed information
kubectl describe deployment nginx-deployment
# View associated ReplicaSet
kubectl get rs -l app=nginx
# View all Pods
kubectl get pods -l app=nginx
# Quick create Deployment (without YAML)
kubectl create deployment nginx --image=nginx:1.24 --replicas=3
Rolling Updates
🔄 正在渲染 Mermaid 图表...
Update Strategy Configuration
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 10
strategy:
type: RollingUpdate # or Recreate
rollingUpdate:
maxSurge: 25% # Maximum percentage above desired replicas
maxUnavailable: 25% # Maximum percentage of unavailable replicas
# Other configuration...
minReadySeconds: 5 # Wait time after Pod ready
progressDeadlineSeconds: 600 # Update timeout
revisionHistoryLimit: 10 # Number of historical versions to keep
Rolling Update - Gradually replace old Pods, ensuring service availability
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1 # Maximum 1 extra Pod
maxUnavailable: 0 # No unavailable Pods allowed
Update Process:
- Create new Pods first, wait for them to be ready
- Then delete old Pods
- Loop until all Pods are updated
Recreate - Delete all old Pods first, then create new Pods
strategy:
type: Recreate
Use Cases:
- Application doesn’t support multiple version coexistence
- Need to free resources before starting
- Can accept brief downtime
Performing Update Operations
# Method 1: Directly modify image
kubectl set image deployment/nginx-deployment nginx=nginx:1.25
# Method 2: Edit Deployment
kubectl edit deployment nginx-deployment
# Method 3: Apply new YAML
kubectl apply -f nginx-deployment-v2.yaml
# View update status
kubectl rollout status deployment/nginx-deployment
# View update history
kubectl rollout history deployment/nginx-deployment
# View specific version details
kubectl rollout history deployment/nginx-deployment --revision=2
# Pause update
kubectl rollout pause deployment/nginx-deployment
# Resume update
kubectl rollout resume deployment/nginx-deployment
# Rollback to previous version
kubectl rollout undo deployment/nginx-deployment
# Rollback to specific version
kubectl rollout undo deployment/nginx-deployment --to-revision=1
Scaling
# Manual scaling
kubectl scale deployment nginx-deployment --replicas=5
# Conditional scaling
kubectl scale deployment nginx-deployment --replicas=3 --current-replicas=5
# Use HPA for autoscaling
kubectl autoscale deployment nginx-deployment --min=2 --max=10 --cpu-percent=80
ReplicaSet
ReplicaSet Working Principle
🔄 正在渲染 Mermaid 图表...
ReplicaSet Configuration
# Usually not used directly, managed by Deployment
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: nginx-replicaset
labels:
app: nginx
spec:
replicas: 3
selector:
matchLabels:
app: nginx
# Also supports matchExpressions
matchExpressions:
- key: tier
operator: In
values:
- frontend
template:
metadata:
labels:
app: nginx
tier: frontend
spec:
containers:
- name: nginx
image: nginx:1.24
Note
In production environments, it’s recommended to use Deployment rather than directly using ReplicaSet. Deployment provides advanced features like rolling updates and rollbacks.
StatefulSet for Stateful Applications
StatefulSet Features
🔄 正在渲染 Mermaid 图表...
StatefulSet Configuration
# mysql-statefulset.yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: mysql
spec:
serviceName: mysql # Must associate with Headless Service
replicas: 3
selector:
matchLabels:
app: mysql
template:
metadata:
labels:
app: mysql
spec:
containers:
- name: mysql
image: mysql:8.0
ports:
- containerPort: 3306
name: mysql
env:
- name: MYSQL_ROOT_PASSWORD
valueFrom:
secretKeyRef:
name: mysql-secret
key: password
volumeMounts:
- name: data
mountPath: /var/lib/mysql
# PersistentVolumeClaim template
volumeClaimTemplates:
- metadata:
name: data
spec:
accessModes: ["ReadWriteOnce"]
storageClassName: standard
resources:
requests:
storage: 10Gi
# Update strategy
updateStrategy:
type: RollingUpdate
rollingUpdate:
partition: 0 # Partition update
# Pod management policy
podManagementPolicy: OrderedReady # or Parallel
Headless Service
StatefulSet must be used with a Headless Service:
# mysql-headless-service.yaml
apiVersion: v1
kind: Service
metadata:
name: mysql
labels:
app: mysql
spec:
clusterIP: None # Headless Service
selector:
app: mysql
ports:
- port: 3306
targetPort: 3306
StatefulSet Network Identity
🔄 正在渲染 Mermaid 图表...
Hands-on: Deploy MySQL Primary-Replica Cluster
# mysql-configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: mysql-config
data:
primary.cnf: |
[mysqld]
log-bin=mysql-bin
server-id=1
replica.cnf: |
[mysqld]
server-id=2
read-only=1
---
# mysql-secret.yaml
apiVersion: v1
kind: Secret
metadata:
name: mysql-secret
type: Opaque
data:
password: cGFzc3dvcmQxMjM= # base64 encoded password123
---
# mysql-statefulset.yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: mysql
spec:
serviceName: mysql
replicas: 3
selector:
matchLabels:
app: mysql
template:
metadata:
labels:
app: mysql
spec:
initContainers:
- name: init-mysql
image: mysql:8.0
command:
- bash
- "-c"
- |
set -ex
[[ $HOSTNAME =~ -([0-9]+)$ ]] || exit 1
ordinal=${BASH_REMATCH[1]}
if [[ $ordinal -eq 0 ]]; then
cp /mnt/config-map/primary.cnf /mnt/conf.d/
else
cp /mnt/config-map/replica.cnf /mnt/conf.d/
fi
volumeMounts:
- name: conf
mountPath: /mnt/conf.d
- name: config-map
mountPath: /mnt/config-map
containers:
- name: mysql
image: mysql:8.0
env:
- name: MYSQL_ROOT_PASSWORD
valueFrom:
secretKeyRef:
name: mysql-secret
key: password
ports:
- containerPort: 3306
volumeMounts:
- name: data
mountPath: /var/lib/mysql
- name: conf
mountPath: /etc/mysql/conf.d
resources:
requests:
cpu: 500m
memory: 1Gi
livenessProbe:
exec:
command: ["mysqladmin", "ping"]
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
exec:
command: ["mysql", "-h", "127.0.0.1", "-e", "SELECT 1"]
initialDelaySeconds: 5
periodSeconds: 2
volumes:
- name: conf
emptyDir: {}
- name: config-map
configMap:
name: mysql-config
volumeClaimTemplates:
- metadata:
name: data
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 10Gi
# Deploy
kubectl apply -f mysql-configmap.yaml
kubectl apply -f mysql-secret.yaml
kubectl apply -f mysql-headless-service.yaml
kubectl apply -f mysql-statefulset.yaml
# Watch deployment order
kubectl get pods -l app=mysql -w
# Verify network identity
kubectl run -it --rm debug --image=mysql:8.0 --restart=Never -- \
mysql -h mysql-0.mysql -u root -ppassword123 -e "SELECT @@hostname"
# Scale up
kubectl scale statefulset mysql --replicas=5
# View PVCs
kubectl get pvc -l app=mysql
DaemonSet Node Daemon
DaemonSet Features
🔄 正在渲染 Mermaid 图表...
DaemonSet Configuration
# node-exporter-daemonset.yaml
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: node-exporter
labels:
app: node-exporter
spec:
selector:
matchLabels:
app: node-exporter
template:
metadata:
labels:
app: node-exporter
spec:
hostNetwork: true # Use host network
hostPID: true # Share host PID namespace
containers:
- name: node-exporter
image: prom/node-exporter:v1.6.0
args:
- '--path.procfs=/host/proc'
- '--path.sysfs=/host/sys'
- '--path.rootfs=/host/root'
ports:
- containerPort: 9100
hostPort: 9100
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 200m
memory: 256Mi
volumeMounts:
- name: proc
mountPath: /host/proc
readOnly: true
- name: sys
mountPath: /host/sys
readOnly: true
- name: root
mountPath: /host/root
readOnly: true
volumes:
- name: proc
hostPath:
path: /proc
- name: sys
hostPath:
path: /sys
- name: root
hostPath:
path: /
tolerations:
- operator: Exists # Tolerate all taints, ensure runs on all nodes
updateStrategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 1
Common DaemonSet Use Cases
# fluentd-daemonset.yaml
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: fluentd
namespace: kube-system
spec:
selector:
matchLabels:
name: fluentd
template:
metadata:
labels:
name: fluentd
spec:
containers:
- name: fluentd
image: fluent/fluentd-kubernetes-daemonset:v1
volumeMounts:
- name: varlog
mountPath: /var/log
- name: containers
mountPath: /var/lib/docker/containers
readOnly: true
volumes:
- name: varlog
hostPath:
path: /var/log
- name: containers
hostPath:
path: /var/lib/docker/containers
# calico-node-daemonset.yaml
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: calico-node
namespace: kube-system
spec:
selector:
matchLabels:
k8s-app: calico-node
template:
metadata:
labels:
k8s-app: calico-node
spec:
hostNetwork: true
containers:
- name: calico-node
image: calico/node:v3.26.0
env:
- name: DATASTORE_TYPE
value: "kubernetes"
securityContext:
privileged: true
# csi-node-daemonset.yaml
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: csi-node
spec:
selector:
matchLabels:
app: csi-node
template:
metadata:
labels:
app: csi-node
spec:
containers:
- name: csi-driver
image: my-csi-driver:v1
securityContext:
privileged: true
volumeMounts:
- name: plugin-dir
mountPath: /csi
- name: pods-mount-dir
mountPath: /var/lib/kubelet
mountPropagation: "Bidirectional"
volumes:
- name: plugin-dir
hostPath:
path: /var/lib/kubelet/plugins/my-csi
- name: pods-mount-dir
hostPath:
path: /var/lib/kubelet
Job and CronJob
Job for One-time Tasks
🔄 正在渲染 Mermaid 图表...
Job Configuration
# batch-job.yaml
apiVersion: batch/v1
kind: Job
metadata:
name: batch-process
spec:
completions: 5 # Number of Pods that need to successfully complete
parallelism: 2 # Number of Pods running in parallel
backoffLimit: 4 # Number of failure retries
activeDeadlineSeconds: 600 # Timeout
template:
spec:
restartPolicy: Never # Job must be Never or OnFailure
containers:
- name: worker
image: busybox
command: ['sh', '-c', 'echo "Processing batch $JOB_INDEX"; sleep 10; echo "Done"']
env:
- name: JOB_INDEX
valueFrom:
fieldRef:
fieldPath: metadata.annotations['batch.kubernetes.io/job-completion-index']
Job Types
# Single Pod runs to completion
spec:
completions: 1
parallelism: 1
# Specified number of Pods need to complete
spec:
completions: 5
parallelism: 2
# Parallel processing, any Pod success completes
spec:
completions: 1
parallelism: 3
# Each Pod has unique index
spec:
completions: 5
parallelism: 5
completionMode: Indexed
CronJob for Scheduled Tasks
# backup-cronjob.yaml
apiVersion: batch/v1
kind: CronJob
metadata:
name: database-backup
spec:
schedule: "0 2 * * *" # Daily at 2 AM
timeZone: "Asia/Shanghai" # Timezone setting
# Concurrency policy
concurrencyPolicy: Forbid # Allow | Forbid | Replace
# History retention
successfulJobsHistoryLimit: 3
failedJobsHistoryLimit: 1
# Starting deadline
startingDeadlineSeconds: 200
# Suspend schedule
suspend: false
jobTemplate:
spec:
template:
spec:
restartPolicy: OnFailure
containers:
- name: backup
image: mysql:8.0
command:
- /bin/sh
- -c
- |
mysqldump -h mysql-primary -u root -p$MYSQL_PASSWORD --all-databases | \
gzip > /backup/backup-$(date +%Y%m%d-%H%M%S).sql.gz
env:
- name: MYSQL_PASSWORD
valueFrom:
secretKeyRef:
name: mysql-secret
key: password
volumeMounts:
- name: backup-volume
mountPath: /backup
volumes:
- name: backup-volume
persistentVolumeClaim:
claimName: backup-pvc
Cron Expressions
┌───────────── Minute (0 - 59)
│ ┌───────────── Hour (0 - 23)
│ │ ┌───────────── Day (1 - 31)
│ │ │ ┌───────────── Month (1 - 12)
│ │ │ │ ┌───────────── Day of Week (0 - 6, 0=Sunday)
│ │ │ │ │
* * * * *
| Expression | Meaning |
|---|---|
*/5 * * * * | Every 5 minutes |
0 * * * * | Every hour on the hour |
0 0 * * * | Daily at midnight |
0 2 * * * | Daily at 2 AM |
0 0 * * 0 | Sunday at midnight |
0 0 1 * * | 1st of month at midnight |
Hands-on Practice
Blue-Green Deployment
# nginx-blue.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-blue
spec:
replicas: 3
selector:
matchLabels:
app: nginx
version: blue
template:
metadata:
labels:
app: nginx
version: blue
spec:
containers:
- name: nginx
image: nginx:1.24
ports:
- containerPort: 80
---
# nginx-green.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-green
spec:
replicas: 3
selector:
matchLabels:
app: nginx
version: green
template:
metadata:
labels:
app: nginx
version: green
spec:
containers:
- name: nginx
image: nginx:1.25
ports:
- containerPort: 80
---
# nginx-service.yaml
apiVersion: v1
kind: Service
metadata:
name: nginx-service
spec:
selector:
app: nginx
version: blue # Switch to green for blue-green deployment
ports:
- port: 80
targetPort: 80
# Deploy blue version
kubectl apply -f nginx-blue.yaml
kubectl apply -f nginx-service.yaml
# Deploy green version (doesn't receive traffic)
kubectl apply -f nginx-green.yaml
# Verify green version
kubectl port-forward deployment/nginx-green 8080:80
# Switch traffic to green version
kubectl patch service nginx-service -p '{"spec":{"selector":{"version":"green"}}}'
# After confirming no issues, delete blue version
kubectl delete deployment nginx-blue
Canary Release
# canary-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-stable
spec:
replicas: 9
selector:
matchLabels:
app: nginx
track: stable
template:
metadata:
labels:
app: nginx
track: stable
spec:
containers:
- name: nginx
image: nginx:1.24
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-canary
spec:
replicas: 1 # 10% traffic
selector:
matchLabels:
app: nginx
track: canary
template:
metadata:
labels:
app: nginx
track: canary
spec:
containers:
- name: nginx
image: nginx:1.25
---
apiVersion: v1
kind: Service
metadata:
name: nginx-service
spec:
selector:
app: nginx # Matches both stable and canary
ports:
- port: 80
# Deploy
kubectl apply -f canary-deployment.yaml
# View traffic distribution
kubectl get pods -l app=nginx -L track
# Gradually increase canary percentage
kubectl scale deployment nginx-canary --replicas=3
kubectl scale deployment nginx-stable --replicas=7
# Complete switch
kubectl scale deployment nginx-canary --replicas=10
kubectl scale deployment nginx-stable --replicas=0
# Rename
kubectl patch deployment nginx-canary -p '{"metadata":{"name":"nginx-stable"}}'
Summary
Through this chapter, you should have mastered:
- Deployment: Declarative deployment and rolling updates for stateless applications
- ReplicaSet: Understanding the working principles of replica control
- StatefulSet: Stable identity and ordered deployment for stateful applications
- DaemonSet: Node-level daemon process management
- Job/CronJob: Configuration for one-time and scheduled tasks
Next Steps
In the next chapter, we will learn about Service and Ingress, mastering Kubernetes’ service discovery and load balancing mechanisms.