今天我们来实验 pod 调度的 nodeName 与 nodeSelector。官网描述如下:
假设有如下三个节点的 K8S 集群:
k8s31master 是控制节点
k8s31node1、k8s31node2 是工作节点
容器运行时是 containerd
一、镜像准备
1.1、镜像拉取
docker pull tomcat:8.5-jre8-alpine
# 查看是否下载完成
docker images | grep tomcat
1.2、镜像导出
docker save -o tomcat-8.5-jre8-alpine.tar.gz 镜像TAG
或者
docker save 镜像TAG -o tomcat-8.5-jre8-alpine.tar.gz
都可以
1.3、镜像导入工作节点 containerd
# k8s31node1 执行
[root@k8s31node1 ~]# ctr -n=k8s.io images import tomcat-8.5-jre8-alpine.tar.gz
[root@k8s31node1 ~]# ctr -n=k8s.io images ls|grep tomcat
# k8s31node2 执行
[root@k8s31node2 ~]# ctr -n=k8s.io images import tomcat-8.5-jre8-alpine.tar.gz
[root@k8s31node2 ~]# ctr -n=k8s.io images ls|grep tomcat
说明:
- ctr 是 containerd 命令
- ctr images import:导入镜像
- -n=k8s.io:K8S 镜像存储命名空间
二、nodeName
- 查看帮助文档
# 查看 pod 帮助文档
kubectl explain pod.spec
# nodeName 属性位于 spec 下
# 它可以指定 pod 运行在哪个 nodeName 的节点上
- 编写资源文件
pod-node-name-demo.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-node-name
spec:
nodeName: k8s31node1
containers:
- name: tomcat
image: tomcat:8.5-jre8-alpine
imagePullPolicy: IfNotPresent
ports:
- containerPort: 8080
nodeName 可以指定节点名称(节点的 metadata.name)。
- 运行并查看
kubectl apply -f pod-node-name-demo.yaml
kubectl get pod -owide
# -o output 的意思,wide 更详细的 -owide 表示输出更详细的信息
查看 pod 被调度到哪个节点:
删除这个 pod,修改 nodeName 为 k8s31node2,重新运行:
# 使用资源文件删除 pod-node-name 这个 pod
kubectl delete -f pod-node-name-demo.yaml
# 修改资源文件 nodeName 改为 k8s31node2
vim pod-node-name-demo.yaml
# 重新运行
kubectl apply -f pod-node-name-demo.yaml
# 查看被调度到哪个节点
kubectl get pod -owide
可以看到 pod 被调度到 k8s31node2 上。
三、nodeSelector
- 查看帮助文档
# 查看 pod 帮助文档
kubectl explain pod.spec
# nodeSelector 属性位于 spec 下
# 它可以指定 pod 调度到具有哪些标签的 node 节点上
# 它是键值对格式
- 给 node 节点打上标签
# 给 node1 节点打上标签 zone=east
kubectl label node k8s31node1 zone=east
# 给 node2 节点打上标签 zone=south
kubectl label node k8s31node2 zone=south
- 查看已打上的标签
kubectl get node --show-labels
# --show-labels 显示标签
- 编写资源文件
pod-node-selector-demo.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-node-selector
spec:
nodeSelector:
zone: east
containers:
- name: tomcat
image: tomcat:8.5-jre8-alpine
imagePullPolicy: IfNotPresent
ports:
- containerPort: 8080
nodeSelector 指定 pod 要被调度到的节点,需满足具有 zone=east 这个标签。
- 运行并查看
kubectl apply -f pod-node-selector-demo.yaml
kubectl get pod -owide
查看 pod 被调度到哪个节点:
删除这个 pod,修改 nodeSelector 为 zone=south,重新运行:
# 使用资源文件删除 pod-node-selector 这个 pod
kubectl delete -f pod-node-selector-demo.yaml
# 修改资源文件 nodeSelector 改为 zone=south
vim pod-node-selector-demo.yaml
# 重新运行
kubectl apply -f pod-node-selector-demo.yaml
# 查看被调度到哪个节点
kubectl get pod -owide
可以看到 pod 被调度到 k8s31node2 上。因为 k8s31node2具有标签 zone=south。
四、同时使用 nodeName 和 nodeSelector
- 编写资源文件
pod-node-name-and-selector-demo.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-node-name-selector
spec:
nodeName: k8s31node1
nodeSelector:
zone: south
containers:
- name: tomcat
image: tomcat:8.5-jre8-alpine
imagePullPolicy: IfNotPresent
ports:
- containerPort: 8080
我们现在 nodeName 希望它被调度到 k8s31node1 上,而 nodeSelector 却希望它有标签
zone=south(k8s31node1 的标签是 zone=east),我们看看会发生什么-->
- 运行并查看
kubectl apply -f pod-node-name-and-selector-demo.yaml
kubectl get pod -owide
它会报 NodeAffinity 节点亲和性问题,无法被正确调度。
- 查看 pod 日志
kubectl describe pod pod-node-name-selector
- 修改资源文件 zone 改为 east,删除原来的 pod,重新执行
# zone 改为 east
vim pod-node-name-and-selector-demo.yaml
# 删除原来的 pod
kubectl delete pod pod-node-name-selector
# 重新执行
kubectl apply -f pod-node-name-and-selector-demo.yaml
# 查看
kubectl get pod -owide
可以看到 pod 被正确调度到 k8s31node1 上了。
也就是说同时使用 nodeName 跟 nodeSelector 需要都满足,pod 才能被正确调度。
注意:
修改完资源文件,一定要先删除原来的 pod,因为没有工作负载管理的自主式 pod,没有声明式更新的能力。直接 apply -f 会报错。
五、还原环境
实验完,删除掉已经创建的所有 pod,节省资源,删除节点标签,为下一次实验做准备。
# 删除节点1的标签 - 删除的意思
kubectl label node k8s31node1 zone-
# 删除节点2的标签
kubectl label node k8s31node2 zone-
# 查看
kubectl get node --show-labels
六、总结
- 给某个资源打上标签语法:
kubectl label [pod|node] 资源名称 key1=value1 key2=value2
- nodeName 使用节点名称进行匹配
- nodeSelector 使用节点标签进行匹配
- 同时使用 nodeName 跟 nodeSelector 需要都满足,pod 才能被正确调度
- 删除资源的标签语法:
kubectl label [pod|node] 资源名称 key-