天天看點

k8s控制器DamenSet

介紹

daemonset 是衆多控制器中的一種(其他還有deployment等等),它的作用是保證在每個節點隻部署一個Pod,而且是隻在pod 模闆中定義的标簽的節點上保證運作一個pod。

如果節點下線, DaemonSet不會在其他地方重新建立pod。但是,當将 一個新節點添加到叢集中時, DaemonSet會立刻部署一個新的pod執行個體 。

與daemonset 相比副本控制器(rc或rs)是保證叢集有固定數量的pod ,而不一定是均勻的每個節點一個這樣分布。

删除了 pod那麼它也會重新啟個新的pod 。與ReplicaSet一樣,DaemonSet 從配 pod 模闆建立pod。

k8s控制器DamenSet

主要特征

  1. 這個 Pod 運作在 Kubernetes 叢集裡的每一個節點(Node)上;
  2. 每個節點上隻有一個這樣的 Pod 執行個體;
  3. 當有新的節點加入 Kubernetes 叢集後,該 Pod 會自動地在新節點上被建立出來;而當舊節點被删除後,它上面的 Pod也相應地會被回收掉。

使用場景

包括pod執行系統級别的與基礎結構相關的操作。例如,希望在每個節點上運作日志收集器和資源監控器。另 一個典型的例子是Kubemetes 自己的 kube-proxy程序,它需要運作在所有節點上才能使服務工作。

  1. 在叢集的每個節點上運作存儲 Daemon,比如 分布式存儲 glusteFS 或 ceph。
  2. 在每個節點上運作日志收集 Daemon,比如 flunentd 或 logstash。
  3. 在每個節點上運作監控 Daemon,比如 Prometheus Node Exporter 或 collectd。

DaemonSet隻在特定的結點上運作pod

DaemonSet pod 預設部署到叢集中所有節點上,除非指定這些pod在部分節點上運作,這是通過pod模闆中的nodeSelector 屬性指定的,這是 DaemonSet定義的一部分似于RSet和RC中的 pod 模闆。

注意節點可以被設定為不可排程防止 pod 被部署到節點上,但是DaemonSet會把pod部署到這些節點上,因為無法排程的屬性隻會被排程器(例如deployment等)使用,而 Daemon Set管理 pod 完全繞過排程器這是預期的,因為DaemonSet 的目的是運作系統服務,即使是在不可排程的節點上,系統服務通常也需要運作。

其實 Kubernetes 自己就在用 DaemonSet 運作系統元件。執行如下指令:

kubectl get daemonset --namespace=kube-system      
k8s控制器DamenSet

daemonSet ​

​kube-flannel-ds​

​​ 和 ​

​kube-proxy​

​ 分别負責在每個節點上運作 flannel 和 kube-proxy 元件。

k8s控制器DamenSet

因為 flannel 和 kube-proxy 屬于系統元件,需要在指令行中通過 ​

​--namespace=kube-system​

​​ 指定 namespace ​

​kube-system​

​​。如果不指定則隻傳回預設 namespace ​

​default​

​ 中的資源。

建立DaemonSet

建立一個yaml 檔案如下:

k8s控制器DamenSet
kubectl  create  -f  xx.yaml      

當把某個節點的标簽(daemonset 中pod 模闆定義的節點标簽)删除,那麼此節點上面的pod 也會消失。  當删除 DaemonSet  也會聯通pod  一起删除。 

下面詳細分析兩個 k8s 自己的 DaemonSet:​

​kube-flannel-ds​

​​ 和 ​

​kube-proxy​

​ 。

kube-flannel-ds

flannel 的 DaemonSet 就定義在 ​

​kube-flannel.yml​

​ 中:

k8s控制器DamenSet

DaemonSet 配置檔案的文法和結構與 Deployment 幾乎完全一樣,隻是将 ​

​kind​

​​ 設為 ​

​DaemonSet​

​。

hostNetwork 指定 Pod 直接使用的是 Node 的網絡,相當于 ​

​docker run --network=host​

​。考慮到 flannel 需要為叢集提供網絡連接配接,這個要求是合理的。

​containers​

​ 定義了運作 flannel 服務的兩個容器。

kube-proxy

由于無法拿到 ​

​kube-proxy​

​ 的 YAML 檔案,隻能運作如下指令檢視其配置:

kubectl edit daemonset kube-proxy --namespace=kube-system      
k8s控制器DamenSet
k8s控制器DamenSet

同樣為了便于了解,這裡隻保留了最重要的資訊。

  • ​kind: DaemonSet​

    ​ 指定這是一個 DaemonSet 類型的資源。
  • ​containers​

    ​​ 定義了 ​

    ​kube-proxy​

    ​ 的容器。
  • ​status​

    ​​ 是目前 DaemonSet 的運作時狀态,這個部分是 ​

    ​kubectl edit​

    ​特有的。

其實 Kubernetes 叢集中每個目前運作的資源都可以通過 ​

​kubectl edit​

​ 檢視其配置和運作狀态,比如 

kubectl edit deployment nginx-deployment      

DaemonSet使用

下面以 Prometheus Node Exporter 為例示範如何運作自己的 DaemonSet。

Prometheus 是流行的系統監控方案,Node Exporter 是 Prometheus 的 agent,以 Daemon 的形式運作在每個被監控節點上。

如果是直接在 Docker 中運作 Node Exporter 容器,指令為:

docker run -d \
  -v "/proc:/host/proc" \
  -v "/sys:/host/sys" \
  -v "/:/rootfs" \
  --net=host \  prom/node-exporter \
  --path.procfs /host/proc \
  --path.sysfs /host/sys \
  --collector.filesystem.ignored-mount-points "^/(sys|proc|dev|host|etc)($|/)"      

将其轉換為 DaemonSet 的 YAML 配置檔案 node_exporter.yml:

apiVersion: extensions/v1beta1
kind: DaemonSet
metadata:
  name: node-exporter-daemonset
spec:
  template:
    metadata:
      labels:
        app: prometheus
    spec:
      hostNetwork: true
      containers:
      - name: node-exporter
        image: prom/node-exporter
        imagePullPolicy: IfNotPresent
        command:
        - /bin/node_exporter
        - --path.procfs
        - /host/proc
        - --path.sysfs
        - /host/sys
        - --collector.filesystem.ignored-mount-points
        - ^/(sys|proc|dev|host|etc)($|/)
        volumeMounts:
        - name: proc
          mountPath: /host/proc
        - name: sys
          mountPath: /host/sys
        - name: root
          mountPath: /rootfs
      volumes:
      - name: proc
        hostPath:
          path: /proc
      - name: sys
        hostPath:
          path: /sys
      - name: root
        hostPath:
          path: /      
k8s控制器DamenSet
  • 直接使用 Host 的網絡。
  • 設定容器啟動指令。
  • 通過 Volume 将 Host 路徑 ​

    ​/proc​

    ​、​

    ​/sys​

    ​ 和 ​

    ​/​

    ​ 映射到容器中。

執行 ​

​kubectl apply -f node_exporter.yml​

​:

k8s控制器DamenSet

DaemonSet ​

​node-exporter-daemonset​

​ 部署成功,k8s-node1 和 k8s-node2 上分别運作了一個 node exporter Pod。

然後我們來稍微看一下源碼,k8s是通過daemon_controller裡面的manage方法來管理Pod删減操作的:

manage方法裡面首先會擷取daemon pod 與 node 的映射關系,然後判斷每一個 node 是否需要運作 daemon pod,然後周遊完node之後将需要建立的Pod清單和需要删除Pod的清單交給syncNodes執行。

func (dsc *DaemonSetsController) manage(ds *apps.DaemonSet, nodeList []*v1.Node, hash string) error { 
  // 擷取已存在 daemon pod 與 node 的映射關系
  nodeToDaemonPods, err := dsc.getNodesToDaemonPods(ds)
  if err != nil {
    return fmt.Errorf("couldn't get node to daemon pod mapping for daemon set %q: %v", ds.Name, err)
  }
 
  // 判斷每一個 node 是否需要運作 daemon pod
  var nodesNeedingDaemonPods, podsToDelete []string
  for _, node := range nodeList {
    nodesNeedingDaemonPodsOnNode, podsToDeleteOnNode, err := dsc.podsShouldBeOnNode(
      node, nodeToDaemonPods, ds)


    if err != nil {
      continue
    }
    //将需要删除的Pod和需要在某個節點建立Pod存入清單中
    nodesNeedingDaemonPods = append(nodesNeedingDaemonPods, nodesNeedingDaemonPodsOnNode...)
    podsToDelete = append(podsToDelete, podsToDeleteOnNode...)
  }
 
  podsToDelete = append(podsToDelete, getUnscheduledPodsWithoutNode(nodeList, nodeToDaemonPods)...)
 
  //為對應的 node 建立 daemon pod 以及删除多餘的 pods
  if err = dsc.syncNodes(ds, podsToDelete, nodesNeedingDaemonPods, hash); err != nil {
    return err
  }


  return nil
}      

下面我們看一下podsShouldBeOnNode方法是如何判斷哪些Pod需要建立和删除的:

在podsShouldBeOnNode會調用nodeShouldRunDaemonPod方法來判斷該node是否需要運作 daemon pod 以及能不能排程成功,然後擷取該node上有沒有建立該daemon pod。

通過判斷shouldRun, shouldContinueRunning将需要建立 daemon pod 的 node 清單以及需要删除的 pod 清單擷取到,shouldSchedule 主要檢查 node 上的資源是否充足,shouldContinueRunning 預設為 true。

func (dsc *DaemonSetsController) podsShouldBeOnNode(
  node *v1.Node,
  nodeToDaemonPods map[string][]*v1.Pod,
  ds *apps.DaemonSet,
) (nodesNeedingDaemonPods, podsToDelete []string, err error) {
  //判斷該 node 是否需要運作 daemon pod 以及能不能排程成功
  shouldRun, shouldContinueRunning, err := dsc.nodeShouldRunDaemonPod(node, ds)
  if err != nil {
    return
  }
  //擷取該節點上的指定ds的pod清單
  daemonPods, exists := nodeToDaemonPods[node.Name]


  switch {
  //如果daemon pod是可以運作在這個node上,但是還沒有建立,那麼建立一個
  case shouldRun && !exists: 
    nodesNeedingDaemonPods = append(nodesNeedingDaemonPods, node.Name)
  //  需要 pod 一直運作
  case shouldContinueRunning: 
    var daemonPodsRunning []*v1.Pod
    for _, pod := range daemonPods {
      if pod.DeletionTimestamp != nil {
        continue
      }
      //如果 pod 運作狀态為 failed,則删除該 pod
      if pod.Status.Phase == v1.PodFailed { 
        ...
        podsToDelete = append(podsToDelete, pod.Name)
      } else {
        daemonPodsRunning = append(daemonPodsRunning, pod)
      }
    } 
    //如果節點上已經運作 daemon pod 數 > 1,保留運作時間最長的 pod,其餘的删除
    if len(daemonPodsRunning) > 1 {
      sort.Sort(podByCreationTimestampAndPhase(daemonPodsRunning))
      for i := 1; i < len(daemonPodsRunning); i++ {
        podsToDelete = append(podsToDelete, daemonPodsRunning[i].Name)
      }
    }
  //  如果 pod 不需要繼續運作但 pod 已存在則需要删除 pod
  case !shouldContinueRunning && exists: 
    for _, pod := range daemonPods {
      if pod.DeletionTimestamp != nil {
        continue
      }
      podsToDelete = append(podsToDelete, pod.Name)
    }
  }


  return nodesNeedingDaemonPods, podsToDelete, nil
}      

DaemonSet 對象的滾動更新和StatefulSet是一樣的,可以通過 .spec.updateStrategy.type 設定更新政策。目前支援兩種政策:

  • OnDelete:預設政策,更新模闆後,隻有手動删除了舊的 Pod 後才會建立新的 Pod;
  • RollingUpdate:更新 DaemonSet 模版後,自動删除舊的 Pod 并建立新的 Pod。

DaemonSet重點方法

|-> dsc.getNodesToDaemonPods()  //擷取目前狀态
                                |
                                |
                  |-> manage -->|-> dsc.podsShouldBeOnNode() --> dsc.nodeShouldRunDaemonPod  //彙總需要建立的pod和待删除的Pod
                  |             |
                  |             |
syncDaemonSet --> |             |-> dsc.syncNodes  //Pod數量一緻性
                  |
                  |-> rollingUpdate  //Pod版本一緻性
                  |
                  |
                  |-> updateDaemonSetStatus  //更新daemonset對象的status字段      

Prometheus監控(1)

三豐,公衆号:soft張三豐Prometheus監控(1)

Prometheus監控(2)

三豐,公衆号:soft張三豐Prometheus監控(2)

Prometheus監控(3)

三豐,公衆号:soft張三豐Prometheus監控(3)

Prometheus監控(4)

三豐,公衆号:soft張三豐Prometheus監控(4)

Prometheus監控(5)

三豐,公衆号:soft張三豐Prometheus監控(5)

繼續閱讀