Kubernetes学习之路(十五)控制器资源之DaemonSet
_____egon新书来袭请看:https://egonlin.com/book.html
一、什么是DaemonSet?
DaemonSet 确保全部(或者一些)Node 上运行一个 Pod 的副本。当有 Node 加入集群时,也会为他们新增一个 Pod 。当有 Node 从集群移除时,这些 Pod 也会被回收。删除 DaemonSet 将会删除它创建的所有 Pod。
使用 DaemonSet 的一些典型用法:
- 运行集群存储 daemon,例如在每个 Node 上运行
glusterd
、ceph
。 - 在每个 Node 上运行日志收集 daemon,例如
fluentd
、logstash
。 - 在每个 Node 上运行监控 daemon,例如 Prometheus Node Exporter、
collectd
、Datadog 代理、New Relic 代理,或 Gangliagmond
。
一个简单的用法是,在所有的 Node 上都存在一个 DaemonSet,将被作为每种类型的 daemon 使用。 一个稍微复杂的用法可能是,对单独的每种类型的 daemon 使用多个 DaemonSet,但具有不同的标志,和/或对不同硬件类型具有不同的内存、CPU要求。
二、编写DaemonSet Spec
(1)必需字段
和其它所有 Kubernetes 配置一样,DaemonSet 需要 apiVersion
、kind
和 metadata
字段。
[root@k8s-master ~]# kubectl explain daemonset
(2)Pod模板
.spec
唯一必需的字段是 .spec.template
。
.spec.template
是一个 Pod 模板。 它与 Pod 具有相同的 schema,除了它是嵌套的,而且不具有 apiVersion
或 kind
字段。
Pod 除了必须字段外,在 DaemonSet 中的 Pod 模板必须指定合理的标签(查看 pod selector)。
在 DaemonSet 中的 Pod 模板必需具有一个值为 Always
的 RestartPolicy
,或者未指定它的值,默认是 Always
。
[root@k8s-master ~]# kubectl explain daemonset.spec.template.spec
(3)Pod Seletor
.spec.selector
字段表示 Pod Selector,它与 Job 或其它资源的 .sper.selector
的原理是相同的。
spec.selector
表示一个对象,它由如下两个字段组成:
matchLabels
- 与 ReplicationController 的.spec.selector
的原理相同。matchExpressions
- 允许构建更加复杂的 Selector,可以通过指定 key、value 列表,以及与 key 和 value 列表的相关的操作符。
当上述两个字段都指定时,结果表示的是 AND 关系。
如果指定了 .spec.selector
,必须与 .spec.template.metadata.labels
相匹配。如果没有指定,它们默认是等价的。如果与它们配置的不匹配,则会被 API 拒绝。
如果 Pod 的 label 与 selector 匹配,或者直接基于其它的 DaemonSet、或者 Controller(例如 ReplicationController),也不可以创建任何 Pod。 否则 DaemonSet Controller 将认为那些 Pod 是它创建的。Kubernetes 不会阻止这样做。一个场景是,可能希望在一个具有不同值的、用来测试用的 Node 上手动创建 Pod。
(4)Daemon Pod通信
与 DaemonSet 中的 Pod 进行通信,几种可能的模式如下:
- Push:配置 DaemonSet 中的 Pod 向其它 Service 发送更新,例如统计数据库。它们没有客户端。
- NodeIP 和已知端口:DaemonSet 中的 Pod 可以使用
hostPort
,从而可以通过 Node IP 访问到 Pod。客户端能通过某种方法知道 Node IP 列表,并且基于此也可以知道端口。 - DNS:创建具有相同 Pod Selector 的 Headless Service,然后通过使用
endpoints
资源或从 DNS 检索到多个 A 记录来发现 DaemonSet。 - Service:创建具有相同 Pod Selector 的 Service,并使用该 Service 访问到某个随机 Node 上的 daemon。(没有办法访问到特定 Node)
三、创建redis-filebeat的DaemonSet演示
先启动redis,kind为Deployment即可
[root@master01 ~]# cat redis.yaml apiVersion: apps/v1 kind: Deployment metadata: name: redis namespace: default spec: replicas: 1 selector: matchLabels: app: redis role: logstor template: metadata: labels: app: redis role: logstor spec: containers: - name: redis image: redis:4.0-alpine ports: - name: redis containerPort: 6379 [root@master01 ~]# kubectl apply -f redis.yaml deployment.apps/redis created [root@master01 ~]# kubectl get pods -o wide # 为了确保实验效果,请确保处于Running状态,再执行后续操作 NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES redis-588694bf8c-7s9tb 1/1 Running 0 66s 10.2.43.162 10.1.1.104 <none> <none>
需要创建service资源,暴漏端口,才可以解析redis.default.svc.cluster.local
[root@master01 ~]# kubectl expose deployment redis --port=6379
service/redis exposed
[root@master01 ~]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
redis ClusterIP 10.0.29.152 <none> 6379/TCP 4s
验证解析
[root@master01 ~]# kubectl exec -ti redis-588694bf8c-7s9tb -- sh
/data # ping redis.default.svc.cluster.local
PING redis.default.svc.cluster.local (10.0.29.152): 56 data bytes
64 bytes from 10.0.29.152: seq=0 ttl=64 time=0.062 ms
再启动filebeat,kind需要为DaemonSet,每个节点一个
[root@master01 ~]# cat filebeat.yaml # 在yaml文件中设置环境变量env,REDIS_HOST:redis.default.svc.cluster.local,通过域名访问我们之前创建的redis apiVersion: apps/v1 kind: DaemonSet metadata: name: filebeat-ds namespace: default spec: selector: matchLabels: app: filebeat release: stable template: metadata: labels: app: filebeat release: stable spec: containers: - name: filebeat image: ikubernetes/filebeat:5.6.5-alpine env: - name: REDIS_HOST value: redis.default.svc.cluster.local - name: REDIS_LOG_LEVEL value: info [root@master01 ~]# kubectl apply -f filebeat.yaml daemonset.apps/filebeat-ds created [root@master01 ~]# kubectl get pods -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES filebeat-ds-bwmkr 1/1 Running 0 2m9s 10.2.60.105 10.1.1.105 <none> <none> filebeat-ds-q2mhk 1/1 Running 0 90s 10.2.73.72 10.1.1.103 <none> <none> filebeat-ds-w9pb7 1/1 Running 0 2m9s 10.2.43.163 10.1.1.104 <none> <none> redis-588694bf8c-7s9tb 1/1 Running 0 5m27s 10.2.43.162 10.1.1.104 <none> <none>
四、DaemonSet的滚动更新
DaemonSet有两种更新策略类型:
- OnDelete:这是向后兼容性的默认更新策略。使用
OnDelete
更新策略,在更新DaemonSet模板后,只有在手动删除旧的DaemonSet pod时才会创建新的DaemonSet pod。这与Kubernetes 1.5或更早版本中DaemonSet的行为相同。 - RollingUpdate:使用
RollingUpdate
更新策略,在更新DaemonSet模板后,旧的DaemonSet pod将被终止,并且将以受控方式自动创建新的DaemonSet pod。
要启用DaemonSet的滚动更新功能,必须将其设置 .spec.updateStrategy.type
为RollingUpdate
。
(1)查看当前的更新策略:
[root@master01 ~]# kubectl get daemonset filebeat-ds -o go-template='{{.spec.updateStrategy.type}}{{"\n"}}' RollingUpdate [root@master01 ~]#
(2)更新DaemonSet模板
对RollingUpdate
DaemonSet的任何更新.spec.template都
将触发滚动更新。这可以通过几个不同的kubectl
命令来完成。
方式一:kuectl edit修改配置清单
kubectl edit ds filebeat-ds
方式二:vim修改配置清单的yaml文件
# 先用vim 修改对应的yyy.yaml文件 # 然后再执行kubectl apply -f yyy.yaml
# 原理通方式一是一样的
方式三:设置镜像
仅仅更新容器镜像还可以使用以下命令:
kubectl set image ds <daemonset-name> <container-name>=<container-new-image>
下面对filebeat-ds的镜像进行版本更新,如下:
kubectl set image daemonset filebeat-ds filebeat=ikubernetes/filebeat:5.6.6-alpine kubectl get pods -w #观察滚动更新状态
从上面的滚动更新,可以看到在更新过程中,是先终止旧的pod,再创建一个新的pod,逐步进行替换的,这就是DaemonSet的滚动更新策略!
方式四:打补丁
kubectl patch ds filebeat-ds -p=<strategic-merge-patch>
例如
kubectl patch daemonsets.apps zabbix-agent -p '{"spec":{"template":{"spec":{"containers":[{"image":"zabbix/zabbix-agent:centos-5.2.4", "name":"zabbix-agent"}]}}}}'
回滚
# 回滚到上一个版本 kubectl rollout undo daemonset filebeat-ds # 回滚到指定版本 kubectl rollout undo daemonset filebeat-ds --to-revision=1