本文是对 Kubernetes 作业管理中的容器化守护进程相关设计的理解,由于 DaemonSet 这个知识点相对较为容易理解,所以主要是作的张磊在极客时间上《深入剖析 Kubernetes》课程的笔记。
使用场景:
一句话:在 Kubernetes 集群中的每一个节点中运行一个 Daemon Pod。
DaemonSet 会保证每个 Node 上有且只有一个被管理的 Pod,是利用“控制器模型”原理实现。
原理: DaemonSet Controller,首先从 Etcd 里获取所有的 Node 列表,然后遍历所有的 Node。这时,它就可以很容易地去检查,当前这个 Node 上是不是有一个携带了指定标签的 Pod 在运行。有多余 Pod 的话就调用 Kubernetes API 删除;没有这种 Pod 的话就利用 Pod 来创建一个。
有2个点:
DaemonSet Controller 会在创建 Pod 的时候,自动在这个 Pod 的 API 对象里,加上一个 nodeAffinity 定义。其中,需要绑定的节点名字,正是当前正在遍历的这个 Node。
此外,DaemonSet 还会给这个 Pod 自动加上另外一个与调度相关的字段,叫作 tolerations。这个字段意味着这个 Pod,会“容忍”(Toleration)某些 Node 的“污点”(Taint)。
具体可以看最后的“使用实例”。
另外,DaemonSet 控制器操作的直接就是 Pod,没有 ReplicaSet 这样的对象参与其中,所以,它的版本维护是使用 API 对象的方式实现,名为 ControllerRevision。
这个 ControllerRevision 对象,实际上会保存某一版本对应的完整的 DaemonSet 的 API 对象。并且,在 Annotation 字段保存了创建这个对象所使用的 kubectl 命令。
DaemonSet Controller 回滚版本实际上就是使用这个历史 API 对象,对现有的 DaemonSet 做一次 PATCH 操作(等价于执行一次 kubectl apply -f “旧的 DaemonSet 对象”)
实例:部署一个 DaemonSet 管理 fluentd-elasticsearch 镜像的 Pod。通过 fluentd 将 Docker 容器里的日志转发到 ElasticSearch 中。
$ kubectl create -f fluentd-elasticsearch.yaml
实际过程分为2步:
(1)用户提交 YAML
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: fluentd-elasticsearch
namespace: kube-system
labels:
k8s-app: fluentd-logging
spec:
selector: # 使用 selector 选择管理所有携带了 name=fluentd-elasticsearch 标签的 Pod
matchLabels:
name: fluentd-elasticsearch
template: # 这些 Pod 的模板,也是用 template 字段定义的
metadata:
labels:
name: fluentd-elasticsearch
spec:
tolerations: # 为了能在 Master 节点上部署 DaemonSet 的 Pod,我就必须让这个 Pod“容忍”这个“污点”
- key: node-role.kubernetes.io/master
effect: NoSchedule
containers:
- name: fluentd-elasticsearch # 管理的是一个 fluentd-elasticsearch 镜像的 Pod
image: k8s.gcr.io/fluentd-elasticsearch:1.20 # 定义了一个使用 fluentd-elasticsearch:1.20 镜像的容器
resources:
limits:
memory: 200Mi
requests:
cpu: 100m
memory: 200Mi
volumeMounts: # 这个容器挂载了两个 hostPath 类型的 Volume,分别对应宿主机的 /var/log 目录和 /var/lib/docker/containers 目录
- 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
(2)Daemon Controller 自动补充 YAML
apiVersion: v1
kind: Pod
metadata:
name: with-node-affinity
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution: # 这个 nodeAffinity 必须在每次调度的时候予以考虑
nodeSelectorTerms:
- matchExpressions: # 这个 Pod,将来只允许运行在“metadata.name”是“node-geektime”的节点上
- key: metadata.name
operator: In
values:
- node-geektime
apiVersion: v1
kind: Pod
metadata:
name: with-toleration
spec:
tolerations:
- key: node.kubernetes.io/unschedulable # “容忍”所有被标记为 unschedulable“污点”的 Node;“容忍”的效果是允许调度。
operator: Exists
effect: NoSchedule
$ kubectl get pod -n kube-system -l name=fluentd-elasticsearch
NAME READY STATUS RESTARTS AGE
fluentd-elasticsearch-dqfv9 1/1 Running 0 53m
fluentd-elasticsearch-pf9z5 1/1 Running 0 53m
$ kubectl get ds -n kube-system fluentd-elasticsearch
NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE
fluentd-elasticsearch 2 2 2 2 2 1h
# 查看版本情况
$ kubectl rollout history daemonset fluentd-elasticsearch -n kube-system
daemonsets "fluentd-elasticsearch"
REVISION CHANGE-CAUSE
1
# 升级镜像
$ kubectl set image ds/fluentd-elasticsearch fluentd-elasticsearch=k8s.gcr.io/fluentd-elasticsearch:v2.2.0 --record -n=kube-system
# 查看“滚动更新”的过程
$ kubectl rollout status ds/fluentd-elasticsearch -n kube-system
Waiting for daemon set "fluentd-elasticsearch" rollout to finish: 0 out of 2 new pods have been updated...
Waiting for daemon set "fluentd-elasticsearch" rollout to finish: 0 out of 2 new pods have been updated...
Waiting for daemon set "fluentd-elasticsearch" rollout to finish: 1 of 2 updated pods are available...
daemon set "fluentd-elasticsearch" successfully rolled out
# 在升级命令后面加上了–record 参数,使用到的指令就会自动出现在 DaemonSet 的 rollout history 里面
$ kubectl rollout history daemonset fluentd-elasticsearch -n kube-system
daemonsets "fluentd-elasticsearch"
REVISION CHANGE-CAUSE
1
2 kubectl set image ds/fluentd-elasticsearch fluentd-elasticsearch=k8s.gcr.io/fluentd-elasticsearch:v2.2.0 --namespace=kube-system --record=true
# 以 ControllerRevision 方式查看版本
$ kubectl get controllerrevision -n kube-system -l name=fluentd-elasticsearch
NAME CONTROLLER REVISION AGE
fluentd-elasticsearch-64dc6799c9 daemonset.apps/fluentd-elasticsearch 2 1h
# 查看某个 ControllerRevision 对象版本详细信息
$ kubectl describe controllerrevision fluentd-elasticsearch-64dc6799c9 -n kube-system
Name: fluentd-elasticsearch-64dc6799c9
Namespace: kube-system
Labels: controller-revision-hash=2087235575
name=fluentd-elasticsearch
Annotations: deprecated.daemonset.template.generation=2
kubernetes.io/change-cause=kubectl set image ds/fluentd-elasticsearch fluentd-elasticsearch=k8s.gcr.io/fluentd-elasticsearch:v2.2.0 --record=true --namespace=kube-system
API Version: apps/v1
Data:
Spec:
Template:
$ Patch: replace
Metadata:
Creation Timestamp:
Labels:
Name: fluentd-elasticsearch
Spec:
Containers:
Image: k8s.gcr.io/fluentd-elasticsearch:v2.2.0
Image Pull Policy: IfNotPresent
Name: fluentd-elasticsearch
...
Revision: 2
Events:
# 回滚到 Revision=1 时的状态
$ kubectl rollout undo daemonset fluentd-elasticsearch --to-revision=1 -n kube-system
daemonset.extensions/fluentd-elasticsearch rolled back
参考:
《深入剖析Kubernetes | 极客时间》张磊,容器编排和Kubernetes作业管理 21