K8S之运用亲和性设置Pod的调度约束
亲和性
- Node节点亲和性
- 硬亲和实践
- 软亲和性实践
- Pod节点亲和性和反亲和性
- pod亲和性
- 硬亲和实践
- pod反亲和性
Pod 的yaml文件里 spec 字段中包含一个 affinity 字段,使用一组亲和性调度规则,指定pod的调度约束。
kubectl explain pods.spec.affinity
配置说明
- nodeAffinity: node节点亲和性,pod倾向于哪个node
- podAffinity: pod亲和性,pod倾向于哪个pod
- podAntiAffinity: pod的反亲和性,pod排斥于哪个pod
Node节点亲和性
Node节点亲和性 是针对 pod和node 的关系,Pod调度到node节点的时候匹配的条件
node节点亲和性调度字段:nodeAffinity
看nodeAffinity下的配置字段
kubectl explain pods.spec.affinity.nodeAffinity
- preferredDuringSchedulingIgnoredDuringExecution 表示有节点尽量满足这个位置定义的亲和性,这不是一个必须的条件,软亲和性
- requiredDuringSchedulingIgnoredDuringExecution 表示必须有节点满足这个位置定义的亲和性,这是个硬性条件,硬亲和性
硬亲和实践
使用requiredDuringSchedulingIgnoredDuringExecution硬亲和性
Node节点硬亲和性选择匹配方式有2种:
- matchFields: 匹配字段的
- matchExpressions:匹配表达式的 (用的多)
对matchExpressions做进一步解读
matchExpressions——匹配表达式的写法:
kubectl explain pods.spec.affinity.nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution.nodeSelectorTerms.matchExpressions
字段配置:
- key:匹配节点标签的KEY(必填)
- operator:表示键与一组值的关系(必填),可选的枚举值如下:
- In (包含)
- NotIn(不包含)
- Exists (存在)
- DoesNotExist (不存在)
- Gt (大于)
- Lt (小于)
- values:给定值
示例 :把pod调度到集群中 拥有zone标签 并且值是foo或者bar的node节点上
创建pod资源文件
vim pod-nodeaffinity-demo.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-node-affinity-demo
namespace: default
spec:
affinity: # 设置亲和性调度规则
nodeAffinity: # 设置node亲和性
requiredDuringSchedulingIgnoredDuringExecution: # 使用硬亲和性
nodeSelectorTerms: # 配置节点选择器规则
- matchExpressions: # 匹配表达式的
- key: zone # 节点标签的key
operator: In # 使用表达式为包含
values: # 包含的值有(foo或者bar)
- foo
- bar
containers:
- name: myapp
image: docker.io/ikubernetes/myapp:v1
imagePullPolicy: IfNotPresent
创建资源
kubectl apply -f pod-nodeaffinity-demo.yaml
查看pod
kubectl get pods -o wide
status的状态是pending,上面说明没有完成调度,因为没有一个节点拥有zone的标签
值是foo或者bar,而且使用的是硬亲和性,必须满足条件才能完成调度
给k8s-node1节点打上标签zone=foo,再查看
kubectl label nodes k8s-node1 zone=foo
kubectl get pods -o wide
pod调度到了k8s-node1节点上
软亲和性实践
使用preferredDuringSchedulingIgnoredDuringExecution软亲和性
示例
创建pod资源文件
vim pod-nodeaffinity-demo-2.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-node-affinity-demo-2
namespace: default
spec:
containers:
- name: myapp
image: docker.io/ikubernetes/myapp:v1
imagePullPolicy: IfNotPresent
affinity: # 设置亲和性调度规则
nodeAffinity: # 设置node亲和性
preferredDuringSchedulingIgnoredDuringExecution: # 使用软亲和性
- preference:
matchExpressions: # 匹配表达式的
- key: zone1 # 节点标签的key
operator: In # # 使用表达式为包含
values: # 包含的值有(foo1或者bar1)
- foo1
- bar1
weight: 10 # 匹配度权重
- preference:
matchExpressions:
- key: zone2
operator: In
values:
- foo2
- bar2
weight: 20 # weight是相对权重,权重越高,pod调度的几率越大
创建资源
kubectl apply -f pod-nodeaffinity-demo-2.yaml
查看pod
kubectl get pods -o wide |grep pod-node-affinity-demo-2
上面说明软亲和性是可以运行这个pod的,尽管没有运行这个pod的节点定义的zone1标签
测试weight权重
先删除pod-node-affinity-demo-2
(ps. 执行强制删除的命令,加上“–force --grace-period=0”)
kubectl delete pod pod-node-affinity-demo-2 --force --grace-period=0
给k8s-node1和k8s-node2都打上标签
kubectl label nodes k8s-node1 zone1=foo1
kubectl label nodes k8s-node2 zone2=foo2
再创建资源
kubectl apply -f pod-nodeaffinity-demo-2.yaml
查看pod
kubectl get pods -o wide
pod在定义node节点亲和性的时候,k8s-node1和k8s-node2都满足调度条件,但是k8s-node2具有的标签是zone2=foo2,pod在匹配zone2=foo2的权重高,那么pod就会优先调度到k8s-node2上
Pod节点亲和性和反亲和性
Pod节点亲和性 是针对 pod和pod 的关系
有两种表示形式
-
podAffinity:pod和pod更倾向在一起,把相近的pod结合到相近的位置。
这样的话pod和pod之间更好通信。比方希望把nginx和tomcat都部署同一个地方的node节点上,可以提高通信效率; -
podAntiAffinity:pod和pod不倾向在一起。如果部署两套程序,那么这两套程序更倾向于反亲和性,这样相互之间不会有影响。
运行方式
第一个pod随机选则一个节点,例如:节点A。做为 评判后续的pod 能否到达节点A上。到达 就称为pod亲和性,反之是反亲和性。
以节点名称为标准,这个节点名称相同的表示是同一个位置,节点名称不相同的表示不是一个位置。
pod亲和性
pod亲和性调度字段:podAffinity
看podAffinity下的配置字段
kubectl explain pods.spec.affinity.podAffinity
- requiredDuringSchedulingIgnoredDuringExecution 硬亲和性
- preferredDuringSchedulingIgnoredDuringExecution 软亲和性
硬亲和实践
使用requiredDuringSchedulingIgnoredDuringExecution硬亲和性
kubectl explain pods.spec.affinity.podAffinity.requiredDuringSchedulingIgnoredDuringExecution
解释说明
- topologyKey:位置拓扑的键,节点的标签(必填)
怎么判断是不是同一个位置,例如:
rack=rack1 使用rack的键是同一个位置
row=row1 使用row的键是同一个位置 - labelSelector:判断pod跟别的pod亲和,通过labelSelector选则一组能作为亲和对象的pod资源
- namespace:指定匹配资源的命名空间,如果不指定namespaces,那么就是当前创建pod的名称空间
- namespaceSelector: :指定匹配资源的命名空间集合,空选择器({})匹配所有命名空间。
对labelSelector进一步解析:
labelSelector——对pod资源的标签查询
kubectl explain pods.spec.affinity.podAffinity.requiredDuringSchedulingIgnoredDuringExecution.labelSelector
字段配置:
- matchExpressions:匹配表达式
- matchLabels:匹配标签
示例1: 定义两个pod,第一个pod做为基准,第二个pod跟着它走
创建第一个pod资源文件
vim pod-required-affinity-demo-1.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-first
labels:
app: myapp
spec:
containers:
- name: myapp
image: ikubernetes/myapp:v1
imagePullPolicy: IfNotPresent
创建第一个pod资源
kubectl apply -f pod-required-affinity-demo-1.yaml
创建第二个pod资源文件,让第二个pod和第一个pod做亲和性
vim pod-required-affinity-demo-2.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-second
labels:
app: backend
spec:
containers:
- name: busybox
image: busybox:latest
imagePullPolicy: IfNotPresent
command: ["sh","-c","sleep 3600"]
affinity:
podAffinity: #使用pod亲和性
requiredDuringSchedulingIgnoredDuringExecution: #使用硬亲和性
- topologyKey: kubernetes.io/hostname # 设置位置拓扑的键
labelSelector: # 设置对pod资源的标签查询
matchExpressions: # 用匹配表达式:找pod标签中key是app 值包含myapp的
- {key: app, operator: In, values: ["myapp"]}
上面表示新创建的pod必须与拥有 “app=myapp” 标签的pod在一个节点上
创建第二个pod资源
kubectl apply -f pod-required-affinity-demo-2.yaml
查看pod
kubectl get pods -o wide
上面说明第一个pod调度到哪,第二个pod也调度到哪,这就是pod节点亲和性
示例2 :接着上面的实验,调整一下pod2 ,让 labelSelector满足 pod1的标签,但是topologyKey不满足pod1所在的node的特点
调整第二个pod资源文件
vim pod-required-affinity-demo-2.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-second
labels:
app: backend
spec:
containers:
- name: busybox
image: busybox:latest
imagePullPolicy: IfNotPresent
command: ["sh","-c","sleep 3600"]
affinity:
podAffinity: #使用pod亲和性
requiredDuringSchedulingIgnoredDuringExecution: #使用硬亲和性
- topologyKey: zone2 # 设置node1节点没有的标签key
labelSelector:
matchExpressions:
- {key: app, operator: In, values: ["myapp"]}
重建第二个pod资源
kubectl delete -f pod-required-affinity-demo-2.yaml
kubectl apply -f pod-required-affinity-demo-2.yaml
查看pod
kubectl get pods -o wide
上面说明 labelSelector和topologyKey必须同时满足才能找到要调度的节点
pod反亲和性
一切配置都是反着来。
例如 硬亲和性
解释说明
- topologyKey:不去有位置拓扑的键的节点上(必填)
- labelSelector:判断pod跟别的pod反亲和
示例1: 定义两个pod,第一个pod做为基准,第二个pod跟它调度节点相反
创建第一个pod资源文件
vim pod-required-anti-affinity-demo-1.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-first
labels:
app1: myapp1
spec:
containers:
- name: myapp
image: ikubernetes/myapp:v1
imagePullPolicy: IfNotPresent
创建第一个pod资源
kubectl apply -f pod-required-anti-affinity-demo-1.yaml
创建第二个pod资源文件
vim pod-required-anti-affinity-demo-2.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-second
labels:
app: backend
spec:
containers:
- name: busybox
image: busybox:latest
imagePullPolicy: IfNotPresent
command: ["sh","-c","sleep 3600"]
affinity:
podAntiAffinity: #使用pod反亲和性
requiredDuringSchedulingIgnoredDuringExecution: #使用硬亲和性
- topologyKey: kubernetes.io/hostname
labelSelector: # 设置对pod资源的标签查询
matchExpressions: # 用匹配表达式:pod标签中key是app1 值包含myapp1的
- {key: app1, operator: In, values: ["myapp1"]}
创建第二个pod资源
kubectl apply -f pod-required-anti-affinity-demo-2.yaml
查看pod
kubectl get pods -o wide
显示两个pod不在一个node节点上,这就是pod节点反亲和性
示例2: 看 topologykey + labelSelector同时满足时,第二个pod的情况
给节点都打上“zone=foo” 标签
kubectl label nodes k8s-node2 zone=foo
kubectl label nodes k8s-node1 zone=foo
创建第一个pod资源文件
vim pod-first-required-anti-affinity-demo-1.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-first
labels:
app3: myapp3
spec:
containers:
- name: myapp
image: ikubernetes/myapp:v1
imagePullPolicy: IfNotPresent
创建第一个pod资源
kubectl apply -f pod-first-required-anti-affinity-demo-1.yaml
创建第二个pod资源文件
vim pod-second-required-anti-affinity-demo-1.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-second
labels:
app: backend
tier: db
spec:
containers:
- name: busybox
image: busybox:latest
imagePullPolicy: IfNotPresent
command: ["sh","-c","sleep 3600"]
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- {key: app3 ,operator: In, values: ["myapp3"]}
topologyKey: zone
创建第二个pod资源
kubectl apply -f pod-second-required-anti-affinity-demo-1.yaml
查看pod
kubectl get pods -o wide
第二个pod是pending,因为两个节点是同一个位置,现在没有不是同一个位置的了,而且要求反亲和性,所以就会处于pending状态,如果在反亲和性这个位置把硬反亲和改成软反亲和,那么也会运行。