寫這篇想要分享的重點:
在 Kubernetes 叢集中,除了由 Control Plane 統一調度的無狀態與有狀態應用外,還有一類特殊需求:例如日誌收集器、節點監控 Agent 或 CNI 網路插件,需要在「每一個 Node」上都常駐運行。本篇將說明 DaemonSet 與 Static Pods 的設計理念、原理與應用場景。這篇想要講什麼:
- DaemonSet 概念:確保全叢集(或指定節點)皆運行一份 Pod copy、遵從一套YAML 定義與版本。
- Static Pods 運作原理:無須通過 API Server 與 Scheduler,由 Kubelet 直接監控本機目錄管理的靜態 Pod,以及 Mirror Pod 的機制。
- 對比與總結:DaemonSet 與 Static Pods 在架構上的差異。
為何要寫這篇:
瞭解這兩種特殊部署方式,有助我們清楚「K8s 控制面組件(如 kube-apiserver, etcd)是如何自我啟動(Bootstrapping)的」,以及叢集該如何維護除錯。
由 K8s 的 DaemonSet Controller 管理,確保 Cluster 中每一個(或符合特定條件的)Node 上,都剛好運行一個 Pod copy。每當有新 Node 加入 Cluster 時,Pod 會自動在該 Node 上被建立;當 Node 被移除時,該 Pod 也會自動被垃圾回收(Garbage Collected)。
Calico、Weave Net 或 Flannel(需在每台 Node 上處理網路封包轉發與跨節點 Tunnel)。kube-proxy,在每個 Node 上維護網路規則。Fluentd、Logstash。Prometheus Node Exporter、自訂的 Monitoring Agent。在 Kubernetes 早期的版本(v1.12 以前),DaemonSet 是由 DaemonSet Controller 直接將 Pod 的 spec.nodeName 欄位填上特定 Node 名稱來指定節點;從 v1.12 版本開始,DaemonSet 正式全面改由預設調度器(Default Scheduler)配合 NodeAffinity 來實現。
即便 Node 被加上 NoSchedule 污點(例如 Control Plane 節點),只要 DaemonSet Pod 帶有對應的 Toleration(容忍度),就能順利部署到控制面節點上。
DaemonSet 的 YAML 寫法與 ReplicaSet 極為相似,主要差異在於 kind 指定為 DaemonSet,且不需要聲明 replicas(因為數量由 Node 的數量決定)。
💡 後面會說明ReplicaSet
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: node-exporter
namespace: kube-system
spec:
selector:
matchLabels:
app: node-exporter
template:
metadata:
labels:
app: node-exporter
spec:
tolerations:
- operator: Exists # 容忍所有污點,確保控制面與工作節點都能部署
containers:
- name: node-exporter
image: prom/node-exporter:v1.3.1
ports:
- containerPort: 9100
hostPort: 9100 # 綁定 Node 主機連接埠
查詢 DaemonSet:
kubectl get daemonsets -n kube-system
查看詳細狀態(包含 desired、current、ready 數量與 Pod Template):
kubectl describe daemonsets node-exporter -n kube-system
通常 Pod 的建立流程都需要經過 API Server -> etcd -> Scheduler -> Kubelet 的完整控制流程。但有一個典型的「雞生蛋、蛋生雞」難題:當控制面(Control Plane)本身還沒建立起來、API Server 與 etcd 都尚未存在時,我們要如何把控制面的組件當作容器跑起來?
答案就是 Static Pods(靜態 Pod)!
containerd、CRI-O)直接啟動並維護該 Pod。kubectl delete pod 刪除(即使強行刪除,Kubelet 發現本機 YAML 依然存在,就會立即重建 Pod)。唯一修改或刪除的方式是直接登入該 Node,修改或移除目錄中的 YAML 檔案。Kubelet 提供了兩種方式來設定Static Pod 的 Manifest 檔案目錄路徑:
kubelet.service 的啟動命令中加入 --pod-manifest-path=/etc/kubernetes/manifests。kubeconfig.yaml 或 config.yaml 中設定 staticPodPath: /etc/kubernetes/manifests。當 Control Plane 出現故障時,無法使用 kubectl 查詢 Pod 狀態,此時可以透過 Container Runtime 工具(如 crictl ps、nerdctl ps 或 docker ps)在 Node 主機上記錄與除錯。
雖然 Static Pods 繞過了 API Server,但為了讓管理者依然能透過 kubectl get pods 看到這些控制面 Pod,Kubelet 會在與 API Server 連線建立後,主動在 API Server 上建立一個唯讀的 Mirror Pod。
kube-apiserver-node01)。kubectl 進行編輯或刪除。使用 kubeadm 初始化 K8s 叢集時,kube-apiserver、kube-controller-manager、kube-scheduler 與 etcd 就是以 Static Pods 的形式部署在 Control Plane 節點上:
# 登入 Control Plane 節點查看靜態 Pod 配置目錄
ls -la /etc/kubernetes/manifests/
# 輸出結果:
# etcd.yaml
# kube-apiserver.yaml
# kube-controller-manager.yaml
# kube-scheduler.yaml
只要執行 kubectl get pods -n kube-system,就能看到這些由 Kubelet 建立 Mirror Pod 並註冊到控制面的組件。
| 項目 | Static Pods | DaemonSet |
|---|---|---|
| 由誰控管 | 該節點上的 kubelet |
Control Plane 的 DaemonSet Controller |
| 建立機制 | 掃描 Node 本機 /etc/kubernetes/manifests/ 目錄直接建立 |
透過 API Server 配合 Default Scheduler 與 NodeAffinity/Tolerations |
| 主要用途 | 部署 Control Plane 核心組件(etcd, apiserver 等) | 部署全叢集基礎設施 Agent(CNI, kube-proxy, 日誌, 監控) |
| 刪除/修改方式 | 直接修改/移除 Node 本機的 YAML 檔案 | 透過 API Server 指令(kubectl delete/edit ds) |
| 檢視工具 | Node 端使用 crictl ps,Cluster 端看 Mirror Pod |
直接使用 kubectl 進行叢集級別管理 |
RollingUpdate 與 Recreate 機制,並示範如何用 kubectl rollout undo 在幾秒內快速復原失敗的版次!敬請期待!kube-proxy、CNI 網路元件、日誌收集與節點監控。NodeAffinity 進行 Pod 的統一調度。/etc/kubernetes/manifests/ 目錄下的 YAML 檔直接啟動與維護。kubectl delete pod 刪除,只能直接移除或修改 Node 當地目錄內的 YAML 檔案;在 API Server 看到的僅為唯讀的 Mirror Pod。kubeadm 建立叢集時,kube-apiserver、etcd 等控制面關鍵組件就是以 Static Pods 的形式運行。