在前面的章節中,學習如何使用 Deployment 或 StatefulSet 在叢集的節點之間散佈工作負載的多個副本。 但是,如果您想在每個節點上只運行一個副本怎麼辦?例如,您可能希望每個節點運行一個agent或daemon,來幫此節點提供系統服務(像是metric收集或log聚合)。 要在k8s中部署這些類型的工作負載,您可以使用DaemonSet。

在開始之前,建立kiada命名空間,切換到Chapter16/目錄,並執行以下指令apply SETUP/目錄中的所有yaml:

$ kubectl create ns kiada
$ kubectl config set-context --current --namespace kiada
$ kubectl apply -f SETUP -R

16.1 介紹 DaemonSet

DaemonSet是一個API物件,可確保在每個叢集節點上運行一個Pod副本。預設情況下,DaemonSet Pod部署在每個節點上,但可以使用節點選擇器將部署限制在某些節點上。

DaemonSet包含一個Pod模板並使用它來建立多個Pod副本,就像Deployment、ReplicaSet、StatefulSets一樣。 但是,使用DaemonSet,您不需要指定期望副本數。相反,DaemonSet controller會建立與叢集中的節點一樣多的Pod。 它確保每個Pod被調度到不同的節點上,不像ReplicaSet部署的Pod,多個Pod可以被調度到同一個節點上,如下圖。

圖 16.1 DaemonSet在每個節點上運行一個Pod副本,而ReplicaSet將它們分散在叢集各處。

圖 16.1 DaemonSet在每個節點上運行一個Pod副本,而ReplicaSet將它們分散在叢集各處。

DaemonSet通常用來部署幫每個叢集節點提供某種系統層級服務的基礎設施Pod。 這包括收集節點系統程序和Pod的log、監控這些程序的daemon、提供叢集網路和儲存、管理套件安裝和更新的工具,以及連結到節點上各種設備提供介面的服務。

Kube Proxy元件負責在叢集中建立的Service物件路由流量,通常利用kube-system命名空間中的DaemonSet部署。 提供Pod網路通訊的Container Network Interface (CNI) plugin通常也利用DaemonSet部署。

儘管您可以使用初始化腳本或systemd等標準方法在叢集節點上運行系統軟體,但使用DaemonSet可確保您以相同的方式管理叢集中的所有工作負載。

就像ReplicaSet和StatefulSets一樣,DaemonSet包含一個Pod模板和一個標籤選擇器,用來確定哪些Pod屬於DaemonSet。 在它的協調循環的每一次通過中,DaemonSet controller都會找到與標籤選擇器匹配的Pod,檢查每個節點是否恰好有一個匹配的Pod,並建立或刪除Pod以確保是這種情況。如下圖。

圖 16.2 DaemonSet controller的協調循環

圖 16.2 DaemonSet controller的協調循環

當您將節點加入到叢集時,DaemonSet controller會建立一個新Pod並將pod與該節點關聯。當你移除一個節點時,DaemonSet會刪除與此節點關聯的Pod物件。 如果這些DaemonSet Pod其中一個消失,例如,因為被手動刪除,controller會立即重新建立它。 如果出現了額外的Pod,例如,如果您建立了一個與DaemonSet中的標籤選擇器匹配的Pod,controller會立即將它刪除。

DaemonSet物件 yaml看起來非常類似於Deployment、ReplicaSet、StatefulSets。讓我們看一個名稱demo的DaemonSet範例,如下:

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: demo
spec:
  selector:
    matchLabels:
      app: demo
  template:
    metadata:
      labels:
        app: demo
    spec:
      containers:
      - name: demo
        image: busybox
        command:
        - sleep
        - infinity

DaemonSet物件類型是apps/v1 API group/version的一部分。 在DaemonSet物件的spec區段中,您指定標籤選擇器selector和Pod模板template,就像ReplicaSet一樣。 在template區段中的metadata區段必須包含labels字段,並且必須與selector中的標籤匹配。

<aside> 💡 選擇器是不可變的,但您可以更改標籤,只要它們仍然與選擇器匹配。 如果需要更改選擇器,則必須刪除DaemonSet並重新建立。 您可以在替換DaemonSet時使用--cascade=orphan選項保留Pod。

</aside>

正如您在yaml中看到的那樣,demo DaemonSet部署了除了執行sleep指令之外什麼都不做的Pod。這是因為本練習的目標是觀察DaemonSet本身的行為,而不是觀察它的Pod。 在本章後面,您將建立一個DaemonSet,它的Pod將實際做某些事。

使用kubectl apply指令apply ds.demo.yaml來建立DaemonSet,然後列出當下命名空間中的所有DaemonSet,如下:

$ kubectl get ds
NAME   DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR   AGE
demo   2         2         2       2            2           <none>          7s