Kubernetes控制器之DaemonSet


  參考: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 需要 apiVersionkind 和 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 進程(例如,使用 initupstartd、或 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。




免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM