这是本节的多页打印视图。 点击此处打印.

返回本页常规视图.

管理集群守护进程

执行 DaemonSet 管理的常见任务,例如执行滚动更新。

1 - 对 DaemonSet 执行滚动更新

本文介绍了如何对 DaemonSet 执行滚动更新。

准备开始

你必须拥有一个 Kubernetes 的集群,同时你必须配置 kubectl 命令行工具与你的集群通信。 建议在至少有两个不作为控制平面主机的节点的集群上运行本教程。 如果你还没有集群,你可以通过 Minikube 构建一个你自己的集群,或者你可以使用下面的 Kubernetes 练习环境之一:

DaemonSet 更新策略

DaemonSet 有两种更新策略:

  • OnDelete:使用 OnDelete 更新策略时,在更新 DaemonSet 模板后,只有当你手动删除老的 DaemonSet Pod 之后,新的 DaemonSet Pod 才会被自动创建。跟 Kubernetes 1.6 以前的版本类似。
  • RollingUpdate:这是默认的更新策略。使用 RollingUpdate 更新策略时,在更新 DaemonSet 模板后, 老的 DaemonSet Pod 将被终止,并且将以受控方式自动创建新的 DaemonSet Pod。 更新期间,最多只能有 DaemonSet 的一个 Pod 运行于每个节点上。

执行滚动更新

要启用 DaemonSet 的滚动更新功能,必须设置 .spec.updateStrategy.typeRollingUpdate

你可能想设置 .spec.updateStrategy.rollingUpdate.maxUnavailable(默认为 1)、 .spec.minReadySeconds(默认为 0)和 .spec.updateStrategy.rollingUpdate.maxSurge (默认为 0)。

创建带有 RollingUpdate 更新策略的 DaemonSet

下面的 YAML 包含一个 DaemonSet,其更新策略为 'RollingUpdate':

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: fluentd-elasticsearch
  namespace: kube-system
  labels:
    k8s-app: fluentd-logging
spec:
  selector:
    matchLabels:
      name: fluentd-elasticsearch
  updateStrategy:
    type: RollingUpdate
    rollingUpdate:
      maxUnavailable: 1
  template:
    metadata:
      labels:
        name: fluentd-elasticsearch
    spec:
      tolerations:
      # 这些容忍度设置是为了让该守护进程集在控制平面节点上运行
      # 如果你不希望自己的控制平面节点运行 Pod,可以删除它们
      - key: node-role.kubernetes.io/master
        effect: NoSchedule
      containers:
      - name: fluentd-elasticsearch
        image: quay.io/fluentd_elasticsearch/fluentd:v2.5.2
        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

检查了 DaemonSet 清单中更新策略的设置之后,创建 DaemonSet:

kubectl create -f https://k8s.io/examples/controllers/fluentd-daemonset.yaml

另一种方式是如果你希望使用 kubectl apply 来更新 DaemonSet 的话, 也可以使用 kubectl apply 来创建 DaemonSet:

kubectl apply -f https://k8s.io/examples/controllers/fluentd-daemonset.yaml

检查 DaemonSet 的滚动更新策略

首先,检查 DaemonSet 的更新策略,确保已经将其设置为 RollingUpdate

kubectl get ds/fluentd-elasticsearch -o go-template='{{.spec.updateStrategy.type}}{{"\n"}}' -n kube-system

如果还没在系统中创建 DaemonSet,请使用以下命令检查 DaemonSet 的清单:

kubectl apply -f https://k8s.io/examples/controllers/fluentd-daemonset.yaml --dry-run=client -o go-template='{{.spec.updateStrategy.type}}{{"\n"}}'

两个命令的输出都应该为:

RollingUpdate

如果输出不是 RollingUpdate,请返回并相应地修改 DaemonSet 对象或者清单。

更新 DaemonSet 模板

RollingUpdate DaemonSet 的 .spec.template 的任何更新都将触发滚动更新。 这可以通过几个不同的 kubectl 命令来完成。

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: fluentd-elasticsearch
  namespace: kube-system
  labels:
    k8s-app: fluentd-logging
spec:
  selector:
    matchLabels:
      name: fluentd-elasticsearch
  updateStrategy:
    type: RollingUpdate
    rollingUpdate:
      maxUnavailable: 1
  template:
    metadata:
      labels:
        name: fluentd-elasticsearch
    spec:
      tolerations:
      # 这些容忍度设置是为了让该守护进程集在控制平面节点上运行
      # 如果你不希望自己的控制平面节点运行 Pod,可以删除它们
      - key: node-role.kubernetes.io/control-plane
        operator: Exists
        effect: NoSchedule
      - key: node-role.kubernetes.io/master
        operator: Exists
        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

声明式命令

如果你使用配置文件来更新 DaemonSet,请使用 kubectl apply

kubectl apply -f https://k8s.io/examples/controllers/fluentd-daemonset-update.yaml

指令式命令

如果你使用指令式命令来更新 DaemonSets,请使用 kubectl edit

kubectl edit ds/fluentd-elasticsearch -n kube-system
只更新容器镜像

如果你只需要更新 DaemonSet 模板里的容器镜像,比如 .spec.template.spec.containers[*].image, 请使用 kubectl set image

kubectl set image ds/fluentd-elasticsearch fluentd-elasticsearch=quay.io/fluentd_elasticsearch/fluentd:v2.6.0 -n kube-system

监视滚动更新状态

最后,观察 DaemonSet 最新滚动更新的进度:

kubectl rollout status ds/fluentd-elasticsearch -n kube-system

当滚动更新完成时,输出结果如下:

daemonset "fluentd-elasticsearch" successfully rolled out

故障排查

DaemonSet 滚动更新卡住

有时,DaemonSet 滚动更新可能卡住,以下是一些可能的原因:

一些节点可用资源耗尽

DaemonSet 滚动更新可能会卡住,其 Pod 至少在某个节点上无法调度运行。 当节点上可用资源耗尽时, 这是可能的。

发生这种情况时,通过对 kubectl get nodes 和下面命令行的输出作比较, 找出没有调度 DaemonSet Pod 的节点:

kubectl get pods -l name=fluentd-elasticsearch -o wide -n kube-system

一旦找到这些节点,从节点上删除一些非 DaemonSet Pod,为新的 DaemonSet Pod 腾出空间。

不完整的滚动更新

如果最近的 DaemonSet 模板更新被破坏了,比如,容器处于崩溃循环状态或者容器镜像不存在 (通常由于拼写错误),就会发生 DaemonSet 滚动更新中断。

要解决此问题,需再次更新 DaemonSet 模板。新的滚动更新不会被以前的不健康的滚动更新阻止。

时钟偏差

如果在 DaemonSet 中指定了 .spec.minReadySeconds,主控节点和工作节点之间的时钟偏差会使 DaemonSet 无法检测到正确的滚动更新进度。

清理

从名字空间中删除 DaemonSet:

kubectl delete ds fluentd-elasticsearch -n kube-system

接下来

2 - 对 DaemonSet 执行回滚

本文展示了如何对 DaemonSet 执行回滚。

准备开始

你必须拥有一个 Kubernetes 的集群,同时你必须配置 kubectl 命令行工具与你的集群通信。 建议在至少有两个不作为控制平面主机的节点的集群上运行本教程。 如果你还没有集群,你可以通过 Minikube 构建一个你自己的集群,或者你可以使用下面的 Kubernetes 练习环境之一:

你的 Kubernetes 服务器版本必须不低于版本 1.7. 要获知版本信息,请输入 kubectl version.

你应该已经了解如何为 DaemonSet 执行滚动更新

对 DaemonSet 执行回滚

步骤 1:找到想要 DaemonSet 回滚到的历史修订版本(revision)

如果只想回滚到最后一个版本,可以跳过这一步。

列出 DaemonSet 的所有版本:

kubectl rollout history daemonset <daemonset-name>

此命令返回 DaemonSet 版本列表:

daemonsets "<daemonset-name>"
REVISION        CHANGE-CAUSE
1               ...
2               ...
...
  • 在创建时,DaemonSet 的变化原因从 kubernetes.io/change-cause 注解(annotation) 复制到其修订版本中。用户可以在 kubectl 命令中设置 --record=true, 将执行的命令记录在变化原因注解中。

执行以下命令,来查看指定版本的详细信息:

kubectl rollout history daemonset <daemonset-name> --revision=1

该命令返回相应修订版本的详细信息:

daemonsets "<daemonset-name>" with revision #1
Pod Template:
Labels:       foo=bar
Containers:
app:
 Image:        ...
 Port:         ...
 Environment:  ...
 Mounts:       ...
Volumes:      ...

步骤 2:回滚到指定版本

# 在 --to-revision 中指定你从步骤 1 中获取的修订版本
kubectl rollout undo daemonset <daemonset-name> --to-revision=<revision>

如果成功,命令会返回:

daemonset "<daemonset-name>" rolled back

步骤 3:监视 DaemonSet 回滚进度

kubectl rollout undo daemonset 向服务器表明启动 DaemonSet 回滚。 真正的回滚是在集群的 控制面 异步完成的。

执行以下命令,来监视 DaemonSet 回滚进度:

kubectl rollout status ds/<daemonset-name>

回滚完成时,输出形如:

daemonset "<daemonset-name>" successfully rolled out

理解 DaemonSet 修订版本

在前面的 kubectl rollout history 步骤中,你获得了一个修订版本列表,每个修订版本都存储在名为 ControllerRevision 的资源中。

要查看每个修订版本中保存的内容,可以找到 DaemonSet 修订版本的原生资源:

kubectl get controllerrevision -l <daemonset-selector-key>=<daemonset-selector-value>

该命令返回 ControllerRevisions 列表:

NAME                               CONTROLLER                     REVISION   AGE
<daemonset-name>-<revision-hash>   DaemonSet/<daemonset-name>     1          1h
<daemonset-name>-<revision-hash>   DaemonSet/<daemonset-name>     2          1h

每个 ControllerRevision 中存储了相应 DaemonSet 版本的注解和模板。

kubectl rollout undo 选择特定的 ControllerRevision,并用 ControllerRevision 中存储的模板代替 DaemonSet 的模板。 kubectl rollout undo 相当于通过其他命令(如 kubectl editkubectl apply) 将 DaemonSet 模板更新至先前的版本。

故障排查

3 - 仅在某些节点上运行 Pod

本页演示了你如何能够仅在某些节点上作为 DaemonSet 的一部分运行Pod

准备开始

你必须拥有一个 Kubernetes 的集群,同时你必须配置 kubectl 命令行工具与你的集群通信。 建议在至少有两个不作为控制平面主机的节点的集群上运行本教程。 如果你还没有集群,你可以通过 Minikube 构建一个你自己的集群,或者你可以使用下面的 Kubernetes 练习环境之一:

仅在某些节点上运行 Pod

设想一下你想要运行 DaemonSet, 但你只需要在配备了本地固态 (SSD) 存储的节点上运行这些守护进程 Pod。 例如,Pod 可以向节点提供缓存服务,而缓存仅在低延迟本地存储可用时才有用。

第 1 步:为节点打标签

在配有 SSD 的节点上打标签 ssd=true

kubectl label nodes example-node-1 example-node-2 ssd=true

第 2 步:创建清单

让我们创建一个 DaemonSet, 它将仅在打了 SSD 标签的节点上制备守护进程 Pod。

接下来,使用 nodeSelector 确保 DaemonSet 仅在 ssd 标签设为 "true" 的节点上运行 Pod。

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: ssd-driver
  labels:
    app: nginx
spec:
  selector:
    matchLabels:
      app: ssd-driver-pod
  template:
    metadata:
      labels:
        app: ssd-driver-pod
    spec:
      nodeSelector:
        ssd: "true"
      containers:
        - name: example-container
          image: example-image

第 3 步:创建 DaemonSet

使用 kubectl createkubectl apply 从清单创建 DaemonSet。

让我们为另一个节点打上标签 ssd=true

kubectl label nodes example-node-3 ssd=true

节点打上标签后将自动触发控制平面(具体而言是 DaemonSet 控制器)在该节点上运行新的守护进程 Pod。

kubectl get pods -o wide

输出类似于:

NAME                              READY     STATUS    RESTARTS   AGE    IP      NODE
<daemonset-name><some-hash-01>    1/1       Running   0          13s    .....   example-node-1
<daemonset-name><some-hash-02>    1/1       Running   0          13s    .....   example-node-2
<daemonset-name><some-hash-03>    1/1       Running   0          5s     .....   example-node-3