參考:https://kubernetes.io/zh/docs/concepts/workloads/controllers/daemonset/
https://www.kubernetes.org.cn/daemonset
DaemonSet
DaemonSet 確保全部(或者某些)節點上運行一個 Pod 的副本。當有節點加入集群時, 也會為他們新增一個 Pod 。當有節點從集群移除時,這些 Pod 也會被回收。刪除 DaemonSet 將會刪除它創建的所有 Pod。
DaemonSet的一些典型用法:
- 日志收集,比如fluentd,logstash等
- 系統監控,比如Prometheus Node Exporter,collectd,New Relic agent,Ganglia gmond等
- 系統程序,比如kube-proxy, kube-dns, glusterd, ceph等
一個簡單的用法是在所有的節點上都啟動一個 DaemonSet,將被作為每種類型的 daemon 使用。
一個稍微復雜的用法是單獨對每種 daemon 類型使用多個 DaemonSet,但具有不同的標志, 並且對不同硬件類型具有不同的內存、CPU 要求。
- 編寫DaemonSet Spec
- 如何調度Daemon Pods
- 與Daemon Pods通信
- 更新DaemonSet
- DaemonSet的可替代選擇
編寫DaemonSet Spec
創建DaemonSet Spec
您可以在 YAML 文件中描述 DaemonSet。例如,下面的 daemonset.yaml 文件描述了一個運行 fluentd-elasticsearch Docker 鏡像的 DaemonSet:
wget https://k8s.io/examples/controllers/daemonset.yaml
# cat daemonset.yaml apiVersion: apps/v1 kind: DaemonSet metadata: name: fluentd-elasticsearch namespace: kube-system labels: k8s-app: fluentd-logging spec: selector: matchLabels: name: fluentd-elasticsearch template: metadata: labels: name: fluentd-elasticsearch spec: tolerations: # this toleration is to have the daemonset runnable on master nodes # remove it if your masters can't run pods - key: node-role.kubernetes.io/master effect: NoSchedule containers: - name: fluentd-elasticsearch image: quay.io/fluentd_elasticsearch/fluentd:v2.5.2 resources: limits: memory: 200Mi requests: cpu: 100m memory: 200Mi volumeMounts: - name: varlog mountPath: /var/log - name: varlibdockercontainers mountPath: /var/lib/docker/containers readOnly: true terminationGracePeriodSeconds: 30 volumes: - name: varlog hostPath: path: /var/log - name: varlibdockercontainers hostPath: path: /var/lib/docker/containers
基於YAML文件創建DaemonSet
kubectl apply -f daemonset.yaml
必要字段
和其它所有 Kubernetes 配置一樣,DaemonSet 需要 apiVersion
、kind
和 metadata
字段。
Pod 模板
.spec中唯一必須的字段是.spec.template.
.spec.template是一個Pod模板。除了它是嵌套的,而且不具有 apiVersion
或 kind
字段,它與 Pod 具有相同的 schema。
除了 Pod 必需字段外,在 DaemonSet 中的 Pod 模板必須指定合理的標簽(查看 Pod Selector)。
在 DaemonSet 中的 Pod 模板必須具有一個值為 Always
的 RestartPolicy
,或者未指定它的值,默認是 Always
。
Pod Selector
.spec.selector
字段表示 Pod Selector,它與 Job 的 .spec.selector
的作用是相同的。
從Kubernetes1.8開始,必須知道與.spec.template的標簽匹配的pod selector。但不匹配時,poe selector將不再有默認值。selector默認與kubectl apply不兼容。此外,一旦創建了DaemonSet,它的.spec.selector就不能修改。修改pod selector可能導致Pod意外懸浮,並且這對用戶來說是困惑的。
spec.selector
表示一個對象,它由如下兩個字段組成:
matchLabels
- 與 ReplicationController 的.spec.selector
的作用相同。matchExpressions
- 允許構建更加復雜的 Selector,可以通過指定 key、value 列表 ,以及與 key 和 value 列表相關的操作符。
當上述兩個字段都指定時,結果表示的是 AND 關系。
如果指定了 .spec.selector
,必須與 .spec.template.metadata.labels
相匹配。如果與它們配置的不匹配,則會被 API 拒絕。
另外,通常不應直接通過另一個 DaemonSet 或另一個工作負載資源(例如 ReplicaSet)來創建其標簽與該選擇器匹配的任何 Pod。否則,DaemonSet 控制器會認為這些 Pod 是由它創建的。Kubernetes 不會阻止你這樣做。您可能要執行此操作的一種情況是,手動在節點上創建具有不同值的 Pod 進行測試。
僅在某些節點上運行Pod
如果指定了 .spec.template.spec.nodeSelector
,DaemonSet Controller 將在能夠與 Node Selector 匹配的節點上創建 Pod。類似這種情況,可以指定 .spec.template.spec.affinity
,然后 DaemonSet Controller 將在能夠與 node Affinity 匹配的節點上創建 Pod。 如果根本就沒有指定,則 DaemonSet Controller 將在所有節點上創建 Pod。
如何調度DaemonSet
通過默認的scheduler調度
DaemonSet確保所有符號條件的節點都運行該Pod的一個副本。通常,運行Pod的的節點由Kubernetes調度器抉擇。不過,DaemonSet pod是由DaemonSet控制器創建和調度。這將引入以下問題
- Pod行為的不一致性:等待調度正常的Pod已被創建並處以Pending,但DaemonSet pods未在Pending狀態下創建。這使用戶感到困惑。
- Pod preemption由默認 scheduler 處理。 啟用搶占后,DaemonSet 控制器將在不考慮 pod 優先級和搶占的情況下制定調度決策。
ScheduleDaemonSetPods
允許您使用默認調度器而不是 DaemonSet 控制器來調度 DaemonSets,方法是將 NodeAffinity
添加到 DaemonSet pods,而不是 .spec.nodeName
。 然后使用默認調度器將 pod 綁定到目標主機。 如果 DaemonSet pod 的親和節點已存在,則替換它。 DaemonSet 控制器僅在創建或修改 DaemonSet pods 時執行這些操作,並且不對 DaemonSet 的 spec.template
進行任何更改。
nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchFields: - key: metadata.name operator: In values: - target-host-name
此外,系統會自動添加 node.kubernetes.io/unschedulable:NoSchedule
容忍度到 DaemonSet Pods。 在調度 DaemonSet Pod 時,默認調度器會忽略 unschedulable
節點
污點和容忍度
盡管 Daemon Pods 遵循污點和容忍度 規則,根據相關特性,會自動將以下容忍度添加到 DaemonSet Pods 中。
容忍度關鍵詞 | 影響 | 版本 | 描述 |
---|---|---|---|
node.kubernetes.io/not-ready |
NoExecute | 1.13+ | DaemonSet pods will not be evicted when there are node problems such as a network partition. |
node.kubernetes.io/unreachable |
NoExecute | 1.13+ | DaemonSet pods will not be evicted when there are node problems such as a network partition. |
node.kubernetes.io/disk-pressure |
NoSchedule | 1.8+ | |
node.kubernetes.io/memory-pressure |
NoSchedule | 1.8+ | |
node.kubernetes.io/unschedulable |
NoSchedule | 1.12+ | DaemonSet pods tolerate unschedulable attributes by default scheduler. |
node.kubernetes.io/network-unavailable |
NoSchedule | 1.12+ | DaemonSet pods, who uses host network, tolerate network-unavailable attributes by default scheduler. |
與Daemon Pods通信
- Push:將 DaemonSet 中的 Pod 配置為將更新發送到另一個 Service,例如統計數據庫。
- NodeIP 和已知端口:DaemonSet 中的 Pod 可以使用
hostPort
,從而可以通過節點 IP 訪問到 Pod。客戶端能通過某種方法獲取節點 IP 列表,並且基於此也可以獲取到相應的端口。 - DNS:創建具有相同 Pod Selector 的 Headless Service,然后通過使用
endpoints
資源或從 DNS 中檢索到多個 A 記錄來發現 DaemonSet。 - Service:創建具有相同 Pod Selector 的 Service,並使用該 Service 隨機訪問到某個節點上的 daemon(沒有辦法訪問到特定節點)。
更新DaemonSet
如果修改了節點標簽,DaemonSet 將立刻向新匹配上的節點添加 Pod,同時刪除不能夠匹配的節點上的 Pod。
您可以修改 DaemonSet 創建的 Pod。然而,不允許對 Pod 的所有字段進行更新。當下次 節點(即使具有相同的名稱)被創建時,DaemonSet Controller 還會使用最初的模板。
您可以刪除一個 DaemonSet。如果使用 kubectl
並指定 --cascade=false
選項,則 Pod 將被保留在節點上。然后可以創建具有不同模板的新 DaemonSet。具有不同模板的新 DaemonSet 將能夠通過標簽匹配並識別所有已經存在的 Pod。 如果有任何 Pod 需要替換,則 DaemonSet 根據它的 updateStrategy
來替換。
DaemonSet的可替代選擇
init腳本
我們很可能希望直接在一個節點上啟動 daemon 進程(例如,使用 init
、upstartd
、或 systemd
)。這非常好,但基於 DaemonSet 來運行這些進程有如下一些好處:
-
像對待應用程序一樣,具備為 daemon 提供監控和管理日志的能力。
-
為 daemon 和應用程序使用相同的配置語言和工具(如 Pod 模板、
kubectl
)。 -
在資源受限的容器中運行 daemon,能夠增加 daemon 和應用容器的隔離性。然而,這也實現了在容器中運行 daemon,但卻不能在 Pod 中運行(例如,直接基於 Docker 啟動)。
裸Pod
可能要直接創建 Pod,同時指定其運行在特定的節點上。然而,DaemonSet 替換了由於任何原因被刪除或終止的 Pod,例如節點失敗、例行節點維護、內核升級。由於這個原因,我們應該使用 DaemonSet 而不是單獨創建 Pod。
靜態Pod
可能需要通過在一個指定目錄下編寫文件來創建 Pod,該目錄受 Kubelet 所監視。這些 Pod 被稱為 靜態 Pod。 不像 DaemonSet,靜態 Pod 不受 kubectl 和其它 Kubernetes API 客戶端管理。靜態 Pod 不依賴於 apiserver,這使得它們在集群啟動的情況下非常有用。而且,未來靜態 Pod 可能會被廢棄掉。
Deployment
DaemonSet 與 Deployments 非常類似,它們都能創建 Pod,這些 Pod 對應的進程都不希望被終止掉(例如,Web 服務器、存儲服務器)。 為無狀態的 Service 使用 Deployments,比如前端 Frontend 服務,實現對副本的數量進行擴縮容、平滑升級,比基於精確控制 Pod 運行在某個主機上要重要得多。 需要 Pod 副本總是運行在全部或特定主機上,並需要先於其他 Pod 啟動,當這被認為非常重要時,應該使用 Daemon Controller。