← 返回上一頁
Kubernetes

Kubernetes DaemonSet、Job、CronJob 與 StatefulSet 控制器完整解析

本頁目錄

前言

除了前面介紹的 ReplicaSet 和 Deployment 之外,Kubernetes 還提供了幾種針對特定場景設計的控制器:DaemonSet 用於在每個節點運行守護程序、Job/CronJob 處理批次任務、StatefulSet 管理有狀態應用。這篇文章會逐一介紹這些控制器的設計理念與實戰應用。

DaemonSet:每個節點一個副本

DaemonSet 確保叢集中的全部(或部分)Node 上都恰好運行一個 Pod 副本。當新 Node 加入叢集時自動建立 Pod,Node 移除時 Pod 也會被回收。

典型使用場景

  • 日誌收集:在每個節點上運行 Fluentd、Filebeat 或 Fluent-bit
  • 監控代理:部署 Prometheus Node Exporter、Datadog Agent
  • 叢集儲存:在每個節點運行 Ceph 或 GlusterFS 守護程序
  • 網路外掛:CNI 外掛如 Calico、Flannel 本身也是以 DaemonSet 部署的

DaemonSet 關鍵欄位

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: my-daemonset
spec:
  selector:
    matchLabels:
      app: monitoring
  template:
    metadata:
      labels:
        app: monitoring
    spec:
      containers:
      - name: node-exporter
        image: prom/node-exporter:v0.18.0
  updateStrategy:
    type: RollingUpdate         # 或 OnDelete(手動刪除 Pod 才更新)
    rollingUpdate:
      maxUnavailable: 1         # 滾動更新時最多同時有幾個不可用

與 Deployment 不同的是,DaemonSet 的更新策略沒有 maxSurge(因為每個 Node 就只能有一個副本),只有 maxUnavailable 參數。預設採用 RollingUpdate 策略,也可以設為 OnDelete,讓管理員手動控制更新節奏。

實戰:部署 Node Exporter

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: node-exporter
  labels:
    app: prometheus
    component: node-exporter
spec:
  selector:
    matchLabels:
      app: prometheus
      component: node-exporter
  template:
    metadata:
      labels:
        app: prometheus
        component: node-exporter
    spec:
      hostNetwork: true     # 使用宿主機網路
      hostPID: true          # 存取宿主機的程序資訊
      containers:
      - name: node-exporter
        image: prom/node-exporter:v0.18.0
        ports:
        - containerPort: 9100
          hostPort: 9100
        livenessProbe:
          tcpSocket:
            port: 9100
          initialDelaySeconds: 3
        readinessProbe:
          httpGet:
            path: '/metrics'
            port: 9100
          initialDelaySeconds: 5

這裡使用了 hostNetwork 和 hostPID 是因為 Node Exporter 需要存取宿主機的網路和程序資訊才能正確收集指標。更新映像檔版本後,DaemonSet 會自動進行滾動更新。

Job:一次性批次任務

Job 負責執行「跑完就結束」的批次任務,保證指定數量的 Pod 成功完成。與 Deployment 等控制器不同,Job 管理的 Pod 在任務完成後不會被重新啟動。

Job 關鍵欄位

欄位 說明 預設值
completions 需要成功完成的總次數 1
parallelism 最大並行數 1
backoffLimit 標記為 Failed 前的重試次數 6
activeDeadlineSeconds 任務最大存活時間(秒) 無限制
ttlSecondsAfterFinished 完成後保留多久才自動清理 不清理
restartPolicy 重啟策略(Job 只能用 Never 或 OnFailure) -

範例:串行與並行任務

串行執行:completions=2, parallelism=1(預設),表示執行完第一個才會啟動第二個。

apiVersion: batch/v1
kind: Job
metadata:
  name: job-serial
spec:
  completions: 2
  parallelism: 1
  backoffLimit: 3
  activeDeadlineSeconds: 300
  ttlSecondsAfterFinished: 3600
  template:
    spec:
      restartPolicy: Never
      containers:
      - name: worker
        image: alpine:3.11
        command: ["/bin/sh", "-c", "echo Processing...; sleep 60"]

並行執行:completions=12, parallelism=2,表示同時最多運行 2 個 Pod,總共需要成功 12 次。

apiVersion: batch/v1
kind: Job
metadata:
  name: job-parallel
spec:
  completions: 12
  parallelism: 2       # 同時運行 2 個 Pod
  backoffLimit: 3
  activeDeadlineSeconds: 1200
  ttlSecondsAfterFinished: 3600
  template:
    spec:
      restartPolicy: Never
      containers:
      - name: worker
        image: alpine:3.11
        command: ["/bin/sh", "-c", "echo Processing...; sleep 60"]

CronJob:週期性排程任務

CronJob 在 Job 的基礎上加入了時間排程功能,語法與 Linux 的 crontab 完全一致。CronJob 與 Job 的關係類似於 Deployment 與 ReplicaSet 的關係。

CronJob 關鍵欄位

apiVersion: batch/v1
kind: CronJob
metadata:
  name: my-cronjob
spec:
  schedule: "*/2 * * * *"        # 每 2 分鐘執行一次(分 時 日 月 週)
  concurrencyPolicy: Forbid      # Allow/Forbid/Replace
  failedJobsHistoryLimit: 1      # 保留失敗紀錄數
  successfulJobsHistoryLimit: 3  # 保留成功紀錄數
  startingDeadlineSeconds: 300   # 錯過排程的容許時間
  jobTemplate:
    spec:
      completions: 1
      parallelism: 1
      ttlSecondsAfterFinished: 600
      backoffLimit: 3
      activeDeadlineSeconds: 60
      template:
        spec:
          restartPolicy: OnFailure
          containers:
          - name: task
            image: alpine
            command: ["/bin/sh", "-c", "date; echo Hello from CronJob; sleep 10"]

concurrencyPolicy 的三個選項值得注意:

  • Allow:允許並行,前一個還沒跑完就啟動下一個
  • Forbid:禁止並行,前一個未完成則跳過本次排程
  • Replace:取消前一個正在運行的 Job,啟動新的

StatefulSet:有狀態應用管理

StatefulSet 是專為有狀態應用設計的控制器,它保證每個 Pod 都有穩定且唯一的身份標識。這是 Deployment 無法提供的能力。

StatefulSet 的四大保證

  1. 穩定的持久化儲存:Pod 重新調度後仍能存取相同的 PVC
  2. 穩定的網路標識:Pod 名稱固定為 ${STATEFULSET_NAME}-${ORDINAL}(如 web-0、web-1、web-2)
  3. 有序部署:從序號 0 開始依序建立,前一個就緒後才建立下一個
  4. 有序縮容:從最大序號開始逆序刪除

StatefulSet 的強制依賴:Headless Service

StatefulSet 必須搭配 Headless Service(clusterIP: None)使用,這樣每個 Pod 都會獲得一個穩定的 DNS 記錄:${POD_NAME}.${SERVICE_NAME}.${NAMESPACE}.svc.cluster.local。

實戰範例

# Headless Service
apiVersion: v1
kind: Service
metadata:
  name: demoapp-sts
spec:
  clusterIP: None
  ports:
  - port: 80
  selector:
    app: demoapp
    controller: sts-demo
---
# StatefulSet
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: sts-demo
spec:
  serviceName: demoapp-sts    # 綁定 Headless Service
  replicas: 2
  selector:
    matchLabels:
      app: demoapp
      controller: sts-demo
  template:
    metadata:
      labels:
        app: demoapp
        controller: sts-demo
    spec:
      containers:
      - name: demoapp
        image: ikubernetes/demoapp:v1.0
        ports:
        - containerPort: 80
        volumeMounts:
        - name: appdata
          mountPath: /app/data
  volumeClaimTemplates:       # 每個 Pod 自動建立獨立的 PVC
  - metadata:
      name: appdata
    spec:
      accessModes: ["ReadWriteOnce"]
      storageClassName: "longhorn"
      resources:
        requests:
          storage: 2Gi

觀察建立過程,會發現 Pod 是嚴格依序建立的:先完成 sts-demo-0 才會建立 sts-demo-1。

DNS 解析驗證

透過 nslookup 可以驗證每個 Pod 都有唯一的 DNS 記錄:

# 正向解析 - 列出所有 Pod IP
nslookup -query=A demodb.default.svc.cluster.local

# 反向解析 - 確認 IP 對應到特定 Pod
nslookup -query=PTR <Pod-IP>
# 結果:demodb-1.demodb.default.svc.cluster.local

擴容、縮容與更新

StatefulSet 的擴縮容和更新都遵循有序原則:

  • 擴容:從最大序號 +1 開始,依序建立
  • 縮容:從最大序號開始,逆序刪除
  • 更新:逆序更新,先更新最大序號的 Pod
# 使用 patch 修改副本數
kubectl patch sts/demodb -p '{"spec":{"replicas":5}}'   # 擴容
kubectl patch sts/demodb -p '{"spec":{"replicas":2}}'   # 縮容

值得注意的是,StatefulSet 的更新策略支援 partition 參數,可以實現分區更新。例如設定 partition: 2 表示只更新序號 >= 2 的 Pod,這在灰度發佈有狀態應用時非常實用。

控制器選擇指南

場景 推薦控制器 原因
Web 應用、API 服務 Deployment 無狀態,需要滾動更新與快速擴縮容
日誌/監控代理 DaemonSet 每個節點需要恰好一個副本
資料庫、訊息佇列 StatefulSet 需要穩定的網路標識和持久化儲存
資料處理、ETL Job 一次性任務,執行完即結束
定時備份、排程報表 CronJob 需要定期執行的任務

總結

K8s 提供了豐富的控制器來應對不同的工作負載場景。DaemonSet 解決了「每節點一個」的需求,Job 和 CronJob 處理批次與排程任務,而 StatefulSet 則為有狀態應用提供了穩定的身份與儲存保證。在實務中,選擇正確的控制器類型比調整控制器參數更重要,先搞清楚你的應用是無狀態還是有狀態、是長期運行還是一次性任務,再決定使用哪種控制器。

分享這篇
X LinkedIn Facebook Hacker News Reddit

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *

這個網站採用 Akismet 服務減少垃圾留言。進一步了解 Akismet 如何處理網站訪客的留言資料。