1. 程式人生 > 其它 >k8s DaemonSet 介紹與例項

k8s DaemonSet 介紹與例項

我們之前說k8s中使用deployment、statefulset工作負載資源來分別維護無狀態和有狀態應用。這篇小作文我們會學習如何使用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的預設容忍規則如下:

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如下

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

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


參考:

daemonset

node-affinity

node-exporter-daemonset

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

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