目录
1 创建Pod的工作流程
- 用户发出创建pod的指令
- APIServer接收到创建pod命令,生成包含Pod创建信息的yaml文件,将yaml文件写入ETCD
- Scheduler被APIServer通知到有新的待创建Pod的请求,于是运用调度算法,找出待部署Pod的目标节点,将结果返回给APIServer
- APIServer更新ETCD中的Pod创建信息,明确了具体要把这个Pod部署到哪个节点上
- 目标节点上的Kubelet被APIServer通知到有创建容器的请求,于是Kubelet调用docker api 创建容器,将容器信息返回给APIServer
- APIServer再将容器信息保存到ETCD,整体过程如下图所示:
2 Pod中影响调度的主要属性
在Deployment资源的yaml文件中:
- 一些字段会间接的影响到Pod的调度策略(resources),比如预设好容器占用资源限制后(最低要求、最高限制),那些达不到容器最低要求的node就不会被选择。
- 还有一些字段可以直接设置Pod的调度策略(schedulerName、nodeName、nodeSelector、affinity、tolerations)
如下的指令可以打开一个集群中现存的Deployment资源的yaml文件进行查看:
#查看集群中的deployment资源
kubectl get deploy
#查看deployment资源的yaml文件
kubectl get deploy nginx -o yaml
3 资源限制对Pod调度的影响
通过编辑Pod的yaml文件中的resources字段来验证资源限制对Pod调度的影响。
#1、当对于容器的资源配置要求在合理范围内时,创建一个nginx容器是没有任何问题的
vi pod-resource.yaml
#2、nginx的yaml文件
apiVersion: v1
kind: Pod
metadata:
name: pod-resource
spec:
containers:
- name: web
image: nginx
resources:
#容器使用的最小资源需求
requests:
memory: "64Mi"
cpu: "250m"
#容器使用的最大资源限制,因此要大于等于request的值
limits:
memory: "64Mi"
cpu: "250m"
#3、部署
kubectl apply -f pod-resource.yaml
#4、查看pod,发现一切正常
kubectl get pod
#5、然而此时,在Pod的yaml中设置nginx容器的最低内存和核心数都远远大于任意节点的的配置
vi pod-resources2
#yaml文件
apiVersion: v1
kind: Pod
metadata:
name: pod-resource2
spec:
containers:
- name: web
image: nginx
resources:
requests:
memory: "4Gi"
cpu: "2500m"
#6、部署
kubectl apply -f pod-resources2.yaml
#7、查看pod,发现pod-resource2处于pending状态
kubectl get pod
#8、继续查看pod的详细信息,发现显示资源不足
kubectl describe pod pod-resource2
注意:资源配额中的"request"即容器所要求的最小配置才会影响到Pod的调度。
4 将Pod调度到指定节点
如果我们想把一些Pod调度到指定的节点上,有两种方式:nodeSelector 、nodeAffinity接下来分别介绍。
4.1 nodeSelector(强硬)
用于将Pod调度到匹配Label的Node上,如果没有匹配的标签会调度失败。
作用
- 约束Pod到特定的节点运行
- 完全匹配节点标签
应用场景
- 专用节点:根据业务线将Node分组管理
- 配备特殊硬件:部分Node配有SSD硬盘、GPU
实践
#1、先查询一下集群中的所有节点,选择一个目标节点,准备让一些Pod都调度到该节点上
kubectl get node
#2、给目标节点打标签
#格式:kubectl label nodes <node-name> <label-key>=<label-value>
kubectl label nodes kubeadm-node1 disktype=ssd
#3、验证是否已经打上了标签
kubectl get nodes --show-labels
#4、添加nodeSelector字段到Pod配置文件中
vi pod-selector.yaml
#yaml文件
apiVersion: v1
kind: Pod
metadata:
name: pod-node-selecter
spec:
nodeSelector:
disktype: "ssd"
containers:
- name: nginx
image: nginx
5、部署pod
kubectl apply -f pod-selector.yaml
6、验证该Pod是否部署到了目标节点node1上
kubectl get pods -o wide
注意
- 如果有多个node被打上了相同的标签,则Pod在调度时又会根据调度算法进行选择
- 如果没有Pod的yaml中指定了一个nodeSelector,然而根本没有任何node被打上对应的标签,则Pod创建会一直处于pending状态。
4.2 nodeAffinity(亲和)
通过4.1的介绍,发现nodeselector对于Pod的调度过于强硬,因此nodeSelector出现了,它与nodeSelector作用类似(软硬结合),但是更加亲和、灵活,满足更多条件,如:
- 匹配有更多的逻辑组合,不只是字符串的完全相等
- 调度分为软策略和硬策略,而不是硬性要求
- 硬(required):必须满足
- 软(preferred):尝试满足,但不保证
操作符(operator):In、NotIn、Exists、DoesNotExist、Gt、Lt
如下操作,测试了nodeAffinity策略的验证过程:
#1、创建Pod的yaml文件(为了验证nodeSelector策略下label不匹配导致Pod创建不成功)
vi pod-selecter2.yaml
#2、编辑yaml,此时集群中所有节点都没有被打上 gpu: "nvidia"这个标签
apiVersion: v1
kind: Pod
metadata:
name: pod-node-selecter2
spec:
nodeSelector:
gpu: "nvidia"
containers:
- name: nginx
image: nginx
#3、部署Pod
kubectl apply -f pod-selecter2.yaml
#4、查看Pod部署情况
#目前Pod采用的是nodeSelector来控制Pod的调度,由于集群节点中没有匹配的标签,因此Pod部署失败,处于pending状态
kubectl get pod
kubectl describe pod pod-node-selecter2
#此时转而使用nodeAffinity,让Pod的调度更具有亲和性:我希望把Pod部署在某个node上,如果没有成功那么也没关系,也允许部署到其他node上
#5、创建Pod的yaml文件(为了验证nodeaffinity的软策略下即便lable不匹配也能成功创建Pod)
vi pod-nodeaffinity.yaml
#6、编辑yaml,此时集群中所有节点都没有被打上 gpu: "nvidia"这个标签
apiVersion: v1
kind: Pod
metadata:
name: pod-node-affinity
spec:
affinity:
nodeAffinity:
#软策略:如果有node的标签和“gpu-nvidia”能够对应,那就直接部署在该node上,对应不上也没关系,也会找个node来部署
preferredDuringSchedulingIgnoredDuringExecution:
#权重越大,越期望将Pod调度到label为"gpu: nvidia"的节点上
- weight: 1
preference:
matchExpressions:
- key: gpu
operator: In
values:
- nvidia
containers:
- name: web
image: nginx
#7、部署Pod
kubectl apply -f pod-nodeaffinity.yaml
#8、查看Pod部署情况,发现采用affinity软策略之后,即便label没有匹配,也能成功部署Pod
kubectl get pod
#9、创建Pod的yaml文件(为了验证nodeaffinity的硬策略下和nodeSelector策略达成相同的效果)
vi pod-selecter2.yaml
#10、编辑yaml,测试nodeaffinity的硬策略,功能和nodeSelector完全一致
apiVersion: v1
kind: Pod
metadata:
name: pod-node-affinity2
spec:
affinity:
nodeAffinity:
#此策略下,功能和nodeSelector完全一致
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: gpu
operator: In
values:
- nvidia
containers:
- name: web
image: nginx
#11、部署Pod
kubectl apply -f pod-nodeaffinity2.yaml
#12、查看Pod部署情况,发现采用affinity硬之后,发现功能和nodeSelector完全一致
kubectl get pod
5 污点及污点容忍
- Taints(污点):避免Pod调度到特定Node上
- Tolerations(污点容忍):允许Pod调度到持有Taints的Node上
应用场景
- 专用节点:根据业务线将Node分组管理,希望在默认情况下不调度该节点,只有配置了污点容忍才允许分配
- 配备特殊硬件:部分Node配有SSD硬盘、GPU,希望在默认情况下不调度该节点,只有配置了污点容忍才允许分配
- 基于Taint的驱逐
步骤
- step1:给节点添加污点
格式:kubectl taint node [node] key=value:[effect]
例如:kubectl taint node kubeadm-node1 gpu=yes:NoSchedule
验证:kubectl describe node kubeadm-node1 |grep Taint
其中[effect] 可取值:
NoSchedule :一定不能被调度
PreferNoSchedule:尽量不要调度,非必须配置容忍
NoExecute:不仅不会调度,还会驱逐Node上已有的Pod
- step2:添加污点容忍(tolrations)字段到Pod配置中
- 去掉污点:kubectl taint node [node] key:[effect]-
实践
#1、给节点node1、node2 都添加污点
kubectl taint node kubeadm-node1 gpu=yes:NoSchedule
kubectl taint node kubeadm-node2 gpu=yes:NoSchedule
#2、查看节点是否已经被添加上了污点,此时该节点上一般不会部署Pod了,除非Pod设置了污点容忍
kubectl describe node |grep Taint
#3、创建Pod
vi pod-taint.yaml
#4、编辑yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-taint
spec:
containers:
- name: nginx
image: nginx
#5、部署pod
kubectl apply -f pod-taint.yaml
#6、查看pod,发现没法创建,因为3个node都被打上了污点,Pod文件中没有设置污点容忍
kubectl get pod
kubectl describe pod pod-taint
#接下来,添加污点容忍(tolrations)字段到Pod配置中
#7、创建另一个Pod,该Pod被设置了污点容忍
vi pod-taint2.yaml
#8、编辑yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-taint2
spec:
tolerations:
- key: "gpu"
values: "yes"
containers:
- name: nginx
image: nginx
#9、部署Pod
kubectl apply -f pod-taint2.yaml
#10、再次查看pod,发现设置污点容忍后又可以创建Pod了,验证完毕
kubectl get pod
#11、把node1、node2的污点去掉,去掉污点后,之前的pod-taint2状态已经不是pending了,而是创建完毕
kubectl taint node kubeadm-node1 gpu-
kubectl taint node kubeadm-node2 gpu-
6 绕过调度器nodeName
在Pod的yaml文件中指定节点名称,用于将Pod调度到指定的Node上,不经过调度器。即便所有节点都被打上了污点也没有关系。在实际中,绕过调度器的应用场景很少。
实践
#1、创建Pod的yaml文件
vi pod-podname.yaml
#2、编辑yaml(直接指定了将该Pod调度到集群中的node2节点上)
apiVersion: v1
kind: Pod
metadata:
name: pod-podname
spec:
podName: kubeadm-node2
containers:
- name: nginx
image: nginx
#3、部署Pod
kubectl apply -f pod-podname.yaml
#4、查看Pod,发现Pod被直接调度到node2节点上了
kubectl get pod