执行 DaemonSet 管理的常见任务,例如执行滚动更新。
本页演示如何构建一个基本的 DaemonSet,
用其在 Kubernetes 集群中的每个节点上运行 Pod。
这个简单的使用场景包含了从主机挂载一个文件,使用
Init 容器记录文件的内容,
以及使用 pause 容器。
你必须拥有一个 Kubernetes 的集群,且必须配置 kubectl 命令行工具让其与你的集群通信。 建议运行本教程的集群至少有两个节点,且这两个节点不能作为控制平面主机。 如果你还没有集群,你可以通过 Minikube 构建一个你自己的集群,或者你可以使用下面的 Kubernetes 练习环境之一:
为了演示 DaemonSet 的行为,Kubernetes 集群至少需包含两个节点(一个控制平面节点和一个工作节点)。
在此任务中,将创建一个基本的 DaemonSet,确保 Pod 的副本被调度到每个节点上。
此 Pod 将使用 Init 容器从主机读取并记录 /etc/machine-id 的内容,
而主容器将是一个 pause 容器,用于保持 Pod 运行。
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: example-daemonset
spec:
selector:
matchLabels:
app.kubernetes.io/name: example
template:
metadata:
labels:
app.kubernetes.io/name: example
spec:
containers:
- name: pause
image: registry.k8s.io/pause
initContainers:
- name: log-machine-id
image: busybox:1.37
command: ['sh', '-c', 'cat /etc/machine-id > /var/log/machine-id.log']
volumeMounts:
- name: machine-id
mountPath: /etc/machine-id
readOnly: true
- name: log-dir
mountPath: /var/log
volumes:
- name: machine-id
hostPath:
path: /etc/machine-id
type: File
- name: log-dir
hostPath:
path: /var/log基于(YAML)清单创建 DaemonSet:
kubectl apply -f https://k8s.io/examples/application/basic-daemonset.yaml
完成创建操作后,你可以验证 DaemonSet 是否在集群中的每个节点上运行 Pod:
kubectl get pods -o wide
输出将列出每个节点上有一个 Pod,类似于:
NAME READY STATUS RESTARTS AGE IP NODE
example-daemonset-xxxxx 1/1 Running 0 5m x.x.x.x node-1
example-daemonset-yyyyy 1/1 Running 0 5m x.x.x.x node-2
你可以通过检查从主机挂载的日志目录来查看 /etc/machine-id 文件的日志内容:
kubectl exec <pod-name> -- cat /var/log/machine-id.log
其中 <pod-name> 是某一个 Pod 的名称。
要删除 DaemonSet,请运行以下命令:
kubectl delete --cascade=foreground --ignore-not-found --now daemonsets/example-daemonset
这个简单的 DaemonSet 例子介绍了 Init 容器和主机路径卷这类关键组件, 你可以在此基础上扩展以应对更高级的使用场景。有关细节参阅 DaemonSet。
本文介绍了如何对 DaemonSet 执行滚动更新。
你必须拥有一个 Kubernetes 的集群,且必须配置 kubectl 命令行工具让其与你的集群通信。 建议运行本教程的集群至少有两个节点,且这两个节点不能作为控制平面主机。 如果你还没有集群,你可以通过 Minikube 构建一个你自己的集群,或者你可以使用下面的 Kubernetes 练习环境之一:
DaemonSet 有两种更新策略:
OnDelete:使用 OnDelete 更新策略时,在更新 DaemonSet 模板后,只有当你手动删除老的
DaemonSet Pod 之后,新的 DaemonSet Pod 才会被自动创建。跟 Kubernetes 1.6 以前的版本类似。RollingUpdate:这是默认的更新策略。使用 RollingUpdate 更新策略时,在更新 DaemonSet 模板后,
老的 DaemonSet Pod 将被终止,并且将以受控方式自动创建新的 DaemonSet Pod。
更新期间,最多只能有 DaemonSet 的一个 Pod 运行于每个节点上。要启用 DaemonSet 的滚动更新功能,必须设置 .spec.updateStrategy.type 为 RollingUpdate。
你可能想设置
.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:v5.0.1
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 的更新策略,确保已经将其设置为 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 对象或者清单。
对 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:v5.0.1
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 滚动更新可能会卡住,其 Pod 至少在某个节点上无法调度运行。 当节点上可用资源耗尽时, 这是可能的。
发生这种情况时,通过对 kubectl get nodes 和下面命令行的输出作比较,
找出没有调度 DaemonSet Pod 的节点:
kubectl get pods -l name=fluentd-elasticsearch -o wide -n kube-system
一旦找到这些节点,从节点上删除一些非 DaemonSet Pod,为新的 DaemonSet Pod 腾出空间。
当所删除的 Pod 不受任何控制器管理,也不是多副本的 Pod 时,上述操作将导致服务中断。 同时,上述操作也不会考虑 PodDisruptionBudget 所施加的约束。
如果最近的 DaemonSet 模板更新被破坏了,比如,容器处于崩溃循环状态或者容器镜像不存在 (通常由于拼写错误),就会发生 DaemonSet 滚动更新中断。
要解决此问题,需再次更新 DaemonSet 模板。新的滚动更新不会被以前的不健康的滚动更新阻止。
如果在 DaemonSet 中指定了 .spec.minReadySeconds,主控节点和工作节点之间的时钟偏差会使
DaemonSet 无法检测到正确的滚动更新进度。
从名字空间中删除 DaemonSet:
kubectl delete ds fluentd-elasticsearch -n kube-system
本文展示了如何对 DaemonSet 执行回滚。
你必须拥有一个 Kubernetes 的集群,且必须配置 kubectl 命令行工具让其与你的集群通信。 建议运行本教程的集群至少有两个节点,且这两个节点不能作为控制平面主机。 如果你还没有集群,你可以通过 Minikube 构建一个你自己的集群,或者你可以使用下面的 Kubernetes 练习环境之一:
你的 Kubernetes 服务器版本必须不低于版本 1.7.要获知版本信息,请输入 kubectl version.
你应该已经了解如何为 DaemonSet 执行滚动更新。
如果只想回滚到最后一个版本,可以跳过这一步。
列出 DaemonSet 的所有版本:
kubectl rollout history daemonset <daemonset-name>
此命令返回 DaemonSet 版本列表:
daemonsets "<daemonset-name>"
REVISION CHANGE-CAUSE
1 ...
2 ...
...
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: ...
# 在 --to-revision 中指定你从步骤 1 中获取的修订版本
kubectl rollout undo daemonset <daemonset-name> --to-revision=<revision>
如果成功,命令会返回:
daemonset "<daemonset-name>" rolled back
--to-revision 参数未指定,将选中最近的版本。kubectl rollout undo daemonset 向服务器表明启动 DaemonSet 回滚。
真正的回滚是在集群的
控制面
异步完成的。
执行以下命令,来监视 DaemonSet 回滚进度:
kubectl rollout status ds/<daemonset-name>
回滚完成时,输出形如:
daemonset "<daemonset-name>" successfully rolled out
在前面的 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 edit 或 kubectl apply)
将 DaemonSet 模板更新至先前的版本。
ControllerRevision 版本号 (.revision 字段) 会增加。
例如,如果用户在系统中有版本 1 和版本 2,并从版本 2 回滚到版本 1,
带有 .revision: 1 的 ControllerRevision 将变为 .revision: 3。本页演示了你如何能够仅在某些节点上作为 DaemonSet 的一部分运行Pod。
你必须拥有一个 Kubernetes 的集群,且必须配置 kubectl 命令行工具让其与你的集群通信。 建议运行本教程的集群至少有两个节点,且这两个节点不能作为控制平面主机。 如果你还没有集群,你可以通过 Minikube 构建一个你自己的集群,或者你可以使用下面的 Kubernetes 练习环境之一:
设想一下你想要运行 DaemonSet, 但你只需要在配备了本地固态 (SSD) 存储的节点上运行这些守护进程 Pod。 例如,Pod 可以向节点提供缓存服务,而缓存仅在低延迟本地存储可用时才有用。
在配有 SSD 的节点上打标签 ssd=true。
kubectl label nodes example-node-1 example-node-2 ssd=true
让我们创建一个 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使用 kubectl create 或 kubectl 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