这是我参与更文挑战的第17天,活动详情查看: 更文挑战
一些概念 Affinity对应pod的pod.spec.affinity字段,下面有多种组合配置,需要先明白一些概念
Affinity和Anti-affinity 亲和性分为正向的Affinity,表示愿意被分配至目标node,和反向的Anti-affinity,表示不愿意被分配至目标node。
NodeAffinity和PodAffinity 两个不同维度的亲和性策略,NodeAffinity是根据node的标签去决定是否分配。而PodAffinity是根据pod的标签去决定要不要和别的pod分配到一个node。
软策略和硬策略 软策略字段以preferred开头,表示尽量达到,没满足也没关系,多个软策略之间会有各自权重。硬策略字段以required开头,表示必须满足。
实际操作 因为本节的概念理解起来相对容易,所以直接上手操作。不过因为字段组合较多,建议多利用kubectl explain pod.spec.affinity查看各个字段的含义。
以下所有yaml文件托管在我的Github仓库
NodeAffinity实际操作
硬策略
通过下面的yaml文件test-nodeaffinity-hard.yaml来验证下node亲和性的硬策略
apiVersion: v1
kind: Pod
metadata:
name: test-nodeaffinity-hard
labels:
app: app1
spec:
containers:
- name: mynginx
image: mynginx:v2
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/hostname
operator: In
values:
- k8s-node3
这里的matchExpressions是比配node的labels,底下的三个字段如下
字段 类型 说明 key string node的标签的key operator string 判断符号,可以选In/NotIn/Exists/DoesNotExist/Gt/Lt values list 一组值,结合上面的运算符号进行判断 node的labels可以用如下方式查看
[root@k8s-master affinity]# kubectl get node --show-labels
NAME STATUS ROLES AGE VERSION LABELS
k8s-master Ready master 14d v1.15.11 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=k8s-master,kubernetes.io/os=linux,node-role.kubernetes.io/master=
k8s-node1 Ready <none> 14d v1.15.11 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=k8s-node1,kubernetes.io/os=linux
我这里有两个node,它们的hostname都不是k8s-nodes,在这种硬策略下该pod没有node可以分配
[root@k8s-master affinity]# kubectl apply -f test-nodeaffinity-hard.yaml
pod/test-nodeaffinity-hard created
[root@k8s-master affinity]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
test-nodeaffinity-hard 0/1 Pending 0 6s <none> <none> <none> <none>
再启动,无论启动多少次都只会在master节点
[root@k8s-master affinity]# kubectl apply -f test-nodeaffinity-hard.yaml
pod/test-nodeaffinity-hard created
[root@k8s-master affinity]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
test-nodeaffinity-hard 1/1 Running 0 5s 10.244.0.19 k8s-master <none> <none>
我这里没有足够节点所以选择master节点,一般master节点是不会分配pod的
软策略
将上面的yaml文件稍微修改成如下的test-nodeaffinity-soft.yaml
apiVersion: v1
kind: Pod
metadata:
name: test-nodeaffinity-soft
labels:
app: app1
spec:
containers:
- name: mynginx
image: mynginx:v2
affinity:
nodeAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 1
preference:
matchExpressions:
- key: kubernetes.io/hostname
operator: In
values:
- k8s-node3
这里虽然还是希望能被调度到node3,但是没有这么一个node存在的时候,还是能被成功调度的
[root@k8s-master affinity]# kubectl apply -f test-nodeaffinity-soft.yaml
pod/test-nodeaffinity-soft created
[root@k8s-master affinity]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
test-nodeaffinity-hard 1/1 Running 0 9m40s 10.244.0.19 k8s-master <none> <none>
test-nodeaffinity-soft 1/1 Running 0 5s 10.244.1.133 k8s-node1 <none> <none>
因为有权重的存在,所以可以设置多条策略,按照权重高低进行选择。权重可配置1-100。
当然硬策略和软策略可以一起配置,优先考虑硬策略。
PodAffinity实际操作 pod与pod之间就开始出现Affinity和Anti-Affinity了
硬策略 目前已存在的两个pod如下,用作参照
[root@k8s-master affinity]# kubectl get pod --show-labels
NAME READY STATUS RESTARTS AGE LABELS
test-nodeaffinity-hard 1/1 Running 0 49m app=app1
test-nodeaffinity-soft 1/1 Running 0 39m app=app1
用如下的yaml文件test-podaffinity-hard.yaml去创建一个pod
apiVersion: v1
kind: Pod
metadata:
name: test-podaffinity-hard
labels:
app: app2
spec:
containers:
- name: mynginx
image: mynginx:v2
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- app1
topologyKey: kubernetes.io/hostname
注意,这里用的是Anti-Affinity,所以是不想和目标pod在一起。然后这里还有个topologyKey字段,表示node的一个label,表示要被创建的pod所在的node的这个label值和被比较pod所在的node这个label值要不一致才行。这个逻辑关系有点绕,就是先选出目标pod,然后根据目标pod所在node的label来决定去哪个node。
这里选出的pod是满足app: app1的pod,上面两个pod都满足,然后是查看node的hostname,上述两个pod已经把集群内的两个node都占据了,所以新的pod没有node可以被分配
[root@k8s-master affinity]# kubectl apply -f test-podaffinity-hard.yaml
pod/test-podaffinity-hard created
[root@k8s-master affinity]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
test-nodeaffinity-hard 1/1 Running 0 53m 10.244.0.19 k8s-master <none> <none>
test-nodeaffinity-soft 1/1 Running 0 43m 10.244.1.133 k8s-node1 <none> <none>
test-podaffinity-hard 0/1 Pending 0 8s <none> <none> <none> <none>
修改其中一个pod的label为app:test
[root@k8s-master affinity]# kubectl edit pod test-nodeaffinity-hard
pod/test-nodeaffinity-hard edited
[root@k8s-master affinity]# kubectl get pod --show-labels -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES LABELS
test-nodeaffinity-hard 1/1 Running 0 63m 10.244.0.19 k8s-master <none> <none> app=test
test-nodeaffinity-soft 1/1 Running 0 54m 10.244.1.133 k8s-node1 <none> <none> app=app1
test-podaffinity-hard 1/1 Running 0 10m 10.244.0.20 k8s-master <none> <none> app=app2
可以看到新的pod被创建了,而且是分配在master