深入K8s:守护进程DaemonSet及其源码分析


深入K8s:守护进程DaemonSet及其源码分析文章插图
建议学习:膜拜!阿里内部都在强推的K8S(kubernetes)学习指南 , 不能再详细了
最近也一直在加班 , 处理项目中的事情 , 发现问题越多越是感觉自己的能力不足 , 希望自己能多学点 。 我觉得人生的意义就是在于能够不断的寻求突破吧 。
这篇文章会讲DaemonSet和Job与CronJob一起 。 在讲其中某一块内容的时候 , 我会将一些其他内容也关联上 , 让读者尽可能的看明白些 , 然后这篇开始我会开始加入一些主要源码的分析 。
Daemon Pod有三个主要特征:

  1. 这个 Pod 运行在 Kubernetes 集群里的每一个节点(Node)上;
  2. 每个节点上只有一个这样的 Pod 实例;
  3. 当有新的节点加入 Kubernetes 集群后 , 该 Pod 会自动地在新节点上被创建出来;而当旧节点被删除后 , 它上面的 Pod 也相应地会被回收掉 。
Daemon Pod可以运用在网络插件的Agent组件上、日志组件、监控组件等 。
创建一个DaemonSetapiVersion: apps/v1kind: DaemonSetmetadata:name: fluentd-elasticsearchnamespace: kube-systemlabels:k8s-app: fluentd-loggingspec:selector:matchLabels:name: fluentd-elasticsearchtemplate:metadata:labels:name: fluentd-elasticsearchspec:tolerations:- key: node-role.kubernetes.io/mastereffect: NoSchedulecontainers:- name: fluentd-elasticsearchimage: mirrorgooglecontainers/fluentd-elasticsearch:v2.4.0resources:limits:memory: 200Mirequests:cpu: 100mmemory: 200MivolumeMounts:- name: varlogmountPath: /var/log- name: varlibdockercontainersmountPath: /var/lib/docker/containersreadOnly: trueterminationGracePeriodSeconds: 30volumes:- name: varloghostPath:path: /var/log- name: varlibdockercontainershostPath:path: /var/lib/docker/containers这个 DaemonSet , 管理的是一个 fluentd-elasticsearch 镜像的 Pod 。 通过 fluentd 将 Docker 容器里的日志转发到 ElasticSearch 中 。
这个DaemonSet中使用 selector 选择管理所有携带了 name=fluentd-elasticsearch 标签的 Pod 。 然后使用template定义了pod模板 。
然后在运行这个DaemonSet后 , 一个叫DaemonSet Controller的控制器会从 Etcd 里获取所有的 Node 列表 , 然后遍历所有的 Node 。 然后检查Node上是不是有name=fluentd-elasticsearch 标签的 Pod 在运行 。
如果没有这样的pod , 那么就创建一个这样的pod;如果node上这样的pod数量大于1 , 那么就会删除多余的pod 。
运行:
$ kubectl apply -f ds-els.yaml然后查看运行情况:
$ kubectl get pod -n kube-system -l name=fluentd-elasticsearchNAMEREADYSTATUSRESTARTSAGEfluentd-elasticsearch-nwqph1/1Running04m11s由于我这是单节点 , 所以只有一个pod运行了 。
然后查看一下 Kubernetes 集群里的 DaemonSet 对象:
$ kubectl get ds -n kube-system fluentd-elasticsearchNAMEDESIREDCURRENTREADYUP-TO-DATEAVAILABLENODE SELECTORAGEfluentd-elasticsearch1111127m然后我们来稍微看一下源码 , k8s是通过daemon_controller里面的manage方法来管理Pod删减操作的:
manage方法里面首先会获取daemon pod 与 node 的映射关系 , 然后判断每一个 node 是否需要运行 daemon pod , 然后遍历完node之后将需要创建的Pod列表和需要删除Pod的列表交给syncNodes执行 。
func (dsc *DaemonSetsController) manage(ds *apps.DaemonSet, nodeList []*v1.Node, hash string) error {// 获取已存在 daemon pod 与 node 的映射关系nodeToDaemonPods, err := dsc.getNodesToDaemonPods(ds)if err != nil {return fmt.Errorf("couldn't get node to daemon pod mapping for daemon set %q: %v", ds.Name, err)}// 判断每一个 node 是否需要运行 daemon podvar nodesNeedingDaemonPods, podsToDelete []stringfor _, node := range nodeList {nodesNeedingDaemonPodsOnNode, podsToDeleteOnNode, err := dsc.podsShouldBeOnNode(node, nodeToDaemonPods, ds)if err != nil {continue}//将需要删除的Pod和需要在某个节点创建Pod存入列表中nodesNeedingDaemonPods = append(nodesNeedingDaemonPods, nodesNeedingDaemonPodsOnNode...)podsToDelete = append(podsToDelete, podsToDeleteOnNode...)}podsToDelete = append(podsToDelete, getUnscheduledPodsWithoutNode(nodeList, nodeToDaemonPods)...)//为对应的 node 创建 daemon pod 以及删除多余的 podsif err = dsc.syncNodes(ds, podsToDelete, nodesNeedingDaemonPods, hash); err != nil {return err}return nil}