kubernete编排技术五:DaemonSet
写留言这篇文章我们来介绍kubernete的一个编排对象,叫DaemonSet,从名字上就能看出,这是一个守护进程。它的作用是在kubernete集群的每个节点上都会创建一个Daemon Pod,而且仅有一个。
作为容器的守护进程,这个Daemon Pod的典型应用是运行网络插件、存储插件、监控和日志组件等。
yaml文件
DaemonSet在yaml中的声明很简单,只要声明api对象的kind是DaemonSet即可。我们写一个文件daemonset.yaml,内容如下:
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:
# this toleration is to have the daemonset runnable on master nodes
# remove it if your masters can't run pods
- key: node-role.kubernetes.io/master
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
- 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
上面这个yaml文件来自官网。可以看到上面的kind是DaemonSet。这个DaemonSet,管理的pod中的镜像是fluentd-elasticsearch镜像,这个镜像的作用是通过fluentd将Docker容器里的日志收集到ElasticSearch。
下面我对这个yaml文件做一个说明:
- 文件中定义了一个template,这个template声明了labels是fluentd-elasticsearch。
- DaemonSet的yaml文件中,RestartPolicy要不不指定,如果指定必须指定为always,其实不指定默认也是always。
- DaemonSet的yaml文件中必须定义.spec.selector,这个selector跟pod中的selector含义是一样的,包括2个元素,matchLabels(跟replicas中一样)和matchExpressions(通过键值列表构建更复杂的选择器)。这个选项是用来匹配携带.spec.template.metadata.labels标签中的api对象。
调度策略
Daemon pod由kubernete scheduler调度到需要的node上,然后由DaemonSet Controller在node上进行创建和调度。
DaemonSet Controller首先从Etcd里获取所有的Node列表,然后依次遍历Node,如果当前node上没有携带name=fluentd-elasticsearch标签的pod,就创建一个,如果有多余一个,就删除多余的。
跟普通pod不一样的是,Daemon pod在创建之前不会进入pending状态。
那DaemonSet怎么控制pod在指定节点上运行呢?它是通过nodeAffinity这个标签来管理的。在Daemon pod中增加NodeAffinity元素来取代.spec.nodeName,就可以使用默认的scheduler来取代DaemonSet Controller来对DaemonSets进行调度,然后默认的调度器再把pod调度到需要的节点上。如下:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchFields:
- key: metadata.name
operator: In
values:
- target-host-name
如果node上已经存在affinity的pod,则默认调度器会用新创建的pod取代它。而DaemonSet controller不会这么做。
上面的requiredDuringSchedulingIgnoredDuringExecution是说,这个nodeAffinity必须在每次调度的时候都进行考虑,而在运行阶段不用考虑。而且这个pod只允许运行在metadata.name是target-host-name的节点上创建。
注:上面的operator的语法非常丰富,这里用in是包含关系,也可以是Equal,等于关系。
DaemonSet还会给Daemon Pod加上Tolerations,它的意思是可以容忍一些Taints(污点)
apiVersion: v1
kind: Pod
metadata:
name: with-toleration
spec:
tolerations:
- key: node.kubernetes.io/unschedulable
operator: Exists
effect: NoSchedule
这段代码中,effect: NoSchedule就是指node一个Taints即不能被任何pod调度,但是DaemonSet给管理的pod加上Toleration后,Daemon pod就会忽略这个限制,继续对有这个node上的pod进行调度。
这就是DaemonSet的特殊之处,它能够通过tolerations来对有Taints限制的节点上的pod进行调度,比如,我们要对有node.kubernetes.io/network-unavailableTaints的节点进行网络调度,就可以定义如下的tolerations
template:
metadata:
labels:
name: network-plugin-agent
spec:
tolerations:
- key: node.kubernetes.io/network-unavailable
operator: Exists
effect: NoSchedule
虽然DaemonSet可以在yaml中声明式的定义toleration,但是下面的toleration会自动添加到DaemonSet创建的pod中,如下图:
创建、升级和回滚
执行下面命令,创建Daemon pod
kubectl apply -f daemonset.yaml
过几分钟查看pods,如下:
[root@master k8s]# kubectl get pod -n kube-system -l name=fluentd-elasticsearch
NAME READY STATUS RESTARTS AGE
fluentd-elasticsearch-5mgqr 1/1 Running 0 147m
fluentd-elasticsearch-6nwlp 1/1 Running 0 147m
可以看到DaemonSet创建了2个pod,而我本地的kubernete集群只有2个节点,一个master和一个普通节点,这2个节点都调度了一个Daemon pod,而普通pod是不能调度到master节点的,这就是DaemonSet的tolerations生效了。
我们可以向Deployment那样管理DaemonSet的版本,如下:
kubectl rollout history daemonset fluentd-elasticsearch -n kube-system
接着我们把fluentd-elasticsearch镜像的版本升级到v2.2.0
kubectl set image ds/fluentd-elasticsearch fluentd-elasticsearch=k8s.gcr.io/fluentd-elasticsearch:v2.2.0 --record -n=kube-system
这时我们再查看版本更新的历史,如下:
kubectl rollout history daemonset fluentd-elasticsearch -n kube-system
daemonset.apps/fluentd-elasticsearch
REVISION CHANGE-CAUSE
1 <none>
2 kubectl set image ds/fluentd-elasticsearch fluentd-elasticsearch=k8s.gcr.io/fluentd-elasticsearch:v2.2.0 --record=true --namespace=kube-system
这时我们再回滚回版本1,命令如下:
kubectl rollout undo daemonset fluentd-elasticsearch --to-revision=1 -n kube-system
这时我们再查看滚动更新的历史,已经有3这个版本了。
[root@worker1 ~]# kubectl rollout history daemonset fluentd-elasticsearch -n kube-system
daemonset.apps/fluentd-elasticsearch
REVISION CHANGE-CAUSE
2 kubectl set image ds/fluentd-elasticsearch fluentd-elasticsearch=k8s.gcr.io/fluentd-elasticsearch:v2.2.0 --record=true --namespace=kube-system
3 <none>
总结
DaemonSet的调度策略其实是在创建Daemon pod时给这个Pod加上一个nodeAffinity,从而保证这个Pod能够在指定节点上启动。通过给这个Pod加上一个 Toleration,从而保证pod能在有Taints限制的节点上创建。
DaemonSet的升级和回滚策略跟Deployment非常相似,不同的是,它管理版本用的是ControllerRevision对象。
一般情况下,Daemon pod跟普通的pod功能一样,但是如果给守护进程做程序配置、监控和日志收集,使用DaemonSet更合适一些。有时候我们要指定一些节点创建pod,也可以使用DaemonSet。
- finecms如何调用多个栏目的子栏目
- 从傅立叶变换到Gabor滤波器
- 三个小时学会wordpress模板制作
- The each() function is deprecated报错的解决方法
- 书接上文:薛定谔的猫是如何诞生的?
- docker源码分析(3)---镜像(1)
- k8s源码分析-----kubelet(8)pod管理
- 大会 | DiracNets:无需跳层连接的ResNet
- golang时间戳格式化与解析
- golang-net/http源码分析之http server
- 白话面向智能体编程(Agent Oriented Programmig, AOP)之四
- 用fpm来做rpm打包
- Nginx配置文件nginx.conf详解
- 这是一位师兄的算法学习之路
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Python作业:BMI评估
- Python笔记
- JavaScript 技术篇-chrome利用ClipboardEvent写入剪切板,没成功的你就差一步
- 搭建一个高可用负载均衡的集群架构(第三部分)
- C语言学习笔记
- JavaScript 技术篇-js获取窗口标题名,获取页面URL地址
- Pyhon海龟绘制木叶村徽章
- MIT大神写给女神的Q版Python画图库—Cutecharts【技术创作101训练营】
- JavaScript 技术篇-js创建dom节点,并设置属性
- 容器中的数据管理
- Java基础 方法
- Python 技术篇-pyperclip库实现读取写入剪切板,超简单
- 基于consul的Docker-overlay跨多宿主机容器网络
- Python 微信机器人-向指定名称的好友发送微信消息
- JavaScript技术篇-js提升网页视频播放速率,提高慕课网视频播放速度