Kuebernetes之DaemonSet
DaemonSet確保叢集中每個(部分)node執行一份pod副本,當node加入叢集時建立pod,當node離開叢集時回收pod。如果刪除DaemonSet,其建立的所有pod也被刪除,DaemonSet中的pod覆蓋整個叢集。
當需要在叢集內每個node運行同一個pod,使用DaemonSet是有價值的,以下是典型使用場景:
- 執行叢集儲存守護程序,如glusterd、ceph。
- 執行叢集日誌收集守護程序,如fluentd、logstash。
- 執行節點監控守護程序,如Prometheus Node Exporter, collectd, Datadog agent, New Relic agent, or Ganglia gmond。
建立DaemonSet
以下是DaemonSet的示例spec檔案,執行fluentd-elasticsearch image:
- 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:
- - key: node-role.kubernetes.io/master
- effect: NoSchedule
- containers:
- - name: fluentd-elasticsearch
- image: k8s.gcr.io/fluentd-elasticsearch:1.20
- 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
以上DaemonSet中沒有restart policy欄位,預設為Always。如果有的話,必需將值設定成Always,否則在建立時出出現不可用錯誤。
DaemonSet同樣會受到Taint的抵制,如果不在配置中加入匹配的Toleration,那麼DaemonSet不會在擁有Taint屬性的node上部署pod。上例中有如下內容:
- tolerations:
- - key: node-role.kubernetes.io/master
- effect: NoSchedule
原因就是系統預設為master節點增加了 “node-role.kubernetes.io/master”的Taint,以抵制普通pod部署,使master成為專用節點。因為我們預期上例DaemonSet在叢集內全域性部署,因此需要加入相匹配的Toleration。
如果預期DaemonSet只在特定節點上執行,可以在上述配置檔案中加入.spec.template.spec.nodeSelector欄位。.
spec.template.spec.nodeSelector欄位內加入節點選擇器(node selector)或者親和選擇器(node affinity),則DaemonSet只會在滿足條件的node上部署pod。總之,可以通過Taint、Toleration、Affinity、node label控制DaemonSet部署pod的節點範圍。
將以上內容儲存在daemonset.yaml檔案中,執行如下命令建立DaemonSet:
kubectl create -f https://k8s.io/examples/controllers/daemonset.yaml
系統如何排程DaemonSet pod?
預設情況下DaemonSet在建立pod時,為其增加spec.nodeName欄位,也就是說所建立的pod執行在那個節上在建立階段就已經確定,所以DaemonSet中的pod實際上沒有接受kubernetes scheduler的排程,它不需要排程,因此產生以下兩個特性:
- DaemonSet中的pod不遵從節點的unreachable條件,也就是即使節點被系統判定為不可達,DaemonSet仍然試圖在其上部署pod。
- 在叢集引導階段,即使kubernetes scheduler還沒有部署生效,DaemonSet仍然可以將pod部署到叢集中的任何節點,此特性主要是在叢集引導階段使用。
因為DaemonSet不同於常規pod的排程特性,它帶來兩個問題:
- pod行為不一致。普通pod被建立以後等待排程的階段稱為pending,因為DaemonSet中的pod無需排程,因而無此狀態,使用者會因此產生迷惑。
- pod優先順序特性由kubernetes scheduler實現,DaemonSet無此特性。當系統開啟pod優先順序功能時,pod優先順序特性會被DaemonSet中的pod忽略。
為了解決以上兩個問題,kubernetes增加了通過設定允許DaemonSet使用kurbernetes scheduler的功能,並在1.11的 alpha版本中成為穩定特性。其實現機制是DaemonSet在建立pod時,不再自動新增.spec.nodeName,而是以nodeAffinity取而代之,示例如下:
- nodeAffinity:
- requiredDuringSchedulingIgnoredDuringExecution:
- nodeSelectorTerms:
- - matchFields:
- - key: metadata.name
- operator: In
- values:
- - target-host-name
其中"target-host-name"就是原來.spec.nodeName的值,這樣pod就會被kubernetes scheduler排程。通過以上操作解決了上述兩個問題。但DaemonSet的排程有自己因有的特性,在上文中提到的“不受節點unreachable條件限制”,為了使DaemonSet在使用kubernetes scheduler時仍然保持此特性需要開啟叢集的"TaintNodesByCondition"特性,如果DaemonSet使用主機網路那麼必需在DaemonSet中新增如下的Toleration:
node.kubernetes.io/network-unavailable:NoSchedule
DaemonSet自動新增的Toleration
系統在某此條件下會自動為節點新增Taint,比如硬碟不足、網路不可達等,以阻止新pod往不滿足條件的節點上排程。但DaemonSet的目的是在全部有資格的node上部署,不希望被這種Taint打斷,因經系統也預設為DaemonSet上的pod新增Toleration。如下表:
Toleration Key | Effect | Alpha Features | Version | Description |
---|---|---|---|---|
node.kubernetes.io/not-ready |
NoExecute | TaintBasedEvictions |
1.8+ | whenTaintBasedEvictions is enabled,they will not be evicted when there are node problems such as a network partition. |
node.kubernetes.io/unreachable |
NoExecute | TaintBasedEvictions |
1.8+ | whenTaintBasedEvictions is enabled,they will not be evicted when there are node problems such as a network partition. |
node.kubernetes.io/disk-pressure |
NoSchedule | TaintNodesByCondition |
1.8+ | |
node.kubernetes.io/memory-pressure |
NoSchedule | TaintNodesByCondition |
1.8+ | |
node.kubernetes.io/unschedulable |
NoSchedule | ScheduleDaemonSetPods ,TaintNodesByCondition |
1.11+ | WhenScheduleDaemonSetPods is enabled,TaintNodesByCondition is necessary to make sure DaemonSet pods tolerate unschedulable attributes by default scheduler. |
node.kubernetes.io/network-unavailable |
NoSchedule | ScheduleDaemonSetPods ,TaintNodesByCondition , hostnework |
1.11+ | WhenScheduleDaemonSetPods is enabled,TaintNodesByCondition is necessary to make sure DaemonSet pods, who uses host network, tolerate network-unavailable attributes by default scheduler. |
node.kubernetes.io/out-of-disk |
NoSchedule | ExperimentalCriticalPodAnnotation (critical pod only),TaintNodesByCondition |
1.8+ |
與DaemonSet中pod通訊的幾種模式
- Push:收集資料並向其它服務傳送,如將收集到的統計資訊傳送給統計型別資料庫。
- NodeIP and Known Port:DaemonSet中的pod可以被設定使用主機網路的一個port,而客戶端可以很方便的知道節點IP列表,因此可以通過節點IP地址與port訪問DaemonSet pod。
- DNS:建立無頭服務並且讓它的選擇器匹配所有DaemonSet的pod,這樣DaemonSet中的pod就會成為無頭服務的endpoints。類似於StatefulSet。
- Service:讓Service選中DaemonSet,為訪問DaemonSet中的pod提供統一入口與負載均衡。