【云原生|Kubernetes】14-DaemonSet资源控制器详解
文章目录
- 【云原生|Kubernetes】14-DaemonSet资源控制器详解
-
- 简介
- 典型用法
- DaemonSet语法规则
-
- Pod模板
- [Pod 选择算符](#Pod 选择算符)
- [在选定的节点上运行 Pod](#在选定的节点上运行 Pod)
- [DaemonSet的 Pods 是如何被调度的](#DaemonSet的 Pods 是如何被调度的)
- 污点和容忍度
- DaemonSet更新和回滚
简介
在 Kubernetes 中,DaemonSet 是一种用于在节点上运行指定的 Pod 的控制器(Controller)。与 ReplicaSet 或 Deployment 不同,DaemonSet 不是为了扩展 Pod 数量而创建的,而是为了在每个节点上运行一个实例或多个实例的 Pod。
DaemonSet 通常用于在 Kubernetes 集群中运行一些系统级别的服务或者网络代理,例如日志收集器、监控代理、网络插件等。通过使用 DaemonSet,可以确保每个节点上都运行了指定的 Pod,从而保证了这些服务或者代理的高可用性和稳定性。
与其他控制器类似,DaemonSet 也会监视 Pod 的状态,并在 Pod 出现故障或者被删除时自动进行替换。当一个新的节点加入到 Kubernetes 集群中时,DaemonSet 也会自动在该节点上创建所需的 Pod。如果需要更新 DaemonSet 中的 Pod 版本或者配置,可以通过更新 DaemonSet 的 YAML 配置文件来实现。
需要注意的是,DaemonSet 中的 Pod 通常会创建在 kube-system 命名空间下,因为这些服务或者代理通常是与 Kubernetes 集群本身相关联的。在创建 DaemonSet 时,可以使用 nodeSelector、tolerations 和 affinity 等方式来控制 DaemonSet 在哪些节点上运行、不在哪些节点上运行以及如何分配 Pod 到节点上。
典型用法
DaemonSet 的一些典型用法:
- 在每个节点上运行集群守护进程
- 在每个节点上运行日志收集守护进程
- 在每个节点上运行监控守护进程
一种简单的用法是为每种类型的守护进程在所有的节点上都启动一个 DaemonSet。 一个稍微复杂的用法是为同一种守护进程部署多个 DaemonSet;每个具有不同的标志, 并且对不同硬件类型具有不同的内存、CPU 要求。
DaemonSet语法规则
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: fluentd-elasticsearch
namespace: kube-system
labels:
k8s-app: fluentd-logging
spec:
selector:
matchLabels:
name: fluentd-elasticsearch
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
terminationGracePeriodSeconds: 30
volumes:
- name: varlog
hostPath:
path: /var/log
与所有其他 Kubernetes 配置一样,DaemonSet 也需要 apiVersion
、kind
和 metadata
字段。DaemonSet 对象的名称必须是一个合法的 DNS 子域名;DaemonSet 也需要 .spec
节区。
Pod模板
.spec
中唯一必需的字段是 .spec.template
。
.spec.template
是一个 Pod 模板。 除了它是嵌套的,因而不具有 apiVersion
或 kind
字段之外,它与 Pod 具有相同的 schema。
除了 Pod 必需字段外,在 DaemonSet 中的 Pod 模板必须指定合理的标签。
在 DaemonSet 中的 Pod 模板必须具有一个值为 Always
的 RestartPolicy
。 当该值未指定时,默认是 Always
。
Pod 选择算符
.spec.selector
字段表示 Pod 选择算符,它与 Job的 .spec.selector
的作用是相同的。
你必须指定与 .spec.template
的标签匹配的 Pod 选择算符。 此外,一旦创建了 DaemonSet,它的 .spec.selector
就不能修改。 修改 Pod 选择算符可能导致 Pod 意外悬浮,并且这对用户来说是费解的。
spec.selector
是一个对象,如下两个字段组成:
matchLabels
- 与 ReplicationController 的.spec.selector
的作用相同。matchExpressions
- 允许构建更加复杂的选择器,可以通过指定 key、value 列表以及将 key 和 value 列表关联起来的 Operator。
当上述两个字段都指定时,结果会按逻辑与(AND)操作处理。.spec.selector
必须与 .spec.template.metadata.labels
相匹配。 如果配置中这两个字段不匹配,则会被 API 拒绝。
在选定的节点上运行 Pod
如果指定了 .spec.template.spec.nodeSelector
,DaemonSet 控制器将在能够与 Node 选择算符匹配的节点上创建 Pod。 类似这种情况,可以指定 .spec.template.spec.affinity
,之后 DaemonSet 控制器将在能够与节点亲和性匹配的节点上创建 Pod。 如果根本就没有指定,则 DaemonSet Controller 将在所有节点上创建 Pod。
DaemonSet的 Pods 是如何被调度的
DaemonSet 确保所有符合条件的节点都运行该 Pod 的一个副本。 DaemonSet 控制器为每个符合条件的节点创建一个 Pod,并添加 Pod 的 spec.affinity.nodeAffinity
字段以匹配目标主机。Pod 被创建之后,默认的调度程序通常通过设置 .spec.nodeName
字段来接管 Pod 并将 Pod 绑定到目标主机。如果新的 Pod 无法放在节点上,则默认的调度程序可能会根据新 Pod 的优先级抢占 (驱逐)某些现存的 Pod。
用户通过设置 DaemonSet 的 .spec.template.spec.schedulerName
字段,可以为 DaemonSet 的 Pod 指定不同的调度程序。
当评估符合条件的节点时,原本在 .spec.template.spec.affinity.nodeAffinity
字段上指定的节点亲和性将由 DaemonSet 控制器进行考量,但在创建的 Pod 上会被替换为与符合条件的节点名称匹配的节点亲和性。
ScheduleDaemonSetPods
允许你使用默认调度器而不是 DaemonSet 控制器来调度这些 DaemonSet, 方法是将 NodeAffinity
条件而不是 .spec.nodeName
条件添加到这些 DaemonSet Pod。 默认调度器接下来将 Pod 绑定到目标主机。 如果 DaemonSet Pod 的节点亲和性配置已存在,则被替换 (原始的节点亲和性配置在选择目标主机之前被考虑)。 DaemonSet 控制器仅在创建或修改 DaemonSet Pod 时执行这些操作, 并且不会更改 DaemonSet 的 spec.template
。
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchFields:
- key: metadata.name
operator: In
values:
- target-host-name
在这个例子中,Pod 指定了一个 requiredDuringSchedulingIgnoredDuringExecution 的调度限制条件,要求 Pod 只能被调度到带有标签 example-label 并且值为 example-value 的节点上运行。如果没有符合条件的节点,Pod 就无法被调度到节点上运行。
requiredDuringSchedulingIgnoredDuringExecution 的调度限制条件,它可以用于指定必须满足的调度要求。具体来说,requiredDuringSchedulingIgnoredDuringExecution 是一个 PodSpec 的字段,它包含一组要求,如果这些要求不能满足,Pod 就无法被调度到节点上运行。
与其他调度限制条件不同,requiredDuringSchedulingIgnoredDuringExecution 是一个硬性要求,即如果不能满足,Pod 就无法被调度到节点上运行。同时,该限制条件在 Pod 运行过程中仍然会被忽略,因此在节点上的运行状态不会受到该限制条件的影响。
污点和容忍度
DaemonSet 控制器会自动将一组容忍度添加到 DaemonSet Pod。
容忍度键名 | 效果 | 描述 |
---|---|---|
node.kubernetes.io/not-ready |
NoExecute | DaemonSet Pod 可以被调度到不健康或还不准备接受 Pod 的节点上。在这些节点上运行的所有 DaemonSet Pod 将不会被驱逐。 |
node.kubernetes.io/unreachable |
NoExecute | DaemonSet Pod 可以被调度到从节点控制器不可达的节点上。在这些节点上运行的所有 DaemonSet Pod 将不会被驱逐。 |
node.kubernetes.io/disk-pressure |
NoSchedule | DaemonSet Pod 可以被调度到具有磁盘压力问题的节点上。 |
node.kubernetes.io/memory-pressure |
NoSchedule | DaemonSet Pod 可以被调度到具有内存压力问题的节点上。 |
node.kubernetes.io/memory-pressure |
NoSchedule | DaemonSet Pod 可以被调度到具有内存压力问题的节点上。 |
node.kubernetes.io/pid-pressure |
NoSchedule | DaemonSet Pod 可以被调度到具有进程压力问题的节点上。 |
node.kubernetes.io/unschedulable |
NoSchedule | DaemonSet Pod 可以被调度到不可调度的节点上。 |
node.kubernetes.io/network-unavailable |
NoSchedule | 仅针对请求主机联网的 DaemonSet Pod 添加此容忍度 ,即 Pod 具有 spec.hostNetwork: true 。这些 DaemonSet Pod 可以被调度到网络不可用的节点上。 |
你也可以在 DaemonSet 的 Pod 模板中定义自己的容忍度并将其添加到 DaemonSet Pod。
因为 DaemonSet 控制器自动设置 node.kubernetes.io/unschedulable:NoSchedule
容忍度, 所以 Kubernetes 可以在标记为不可调度的节点上运行 DaemonSet Pod。
如果你使用 DaemonSet 提供重要的节点级别功能, 例如集群联网, Kubernetes 在节点就绪之前将 DaemonSet Pod 放到节点上会很有帮助。 例如,如果没有这种特殊的容忍度,因为网络插件未在节点上运行,所以你可能会在未标记为就绪的节点上陷入死锁状态, 同时因为该节点还未就绪,所以网络插件不会在该节点上运行。
DaemonSet更新和回滚
DaemonSet更新策略
DaemonSet 有两种更新策略:
OnDelete
: 使用OnDelete
更新策略时,在更新 DaemonSet 模板后,只有当你手动删除老的 DaemonSet pods 之后,新的 DaemonSet Pod 才会被自动创建。跟 Kubernetes 1.6 以前的版本类似。RollingUpdate
: 这是默认的更新策略。使用RollingUpdate
更新策略时,在更新 DaemonSet 模板后, 老的 DaemonSet Pod 将被终止,并且将以受控方式自动创建新的 DaemonSet Pod。 更新期间,最多只能有 DaemonSet 的一个 Pod 运行于每个节点上。
执行滚动更新
要启用 DaemonSet 的滚动更新功能,必须设置 .spec.updateStrategy.type
为 RollingUpdate
。
-
updateStrategy.type (string)
守护进程集更新的类型。可以是 "RollingUpdate" 或 "OnDelete"。默认为 RollingUpdate。
-
updateStrategy.rollingUpdate (RollingUpdateDaemonSet)
滚动更新配置参数。仅在 type 值为 "RollingUpdate" 时出现。
用于控制守护进程集滚动更新的预期行为的规约。
-
updateStrategy.rollingUpdate.maxSurge (
IntOrString
)对于拥有可用 DaemonSet Pod 的节点而言,**在更新期间可以拥有更新后的 DaemonSet Pod 的最大节点数。**属性值可以是绝对数量(例如:5)或所需 Pod 的百分比(例如:10%)。 如果 maxUnavailable 为 0,则该值不能为 0。绝对数是通过四舍五入从百分比计算得出的,最小值为 1。 默认值为 0。示例:当设置为 30% 时,最多为节点总数的 30% 节点上应该运行守护进程 Pod (即 status.desiredNumberScheduled) 可以在旧 Pod 标记为已删除之前创建一个新 Pod。更新首先在 30% 的节点上启动新的 Pod。 一旦更新的 Pod 可用(就绪时长至少 minReadySeconds 秒),该节点上的旧 DaemonSet pod 就会被标记为已删除。 如果旧 Pod 因任何原因变得不可用(Ready 转换为 false、被驱逐或节点被腾空), 则会立即在该节点上创建更新的 Pod,而不考虑激增限制。 允许激增意味着如果就绪检查失败,任何给定节点上的守护进程集消耗的资源可能会翻倍, 因此资源密集型守护进程集应该考虑到它们可能会在中断期间导致驱逐。
IntOrString 是一种可以容纳 int32 或字符串的类型。在 JSON 或 YAML 编组和解组中使用时,它会生成或使用内部类型。 例如,这允许你拥有一个可以接受名称或数字的 JSON 字段。
-
updateStrategy.rollingUpdate.maxUnavailable (IntOrString)
**更新期间不可用的 DaemonSet Pod 的最大数量。**值可以是绝对数(例如:5)或更新开始时 DaemonSet Pod 总数的百分比(例如:10%)。 绝对数是通过四舍五入的百分比计算得出的。如果 maxSurge 为 0,则此值不能为 0 默认值为 1。 例如:当设置为 30% 时,最多节点总数 30% 的、应该运行守护进程的节点总数(即 status.desiredNumberScheduled) 可以在任何给定时间停止更新。更新首先停止最多 30% 的 DaemonSet Pod, 然后在它们的位置启动新的 DaemonSet Pod。 一旦新的 Pod 可用,它就会继续处理其他 DaemonSet Pod,从而确保在更新期间至少 70% 的原始 DaemonSet Pod 数量始终可用。
IntOrString 是一种可以保存 int32 或字符串的类型。在 JSON 或 YAML 编组和解组中使用时,它会生成或使用内部类型。例如,这允许你拥有一个可以接受名称或数字的 JSON 字段。
-
-
revisionHistoryLimit (int32)
用来允许回滚而保留的旧历史记录的数量。此字段是个指针,用来区分明确的零值和未指定的指针。默认值是 10。
- 下面的 YAML 包含一个 DaemonSet,其更新策略为 'RollingUpdate':
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: fluentd-elasticsearch
annotations:
kubernetes.io/change-cause: "fluentd version is latest"
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
## 用于指定 Pod 被删除后等待多长时间再强制终止。
terminationGracePeriodSeconds: 30
volumes:
- name: varlog
hostPath:
path: /var/log
- name: varlibdockercontainers
hostPath:
path: /var/lib/docker/containers
-
创建DaemonSet的Pod
[root@master daemonset]# kubectl apply -f fluentd-daemonset.yaml
daemonset.apps/fluentd-elasticsearch configured
[root@master daemonset]# -
查看daemonset和pod
[root@master daemonset]# kubectl get daemonset -n kube-system
NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE
fluentd-elasticsearch 3 3 3 3 3 <none> 14m
[root@master daemonset]#
[root@master daemonset]# kubectl get pod -n kube-system -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
fluentd-elasticsearch-bjh69 1/1 Running 0 2m35s 10.244.0.51 192.168.194.128 <none> <none>
fluentd-elasticsearch-j59h8 1/1 Running 0 2m33s 10.244.1.112 192.168.194.130 <none> <none>
fluentd-elasticsearch-jnvfk 1/1 Running 0 2m26s 10.244.2.162 192.168.194.131 <none> <none>
[root@master daemonset]# -
检查 DaemonSet 的滚动更新策略
[root@master daemonset]# kubectl get ds/fluentd-elasticsearch -o go-template='{{.spec.updateStrategy.type}}{{"\n"}}' -n kube-system
RollingUpdate
[root@master daemonset]# -
更新DaemonSet
[root@master daemonset]# kubectl edit -n kube-system ds fluentd-elasticsearch
daemonset.apps/fluentd-elasticsearch edited
[root@master daemonset]#
对DaemonSet执行回滚
在创建Daploymen,DaemonSet等等可以回滚的资源类型的时候,一定要添加
annotations
信息,该信息是你定义资源简介的,便于你分辨该资源是做什么的,用的镜像版本,等等。metadata: name: fluentd-elasticsearch annotations: kubernetes.io/change-cause: "fluentd version is latest"
-
查看DaemonSet使用的镜像版本
[root@master daemonset]# kubectl -n kube-system get ds fluentd-elasticsearch -o wide
NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE CONTAINERS IMAGES SELECTOR
fluentd-elasticsearch 3 3 2 1 2 <none> 2m23s fluentd-elasticsearch quay.io/fluentd_elasticsearch/fluentd:v2.5.2 name=fluentd-elasticsearch
[root@master daemonset]# -
查看DaemonSet的历史版本
[root@master daemonset]# kubectl -n kube-system rollout history ds fluentd-elasticsearch
daemonset.apps/fluentd-elasticsearch
REVISION CHANGE-CAUSE
1 fluentd version is latest
2 fluentd version is 2.6.0
3 fluentd version is 2.5.2
[root@master daemonset]#
说明: 注意 DaemonSet 修订版本只会正向变化。也就是说,回滚完成后,所回滚到的
ControllerRevision
版本号 (.revision
字段) 会增加。 例如,如果用户在系统中有版本 1 和版本 2,并从版本 2 回滚到版本 1, 带有.revision: 1
的ControllerRevision
将变为.revision: 3
。
- --to-revision指导回滚到指定版本
说明: 如果
--to-revision
参数未指定,将选中最近的版本。
[root@master daemonset]# kubectl -n kube-system rollout undo --to-revision=1 ds fluentd-elasticsearch
daemonset.apps/fluentd-elasticsearch rolled back
[root@master daemonset]#
-
再次确认版本(回滚正常)
[root@master daemonset]# kubectl -n kube-system get ds fluentd-elasticsearch -o wide
NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE CONTAINERS IMAGES SELECTOR
fluentd-elasticsearch 3 3 3 3 3 <none> 5m31s fluentd-elasticsearch quay.io/fluentd_elasticsearch/fluentd name=fluentd-elasticsearch
[root@master daemonset]#