Các Loại Workload: StatefulSet, DaemonSet, Job và CronJob
Suốt series ta dùng Deployment — và đúng là nó lo phần lớn nhu cầu (app web, API không trạng thái). Nhưng Kubernetes có vài loại workload khác cho những bài toán Deployment không hợp. Biết chúng tồn tại và khi nào dùng giúp bạn chọn đúng công cụ thay vì gò ép Deployment cho mọi thứ.
Deployment → app KHÔNG trạng thái, các pod như nhau, thay thế tự do (web, API)
StatefulSet → app CÓ trạng thái, mỗi pod một danh tính ổn định (database)
DaemonSet → một pod trên MỖI node (agent log, monitoring)
Job → chạy tới khi HOÀN THÀNH rồi dừng (batch, migration)
CronJob → Job chạy theo LỊCH (backup hằng đêm)
Job: chạy tới khi xong
Deployment giả định pod chạy mãi. Nhưng nhiều tác vụ có điểm kết thúc: chạy migration, xử lý một lô dữ liệu, gửi báo cáo. Job chạy pod tới khi hoàn thành thành công rồi dừng — không restart vô hạn.
apiVersion: batch/v1
kind: Job
metadata:
name: pi
spec:
template:
spec:
containers:
- name: pi
image: perl:5.40-slim
command: ["perl", "-Mbignum=bpi", "-wle", "print bpi(50)"]
restartPolicy: Never
backoffLimit: 2
kubectl apply -f job.yaml
kubectl get job pi
kubectl logs job/pi
NAME STATUS COMPLETIONS DURATION AGE
pi Complete 1/1 17s 17s
3.1415926535897932384626433832795028841971693993751
Job chạy, tính 50 chữ số của số pi, rồi Complete (1/1). restartPolicy: Never và backoffLimit: 2 (thử lại tối đa 2 lần nếu fail) là hai trường đặc trưng của Job. Job giữ lại pod sau khi xong để bạn đọc log — khác hẳn Deployment.
CronJob: Job theo lịch
CronJob là Job chạy định kỳ, theo cú pháp cron quen thuộc (nhớ series Linux):
apiVersion: batch/v1
kind: CronJob
metadata:
name: hello
spec:
schedule: "*/1 * * * *" # mỗi phút (cú pháp cron)
jobTemplate:
spec:
template:
spec:
containers:
- name: hello
image: busybox:1.36
command: ["sh", "-c", "date; echo 'Xin chào từ CronJob'"]
restartPolicy: OnFailure
kubectl get cronjob hello
NAME SCHEDULE SUSPEND ACTIVE LAST SCHEDULE AGE
hello */1 * * * * False 0 <none> 0s
Mỗi phút (*/1 * * * *), CronJob tạo một Job mới chạy lệnh. Đây là cách Kubernetes-native để làm backup hằng đêm, dọn dẹp định kỳ, gửi báo cáo — thay cho crontab trên một máy đơn lẻ.
DaemonSet: một pod trên mỗi node
Có những thứ phải chạy trên mọi node, không phải "N bản sao đặt đâu cũng được": agent thu log, exporter giám sát, plugin mạng/lưu trữ. DaemonSet đảm bảo đúng một pod trên mỗi node — thêm node mới, nó tự thêm pod lên node đó.
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: node-logger
spec:
selector:
matchLabels: { app: node-logger }
template:
metadata:
labels: { app: node-logger }
spec:
containers:
- name: logger
image: busybox:1.36
command: ["sh", "-c", "while true; do sleep 3600; done"]
kubectl get daemonset node-logger
NAME DESIRED CURRENT READY NODE SELECTOR AGE
node-logger 1 1 1 <none> 5s
DESIRED 1 vì minikube có một node. Trên cluster 10 node, DaemonSet sẽ tự có 10 pod — một trên mỗi node. Bạn không khai replicas; số pod luôn bằng số node. (Chính các thành phần như kube-proxy ở Bài 1 chạy dưới dạng DaemonSet.)
StatefulSet: cho app có trạng thái
Đây là loại tinh tế nhất. Với Deployment, các pod vô danh và thay thế được — tên ngẫu nhiên (web-5687-9n9j7), chết cái nào dựng cái khác cũng như nhau. Nhưng database thì khác: node 0 là primary, node 1–2 là replica; mỗi node cần danh tính ổn định và đĩa riêng của nó. StatefulSet cung cấp đúng vậy.
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: web-sts
spec:
serviceName: nginx-sts
replicas: 3
selector:
matchLabels: { app: nginx-sts }
template:
# ... như Deployment ...
volumeClaimTemplates: # mỗi pod tự có một PVC riêng
- metadata: { name: data }
spec:
accessModes: ["ReadWriteOnce"]
resources: { requests: { storage: 50Mi } }
kubectl get pods -l app=nginx-sts
kubectl get pvc -l app=nginx-sts
NAME READY STATUS AGE
web-sts-0 1/1 Running 6s
web-sts-1 1/1 Running 4s
web-sts-2 1/1 Running 2s
NAME STATUS VOLUME CAPACITY STORAGECLASS
data-web-sts-0 Bound pvc-a745d57d... 50Mi standard
data-web-sts-1 Bound pvc-c50a2045... 50Mi standard
data-web-sts-2 Bound pvc-f1eaa136... 50Mi standard
Ba khác biệt cốt lõi so với Deployment hiện ra ngay:
- Tên ổn định, có thứ tự:
web-sts-0,web-sts-1,web-sts-2— không phải hash ngẫu nhiên. Podweb-sts-0chết và dựng lại vẫn tên đó, vẫn nối lại đúng đĩa của nó. - PVC riêng mỗi pod:
volumeClaimTemplatestự tạo một PVC cho từng pod (data-web-sts-0/1/2) — dữ liệu của pod 0 không lẫn pod 1. Đây là điều database cần. - Tạo/xoá tuần tự: pod sinh theo thứ tự 0→1→2 (để ý
AGEgiảm dần), xoá theo chiều ngược. Quan trọng cho cụm có primary/replica.
Lưu ý StatefulSet thường đi với headless Service (clusterIP: None) để mỗi pod có một tên DNS riêng (web-sts-0.nginx-sts...) — cho phép gọi đích danh từng pod, thứ database cluster cần.
Thực tế, vận hành database trên Kubernetes thường dùng Operator (cài qua CRD) chứ ít khi tự viết StatefulSet trần, vì backup/failover phức tạp. Nhưng hiểu StatefulSet là nền để hiểu các Operator đó.
Tổng kết
Ngoài Deployment (app không trạng thái), Kubernetes có: Job (chạy tới hoàn thành rồi dừng — migration, batch), CronJob (Job theo lịch cron — backup hằng đêm), DaemonSet (đúng một pod trên mỗi node — agent log/giám sát, tự co giãn theo số node), và StatefulSet (cho app có trạng thái — tên ổn định có thứ tự, PVC riêng mỗi pod, tạo/xoá tuần tự, thường kèm headless Service). Chọn đúng loại theo bản chất tác vụ thay vì gò mọi thứ vào Deployment.
Ta đã có gần đủ công cụ. Bài 13 lùi lại một bước để rèn kỹ năng sống còn hằng ngày: quan sát và gỡ lỗi — đọc log, exec, describe, events, và dùng dashboard.