探討 K8s 的守護進程集(DaemonSet)
顧名思義,DaemonSet?的主要功能是可讓你在 K8s 集群中運行一個守護進程 Pod。DaemonSet?可確保在所有(或部分)工作節上點運行 Pod 的副本。
隨著節點被添加到集群中,Pod 也被添加進去。當從集群中刪除節點時,這些 Pod 會被垃圾回收。刪除DaemonSet將清理其創建的 Pod。與其他編排對象不同的是,DaemonSet 開始運行的時間往往早于整個 K8s 集群出現的時間。
守護進程 Pod?具有以下特點:
-
它運行在 K8s 集群中的每個節點(大多數情況下)上 -
每個節點上只有一個這樣的 Pod -
當有新節點加入 K8s 集群時,就會在該新節點上自動創建 Pod -
當一個節點被刪除時,Pod 會相應地被回收
DaemonSet的一些典型用途:
-
在每個節點上運行集群存儲守護進程,例如? ceph
。 -
在每個節點上運行日志收集守護進程,例如? fluentd
。 -
在每個節點上運行節點監控守護進程,例如? Prometheus node exporter
。
K8s 系統守護程序集
事實上,K8s 本身就是使用?DaemonSet?來運行系統組件的。如果您運行以下命令:
可以看到 K8s 集群中運行著?aws-node
?和?kube-proxy
?兩個?DaemonSet?。
DaemonSet 定義
為了理解?DaemonSet?是如何工作的,首先你需要看一下它的定義:
這個?DaemonSet?管理著一個?fluentd-elasticsearch
?鏡像 Pod。該鏡像的功能非常有用:通過?fluentd
?可將 Docker 容器中的日志轉發到 ElasticSearch。
需要注意的是,在?DaemonSet?上,為了防止它占用過多的主機資源,我們一般應該添加?
resources
?字段來限制它的 CPU 和內存使用。
可以看到,DaemonSet?其實和 Deployment很像,只不過沒有?replicas
?字段;它還使用選擇器來選擇和管理所有帶有?name=fluentd-elasticsearch
?標簽的 Pod。
這些 Pod 模板也是用?template
?字段定義的。在該字段中,我們使用?fluentd-elasticsearch:2.5.2
?鏡像定義了一個容器,該容器掛載了兩個?hostPath
?類型的卷,分別對應主機的?/var/log
?和?/var/lib/docker/
?容器目錄。
很明顯,fluentd
?啟動后,會從這兩個目錄中收集日志信息,然后轉發給 ElasticSearch 保存。這樣,我們就可以通過 ElasticSearch 來輕松檢索這些日志。
在所有節點上運行 Pod
那么?DaemonSet?是如何保證每個節點上只托管一個 Pod 的呢?這通常由守護進程集控制器DaemonSet Controller
?處理。
DaemonSet 控制器首先從 api-server 上獲取所有節點的列表(從 etcd 獲取數據),然后遍歷所有節點,并檢查當前每個節點上是否有 DaemonSet Pod 在運行。
檢查結果可能有以下三種情況:
-
沒有這樣的 Pod,就意味著是在該 Node 上創建這樣的 Pod; -
如果有這樣的 Pod,但數量大于 1,則表示應該從該 Node 中刪除多余的 Pod; -
正好有 1 個這樣的 Pod,說明這個節點是正常的。
如果要在選定節點上調度 Pod,則必須指定?.spec.template.spec.nodeSelector
,然后?DaemonSet 控制器將在匹配節點選擇器的節點上創建 Pod。如果您不指定,則?DaemonSet 控制器將在所有節點上創建 Pod。例如:
但是,在 K8s 項目中,nodeSelector
?實際上是一個會被棄用的字段 因為,現在有一個功能更全的新字段來代替它,即:nodeAffinity
。
nodeAffinity
讓我們舉個例子吧:
在上面的例子中,我聲明了一個?spec.affinity
?字段,并定義了一個?nodeAffinity
。其中,spec.affinity
?字段是 Pod 中與調度相關的字段。
-
requiredDuringSchedulingIgnoredDuringExecution
:表示每次調度時都要考慮該?nodeAffinity
。同時,這也意味著在某些情況下 nodeAffinity 也可以設置為被忽略; -
這個 Pod 以后只被允許在 “ metadata.name
” 為 “node-name
” 的節點上運行。
因此,DaemonSet 控制器在創建 Pod 時會自動將這樣的?nodeAffinity
?定義添加到 Pod 的 API 對象中。其中,需要綁定的節點名稱為當前正在遍歷的節點。
容忍度(Tolerations)
另外,DaemonSet?會自動為這個 Pod 添加另一個稱為 tolerations 的調度相關字段。該字段意味著這個 Pod 將“容忍(Toleration)”一些節點“污點(Taint)”。
讓我們看一個例子:
這個?Toleration?的意思是:“容忍”所有標記為不可調度的“污點”的節點;“容忍”的效果是允許調度。
正常情況下,標記為不可調度的“污點”的 Node 不會有任何 Pod 被調度(效果:NoSchedule)。但是,DaemonSet?會自動將這個特殊的?Toleration?添加到托管的 Pod 中,這樣這些 Pod 就可以忽略這個限制,然后確保每個節點上都會調度一個 Pod。當然,如果節點出現故障,Pod 可能啟動失敗,DaemonSet?會一直嘗試,直到 Pod 啟動成功。
創建 DaemonSet
最后,讓我們創建這個?fluentd
?DaemonSet。執行以下命令:
創建成功之后,可以看到如下輸出:
此時,若想通過?kubectl get
?查看 Kubernetes 集群中的?DaemonSet?對象,則:
結論
DaemonSet?只管理 Pod 對象,然后通過?nodeAffinity?和?Toleration?的小功能保證每個節點上只有一個 Pod。這個控制器的實現原理和 Deployment 類似,應該簡單易懂。
鏈接:https://medium.com/dev-genius/k8s-daemonset-89273009150c
(版權歸原作者所有,侵刪)