探討 K8s 的守護(hù)進(jìn)程集(DaemonSet)
顧名思義,DaemonSet?的主要功能是可讓你在 K8s 集群中運(yùn)行一個(gè)守護(hù)進(jìn)程 Pod。DaemonSet?可確保在所有(或部分)工作節(jié)上點(diǎn)運(yùn)行 Pod 的副本。
隨著節(jié)點(diǎn)被添加到集群中,Pod 也被添加進(jìn)去。當(dāng)從集群中刪除節(jié)點(diǎn)時(shí),這些 Pod 會(huì)被垃圾回收。刪除DaemonSet將清理其創(chuàng)建的 Pod。與其他編排對(duì)象不同的是,DaemonSet 開始運(yùn)行的時(shí)間往往早于整個(gè) K8s 集群出現(xiàn)的時(shí)間。
守護(hù)進(jìn)程 Pod?具有以下特點(diǎn):
-
它運(yùn)行在 K8s 集群中的每個(gè)節(jié)點(diǎn)(大多數(shù)情況下)上 -
每個(gè)節(jié)點(diǎn)上只有一個(gè)這樣的 Pod -
當(dāng)有新節(jié)點(diǎn)加入 K8s 集群時(shí),就會(huì)在該新節(jié)點(diǎn)上自動(dòng)創(chuàng)建 Pod -
當(dāng)一個(gè)節(jié)點(diǎn)被刪除時(shí),Pod 會(huì)相應(yīng)地被回收
DaemonSet的一些典型用途:
-
在每個(gè)節(jié)點(diǎn)上運(yùn)行集群存儲(chǔ)守護(hù)進(jìn)程,例如? ceph
。 -
在每個(gè)節(jié)點(diǎn)上運(yùn)行日志收集守護(hù)進(jìn)程,例如? fluentd
。 -
在每個(gè)節(jié)點(diǎn)上運(yùn)行節(jié)點(diǎn)監(jiān)控守護(hù)進(jìn)程,例如? Prometheus node exporter
。
K8s 系統(tǒng)守護(hù)程序集
事實(shí)上,K8s 本身就是使用?DaemonSet?來運(yùn)行系統(tǒng)組件的。如果您運(yùn)行以下命令:

可以看到 K8s 集群中運(yùn)行著?aws-node
?和?kube-proxy
?兩個(gè)?DaemonSet?。
DaemonSet 定義
為了理解?DaemonSet?是如何工作的,首先你需要看一下它的定義:

這個(gè)?DaemonSet?管理著一個(gè)?fluentd-elasticsearch
?鏡像 Pod。該鏡像的功能非常有用:通過?fluentd
?可將 Docker 容器中的日志轉(zhuǎn)發(fā)到 ElasticSearch。
需要注意的是,在?DaemonSet?上,為了防止它占用過多的主機(jī)資源,我們一般應(yīng)該添加?
resources
?字段來限制它的 CPU 和內(nèi)存使用。
可以看到,DaemonSet?其實(shí)和 Deployment很像,只不過沒有?replicas
?字段;它還使用選擇器來選擇和管理所有帶有?name=fluentd-elasticsearch
?標(biāo)簽的 Pod。
這些 Pod 模板也是用?template
?字段定義的。在該字段中,我們使用?fluentd-elasticsearch:2.5.2
?鏡像定義了一個(gè)容器,該容器掛載了兩個(gè)?hostPath
?類型的卷,分別對(duì)應(yīng)主機(jī)的?/var/log
?和?/var/lib/docker/
?容器目錄。
很明顯,fluentd
?啟動(dòng)后,會(huì)從這兩個(gè)目錄中收集日志信息,然后轉(zhuǎn)發(fā)給 ElasticSearch 保存。這樣,我們就可以通過 ElasticSearch 來輕松檢索這些日志。
在所有節(jié)點(diǎn)上運(yùn)行 Pod
那么?DaemonSet?是如何保證每個(gè)節(jié)點(diǎn)上只托管一個(gè) Pod 的呢?這通常由守護(hù)進(jìn)程集控制器DaemonSet Controller
?處理。
DaemonSet 控制器首先從 api-server 上獲取所有節(jié)點(diǎn)的列表(從 etcd 獲取數(shù)據(jù)),然后遍歷所有節(jié)點(diǎn),并檢查當(dāng)前每個(gè)節(jié)點(diǎn)上是否有 DaemonSet Pod 在運(yùn)行。
檢查結(jié)果可能有以下三種情況:
-
沒有這樣的 Pod,就意味著是在該 Node 上創(chuàng)建這樣的 Pod; -
如果有這樣的 Pod,但數(shù)量大于 1,則表示應(yīng)該從該 Node 中刪除多余的 Pod; -
正好有 1 個(gè)這樣的 Pod,說明這個(gè)節(jié)點(diǎn)是正常的。
如果要在選定節(jié)點(diǎn)上調(diào)度 Pod,則必須指定?.spec.template.spec.nodeSelector
,然后?DaemonSet 控制器將在匹配節(jié)點(diǎn)選擇器的節(jié)點(diǎn)上創(chuàng)建 Pod。如果您不指定,則?DaemonSet 控制器將在所有節(jié)點(diǎn)上創(chuàng)建 Pod。例如:
但是,在 K8s 項(xiàng)目中,nodeSelector
?實(shí)際上是一個(gè)會(huì)被棄用的字段 因?yàn)?,現(xiàn)在有一個(gè)功能更全的新字段來代替它,即:nodeAffinity
。
nodeAffinity
讓我們舉個(gè)例子吧:

在上面的例子中,我聲明了一個(gè)?spec.affinity
?字段,并定義了一個(gè)?nodeAffinity
。其中,spec.affinity
?字段是 Pod 中與調(diào)度相關(guān)的字段。
-
requiredDuringSchedulingIgnoredDuringExecution
:表示每次調(diào)度時(shí)都要考慮該?nodeAffinity
。同時(shí),這也意味著在某些情況下 nodeAffinity 也可以設(shè)置為被忽略; -
這個(gè) Pod 以后只被允許在 “ metadata.name
” 為 “node-name
” 的節(jié)點(diǎn)上運(yùn)行。
因此,DaemonSet 控制器在創(chuàng)建 Pod 時(shí)會(huì)自動(dòng)將這樣的?nodeAffinity
?定義添加到 Pod 的 API 對(duì)象中。其中,需要綁定的節(jié)點(diǎn)名稱為當(dāng)前正在遍歷的節(jié)點(diǎn)。
容忍度(Tolerations)
另外,DaemonSet?會(huì)自動(dòng)為這個(gè) Pod 添加另一個(gè)稱為 tolerations 的調(diào)度相關(guān)字段。該字段意味著這個(gè) Pod 將“容忍(Toleration)”一些節(jié)點(diǎn)“污點(diǎn)(Taint)”。
讓我們看一個(gè)例子:

這個(gè)?Toleration?的意思是:“容忍”所有標(biāo)記為不可調(diào)度的“污點(diǎn)”的節(jié)點(diǎn);“容忍”的效果是允許調(diào)度。
正常情況下,標(biāo)記為不可調(diào)度的“污點(diǎn)”的 Node 不會(huì)有任何 Pod 被調(diào)度(效果:NoSchedule)。但是,DaemonSet?會(huì)自動(dòng)將這個(gè)特殊的?Toleration?添加到托管的 Pod 中,這樣這些 Pod 就可以忽略這個(gè)限制,然后確保每個(gè)節(jié)點(diǎn)上都會(huì)調(diào)度一個(gè) Pod。當(dāng)然,如果節(jié)點(diǎn)出現(xiàn)故障,Pod 可能啟動(dòng)失敗,DaemonSet?會(huì)一直嘗試,直到 Pod 啟動(dòng)成功。
創(chuàng)建 DaemonSet
最后,讓我們創(chuàng)建這個(gè)?fluentd
?DaemonSet。執(zhí)行以下命令:

創(chuàng)建成功之后,可以看到如下輸出:

此時(shí),若想通過?kubectl get
?查看 Kubernetes 集群中的?DaemonSet?對(duì)象,則:

結(jié)論
DaemonSet?只管理 Pod 對(duì)象,然后通過?nodeAffinity?和?Toleration?的小功能保證每個(gè)節(jié)點(diǎn)上只有一個(gè) Pod。這個(gè)控制器的實(shí)現(xiàn)原理和 Deployment 類似,應(yīng)該簡(jiǎn)單易懂。
鏈接:https://medium.com/dev-genius/k8s-daemonset-89273009150c
(版權(quán)歸原作者所有,侵刪)