Kubernetes Pod资源调度之全自动调度和定向调度
1、控制器类型
在Kubernetes
上,很少会直接创建一个Pod
,在大多数情况下,会通过RC
、Deployment
、DaemonSet
、Job
等控制器完成对一组Pod
副本的创建、调度和整个生命周期的自动化控制。
在最早的Kubernetes
版本里没有这么多Pod
副本控制器的,只有一 个Pod
副本控制器RC
(Replication Controller),这个控制器是这样设计 实现的:RC
独立于所控制的Pod
,并通过Label
标签这个松耦合关联关系 控制目标Pod
实例的创建和销毁,随着Kubernetes
的发展,RC
也出现了新的继任者Deployment
,用于更加自动地完成Pod
副本的部署、版 本更新、回滚等功能。
严谨地说,RC
的继任者其实并不是Deployment
,而是ReplicaSet
, 因为ReplicaSet
进一步增强了RC
标签选择器的灵活性。之前RC
的标签选择器只能选择一个标签,而ReplicaSet
拥有集合式的标签选择器,可以选择多个Pod
标签,如下所示
selector:
matchLables:
tier: frontend
matchExpressions:
- {key: tier, operator: In, values: [frontend]}
与RC
不同,ReplicaSet
被设计成能控制多个不同标签的Pod
副本。 一种常见的应用场景是,应用MyApp
目前发布了v1
与v2
两个版本,用户 希望MyApp
的Pod
副本数保持为3
个,可以同时包含v1
和v2
版本的Pod
, 就可以用ReplicaSet
来实现这种控制,写法如下
selector:
matchLables:
version: v2
matchExpressions:
- {key: version, operator: In, values: [v1,v2]}
Kubernetes
的滚动升级就是巧妙运用ReplicaSet
的这个特性来实现的,同时,Deployment
也是通过ReplicaSet
来实现Pod
副本自动控制功能的。我们不应该直接使用底层的ReplicaSet
来控制Pod
副本,而应该 使用管理ReplicaSet
的Deployment
对象来控制副本,这是来自官方的建议。
2、全自动调度
全自动调度的控制器是Deployment
或RC
,Deployment
或RC
的主要功能之一就是自动部署一个容器应用的 份副本,以及持续监控副本的数量,在集群内始终维持用户指定的副本数量。
下面是一个Deployment
配置的例子,使用这个配置文件可以创建一个ReplicaSet
,这个ReplicaSet
会创建3
个Nginx
应用的Pod
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 3
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
运行kubectl create
命令创建这个Deployment
# kubectl apply -f nginx-deployment.yaml
deployment.apps/nginx-deployment created
查看Deployment
、RS
、Pod
的状态
# kubectl get deployment
NAME READY UP-TO-DATE AVAILABLE AGE
nginx-deployment 3/3 3 3 58s
# kubectl get rs
NAME DESIRED CURRENT READY AGE
nginx-deployment-7bffc778db 3 3 3 85s
# kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx-deployment-7bffc778db-j5czg 1/1 Running 0 1m34s
nginx-deployment-7bffc778db-lbpjg 1/1 Running 0 1m34s
nginx-deployment-7bffc778db-zcn6m 1/1 Running 0 1m34s
从调度策略上来说,这3
个Nginx Pod
由系统全自动完成调度。它们各自最终运行在哪个节点上,完全由Master
的Scheduler
经过一系列算法计算得出,用户无法干预调度过程和结果。
# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-deployment-7bffc778db-j5czg 1/1 Running 0 3m36s 172.20.3.229 k8s-node-1 <none> <none>
nginx-deployment-7bffc778db-lbpjg 1/1 Running 0 3m36s 172.20.4.27 k8s-node-2 <none> <none>
nginx-deployment-7bffc778db-zcn6m 1/1 Running 0 3m36s 172.20.5.203 k8s-node-3 <none> <none>
3、定向调度
定向调度通过NodeSelector
标签实现, Master
上的Scheduler
服务(kube-scheduler
进程)负责实现Pod
的调度,整个调度过程通过执行一系列复杂的算法,最终为每个Pod
都计算出一个最佳的目标节点,这一过程是自动完成的,通常我们 无法知道Pod
最终会被调度到哪个节点上。在实际情况下,也可能需要将Pod
调度到指定的一些Node
上,可以通过Node
的标签(Label
)和Pod
的nodeSelector
属性相匹配,来达到上述目的。
首先通过kubectl label
命令给目标Node
打上一些标签
# kubectl label nodes k8s-node-1 zone=north
然后,在Pod
的定义中加上nodeSelector
的设置,以redismaster-controller.yaml
为例
apiVersion: v1
kind: ReplicationController
metadata:
name: redis-master
labels:
name: redis-master
spec:
replicas: 1
selector:
name: redis-master
template:
metadata:
labels:
name: redis-master
spec:
containers:
- name: master
image: redis
ports:
- containerPort: 6379
nodeSelector:
zone: north
创建Pod
,scheduler
就会将该Pod
调度到拥有zone=north
标签的Node
上
如果我们给多个Node
都定义了相同的标签(例如zone=north
),则scheduler
会根据调度算法从这组Node
中挑选一个可用的Node
进行Pod
调度。
通过基于Node
标签的调度方式,我们可以把集群中具有不同特点的Node
都贴上不同的标签,例 如role=frontend
、role=backend``、role=database
等标签,在部署应用时就可以根据应用的需求设置NodeSelector
来进行指定Node
范围的调度。
如果我们指定了Pod
的nodeSelector
条件,且在集群中不存在包含相应标签的Node
,则即使在集群中还有其他可供使用的Node
,这个Pod
也无法被成功调度。
除了用户可以自行给Node
添加标签,Kubernetes
也会给Node
预定义 一些标签,包括
- kubernetes.io/hostname
- beta.kubernetes.io/os(从1.14版本开始更新为稳定版,到1.18版 本删除)
- beta.kubernetes.io/arch(从1.14版本开始更新为稳定版,到1.18 版本删除)
- kubernetes.io/os(从1.14版本开始启用)
- kubernetes.io/arch(从1.14版本开始启用)
也可以使用这些系统标签进行Pod的定向调度。
NodeSelector通过标签的方式,简单实现了限制Pod
所在节点的方法。亲和性调度机制则极大扩展了Pod
的调度能力,主要的增强功能如 下。
- 更具表达力(不仅仅是“符合全部”的简单情况)
- 可以使用软限制、优先采用等限制方式,代替之前的硬限制, 这样调度器在无法满足优先需求的情况下,会退而求其次,继续运行该
Pod
- 可以依据节点上正在运行的其他
Pod
的标签来进行限制,而非节点本身的标签。这样就可以定义一种规则来描述Pod
之间的亲和或互斥关系
亲和性调度功能包括节点亲和性NodeAffinity
和Pod
亲和性PodAffinity
两个维度的设置。节点亲和性与NodeSelector
类似,增 强了上述前两点优势;Pod
的亲和与互斥限制则通过Pod
标签而不是节点标签来实现,也就是上面所陈述的方式,同时具有前两点提到的优点。
NodeSelector
将会继续使用,随着节点亲和性越来越能够表达nodeSelector
的功能,最终NodeSelector
会被废弃。
文章参考来源:《kubernetes权威指南-第4版》