k8s DaemonSet 介紹與實例


我們之前說k8s中使用deployment、statefulset工作負載資源來分別維護無狀態和有狀態應用。這篇小作文我們會學習如何使用DaemonSet來維護一個守護進程(應用)。


一、DaemonSet是什么?

DaemonSet 是一個確保全部或者某些節點上必須運行一個 Pod的工作負載資源(守護進程),當有節點加入集群時, 也會為他們新增一個 Pod。

下面是常用的使用案例:

  • 集群守護進程,如Kurednode-problem-detector
  • 日志收集守護進程,如fluentdlogstash
  • 監控守護進程,如promethues node-exporter

通過創建DaemonSet 可以確保 守護進程pod 被調度到每個可用節點上運行。


二、DaemonSet 如何工作?

DaemonSet 是由控制器(controller manager)管理的 Kubernetes 工作資源對象。我們通過聲明一個想要的daemonset狀態,表明每個節點上都需要有一個特定的 Pod。協調控制回路會比較期望狀態和當前觀察到的狀態。如果觀察到的節點沒有匹配的 Pod,DaemonSet controller將自動創建一個。可以參考之前《k8s工作流程詳解》

在這個過程包括現有節點和所有新創建的節點。不過DaemonSet 控制器創建的 Pod 會被Kubernetes 調度器忽略,即DaemonSet Pods 由 DaemonSet 控制器創建和調度。這樣帶來的兩個微妙的問題:

  • Pod 行為的不一致性:正常 Pod 在被創建后等待調度時處於 Pending 狀態, DaemonSet Pods 創建后不會處於 Pending 狀態下。
  • Pod 搶占行為由默認調度器處理。啟用搶占后,DaemonSet 控制器將在不考慮 Pod 優先級和搶占 的情況下制定調度決策。

所以在k8s v1.12以后DaemonSet Controller 將會向 DaemonSet 的 Pod 添加 .spec.nodeAffinity 字段,而不是 .spec.nodeName 字段,並進一步由 kubernetes 調度器將 Pod 綁定到目標節點。如果 DaemonSet 的 Pod 已經存在了 nodeAffinity 字段,該字段的值將被替換。

nodeAffinity:
  requiredDuringSchedulingIgnoredDuringExecution:
    nodeSelectorTerms:
    - matchFields:
      - key: metadata.name
        operator: In
        values:
        - target-host-name

daemonset pod的默認容忍規則如下:

image-20211021134258976

DaemonSet 默認在每個節點上創建一個 Pod。當然也可以使用節點選擇器來限制可接受節點的數量。DaemonSet 控制器將僅在與 YAML 文件中預定義的nodeSelector字段匹配的節點上創建Pod。我們在下面會使用到。


三、DaemonSet實例

創建DaemonSet

我們只需要將前面deployment中的kind調整為DaemonSet 就可以創建出一個DaemonSet守護進程

apiVersion: apps/v1 
kind: DaemonSet 
metadata: 
  name: my-daemonset
spec: 
  selector: 
    matchLabels: 
      app: my-daemon
  template: 
    metadata: 
      labels: 
        app: my-daemon
    spec: 
      containers: 
        - name: daemonset-container 
          image: httpd 
          ports: 
          - containerPort : 80

通過apply應用后查看資源狀態

$ kubectl get daemonset
NAME            DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR            AGE
my-daemonset    1         1         1       1            1           <none>                   10m

由於我們minikube只有一個node 所以只建立了一個副本,在節點通過get查看到已創建出這個daemonset pod

$ kubectl get pod 
NAME                  READY   STATUS    RESTARTS   AGE
my-daemonset-97z2g    1/1     Running   0          10m

在daemonset資源狀態中可以看到NODE SELECTOR的值為none,顯然我們可以通過在pod模板中添加nodeSelector使DaemonSet 控制器僅在與Node 選擇算符匹配的節點上創建出pod,接下來我們添加一個nodeSelector

apiVersion: apps/v1 
kind: DaemonSet 
metadata: 
  name: my-daemonset
spec: 
  selector: 
    matchLabels: 
      app: my-daemon
  template: 
    metadata: 
      labels: 
        app: my-daemon
    spec: 
      containers: 
        - name: daemonset-container 
          image: httpd 
          ports: 
          - containerPort : 80
      nodeSelector:
       kubernetes.io/hostname: minikube 

這樣我們的pod只會在hostname為minikube的Node上創建DaemonSet守護進程的pod

$ kubectl get daemonset
NAME            DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR                     AGE
my-daemonset    1         1         1       1            1           kubernetes.io/hostname=minikube   30m

除了通過nodeSelector來控制節點調度外,還可以通過上面提到的容忍策略即tolerations使daemonset pod 調度到“非正常“Node。

我們可以來看一個fluentd的官方elasticsearch daemonset

源文件地址:fluentd-daemonset-elasticsearch.yaml

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: fluentd
  namespace: kube-system
  labels:
    k8s-app: fluentd-logging
    version: v1
spec:
  selector:
    matchLabels:
      k8s-app: fluentd-logging
      version: v1
  template:
    metadata:
      labels:
        k8s-app: fluentd-logging
        version: v1
    spec:
      tolerations:
      - key: node-role.kubernetes.io/master
        effect: NoSchedule
      containers:
      - name: fluentd
        image: fluent/fluentd-kubernetes-daemonset:v1-debian-elasticsearch
        env:
          - name:  FLUENT_ELASTICSEARCH_HOST
            value: "elasticsearch-logging"
          - name:  FLUENT_ELASTICSEARCH_PORT
            value: "9200"
          - name: FLUENT_ELASTICSEARCH_SCHEME
            value: "http"
          # Option to configure elasticsearch plugin with self signed certs
          # ================================================================
          - name: FLUENT_ELASTICSEARCH_SSL_VERIFY
            value: "true"
          # Option to configure elasticsearch plugin with tls
          # ================================================================
          - name: FLUENT_ELASTICSEARCH_SSL_VERSION
            value: "TLSv1_2"
          # X-Pack Authentication
          # =====================
          - name: FLUENT_ELASTICSEARCH_USER
            value: "elastic"
          - name: FLUENT_ELASTICSEARCH_PASSWORD
            value: "changeme"
          # Logz.io Authentication
          # ======================
          - name: LOGZIO_TOKEN
            value: "ThisIsASuperLongToken"
          - name: LOGZIO_LOGTYPE
            value: "kubernetes"
        resources:
          limits:
            memory: 200Mi
          requests:
            cpu: 100m
            memory: 200Mi
        volumeMounts:
        - name: varlog
          mountPath: /var/log
        # When actual pod logs in /var/lib/docker/containers, the following lines should be used.
        # - name: dockercontainerlogdirectory
        #   mountPath: /var/lib/docker/containers
        #   readOnly: true
        # When actual pod logs in /var/log/pods, the following lines should be used.
        - name: dockercontainerlogdirectory
          mountPath: /var/log/pods
          readOnly: true
      terminationGracePeriodSeconds: 30
      volumes:
      - name: varlog
        hostPath:
          path: /var/log
      # When actual pod logs in /var/lib/docker/containers, the following lines should be used.
      # - name: dockercontainerlogdirectory
      #   hostPath:
      #     path: /var/lib/docker/containers
      # When actual pod logs in /var/log/pods, the following lines should be used.
      - name: dockercontainerlogdirectory
        hostPath:
          path: /var/log/pods

特別之處在於,為了收集master節點上的pod日志,將會容忍fluentd調度到master節點。其中tolerations如下

image-20211021114701977

Daemon Pods 通信

與 DaemonSet 中的 Pod 進行通信的幾種模式如下:

  • 推送(Push):配置 DaemonSet 中的 Pod,將更新發送到另一個服務,例如統計數據庫。
  • NodeIP 和已知端口:DaemonSet 中的 Pod 可以使用 hostPort,從而可以通過節點 IP 訪問到 Pod。客戶端能通過某種方法獲取節點 IP 列表,並且基於此也可以獲取到相應的端口。比如prometheus的node-exporter。
  • DNS:創建具有相同 Pod 選擇算符的 無頭服務 通過使用 endpoints 資源或從 DNS 中檢索到多個 A 記錄來發現 DaemonSet。

DaemonSet 更新

如果節點的標簽被修改,DaemonSet 將立刻向新匹配上的節點添加 Pod, 同時刪除不匹配的節點上的 Pod。

可以刪除一個 DaemonSet。如果使用 kubectl 指定 --cascade=orphan 選項, 則 Pod 將被保留在節點上。接下來如果創建使用相同選擇算符的新 DaemonSet, 新的 DaemonSet 會收養已有的 Pod。 如果有 Pod 需要被替換,DaemonSet 會根據其 updateStrategy 來替換。

比如prometheus中的node-exporter

image-20211021121548126

以上是關於k8s中的DaemonSet相關內容。


參考:

daemonset

node-affinity

node-exporter-daemonset

希望小作文對你有些許幫助,如果內容有誤請指正。

您可以隨意轉載、修改、發布本文,無需經過本人同意。blogiqsing.github.io


免責聲明!

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



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