原文 https://www.chenshaowen.com/blog/how-to-set-up-pod-to-run-to-a-specified-node.html
1 | kubectl label node node2 project=A |
---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | cat <<EOF | kubectl apply -f - apiVersion: apps/v1 kind: Deployment metadata: name: nginx-nodeselector spec: replicas: 1 selector: matchLabels: app: nginx-nodeselector template: metadata: labels: app: nginx-nodeselector spec: nodeSelector: project: A containers: - name: nginx image: nginx EOF |
---|
1 2 3 4 | kubectl get pod -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES nginx-nodeselector-7bb75b7687-7r5xk 1/1 Running 0 19s 10.233.96.60 node2 <none> <none> |
---|
符合预期,Pod 运行在指定的节点 node2 上。
1 2 | kubectl delete deployments nginx-nodeselector kubectl label node node2 project- |
---|
实际上,还有另外一个节点选择参数 nodeName
,直接指定节点名。但是这种设置过于生硬,而且越过了 Kubernetes 本身的调度机制,实际生产用得很少。
创建负载时指定 nodeSelector,可以设置 Pod 运行的节点。但是如果想要绑定命名空间下全部 Pod 在指定节点下运行,就显得力不从心。而使用 kube-apiserver 的准入控制就可以达到这一目的,这是一个在 Kubernetes 1.5 时就进入 alpha 阶段的特性。
编辑 kube-apiserver 文件:
1 | vim /etc/kubernetes/manifests/kube-apiserver.yaml |
---|
在 admission-plugins
中新增 PodNodeSelector
:
1 | - --enable-admission-plugins=NodeRestriction,PodNodeSelector |
---|
这里的 NodeRestriction
是默认开启的。如果是高可用的集群,那么需要修改每一个 kube-apiserver。修改完成之后,稍等一会儿 kube-apiserver 会完成重启过程。
编辑命名空间,增加注解:
1 | kubectl edit ns default |
---|
1 2 3 4 5 6 | apiVersion: v1 kind: Namespace metadata: name: default annotations: scheduler.alpha.kubernetes.io/node-selector: project=A |
---|
scheduler.alpha.kubernetes.io/node-selector
可以是节点名,也可以是 label 键值对。
给 node3 节点打上 project=A
的标签:
1 | kubectl label node node3 project=A |
---|
这里将命名空间 default 上的负载,绑定到了节点 node3 上。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | cat <<EOF | kubectl apply -f - apiVersion: apps/v1 kind: Deployment metadata: name: nginx-scheduler spec: replicas: 3 selector: matchLabels: app: nginx-scheduler template: metadata: labels: app: nginx-scheduler spec: containers: - name: nginx image: nginx EOF |
---|
1 2 3 4 5 6 | kubectl get pod -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES nginx-scheduler-6478998698-brkzn 1/1 Running 0 84s 10.233.92.52 node3 <none> <none> nginx-scheduler-6478998698-m422x 1/1 Running 0 84s 10.233.92.51 node3 <none> <none> nginx-scheduler-6478998698-mnf4d 1/1 Running 0 84s 10.233.92.50 node3 <none> <none> |
---|
可以看到,虽然集群上有 4 个可用的节点,但是 default 空间下的负载都运行在 node3 节点之下。
1 | kubectl label node node3 project- |
---|
1 | kubectl delete deployments nginx-scheduler |
---|
kubectl edit ns default
需要注意的是,如果命名空间已经开启了 scheduler.alpha.kubernetes.io/node-selector
,而节点没有相关的标签,此时,Pod 将会一直处于 Pending 状态,无法得到调度,直至有符合标签的 Node 出现。
如下图,通过 kube-apiserver 的访问控制插件,我们可以建立模型,每个项目一个命名空间,每个命名空间包含指定的节点。这样就可以满足,业务隔离、成本计费的要求。但是随着集群越来越大,项目需要在集群下划分若干的可用区,用于保障业务的可用性。
而拓扑域主要就是解决 Pod 在集群的分布问题,可以用于实现 Pod 对节点的定向选择的需求。Kubernetes 集群调度器的拓扑域特性在 1.16 进入 Alpha 阶段,在 1.18 进入 Beta 阶段。下面我们进行一些实验:
这里将节点 node2 划分到 zone a,将 node3、node4 划分到 zone b。
1 | kubectl label node node2 zone=a |
---|
1 | kubectl label node node3 node4 zone=b |
---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | cat <<EOF | kubectl apply -f - apiVersion: apps/v1 kind: Deployment metadata: name: nginx-topology spec: replicas: 20 selector: matchLabels: app: nginx-topology template: metadata: labels: app: nginx-topology spec: topologySpreadConstraints: - maxSkew: 1 topologyKey: zone whenUnsatisfiable: DoNotSchedule labelSelector: matchLabels: app: nginx-topology containers: - name: nginx image: nginx EOF |
---|
这里 topologyKey
用于指定划分拓扑域的 Key,maxSkew
表示在 zone=a、zone=b 中 Pod 数量相差不能超过 1, whenUnsatisfiable: DoNotSchedule
表示不满足条件时,不进行调度。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | kubectl get pod -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES nginx-topology-7d8698544d-2srcj 1/1 Running 0 3m3s 10.233.92.63 node3 <none> <none> nginx-topology-7d8698544d-2wxkp 1/1 Running 0 3m3s 10.233.96.53 node2 <none> <none> nginx-topology-7d8698544d-4db5b 1/1 Running 0 3m3s 10.233.105.43 node4 <none> <none> nginx-topology-7d8698544d-9tqvn 1/1 Running 0 3m3s 10.233.96.58 node2 <none> <none> nginx-topology-7d8698544d-9zll5 1/1 Running 0 3m3s 10.233.105.45 node4 <none> <none> nginx-topology-7d8698544d-d6nbm 1/1 Running 0 3m3s 10.233.105.44 node4 <none> <none> nginx-topology-7d8698544d-f4nw9 1/1 Running 0 3m3s 10.233.96.54 node2 <none> <none> nginx-topology-7d8698544d-ggfgv 1/1 Running 0 3m3s 10.233.92.66 node3 <none> <none> nginx-topology-7d8698544d-gj4pg 1/1 Running 0 3m3s 10.233.92.61 node3 <none> <none> nginx-topology-7d8698544d-jc2xt 1/1 Running 0 3m3s 10.233.92.62 node3 <none> <none> nginx-topology-7d8698544d-jmmcx 1/1 Running 0 3m3s 10.233.96.56 node2 <none> <none> nginx-topology-7d8698544d-l45qj 1/1 Running 0 3m3s 10.233.92.65 node3 <none> <none> nginx-topology-7d8698544d-lwp8m 1/1 Running 0 3m3s 10.233.92.64 node3 <none> <none> nginx-topology-7d8698544d-m65rx 1/1 Running 0 3m3s 10.233.96.57 node2 <none> <none> nginx-topology-7d8698544d-pzrzs 1/1 Running 0 3m3s 10.233.96.55 node2 <none> <none> nginx-topology-7d8698544d-tslxx 1/1 Running 0 3m3s 10.233.92.60 node3 <none> <none> nginx-topology-7d8698544d-v4cqx 1/1 Running 0 3m3s 10.233.96.50 node2 <none> <none> nginx-topology-7d8698544d-w4r86 1/1 Running 0 3m3s 10.233.96.52 node2 <none> <none> nginx-topology-7d8698544d-wwn95 1/1 Running 0 3m3s 10.233.96.51 node2 <none> <none> nginx-topology-7d8698544d-xffpx 1/1 Running 0 3m3s 10.233.96.59 node2 <none> <none> |
---|
其中在 node2 节点 10 个 Pod、node3 节点 7 个节点、node4 节点 3 个节点。可以看到,Pod 均匀地分布在 zone=a、zone=b 上。
1 2 | kubectl label node node2 node3 node4 zone- kubectl delete deployments nginx-topology |
---|
随着集群越来越大,业务之间的隔离、业务对节点的独占等问题就会浮现出来。通常,每个业务都会有一个单独的命名空间,因此,我们可以将命名空间与节点进行绑定。
本文主要给出了两种方法,一种是创建负载时,直接设置 nodeSelector,取巧的方法是用命名空间值作为 value;另外一种方式是,借助于 kube-apiserver 提供的访问控制插件,通过注解的方式,在创建命名空间下的负载时,通过标签筛选指定节点,完成命名空间与节点之间的绑定。
再进一步考虑,如果节点数量非常庞大,需要划分可用区分散负载,那么我们可以借助于拓扑域来实现。通过拓扑域,我们可以让负载,根据配置的策略均匀的分布在指定的可用区、机柜上。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。