携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第5天,点击查看活动详情
一、简介
在大多数情况下,我们不关心 pod 会被调度到哪个节点,只关心 pod 是否被成功调度到集群的一个可用节点。但是,在真实生产环境中存在一种需求:希望某种 pod 全部运行在一个或一些节点上。比如需要 ssd 的 pod 都运行在具有 ssd 磁盘的目标节点上。
二、全自动调度
deployment或rc的主要功能之一就是自动部署一个容器应用的多份副本,以及持续监控副本的数量,在集群中始终维持用户指定的副本数量。
nginx-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
selector:
matchLabels:
app: nginx
replicas: 3
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.7.9
ports:
- containerPort: 80
使用kubectl create命令创建这个deployment:
# kubectl create -f nginx-deployment.yaml
deployment "nginx-deployment" created
可以看到Deployment已经创建好 3 个副本,并且所有副本都是最新可用的。从调度策略上来说,这 3 个pod由系统全自动完成调度,用户无法干预调度过程和结果。
三、NodeSelector:定向调度
通过Node的标签(Label)和Pod的nodeSelector属性相匹配来讲Pod调度到指定的一些Node上。
1、通过kubectl label命令给目标Node打上一些标签:
kubectl label nodes <node-name> <label-key>=<label-value>
2、在Pod的定义中加上nodeSelector的设置
apiVersion: v1
kind: ReplicationController
metadata:
name: redis-master
labels:
name: redis-master
spec:
replicas: 3
selector:
name: redis-master
template:
metadata:
labels:
name: redis-master
spec:
containers:
- name: master
image: reids-master
ports:
- containerPort: 6379
nodeSelector: # 节点标签选择器
zone: north
如果给多个Node都定义了相同的标签,则scheduler会根据调度算法从Node组中挑选一个可用的Node进行调度。
除了用户可以自行给Node添加标签,kubernetes也会给Node预定义一些标签。
- kubernetes.io/hostname
- kubernetes.io/os
- kubernetes.io/arch
四、NodeAffinity:Node 亲和性调度
NodeAffinity为 Node 亲和性的调度策略,是用于替换NodeSelector的全新调度策略。目前有两种节点亲和性表达。
- RequiredDuringSchedulingIgnoredDuringExecution:必须满足指定的规则才能调度 Pod 到 Node 上,相当于硬限制。
- PreferredDuringSchedulingIgnoredDuringExecution:强调优先满足指定规则,调度器会尝试调度 Pod 到 Node 上,但不强求,相当于软限制。多个优先级规则还可以设置权重(weight)值,以定义执行的先后顺序。
IgnoredDuringExecution:如果一个 Pod 所在的结点在 Pod 运行期间标签发生了变更,不再符合 Pod 的结点亲和性需求,则系统将忽略 Node 上的 Label 变化,该 Pod 能继续在该节点上运行。
apiVersion: v1
kind: Pod
metadata:
name: with-node-affinity
spec:
affinity:
nodeAffinity: # 要求只在amd64的节点上运行
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: beta.kubernetes.io/arch
operator: In
values:
- amd64
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 1 # 尽量运行在磁盘类型为ssd的节点上
preference:
matchExpressions:
- key: disk-type
operator: In
values:
- ssd
containers:
- name: with-node-affinity
image: pause:2.0
NodeAffinity语法支持的操作符包括In、NotIn、Exists、DoesNotExist、Gt、Lt。
NodeAffinity规则设置的注意事项:
- 如果同时定义了
nodeSelector和nodeAffinity,那么必须两个条件都得到满足,Pod 才能最终运行在指定的 Node 上 - 如果
nodeAffinity指定了多个nodeSelectorTerms,那么其中一个能够匹配成功即可 - 如果
nodeSelectorTerms中有多个matchExpressions,则一个节点必须满足所有matchExpressions才能运行 Pod。
五、PodAffinity:Pod 亲和与互斥调度策略
如果在具有标签相同的 Node 上运行了一个或多个符合条件的 Pod,那么 Pod 应该运行在这个 Node 上。
topologyKey:节点所属的topoloty
- kubernets.io/hostname
- failure-domain.beta.kubernetse.io/zone
- failure-domain.beta.kubernets.io/region
pod 的亲和与互斥的条件设置也是RequiredDuringSchedulingIgnoredDuringExecution和PreferredDuringSchedulingIgnoredDuringExecution。
Pod 的亲和性被定义在podAffinity,Pod 的互斥性被定义在podAntiAffinity。
1、参考目标 Pod
创建一个名为pod-flag的 pod,带有标签security=S1和app=nginx。
apiVerson: v1
kind: Pod
metadata:
name: pod-flag
labels:
security: "S1"
app: "nginx"
spec:
containers:
- name: nginx
image: nginx
2、Pod 的亲和性调度
apiVerson: v1
kind: Pod
metadata:
name: pod-affinity
spec:
affinity:
podAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: security
operator: In
values:
- S1
topologyKey: kubernets.io/hostname
containers:
- name: with-pod-affinity
image: pause:2.0
3、Pod 的互斥性调度
apiVerson: v1
kind: Pod
metadata:
name: anti-affinity
spec:
affinity:
podAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: security
operator: In
values:
- S1
topologyKey: failure-domain.beta.kubernets.io/zone
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: security
operator: In
values:
- nginx
topologyKey: kubernets.io/hostname
containers:
- name: anti-pod-affinity
image: pause:2.0
新 pod 与security=S1的 pod 为同一个zone,但不与app=nginx的 Pod 为同一个zone。
topologyKey 的限制(出于性能和安全方面考虑):
- 在 Pod 亲和性和 RequiredDuringScheduing 的 Pod 互斥性的定义中,不允许使用空的 topologyKey。
- 如果 Admission Controller 包含了
LimitPodHardAntiAffinityTopology,那么针对Required DuringScheduling的 Pod 互斥性定义就被限制为kubernetes.io/hostname,要使用自定义的topologyKey就要改写或禁用该控制器。 - 在
PreferredDruingScheduling类型的 Pod 互斥性定义中,空的topologyKey会被解释为kubernets.io/hostname、failure-domain.beta.kubernetse.io/zone、failure-domain.beta.kubernets.io/region的组合。 - 如果不是上述情况,就可以采用任意合法的
topologyKey。
PodAffinity规则设置的注意事项:
- 除了设置
Label Selector和topologyKey,用户还可以指定Namespace列表来进行限制,同样,使用Label Selector对Namespace进行选择。 - 在所有关联
requiredDuringSchedulingIgnoredDuringExecution的matchExpressions全部满足之后,系统才能将 Pod 调度到某个 Node 上。
六、Taints 和 Tolerations(污点和容忍)
在 Node 上设置一个或多个 Taint 之后,除非 Pod 明确声明能够容忍这些污点,否则无法在这些 Node 上运行。Toleration 是 Pod 的属性,让 Pod 能够运行在标注了 taint 的 Node 上。
# kubectl taint nodes node1 key=value:NoSchedule
然后在 pod 上声明 toleration。
tolerations:
- key: "key"
operator: "Equal"
value: "value"
effect: "NoSchedule"
tolerations:
- key: "key"
operator: "Exists"
effect: "NoSchedule"
如果不指定operator,默认值为Equal。空的 key 配合 Exists 能够匹配所有键和值。空的 effect 能够匹配所有的 effect。
- NoSchedule:不调度
- PreferNoSchedule:不优先调度
- NoExecute:不运行,已经在这个节点上的 Pod 会被驱逐。
七、Pod Priority Preemption:Pod 优先级调度
优先级抢占调度策略的核心行为分别是驱逐(Eviction)和抢占(Preemption)。Evection 是 kubelet 行为,即当一个 Node 发生资源不足情况时,该节点上的 kubelet 进程会发生驱逐动作,此时 kubelet 会综合考虑 Pod 的优先级、资源申请量与实际使用量等信息极端哪些 Pod 需要被驱逐;当同样优先级的 Pod 需要被驱逐时,实际使用的资源量超过申请量最大倍数的高耗能 Pod 会被首先驱逐。
服务质量等级 Qos:
- Guaranteed:pod 设置了
limit或limit=request - Burstable:pod 里的一个容器
limit!=request - Best-Effort:
limit和request均未设置
1、创建 PriorityClasses
apiVersion: scheduling.k8s.io/v1beta1
kind: PriorityClass
metadata:
name: high-priority
value: 1000000
globalDefault: false
description: "This priority class should be used for service pods only"
2、可以在任意 pod 中引用优先级类别
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
env: test
spec:
containers:
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent
priorityClassName: high-priority
八、其他情况
1、DaemonSet:在每个 Node 上都调度一个 Pod
2、Job 和 CronJob 的批处理调度,可以设置任务数completions和并行度parallelism