k8s之DaemonSet-创新互联

写在前面

本文接k8s之Deployment 。

我们提供的服务有:网站建设、网站制作、微信公众号开发、网站优化、网站认证、泰顺ssl等。为上千余家企事业单位解决了网站和推广的问题。提供周到的售前咨询和贴心的售后服务,是有科学管理、有技术的泰顺网站制作公司

假定现在有一个这样的需求,需要收集每个Node的运行状态信息,并进行上报,假设有4个节点,我们可以使用Deployment 来实现吗?好像是可以的,我们只需要将repliacas设置为4不就行了,但是deployment只能保证有4个POD在运行,不能保证4个POD是分布在4个Node上的,即deployment的POD分布和节点是没有关系的,那怎么办呢?能否让deployment具备这种功能,然后在yaml中提供相关的配置参数就行了?行是行,但是这样就违背了单一职责的原则,使得单一对象功能过于复杂,维护成本高,因此我们就需要另外一个API对象来完成这个功能,k8s提供的这个API对象就是DaemonSet,也是本文的绝对主角。

1:k8s集群说明

我本地k8s集群一共有2个Node,一个Maser Node,一个Worker Node,如下:

dongyunqi@mongodaddy:~/k8s$ kubectl get node
NAME         STATUS   ROLES                  AGE   VERSION
mongodaddy   Ready    control-plane,master   43h   v1.23.3
mongomummy   Ready 29h   v1.23.3
2:apply

先看下DaemonSet的API定义:

dongyunqi@mongodaddy:~/k8s$ kubectl api-resources | egrep "DaemonSet|KIND"
NAME                              SHORTNAMES   APIVERSION                             NAMESPACED   KIND
daemonsets                        ds           apps/v1                                true         DaemonSet

还是老套路来生成API模板:

dongyunqi@mongodaddy:~/k8s$ export out="--dry-run=client -o yaml" && kubectl create ds info $out
Error: must specify one of -f and -k

error: unknown command "ds info"
See 'kubectl create -h' for help and examples

竟然提示error: unknown command "ds info",难道是不支持缩写,用全称试下:

dongyunqi@mongodaddy:~/k8s$ export out="--dry-run=client -o yaml" && kubectl create DaemonSet info $out
Error: must specify one of -f and -k

error: unknown command "DaemonSet info"
See 'kubectl create -h' for help and examples
dongyunqi@mongodaddy:~/k8s$ export out="--dry-run=client -o yaml" && kubectl create daemonsets info $out
Error: must specify one of -f and -k

error: unknown command "daemonsets info"
See 'kubectl create -h' for help and examples

都是一样的错误,其实就是因为k8s不支持生成ds的yaml模板文件,我想可能是k8s漏掉了吧!故意不支持实在是没有任何道理。这个时候我们该怎么办呢?可以抄啊! 可以在kubenetes的官网 找到一份这样的yaml然后我们再稍作修改就可以了,最终如下:

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: redis-ds
  labels:
    app: redis-ds

spec:
  selector:
    matchLabels:
      name: redis-ds

  template:
    metadata:
      labels:
        name: redis-ds
    spec:
      containers:
      - image: redis:5-alpine
        name: redis
        ports:
        - containerPort: 6379

其实daemonset的yaml和deployment的yaml相比就少了replicas这个指定API对象实例个数的属性,这也很好理解,因为daemonset的API对象的个数是和节点数一样的,且一个Node一个API对象实例,通过下图对比会更加明显:

在这里插入图片描述

yaml编写完毕后我们就可以apply了,如下:

dongyunqi@mongodaddy:~/k8s$ kubectl apply -f daemon.yml 
daemonset.apps/redis-ds created
dongyunqi@mongodaddy:~/k8s$ kubectl get ds
NAME       DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR   AGE
redis-ds   1         1         0       1            0  13s
稍等一会就READY了:
dongyunqi@mongodaddy:~/k8s$ kubectl get daemonset
NAME       DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR   AGE
redis-ds   1         1         1       1            1  3m22s

但是我们注意到ds API对象的个数只有1个,不是应该和节点的个数一样吗?出现这个现象的原因是k8s默认是不向master node部署API对象实例的,这又是怎么实现的呢?要想解释清楚这个问题,我们就得先来看下k8s中的另外两个概念污点 taint容忍度 toleration。污点是k8s集群的Node一个标签,其实就是一个字符串,但污点Node可以配置也可以不配置,通过命令kubectl describe node nodename/hostname可以查看Node配置的污点信息,如下:

dongyunqi@mongodaddy:~/k8s$ kubectl describe node mongodaddy | grep Taints
Taints:             node-role.kubernetes.io/master:NoSchedule
dongyunqi@mongodaddy:~/k8s$ kubectl describe node mongomummy | grep Taints
Taints:  

mongodaddy是我本地master node的主机名,mongomummy是我本地worker node的主机名,需要根据自己的来修改,否则会报找不到节点错误。

可以看到master node配置了污点node-role.kubernetes.io/master:NoSchedule,而worker node没有配置任何污点,是一个非常纯洁的Node。什么是容忍度呢?容忍度是POD上的概念,即允许Node上有哪些污点自己才会在其上创建,默认POD是非常挑剔的,不允许Node有任何的污点,这是为什么DaemonSet的Pod没有在master node上部署的原因,知道了这个,我们只需要让master node没有污点,是不是非常挑剔的POD就会向已经变得纯洁的master node部署pod了呢,我们试一下,要想去除master node的污点,我们需要使用命令kubectl taint node nodename/hostname node-role.kubernetes.io/master:NoSchedule-,如下:

dongyunqi@mongodaddy:~/k8s$ kubectl taint node mongodaddy node-role.kubernetes.io/master:NoSchedule-
node/mongodaddy untainted

此时我们再查看POD是否在master node创建了:

dongyunqi@mongodaddy:~/k8s$ kubectl get daemonset
NAME       DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR   AGE
redis-ds   2         2         2       2            2  43m

可以看到确实创建了,也可以看下是不是在master node上创建的,如下:

dongyunqi@mongodaddy:~/k8s$ kubectl get pod -o wide -l 'app!=ngx-dep'
NAME             READY   STATUS    RESTARTS   AGE   IP           NODE         NOMINATED NODE   READINESS GATES
redis-ds-6ldlr   1/1     Running   0          18m   10.10.0.4    mongodaddyredis-ds-w5bmk   1/1     Running   0          44m   10.10.1.10   mongomummy

但是这种方式影响太大了,改变了master node的污点,会直接影响到其它所有的API对象,因此我们最好还是不要这样搞,所以,还是把master node的污点恢复比较好,而恢复污点使用命令kubectl taint node nodename/hostname node-role.kubernetes.io/master:NoSchedule,如下:

dongyunqi@mongodaddy:~/k8s$ kubectl taint node mongodaddy node-role.kubernetes.io/master:NoSchedule
node/mongodaddy tainted

这个时候污点已经加回去了,那daemonset在master node部署的POD是不是就该被剔除了呢,看下:

dongyunqi@mongodaddy:~/k8s$ kubectl get daemonset
NAME       DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR   AGE
redis-ds   1         1         1       1            1  51m
dongyunqi@mongodaddy:~/k8s$ kubectl get pod -o wide -l 'app!=ngx-dep'
NAME             READY   STATUS    RESTARTS   AGE   IP           NODE         NOMINATED NODE   READINESS GATES
redis-ds-6ldlr   1/1     Running   0          30m   10.10.0.4    mongodaddyredis-ds-w5bmk   1/1     Running   0          56m   10.10.1.10   mongomummy

可以看到kubectl get daemonset的结果已经变成了1,但pod还依然在,不知道这算不算是k8s的一个bug,为什么pod没有被删除,不过也没有关系,我们就手动先把master node上的删除吧:

dongyunqi@mongodaddy:~/k8s$ kubectl delete pod redis-ds-6ldlr
pod "redis-ds-6ldlr" deleted

我们继续往后看,既然修改master node让其变的纯洁影响太大,那么我们能不能只修改POD呢?让它不那么挑剔,这就需要修改其容忍度了,如下:

tolerations:
- key: node-role.kubernetes.io/master
  effect: NoSchedule
  operator: Exists

意思就是容忍存在Exists通过key和effect指定的污点,这里设置的就是master node当前的污点node-role.kubernetes.io/master:NoSchedule,修改yaml后如下:

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: redis-ds
  labels:
    app: redis-ds

spec:
  selector:
    matchLabels:
      name: redis-ds

  template:
    metadata:
      labels:
        name: redis-ds
    spec:
      tolerations:
      - key: node-role.kubernetes.io/master
        effect: NoSchedule
        operator: Exists
      containers:
      - image: redis:5-alpine
        name: redis
        ports:
        - containerPort: 6379

重新apply,如下:

dongyunqi@mongodaddy:~/k8s$ kubectl apply -f daemon.yml 
daemonset.apps/redis-ds configured
dongyunqi@mongodaddy:~/k8s$ kubectl get daemonset
NAME       DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR   AGE
redis-ds   2         2         1       2            1  80m
dongyunqi@mongodaddy:~/k8s$ kubectl get daemonset
NAME       DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR   AGE
redis-ds   2         2         2       2            2  81m

可以看到成功了。

3:静态POD

daemonset会在每个NODE上都部署一个POD,k8s中还有一种方式能够在指定的Node上部署POD,这种方式是静态POD,想要生成静态POD的话只需要在/etc/kubernetes/manifests目录下创建需要的yaml就行了,系统会自动检测并生成POD,如下是当前的:

dongyunqi@mongodaddy:~/k8s$ ll /etc/kubernetes/manifests
total 24
drwxr-xr-x 2 root root 4096  1月  8 21:45 ./
drwxr-xr-x 4 root root 4096  1月  8 21:45 ../
-rw------- 1 root root 2229  1月  8 21:45 etcd.yaml
-rw------- 1 root root 4014  1月  8 21:45 kube-apiserver.yaml
-rw------- 1 root root 3514  1月  8 21:45 kube-controller-manager.yaml
-rw------- 1 root root 1435  1月  8 21:45 kube-scheduler.yaml

可以看到master node的主要组件都是通过这种方式来运行的,但这种POD游离于集群之外,不容易管控,所以最好还是不要使用。

写在后面 总结

本文分析了daemonset API对象,介绍了其在每个Node部署一个POD的特点,并引入了POD选择Node时相关的误点taint和容忍度toleration概念,并给出了具体的例子,最后作为对比引出了静态POD的概念,知道了master node的apiserver,etcd,controller manager,scheduler组件都是以这种方式运行的。最后,希望这篇文章能够帮助到你。

多知道一点

污点的格式是key:NoSchedule,如node-role.kubernetes.io/master:NoSchedule,k8s还定义了很多其他的污点,可以参考官网 。

参考文章列表

你是否还在寻找稳定的海外服务器提供商?创新互联www.cdcxhl.cn海外机房具备T级流量清洗系统配攻击溯源,准确流量调度确保服务器高可用性,企业级服务器适合批量采购,新人活动首月15元起,快前往官网查看详情吧


本文题目:k8s之DaemonSet-创新互联
本文链接:http://hbruida.cn/article/dicpjs.html