玩转k8s pod调度之定向调度与全自动调度
在大多数情况下,我们希望Deployment创建的Pod副本被成功调度到集群中的任何一个可用节点,而不关心具体会调度到哪个节点。但是,在真实的生产环境中比如希望将MySQL数据库调度到一个具有SSD磁盘的目标节点上,此时Pod模板中的NodeSelector属性就开始发挥作用了,上述MySQL定向调度案例的实现方式可分为以下两步。
(1)把具有SSD磁盘的Node都打上自定义标签“disk=ssd”。
(2)在Pod模板中设定NodeSelector的值为“disk: ssd”。
如此一来,Kubernetes在调度Pod副本的时候,就会先按照Node的标签过滤出合适的目标节点,然后选择一个最佳节点进行调度。
上述逻辑看起来既简单又完美,但在真实的生产环境中可能面临以下令人尴尬的问题。
(1)如果NodeSelector选择的Label不存在或者不符合条件,比如这些目标节点此时宕机或者资源不足,该怎么办?
(2)如果要选择多种合适的目标节点,比如SSD磁盘的节点或者超高速硬盘的节点,该怎么办?Kubernates引入了NodeAffinity(节点亲和性设置)来解决该需求。
在真实的生产环境中还存在如下所述的特殊需求。
(1)不同Pod之间的亲和性(Affinity)。比如MySQL数据库与Redis中间件不能被调度到同一个目标节点上(反亲和),或者两种不同的Pod必须被调度到同一个Node上(亲和性),以实现本地文件共享或本地网络通信等特殊需求,这就是PodAffinity要解决的问题。
(2)有状态集群的调度。对于ZooKeeper、Elasticsearch、MongoDB、Kafka等有状态集群,虽然集群中的每个Worker节点看起来都是相同的,但每个Worker节点都必须有明确的、不变的唯一ID(主机名或IP地址),这些节点的启动和停止次序通常有严格的顺序。此外,由于集群需要持久化保存状态数据,所以集群中的Worker节点对应的Pod不管在哪个Node上恢复,都需要挂载原来的Volume,因此这些Pod还需要捆绑具体的PV。针对这种复杂的需求,Kubernetes提供了StatefulSet这种特殊的副本控制器来解决问题,在Kubernetes 1.9版本发布后,StatefulSet才可用于正式生产环境中。
(3)在每个Node上调度并且仅仅创建一个Pod副本。这种调度通常用于系统监控相关的Pod,比如主机上的日志采集、主机性能采集等进程需要被部署到集群中的每个节点,并且只能部署一个副本,这就是DaemonSet这种特殊Pod副本控制器所解决的问题。
(4)对于批处理作业,需要创建多个Pod副本来协同工作,当这些Pod副本都完成自己的任务时,整个批处理作业就结束了。这种Pod运行且仅运行一次的特殊调度,用常规的RC或者Deployment都无法解决,所以Kubernates引入了新的Pod调度控制器Job来解决问题,并继续延伸了定时作业的调度控制器CronJob。
与单独的Pod实例不同,由RC、ReplicaSet、Deployment、DaemonSet等控制器创建的Pod副本实例都是归属于这些控制器的,这就产生了一个问题:控制器被删除后,归属于控制器的Pod副本该何去何从?在Kubernates 1.9之前,在RC等对象被删除后,它们所创建的Pod副本都不会被删除;在Kubernates 1.9以后,这些Pod副本会被一并删除。如果不希望这样做,则可以通过kubectl命令的--cascade=false参数来取消这一默认特性:
Deployment或RC:全自动调度
NodeSelector:定向调度
首先通过kubectl label命令给目标Node打上一些标签
我们为k8s-node-1节点打上一个zone=north标签,表明它是“北方”的一个节点
[root@master-1 busybox]# kubectl label node node-1 onne=north node/node-1 labeled [root@master-1 busybox]# kubectl get node --show-labels NAME STATUS ROLES AGE VERSION LABELS master-1 Ready <none> 28d v1.20.15 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=master-1,kubernetes.io/master=true,kubernetes.io/os=linux node-1 Ready <none> 28d v1.20.15 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=node-1,kubernetes.io/os=linux,onne=north node-2 Ready <none> 28d v1.20.15 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=node-2,kubernetes.io/os=linux
在Pod的定义中加上nodeSelector的设置
apiVersion: apps/v1 kind: Deployment ... spec: restartPolicy: Always serviceAccountName: default containers: - name: nginx-configmap-container image: 124.222.68.142:10006/k8s/nginx:latest imagePullPolicy: IfNotPresent ports: - containerPort: 80 protocol: TCP name: http - containerPort: 443 protocol: TCP name: https ... nodeSelector: onne: north
查看pod
[root@master-1 hostpath]# kubectl get pod -n app -owide -w NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES nginx-configmap-6b66d56f59-sncrb 1/1 Running 0 17s 10.244.84.159 node-1 <none> <none>
如果未匹配到nodeSelector则调度失败
Events: Type Reason Age From Message ---- ------ ---- ---- ------- Warning FailedScheduling 27s default-scheduler 0/3 nodes are available: 3 node(s) didn't match Pod's node affinity. # 3台node没有一个匹配pod亲和性 Warning FailedScheduling 27s default-scheduler 0/3 nodes are available: 3 node(s) didn't match Pod's node affinity.
nodeName: 指定集群中主机名称调度
#nodeSelector: # zone: north nodeName: node-3