- A+
简介
一般情况下我们部署的 Pod 是通过集群的自动调度策略来选择节点的,默认情况下调度器考虑的是资源足够,并且负载尽量平均,但是有的时候我们需要能够更加细粒度的去控制 Pod 的调度。比如我们内部的一些服务 gitlab 之类的也是跑在Kubernetes集群上的,我们就不希望对外的一些服务和内部的服务跑在同一个节点上了,担心内部服务对外部的服务产生影响;但是有的时候我们的服务之间交流比较频繁,又希望能够将这两个服务的 Pod 调度到同一个的节点上。这就需要用到 Kubernetes 里面的一个概念:亲和性和反亲和性。
亲和性/反亲和性策略区别
node亲和性nodeAffinity
pod亲和性podAffinity
pod反亲和性podAntiAffinity
调度策略 | 匹配标签 | 操作符 | 拓扑域支持 | 调度目标 |
nodeAffinity | node | In, NotIn, Exists,DoesNotExist, Gt, Lt | 不支持 | 决定pod部署在哪个node节点 |
podAffinity | POD | In, NotIn, Exists,DoesNotExist | 支持 | 决定pod可以和哪些pod部署在同一拓扑域 |
podAntiAffinity | POD | In, NotIn, Exists,DoesNotExist | 支持 | pod不可以和哪些pod部署在同一拓扑域 |
什么是拓扑域?为什么node不支持?
podAffinity特性是Kubernetes 1.4后增加的,允许用户通过已经运行的Pod上的标签来决定调度策略,用文字描述就是“如果Node X上运行了一个或多个满足Y条件的Pod,那么这个Pod在Node应该运行在Pod X”,因为Node没有命名空间,Pod有命名空间,这样就允许管理员在配置的时候指定这个亲和性策略适用于哪个命名空间,可以通过topologyKey来指定。topology(拓扑域)是一个范围的概念,可以是一个Node、一个机柜、一个机房或者是一个区域(如北美、亚洲)等,实际上对应的还是Node上的标签。
键值运算关系
In:label 的值在某个列表中
NotIn:label 的值不在某个列表中
Gt:label 的值大于某个值
Lt:label 的值小于某个值
Exists:某个 label 存在
DoesNotExist:某个 label 不存在
软策略和硬策略区别
preferredDuringSchedulingIgnoredDuringExecution:软策略
软策略:没有满足要求的节点,Pod就会忽略,继续完成调度(不是必须,不满足的情况下会调度到其它不符合条件的node/pod)
requiredDuringSchedulingIgnoredDuringExecution:硬策略
硬策略:没有满足条件的节点,就不断重试,直到满足条件位置(必须满足,否则不进行调度)
示例:node硬策略
目标:pod不会被创建在标签hostname=k8s-04这台节点
apiVersion: apps/v1beta1 kind: Deployment metadata: name: affinity labels: app: affinity spec: replicas: 3 revisionHistoryLimit: 10 template: metadata: labels: app: affinity spec: containers: - name: nginx image: nginx ports: - name: http containerPort: 80 affinity: #亲和性的调度设置 nodeAffinity: #策略为节点亲和性 requiredDuringSchedulingIgnoredDuringExecution: #亲和性的硬策略 nodeSelectorTerms: #这里不再使用nodeselector,使用这个参数可以进行相对简单的逻辑运算 - matchExpressions: #匹配表达式 - key: kubernetes.io/hostname #具体匹配规则(可以通过kubectl get node --show-labels找到相应规则) operator: NotIn #不在,简单的来说就是不在k8s-04节点 values: - k8s-04
示例:node软策略
目前我们有4个节点{1-4},但是我们希望pod不调度在k8s-01和k8s-02节点
apiVersion: apps/v1beta1 kind: Deployment metadata: name: affinity-preferred labels: app: affinity-preferred spec: replicas: 3 revisionHistoryLimit: 10 template: metadata: labels: app: affinity-preferred spec: containers: - name: nginx image: nginx ports: - name: http containerPort: 80 affinity: #亲和性的调度设置 nodeAffinity: #策略为节点亲和性 requiredDuringSchedulingIgnoredDuringExecution: # 硬策略 nodeSelectorTerms: - matchExpressions: - key: kubernetes.io/hostname operator: NotIn values: - k8s-01 - k8s-02 preferredDuringSchedulingIgnoredDuringExecution: #软策略 - weight: 10 #权重, weight范围1-100。这个涉及调度器的优选打分过程 preference: #调度策略,而不是硬性的要求 (属于软策略的参数) matchExpressions: #匹配表达式 - key: kubernetes.io/hostname operator: In values: - k8s-04
kubectl create -f pod.yaml && kubectl get pod -o wide && kubectl delete -f pod.yaml
反复测试,可以发现,因为加了软策略,所以并不是强制调度在K8s-04节点上,所以在03节点上也有。
示例:pod硬策略
创建一个标签为app=web01的Deployment
apiVersion: apps/v1beta1 kind: Deployment metadata: name: tomcat-test labels: app: web01 spec: replicas: 3 revisionHistoryLimit: 10 template: metadata: labels: app: web01 spec: containers: - name: tomcat image: tomcat ports: - name: http containerPort: 8080
查看pod标签
kubectl get pod -o wide --show-labels
apiVersion: apps/v1beta1 kind: Deployment metadata: name: nginx-test labels: app: nginx spec: replicas: 3 revisionHistoryLimit: 10 template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx ports: - name: http containerPort: 8080 affinity: podAffinity: #pod亲和力参数 requiredDuringSchedulingIgnoredDuringExecution: #硬策略 (在podAffinity中也可以添加软策略和硬策略) - labelSelector: #匹配label标签 (Pod具有的label标签,而不是Node的标签) matchExpressions: #匹配规则 - key: app #对应的标签 operator: In values: - web01 #对应的标签 topologyKey: kubernetes.io/hostname
现在我们将Pod调度在app=web01所在的节点上,因为我们加了top域kubernetes.io/hostname,也就是当我们app=web01在哪个节点上,我们创建的pod就会追随到那个节点上。但是如果我们将topologyKey修改为kubernetes.io/os那么,所有的Pod都会在所有的节点上运行. 因为kubernetes.io/os是在所有节点都有的一个策略。
查看node标签
kubectl get node -o wide --show-labels|grep os
示例:pod反亲和
podAntiAffinity反亲和性大致意思是比如一个节点运行了某个Pod,那么我们希望我们的Pod调度到其他节点上去,保证不会有相同业务的Pod来分享节点资源。
应用场景:
将一个服务的POD分散在不同的主机或者拓扑域中,提高服务本身的稳定性。
给POD对于一个节点的独占访问权限来保证资源隔离,保证不会有其它pod来分享节点资源。
把可能会相互影响的服务的POD分散在不同的主机上。
apiVersion: apps/v1beta1 kind: Deployment metadata: name: nginx-test-not labels: app: nginx spec: replicas: 3 revisionHistoryLimit: 10 template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx ports: - name: http containerPort: 8080 affinity: podAntiAffinity: #修改为反亲和力,其他参数不变 requiredDuringSchedulingIgnoredDuringExecution: - labelSelector: matchExpressions: - key: app operator: In values: - web01 topologyKey: kubernetes.io/hostname
创建后,因为标签为app=web01的节点上已经有k8s-01..k8s-03占用,只有k8s-04没有。所以这里会强制在k8s-04节点创建Pod