K8s的亲和性调度
一般情况下我们部署的 Pod 是通过集群的自动调度策略来选择节点的,默认情况下调度器考虑的是资源足够,并且负载尽量平均,但是有的时候我们需要能够更加细粒度的去控制 Pod 的调度,比如我们内部的一些服务gitlab、jenkins 之类的也是跑在Kubernetes 集群上的,我们就不希望对外的一些服务和内部的服务跑在同一个节点上了,害怕内部服务对外部的服务产生影响;但是有的时候我们的服务之间交流比较频繁,又希望能够将这两个服务的 Pod 调度到同一个的节点上。这就需要用到 Kubernetes 里面的一个概念:亲和性和反亲和性。
亲和性又分成节点亲和性( nodeAffinity )和 Pod 亲和性( podAffinity )。
nodeSelector
非常常用的调度方式:nodeSelector。我们知道label 是kubernetes 中一个非常重要的概念,用户可以非常灵活的利用 label 来管理集群中的资源,比如最常见的一个就是 service 通过匹配 label 去匹配 Pod 资源,而 Pod 的调度也可以根据节点的 label 来进行调度。可以通过下面的命令查看我们的 node 的 label:
kubectl get nodes --show-labels
#给节点增加标签,命令如下:
kubectl label nodes k8s-node1 com=jjy1
#给节点删除标签
kubectl label nodes k8s-node1 com-
vim node-selector-demo.yaml
apiVersion: v1
kind: Pod
metadata:
labels:
app: busybox-pod
name: test-busybox
spec:
containers:
- command:
- sleep
- "3600"
image: busybox
imagePullPolicy: Always
name: test-busybox
nodeSelector:
com: jjy1
#查看调度节点
kubectl get po -o wide
如果目标节点没有可用的资源, Pod 就会一直处于 Pending 状态,这就是nodeSelector 的用法
亲和性和反亲和性调度
在 kubernetes 默认调度器的一个调度流程中,经过了预选(predicates) 和 优选(priorities) 两个阶段,但是在实际的生产环境中,往往需要根据自己的一些实际需求来控制 pod 的调度,这就需要用到 nodeAffinity (节点亲和性)、podAffinity(pod 亲和性) 以及podAntiAffinity(pod 反亲和性)。
亲和性调度可以分成软策略和硬策略两种方式:
软策略就是如果你没有满足调度要求的节点的话,pod 就会忽略这条规则,继续完成调度过程,说白了就是满足条件最好了,没有的话也无所谓了的策略
硬策略 就比较强硬了,如果没有满足条件的节点的话,就不断重试直到满足条件为止,不满足就是pending状态
对于亲和性和反亲和性都有这两种规则可以设置:
软策略 :preferredDuringSchedulingIgnoredDuringExecution
硬策略: requiredDuringSchedulingIgnoredDuringExecution
apiVersion: apps/v1
kind: Deployment
metadata:
name: affinity
labels:
app: affinity
spec:
replicas: 2
revisionHistoryLimit: 15 #版本记录15个
selector:
matchLabels:
app: affinity
role: test
template:
metadata:
labels:
app: affinity
role: test
spec:
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
name: nginxweb
affinity:
nodeAffinity: #这是一个pod亲和
requiredDuringSchedulingIgnoredDuringExecution: #硬策略
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/hostname
operator: NotIn #不能在node1
values:
- k8s-node1
preferredDuringSchedulingIgnoredDuringExecution: #软策略
- weight: 1 #权重为1
preference:
matchExpressions:
- key: com
operator: In #最好在node标签为jjy1上
values:
- jjy1
污点(taints)与容忍(tolerations)
对于nodeAffinity 无论是硬策略还是软策略方式,都是调度 pod 到预期节点上,而Taints 恰好与之相反,如果一个节点标记为 Taints ,除非Pod 也被标识为可以容忍污点节点,否则该 Taints 节点不会被调度pod。
比如用户希望把 Master 节点保留给 Kubernetes 系统组件使用,或者把一组具有特殊资源预留给某些 pod,则污点就很有用了,pod 不会再被调度到 taint 标记过的节点。我们使用kubeadm搭建的集群默认就给master 节点添加了一个污点标记,所以我们看到我们平时的 pod 都没有被调度到 master 上去:
kubectl describe node k8s-master | grep Taints
Taints: node-role.kubernetes.io/master:NoSchedule
#添加污点
kubectl taint node k8s-node1 node-role.kubernetes.io/master:NoSchedule #对旧的pod是没有影响的,只对新的pod有影响不会被调度
NoSchedule :表示 pod 不会被调度到标记为 taints 的节点
PreferNoSchedule :NoSchedule 的软策略版本,表示尽量不调度到污点节点上去
NoExecute :该选项意味着一旦 Taint 生效,如该节点内正在运行的pod 没有对应 Tolerate 设置,会直接被逐出 (可能会对静态pod有影响,未实践)
kubectl taint nodes k8s-node02 test=node02:NoSchedule2 node "k8s-node02" tainted
#上面的命名将 node02 节点标记为了污点,影响策略是 NoSchedule,只会影响新的 pod 调度,如果仍然希望某个 pod 调度到 taint 节点上,则必须在 Spec 中做出Toleration 定义,才能调度到该节点,比如现在我们想要将一个 pod 调度到 node02 节点:
vim taint-demo.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: taint
labels:
app: taint
spec:
replicas: 3
revisionHistoryLimit: 10
selector:
matchLabels:
......
......
spec:
containers:
- name: nginx
image:
.....
tolerations: #宽容
- key: "test"
operator: "Exists"
effect: "NoSchedule"