1 概述
Pod 的定义
<font color="#9bbb59">Pod 是 Kubernetes 集群中调度的最小单元,也是 Kubernetes 的核心概念之一。它是一个或多个容器(通常是 Docker 容器)的集合,这些容器共享相同的资源和网络命名空间</font>。Pod 的设计目标是支持多个容器之间的协作和通信。
Pod 的特点
-
最小调度单元:Pod 是 Kubernetes 调度的最小单位。Kubernetes 会将 Pod 调度到集群中的某个节点(Node)上运行,而不会将一个 Pod 的不同部分分散到多个节点。
-
容器共享资源:Pod 内的容器共享相同的网络命名空间、存储卷等资源。这意味着它们可以通过
localhost
相互通信,并且可以访问相同的文件系统。 -
生命周期一致:Pod 内的容器共享相同的生命周期。如果 Pod 被删除,那么 Pod 内的所有容器都会被一起删除。
Pod 中的容器类型
你提到 Pod 中有三种类型的容器,这是非常准确的。以下是每种容器的详细说明:
(1)基础架构容器
-
作用:基础架构容器是 Pod 中的第一个容器,由 Kubernetes 自动创建和管理。
-
功能:
-
它的主要作用是为 Pod 提供一个稳定的网络命名空间。
-
它使用一个特殊的镜像(如
k8s.gcr.io/pause
),该镜像非常小,只包含必要的网络初始化工具。 -
它在 Pod 启动时首先运行,为其他容器提供网络环境。
-
-
特点:
-
每个 Pod 只有一个基础架构容器。
-
它通常不会执行任何实际的业务逻辑。
-
它的生命周期与 Pod 的生命周期一致。
-
(2)初始化容器
-
作用:初始化容器用于在业务容器启动之前执行一些初始化任务。
-
特点:
-
初始化容器是可选的,用户可以根据需要定义。
-
它们在业务容器启动之前按顺序运行。
-
每个初始化容器必须成功完成后,下一个初始化容器才会启动。
-
如果某个初始化容器失败,Pod 会根据其重启策略决定是否重新启动该初始化容器。
-
-
常见用途:
-
下载配置文件或脚本。
-
检查依赖服务是否可用(如数据库是否启动)。
-
设置环境变量或配置文件。
-
(3)业务容器
-
作用:业务容器是 Pod 中实际运行用户业务逻辑的容器。
-
特点:
-
一个 Pod 中可以有多个业务容器,但它们通常共享相同的上下文和资源。
-
业务容器的启动顺序不保证,它们会在所有初始化容器成功完成后并行启动。
-
-
常见用途:
-
运行应用程序、服务或微服务。
-
执行数据处理或计算任务。
-
Pod 的生命周期
-
基础架构容器的退出:如果基础架构容器退出,Pod 的网络命名空间将不再存在,此时所有业务容器也会被迫退出。这是因为 Pod 的网络依赖于基础架构容器提供的网络环境。
-
Pod 的重启策略:Pod 的重启策略(如
Always
、OnFailure
、Never
)决定了业务容器在失败时的行为。但请注意,Pod 本身不会自动重新调度到其他节点,除非它被删除并重新创建。
2 pod基础操作
创建 Pod
(1)通过 YAML 文件创建 Pod
- 编写 Pod 的 YAML 文件:
创建一个名为mypod.yaml
的文件,内容如下:apiVersion: v1 kind: Pod metadata: name: mypod spec: containers: - name: mycontainer image: nginx
- 使用
kubectl apply
创建 Pod:kubectl apply -f mypod.yaml
(2)直接通过命令行创建 Pod
kubectl run mypod --image=nginx --restart=Never
--restart=Never
表示 Pod 不会自动重启。
查看 Pod
(1)查看所有 Pod
kubectl get pods
- 添加
-o wide
选项可以显示更多的信息,例如 Pod 所在的节点:kubectl get pods -o wide
(2)查看 Pod 的详细信息
kubectl describe pod <pod-name>
- 例如:
kubectl describe pod mypod
删除 Pod
kubectl delete pod <pod-name>
kubectl delete pod <pod-name> --force --grace-period=0
- 例如:
kubectl delete pod mypod
进入 Pod 的容器
如果你需要进入 Pod 的容器进行调试,可以使用以下命令:
kubectl exec -it <pod-name> -- /bin/bash
- 如果容器没有
/bin/bash
,可以尝试/bin/sh
或其他可用的 shell。 - 例如:
kubectl exec -it mypod -- /bin/bash kubectl exec -it test -c xx -- sh
查看 Pod 的日志
kubectl logs <pod-name>
- 如果 Pod 中有多个容器,可以通过
-c
参数指定容器:kubectl logs -f <pod-name> -c <container-name>
pod之cp
# 从 Pod 复制文件到本地
kubectl cp my-namespace/my-pod:/tmp/logs.txt ./logs.txt
# 从本地复制文件到 Pod
kubectl cp ./config.yaml my-namespace/my-pod:/etc/config.yaml
更新 Pod
Pod 是不可变的,不能直接修改。如果需要更新 Pod,通常需要删除旧的 Pod 并重新创建一个新的 Pod。不过,如果 Pod 是通过 Deployment 或其他控制器管理的,可以通过更新控制器的配置来间接更新 Pod。
示例:更新 Deployment 中的 Pod
- 编辑 Deployment 的 YAML 文件:
kubectl edit deployment <deployment-name>
- 修改
image
或其他配置。 - 保存并退出,Kubernetes 会自动更新 Pod。
暂停和恢复 Pod
虽然 Pod 本身没有暂停和恢复的操作,但可以通过以下方式实现类似的效果:
- 暂停 Pod:将 Pod 的容器设置为
sleep
状态。kubectl exec -it <pod-name> -- /bin/sh -c "sleep infinity"
- 恢复 Pod:删除 Pod 并重新创建。
查看 Pod 的资源使用情况
kubectl top pod <pod-name>
- 这需要集群中安装了 Metrics Server。
查看 Pod 的事件
kubectl describe pod <pod-name>
- 在
Events
部分可以看到 Pod 的生命周期事件。
查看 Pod 的存储卷
kubectl describe pod <pod-name>
- 在
Volumes
部分可以看到 Pod 的存储卷信息。
好的!以下是关于 Kubernetes 标签(Labels)的整理,包括标签的概念、操作以及基于标签的资源管理。
3 k8s标签(Labels)
- 概念:Kubernetes 中的标签是键值对(key-value pairs),用于对资源(如 Pod、Deployment、Service 等)进行分类和选择。
- 作用:
- 标签可以用于组织和管理资源。
- 标签可以用于选择特定的资源集,例如在部署、服务发现或资源监控中。
- 标签不直接修改资源的行为,但可以通过控制器(如 Deployment、Service)间接影响资源的调度和管理。
标签的基本操作
(1)查看 Pod 的标签
kubectl get pods --show-labels
- 使用
--show-labels
选项可以显示 Pod 的标签信息。
(2)为 Pod 添加标签
kubectl label pod <pod-name> key=value
- 示例:
kubectl label pod text01 school=oldboyedu
(3)修改标签
kubectl label pod <pod-name> key=value --overwrite
--overwrite
参数允许覆盖已存在的标签。- 示例:
kubectl label pod text01 school=laonanhai --overwrite
(4)删除标签
kubectl label pod <pod-name> key-
- 示例:
kubectl label pod text01 school-
(5)批量操作
- 为多个 Pod 打标签:
kubectl label pod text01 text03 school=oldboyedu
- 删除所有 Pod 的某个标签:
kubectl label pods --all key-
基于标签的资源选择
(1)使用标签选择 Pod
kubectl get pods -l key=value
- 示例:
kubectl get pods -l school=oldboyedu
(2)使用多个标签选择 Pod
kubectl get pods -l key1=value1,key2=value2
- 示例:
kubectl get pods -l class=linux97,school=yitiantian
(3)使用标签范围选择 Pod
kubectl get pods -l 'key in (value1,value2)'
- 示例:
kubectl get pods -l 'school in (oldboyedu,laonanhai)'
(4)删除匹配标签的 Pod
kubectl delete pods -l key=value
- 示例:
kubectl delete pods -l class=linux97
总结
- 标签 是 Kubernetes 中用于分类和选择资源的键值对。
- 标签可以用于管理资源、选择特定资源集或进行资源监控。
- 通过
kubectl label
命令可以添加、修改或删除标签。 - 使用
-l
参数可以基于标签过滤资源。 - 标签是 Kubernetes 资源管理的重要工具,能够帮助你更高效地组织和操作资源。
4 声明式管理pod
4.1 编写资源清单
cat 01-pods-text.yaml
apiVersion: v1
kind: Pod
metadata:
labels:
name: cmy
name: text-v1
spec:
containers:
- image: registry.cn-hangzhou.aliyuncs.com/cmy-k8s/apps:v1
name: v1
#应用资源清单
kubectl apply -f 01-pods-text.yaml
#查看资源清单创建的资源
kubectl get -f 01-pods-text.yaml -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
text-v1 1/1 Running 0 8m34s 10.100.203.138 worker232 <none> <none>
#删除资源清单创建的资源
kubectl delete -f 01-pods-text.yaml
5 pod故障排查技巧总结!!!
- 故障排查技巧总结
如果Pod非Runing状态,说明该Pod处于不正常状态,因此需要借助K8S相关技术栈来解决问题。
具体解决思路如下:
- 1.kubectl describe <资源类型> 名称|标签
思路解读:
- 使用该命令可以对Pod故障做一些基础性拍错,包括但不限于镜像拉取失败,容器启动失败,探针检测失败,存储卷挂载失败,资源不足,网络插件,调度失败,认证失败等各种故障原因。
- 2.kubectl logs POD -c CONTAINER
思路解读:
- 使用该命令的前提是Pod已经完成了调度工作,且启动过容器才会有日志产生。如果Pod无法完成调度,则该命令无效。看不到任何有效的帮助信息。
面试题:
--since 20m
查看20分钟内的日志。
-p
查看上一次容器重启的日志。前提是有重启过,如果没有重启或者容器不存在,则此参数无效。
- 3.kubectl exec POD -c CONTAINER
思路解决:
- 相当于传统的Linux运维,进入到了Linux服务器,可以实现各种操作,从而快速定位问题。
- 如果想要执行该命令的前提是pod已经能够启动成功。说白了,就是其正常运行。
- 4.command & args
思路解决:
- 解决容器无法正常启动的情况,启动后,使用exec进入到容器进行结合排查。
- 5.cp
思路解决:
- 一般情况下,如果有需要将本地文件或者容器的某个文件进行互相拷贝的时候,就可以使用该命令。
6 pod状态!!!
1. Pending(等待中)
-
状态描述:Pod 已被 Kubernetes 系统接受,但尚未创建容器。通常是因为镜像正在下载,或者调度器正在寻找合适的节点来运行 Pod。
-
常见原因:
-
镜像拉取失败(如镜像不存在、网络问题)。
-
调度器无法找到合适的节点(如资源不足、节点亲和性规则不匹配)。
-
Pod 的初始化容器尚未运行完成。
-
2. Running(运行中)
-
状态描述:Pod 已经绑定到某个节点上,且所有容器都已创建并正在运行。至少有一个容器处于运行状态,或者处于启动或重启过程中。
-
特点:
-
Pod 的状态被设置为
Running
,表示它已经成功调度到节点上。 -
容器的生命周期管理(如启动、重启)由 kubelet 负责。
-
如果容器崩溃,kubelet 会根据
RestartPolicy
(重启策略)来决定是否重启容器。
-
3. Succeeded(成功)
-
状态描述:Pod 中的所有容器都已成功运行完成,并且不会再重启。通常用于执行一次性任务的 Pod,如批量处理作业。
-
特点:
-
Pod 的生命周期结束,但不会被自动删除。可以通过设置
ttlSecondsAfterFinished
来指定 Pod 在完成后保留的时间。 -
Pod 的状态不会再次变为其他状态。
-
4. Failed(失败)
-
状态描述:Pod 中至少有一个容器以失败状态退出,并且不会被重启。通常是因为容器运行时出现错误,或者达到了重启策略的限制。
-
常见原因:
-
容器运行时错误(如程序崩溃、资源耗尽)。
-
容器健康检查失败(如就绪探针或存活探针失败)。
-
重启策略为
Never
,且容器退出状态码非零。
-
5. Unknown(未知)
-
状态描述:Pod 的状态无法确定,通常是因为与 Pod 所在节点的通信出现问题。例如,节点网络故障或 kubelet 崩溃。
-
特点:
-
Kubernetes 会尝试重新获取 Pod 的状态,如果长时间无法获取,可能会自动删除 Pod 或重新调度。
-
这是一个临时状态,通常需要人工干预来解决节点问题。
-
6.2 容器3种状态
Waiting(等待):
如果容器并不处在 Running 或 Terminated 状态之一,它就处在 Waiting 状态。 处于 Waiting 状态的容器仍在运行它完成启动所需要的操作:例如, 从某个容器镜像仓库拉取容器镜像,或者向容器应用 Secret 数据等等。 当你使用 kubectl 来查询包含 Waiting 状态的容器的 Pod 时,你也会看到一个 Reason 字段,其中给出了容器处于等待状态的原因。
Running(运行中):
Running 状态表明容器正在执行状态并且没有问题发生。 如果配置了 postStart 回调,那么该回调已经执行且已完成。 如果你使用 kubectl 来查询包含 Running 状态的容器的 Pod 时, 你也会看到关于容器进入 Running 状态的信息。
Terminated(已终止):
处于 Terminated 状态的容器开始执行后,或者运行至正常结束或者因为某些原因失败。 如果你使用 kubectl 来查询包含 Terminated 状态的容器的 Pod 时, 你会看到容器进入此状态的原因、退出代码以及容器执行期间的起止时间。
6.3 Pod 重启策略!!!
restartPolicy
的值可以是Always
、OnFailure
或Never
。Always
:无论容器是否正常退出,都会重启容器。OnFailure
:容器异常退出时会重启,正常退出时不会重启。Never
:容器退出后不会重启。
- 如果不指定
restartPolicy
,默认值为Always
。
Pod 重启策略配置文件
apiVersion: v1
kind: Pod
metadata:
labels:
name: cmy
name: lx
spec:
restartPolicy: "OnFailure"
containers:
- image: registry.cn-hangzhou.aliyuncs.com/cmy-k8s/apps:v1
name: c1
command:
- sh
- -c
- "sleep 60; exit 1"
7 pod创建流程 !!!!!
Pod的创建,删除,修改流程:
1.执行kubectl命令时会加载"~/.kube/config",从而识别到apiserver的地址,端口及认证证书;
2.apiserver进行证书认证,鉴权,语法检查,若成功则可以进行数据的读取或者写入;
3.若用户是写入操作(创建,修改,删除)则需要修改etcd数据库的信息;
4.如果创建Pod,此时scheduler负责Pod调度,将Pod调度到合适的worker节点,并将结果返回给ApiServer,由apiServer负责存储到etcd中;
5.kubelet组件会周期性上报给apiServer节点,包括Pod内的容器资源(cpu,memory,disk,gpu,...)及worker宿主机节点状态,apiServer并将结果存储到etcd中,若有该节点的任务也会直接返回给该节点进行调度;
6.kubelet开始调用CRI(Container Runtime Interface)接口创建容器(依次创建pause,initContainers,containers);
7.在运行过程中,若Pod容器,正常或者异常退出时,kubelet会根据重启策略是否重启容器(Never,Always,OnFailure);
8.若一个节点挂掉,则需要controller manager介入维护,比如Pod副本数量缺失,则需要创建watch事件,要求控制器的副本数要达到标准,从而要创建新的Pod,此过程重复步骤4-6。
基于资源清单创建 Pod
- 用户通过
kubectl apply
或其他工具提交 Pod 的资源清单文件到 Kubernetes API Server。 - API Server 验证资源清单的合法性,并将其存储到 etcd 数据库中。
- 补充说明:
- etcd 是 Kubernetes 的分布式存储系统,用于存储集群的状态信息。
- API Server 是 Kubernetes 的核心组件,负责处理所有资源的增删改查操作,并将数据持久化到 etcd。
调度器(Scheduler)调度 Pod
- 调度决策:
- Scheduler 负责决定将 Pod 调度到哪个 Worker 节点。
- Scheduler 会根据多种因素进行调度决策,包括节点的资源利用率(CPU、内存等)、亲和性规则、污点与容忍等。
- 调度结果上报:
- Scheduler 将调度结果发送给 API Server。
- API Server 将调度结果(即 Pod 被分配到的节点信息)存储到 etcd 中。
- 补充说明:
- 如果调度失败(例如没有合适的节点),Pod 会处于
Pending
状态,直到找到合适的节点。
- 如果调度失败(例如没有合适的节点),Pod 会处于
Controller Manager 维护集群状态
- Pod 控制器(Replication Controller/ReplicaSet/Deployment 等):
- Controller Manager 组件中的 Pod 控制器会监控集群中 Pod 的状态。
- 如果发现某个 Pod 出现故障或被删除,控制器会根据定义的期望状态(如副本数量)自动创建新的 Pod。
- Watch 事件处理:
- Controller Manager 通过监听 etcd 中的资源变更事件(如 Pod 的创建、更新或删除),确保集群的实际状态与期望状态一致。
- 补充说明:
- Controller Manager 还负责其他资源的管理,例如 Service、DaemonSet 等。
Worker 节点上报状态信息
- 状态上报:
- 各个 Worker 节点上的 kubelet 组件会定期向 API Server 上报自己节点上 Pod 的运行状态(如容器的健康状态、资源使用情况等)。
- 同时,kubelet 也会上报节点自身的资源使用情况(如 CPU、内存的利用率等)。
- 调度命令同步:
- API Server 将 etcd 中记录的调度命令(即 Pod 被分配到的节点信息)同步到对应的 Worker 节点。
- 补充说明:
- kubelet 是 Kubernetes 在每个节点上的代理组件,负责管理 Pod 的生命周期。
Worker 节点创建 Pod
- 容器运行时接口(CRI)调用:
- Worker 节点上的 kubelet 根据调度命令,调用容器运行时接口(CRI)来创建 Pod。
- CRI 是 Kubernetes 提供的一种标准化接口,用于与容器运行时(如 Docker、containerd 等)进行交互。
- 容器创建:
- 容器运行时通过调用底层的容器运行时工具(如
runc
)来创建容器。 - 容器运行时会拉取指定的镜像,并启动容器。
- 容器运行时通过调用底层的容器运行时工具(如
- 网络配置:
- Kubernetes 网络插件(如 Flannel、Calico 等)会为 Pod 分配 IP 地址,并配置网络,确保 Pod 之间可以相互通信。
- 补充说明:
- Pod 的生命周期由 kubelet 管理,包括启动、停止和删除容器。
- kubelet启动容器的原理图解【了解】
1.kubelet创建Pod的全流程:
- 1.kubelet调用CRI接口创建容器,底层支持docker|containerd作为容器运行时;
- 2.底层基于runc(符合OCI规范)创建容器:
- 3.优先创建pause基础镜像;
- 4.创建初始化容器
- 5.业务容器,业务容器如果定义了优雅终止,探针则顺序如下:
- 5.1 启动命令【COMMAND】
- 5.2 启动postStart;
- 5.3 Probe
- StartupProbe
- LivenessProbe | readinessProbe
- 5.4 启动PreStop
受限于优雅终止时间(默认30s)。
总结
Kubernetes 创建 Pod 的流程涉及多个组件的协同工作:
- API Server:接收用户请求,验证并存储资源清单到 etcd。
- Scheduler:负责调度决策,将 Pod 分配到合适的 Worker 节点。
- Controller Manager:监控集群状态,确保 Pod 按期望状态运行。
- Worker 节点(kubelet):接收调度命令,调用 CRI 创建 Pod,并上报状态信息。
- 容器运行时(如 Docker、containerd):实际创建和管理容器。
8 玩转pod调度
8.1 使用 nodeName
将 Pod 调度到指定节点
通过在 Pod 的配置中指定 nodeName
,可以将 Pod 直接调度到指定的节点。这种方式简单直接,但缺乏灵活性。
示例配置
01-nodeName.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: text-nodename
spec:
replicas: 5
selector:
matchLabels:
apps: v1
template:
metadata:
labels:
apps: v1
spec:
# 指定 Pod 调度到名为 worker232 的节点
nodeName: worker232
containers:
- name: c1
image: registry.cn-hangzhou.aliyuncs.com/cmy-k8s/apps:v1
8.2 hostPort
绑定宿主机端口
通过设置 hostPort
,Pod 内的容器可以直接绑定宿主机的端口,从而实现外部访问。
hostPort是Pod使用worker节点进行NAT转发,从而达到暴露服务到K8S集群外部的一种方式。
早期K8S 1.5.2 版本会监听相应的端口,现在新版本中并不会监听端口。
示例配置
03-hostPorts.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: text-ports
spec:
replicas: 3
selector:
matchLabels:
apps: v1
template:
metadata:
labels:
apps: v1
spec:
containers:
- name: c1
image: registry.cn-hangzhou.aliyuncs.com/cmy-k8s/apps:v1
ports:
- containerPort: 80
hostPort: 30080
[root@worker233 ~]# iptables -t nat -vnL | grep 30080 | grep DNAT
0 0 DNAT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:30080 to:10.100.140.73:80
<font color="#9bbb59">发现底层调用的是DNAT做端口转发</font>
注意:如果宿主机的端口已经被占用,Pod 会处于 Pending
状态,无法完成调度。
8.3 hostNetwork 共享宿主机网络命名空间
通过设置 hostNetwork: true
,Pod 内的容器将直接使用宿主机的网络命名空间,共享网络接口和端口。
- hostNetwork之DNS解析策略
1.编写资源清单
[root@master231 pods]# cat 15-pods-text-dnsPolicy.yaml
apiVersion: v1
kind: Pod
metadata:
name: pods-text
labels:
apps: text
spec:
containers:
- image: registry.cn-hangzhou.aliyuncs.com/cmy-k8s/apps:v1
name: c1
ports:
- containerPort: 80
name: web
- containerPort: 8080
name: security
---
apiVersion: v1
kind: Service
metadata:
name: svc-text
spec:
# 自定义CLusterIP地址,通常情况下不建议使用该字段,因为可能会导致端口冲突的问题!
clusterIP: 10.200.0.100
ports:
- port: 90
targetPort: web
selector:
apps: text
type: ClusterIP
---
apiVersion: v1
kind: Pod
metadata:
name: pods-dnspolicy
spec:
hostNetwork: true
# 如果使用了宿主机网络,通常情况下要指定DNS解析策略,否则就无法使用内部的svc名称解析了
dnsPolicy: ClusterFirstWithHostNet
containers:
- image: registry.cn-hangzhou.aliyuncs.com/cmy-k8s/apps:v1
name: c1
[root@master231 pods]#
2.测试验证
[root@master231 pods]# kubectl apply -f 15-pods-text-dnsPolicy.yaml
pod/pods-text created
service/svc-text created
pod/pods-dnspolicy created
[root@master231 pods]#
[root@master231 pods]# kubectl get pods,svc -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod/pods-dnspolicy 1/1 Running 0 5s 10.0.0.232 worker232 <none> <none>
pod/pods-text 1/1 Running 0 5s 10.100.203.157 worker232 <none> <none>
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
service/kubernetes ClusterIP 10.200.0.1 <none> 443/TCP 9d <none>
service/svc-text ClusterIP 10.200.0.100 <none> 90/TCP 5s apps=text
[root@master231 pods]#
[root@master231 pods]# kubectl -n kube-system get svc kube-dns
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kube-dns ClusterIP 10.200.0.10 <none> 53/UDP,53/TCP,9153/TCP 17d
[root@master231 pods]#
[root@master231 pods]# kubectl exec -it pods-dnspolicy -- sh
/ # cat /etc/resolv.conf
nameserver 10.200.0.10
search default.svc.oldboyedu.com svc.oldboyedu.com oldboyedu.com
options ndots:5
/ #
/ # ping svc-text -c 3
PING svc-text (10.200.0.100): 56 data bytes
64 bytes from 10.200.0.100: seq=0 ttl=64 time=0.045 ms
64 bytes from 10.200.0.100: seq=1 ttl=64 time=0.076 ms
64 bytes from 10.200.0.100: seq=2 ttl=64 time=0.049 ms
注意:
- 使用
hostNetwork
时,Pod 内的容器可以直接使用宿主机的网络接口,但可能会导致端口冲突。 - 如果多个 Pod 使用了相同的宿主机端口,可能会导致调度失败或端口冲突。
8.4 资源限制resources
resources可以对Pod的容器进行资源的限制。
有两个字段可以进行配置:
requests:
容器的期望资源,如果worker节点无法满足该期望,则Pod不会调度到该节点。
调度到该节点后,也并不会即可消耗掉所有的期望资源。
limits:
容器资源的使用上限。
温馨提示:
<font color="#9bbb59"> – 1.若没有定义resources资源,则Pod的容器默认可以使用worker节点的所有资源(CPU,内存,磁盘);</font>
<font color="#9bbb59"> – 2.若定义了resources资源,但没有配置limits,也会默认使用宿主机的所有资源;</font>
<font color="#9bbb59"> – 3.若定义了resources资源,但没有配置requests,则requests的资源和limits一致;</font>
示例配置
(04-resources.yaml
)
apiVersion: apps/v1
kind: Deployment
metadata:
name: text-resources
spec:
replicas: 3
selector:
matchLabels:
apps: v1
template:
metadata:
labels:
apps: v1
spec:
containers:
- name: c1
image: harbor.oldboyedu.com/oldboyedu-elasticstack/filebeat:ubuntu-v7.17.21
# 定义资源限制
resources:
# 定义期望资源,不满足该条件时无法调度到指定节点
requests:
cpu: 0.5
memory: 200Mi
# 定义资源使用的上限,容器不会超过该资源限制
limits:
cpu: 1500m
memory: 500Mi
注意:
requests
是容器期望分配的资源量,调度时会考虑该值。limits
是容器可以使用的最大资源量,容器运行时不会超过该值。- 如果宿主机的资源不足,Pod 可能无法被调度。
8.5 污点(Taints)
污点(Taint) 是一种节点级别的标记机制,用于阻止或限制 Pod 调度到特定节点。污点通常与 Pod 的容忍度(Toleration) 配合使用,实现精细化的调度控制。
常见的污点类型(Effect)
NoSchedule
:- 不接受新的 Pod 调度,但已经调度到该节点的 Pod 不会被驱逐。
PreferNoSchedule
:- 尽可能不调度 Pod 到该节点,但如果其他节点无法满足调度条件,Pod 仍可能被调度到该节点。
NoExecute
:- 不接受新的 Pod 调度,并且会驱逐已经调度到该节点的 Pod。
污点的操作
(1)查看现有的污点信息
kubectl describe nodes | grep Taints
(2)打污点
kubectl taint node <node-name> key=value:effect
- 示例:
kubectl taint node worker232 school=oldboyedu:NoSchedule kubectl taint node worker232 class:NoSchedule
(3)修改污点
kubectl taint node <node-name> key=value:effect --overwrite
- 示例:
kubectl taint node worker232 class=linux91:NoSchedule --overwrite
(4)删除污点
kubectl taint node <node-name> key:effect-
- 示例:
kubectl taint node worker232 class:NoSchedule-
实战案例
cat 05-taints-NoSchedule.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: scheduler-taints-noschedule
spec:
replicas: 5
selector:
matchLabels:
apps: text
template:
metadata:
labels:
apps: text
version: v1
spec:
containers:
- image: harbor.cmy.cn/caswdemo/tool:v1
command:
- tail
- -f
- /etc/hosts
name: c1
ports:
- containerPort: 80
resources:
requests:
cpu: 400m
memory: 2Gi
kubectl taint node worker232 name=donottouchme:NoSchedule
node/worker232 tainted
[root@master-231 /oldboyedu/manifests/scheduler]# kubectl describe nodes | grep Taints
Taints: node-role.kubernetes.io/master:NoSchedule
Taints: name=donottouchme:NoSchedule
Taints: <none>
kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
scheduler-taints-noschedule-b57558bfd-4smlj 0/1 Pending 0 9s <none> <none> <none> <none>
scheduler-taints-noschedule-b57558bfd-bh4mk 1/1 Running 0 9s 10.100.140.103 worker233 <none> <none>
scheduler-taints-noschedule-b57558bfd-j4hfr 0/1 Pending 0 9s <none> <none> <none> <none>
scheduler-taints-noschedule-b57558bfd-mdxtm 1/1 Running 0 9s 10.100.140.77 worker233 <none> <none>
scheduler-taints-noschedule-b57558bfd-q7jth 1/1 Running 0 9s 10.100.140.90 worker233 <none> <none>
[root@master-231 /oldboyedu/manifests/scheduler]#
解释
worker233 只能运行3个POD,worker232污点不允许pod调度
kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
scheduler-taints-noschedule-b57558bfd-4smlj 1/1 Running 0 2m17s 10.100.203.150 worker232 <none> <none>
scheduler-taints-noschedule-b57558bfd-bh4mk 1/1 Running 0 2m17s 10.100.140.103 worker233 <none> <none>
scheduler-taints-noschedule-b57558bfd-j4hfr 0/1 Pending 0 2m17s <none> <none> <none> <none>
scheduler-taints-noschedule-b57558bfd-mdxtm 1/1 Running 0 2m17s 10.100.140.77 worker233 <none> <none>
scheduler-taints-noschedule-b57558bfd-q7jth 1/1 Running 0 2m17s 10.100.140.90 worker233 <none> <none>
[root@master-231 /oldboyedu/manifests/scheduler]# kubectl describe nodes | grep Taints
Taints: node-role.kubernetes.io/master:NoSchedule
Taints: name=ifokdonttouchme:PreferNoSchedule
Taints: <none>
解释
修改worker232污点为PreferNoSchedule ,则232资源不够时可以调度到233
kubectl taint node worker233 name=alldonottouchme:NoExecute
node/worker233 tainted
[root@master-231 /oldboyedu/manifests/scheduler]# kubectl describe nodes | grep Taints
Taints: node-role.kubernetes.io/master:NoSchedule
Taints: name=ifokdonttouchme:PreferNoSchedule
Taints: name=alldonottouchme:NoExecute
kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
scheduler-taints-noschedule-b57558bfd-4smlj 1/1 Running 0 4m30s 10.100.203.150 worker232 <none> <none>
scheduler-taints-noschedule-b57558bfd-g7z8j 0/1 Pending 0 33s <none> <none> <none> <none>
scheduler-taints-noschedule-b57558bfd-j4hfr 0/1 Pending 0 4m30s <none> <none> <none> <none>
scheduler-taints-noschedule-b57558bfd-xvf8c 0/1 Pending 0 33s <none> <none> <none> <none>
scheduler-taints-noschedule-b57558bfd-zjvdn 0/1 Pending 0 33s <none> <none> <none> <none>
[root@master-231 /oldboyedu/manifests/scheduler]#
解释
233打上NoExecute污点后驱逐所有污点且不允许调度到233
8.6 污点容忍(Tolerations)
Pod 的容忍配置允许它被调度到带有特定污点的节点。如果 Pod 配置了容忍某个污点,它将能够被调度到该节点。
- 示例配置(
06-tolerations.yaml
):apiVersion: apps/v1 kind: Deployment metadata: name: text-tolerations spec: replicas: 10 selector: matchLabels: apps: v1 template: metadata: labels: apps: v1 spec: tolerations: # 指定key和value之间的关系,有效值为: Exists, Equal(默认值) # Exists: # 只要key存在,则匹配所有的value,因此可以不定义value。 # Equal: # 要求key的值必须是value指定的值。 - key: school # 容忍特定污点 value: oldboyedu effect: NoSchedule operator: Equal - key: class #匹配所有key为class的污点 operator: Exists - operator: Exists #不定义key,value,effect,则默认匹配所有的值,如果你这样做将无视任何污点! containers: - name: c1 image: registry.cn-hangzhou.aliyuncs.com/cmy-k8s/apps:v1
8.7 nodeSelector
1.什么是nodeSelector
nodeSelector是节点选择器,选择pod调度到特定节点。
和nodeName不同的是,<font color="#9bbb59">nodeSelector可以调度到多个符合选择的节点</font>。
1.给指定节点打标签
kubectl label nodes master-231 worker233 school=oldboyedu
2.根据标签选择节点
cat 07-ds-nodeselector.yaml
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: scheduler-nodeselector
spec:
selector:
matchLabels:
apps: text
template:
metadata:
labels:
apps: text
version: v1
spec:
# 配置Pod的污点容忍
nodeSelector:
school: oldboyedu
tolerations:
- operator: Exists
containers:
- image: harbor.cmy.cn/caswdemo/tool:v1
command:
- tail
- -f
- /etc/hosts
name: c1
ports:
- containerPort: 80
resources:
requests:
cpu: 400m
memory: 2Gi
3.查看效果
kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
scheduler-nodeselector-c85r9 1/1 Running 0 10s 10.100.209.35 master-231 <none> <none>
scheduler-nodeselector-m4v5x 1/1 Running 0 10s 10.100.140.66 worker233 <none> <none>
[root@master-231 /oldboyedu/manifests/scheduler]#
8.8 cordon与uncordon
1.cordon
cordon可以标记节点不可调度,本质上是给改节点打了污点。
2.uncordon
uncordon的作用是cordon的反向操作,说白了就是取消节点不可调度,底层也会删除污点。
2.1 操作前查看污点情况
[root@master231 ~]# kubectl describe nodes | grep Taints -A 2
Taints: node-role.kubernetes.io/master:NoSchedule
Unschedulable: false
Lease:
--
Taints: school=oldboyedu:NoSchedule
Unschedulable: false
Lease:
--
Taints: class=linux97:NoExecute
class=LINUX97:PreferNoSchedule
Unschedulable: false
[root@master231 ~]#
[root@master231 ~]#
2.2 将节点标记为不可调度
[root@master231 scheduler-pods]# kubectl get nodes
NAME STATUS ROLES AGE VERSION
master231 Ready control-plane,master 6d4h v1.23.17
worker232 Ready <none> 6d4h v1.23.17
worker233 Ready <none> 6d4h v1.23.17
[root@master231 scheduler-pods]#
[root@master231 scheduler-pods]# kubectl cordon worker232
node/worker232 cordoned
[root@master231 scheduler-pods]#
[root@master231 scheduler-pods]# kubectl get nodes
NAME STATUS ROLES AGE VERSION
master231 Ready control-plane,master 6d4h v1.23.17
worker232 Ready,SchedulingDisabled <none> 6d4h v1.23.17
worker233 Ready <none> 6d4h v1.23.17
[root@master231 scheduler-pods]#
2.3 再次查看节点污点
[root@master231 ~]# kubectl describe nodes | grep Taints -A 2
Taints: node-role.kubernetes.io/master:NoSchedule
Unschedulable: false
Lease:
--
Taints: node.kubernetes.io/unschedulable:NoSchedule
school=oldboyedu:NoSchedule
Unschedulable: true
--
Taints: class=linux97:NoExecute
class=LINUX97:PreferNoSchedule
Unschedulable: false
[root@master231 ~]#
- 玩转Pod调度之uncordon
2.实战案例
2.1 操作前污点查看
[root@master231 ~]# kubectl describe nodes | grep Taints -A 2
Taints: node-role.kubernetes.io/master:NoSchedule
Unschedulable: false
Lease:
--
Taints: node.kubernetes.io/unschedulable:NoSchedule
school=oldboyedu:NoSchedule
Unschedulable: true
--
Taints: class=linux97:NoExecute
class=LINUX97:PreferNoSchedule
Unschedulable: false
[root@master231 ~]#
2.2 取消节点不可调度
[root@master231 scheduler-pods]# kubectl get nodes
NAME STATUS ROLES AGE VERSION
master231 Ready control-plane,master 6d4h v1.23.17
worker232 Ready,SchedulingDisabled <none> 6d4h v1.23.17
worker233 Ready <none> 6d4h v1.23.17
[root@master231 scheduler-pods]#
[root@master231 scheduler-pods]# kubectl uncordon worker232
node/worker232 uncordoned
[root@master231 scheduler-pods]#
[root@master231 scheduler-pods]# kubectl get nodes
NAME STATUS ROLES AGE VERSION
master231 Ready control-plane,master 6d4h v1.23.17
worker232 Ready <none> 6d4h v1.23.17
worker233 Ready <none> 6d4h v1.23.17
[root@master231 scheduler-pods]#
2.3 操作后污点查看
[root@master231 ~]# kubectl describe nodes | grep Taints -A 2
Taints: node-role.kubernetes.io/master:NoSchedule
Unschedulable: false
Lease:
--
Taints: school=oldboyedu:NoSchedule
Unschedulable: false
Lease:
--
Taints: class=linux97:NoExecute
class=LINUX97:PreferNoSchedule
Unschedulable: false
[root@master231 ~]#
8.9 驱逐(Drain)节点
驱逐节点是将节点上的 Pod 驱逐到其他节点的过程,通常用于节点维护或下线。
[root@master231 scheduler-pods]# kubectl describe nodes | grep Taints -A 2
Taints: node-role.kubernetes.io/master:NoSchedule
Unschedulable: false
Lease:
--
Taints: school=oldboyedu:NoSchedule
Unschedulable: false
Lease:
--
Taints: class=linux97:NoExecute
class=LINUX97:PreferNoSchedule
Unschedulable: false
[root@master231 scheduler-pods]#
[root@master231 scheduler-pods]# kubectl taint node worker233 class-
node/worker233 untainted
[root@master231 scheduler-pods]#
[root@master231 scheduler-pods]# kubectl taint node worker232 school-
node/worker232 untainted
[root@master231 scheduler-pods]#
[root@master231 scheduler-pods]# kubectl describe nodes | grep Taints -A 2
Taints: node-role.kubernetes.io/master:NoSchedule
Unschedulable: false
Lease:
--
Taints: <none>
Unschedulable: false
Lease:
--
Taints: <none>
Unschedulable: false
Lease:
[root@master231 scheduler-pods]#
[root@master231 scheduler-pods]# kubectl apply -f 07-scheduler-tolerations.yaml
deployment.apps/scheduler-taints-tolerations created
[root@master231 scheduler-pods]#
[root@master231 scheduler-pods]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
scheduler-taints-tolerations-99f696b5d-2kfsq 1/1 Running 0 3s 10.100.140.72 worker233 <none> <none>
scheduler-taints-tolerations-99f696b5d-hvhfj 1/1 Running 0 3s 10.100.160.152 master231 <none> <none>
scheduler-taints-tolerations-99f696b5d-khpfk 1/1 Running 0 3s 10.100.140.65 worker233 <none> <none>
scheduler-taints-tolerations-99f696b5d-p4lpq 1/1 Running 0 3s 10.100.203.146 worker232 <none> <none>
scheduler-taints-tolerations-99f696b5d-vhmkc 1/1 Running 0 3s 10.100.203.153 worker232 <none> <none>
[root@master231 scheduler-pods]#
[root@master231 scheduler-pods]#
2.2 驱逐worker233节点
[root@master231 scheduler-pods]# kubectl drain worker233 --ignore-daemonsets
node/worker233 already cordoned
WARNING: ignoring DaemonSet-managed Pods: calico-system/calico-node-82zlb, calico-system/csi-node-driver-pxq6d, kube-system/kube-proxy-w678l
evicting pod tigera-operator/tigera-operator-8d497bb9f-bnflh
evicting pod default/scheduler-taints-tolerations-99f696b5d-2kfsq
evicting pod default/scheduler-taints-tolerations-99f696b5d-khpfk
pod/tigera-operator-8d497bb9f-bnflh evicted
pod/scheduler-taints-tolerations-99f696b5d-khpfk evicted
pod/scheduler-taints-tolerations-99f696b5d-2kfsq evicted
node/worker233 drained
[root@master231 scheduler-pods]#
[root@master231 scheduler-pods]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
scheduler-taints-tolerations-99f696b5d-hvhfj 1/1 Running 0 3m43s 10.100.160.152 master231 <none> <none>
scheduler-taints-tolerations-99f696b5d-jmxlk 1/1 Running 0 2m2s 10.100.160.153 master231 <none> <none>
scheduler-taints-tolerations-99f696b5d-m27kf 1/1 Running 0 2m2s 10.100.203.190 worker232 <none> <none>
scheduler-taints-tolerations-99f696b5d-p4lpq 1/1 Running 0 3m43s 10.100.203.146 worker232 <none> <none>
scheduler-taints-tolerations-99f696b5d-vhmkc 1/1 Running 0 3m43s 10.100.203.153 worker232 <none> <none>
[root@master231 scheduler-pods]#
2.3 drain驱逐底层调用了cordon
[root@master231 scheduler-pods]# kubectl get nodes
NAME STATUS ROLES AGE VERSION
master231 Ready control-plane,master 6d5h v1.23.17
worker232 Ready <none> 6d4h v1.23.17
worker233 Ready,SchedulingDisabled <none> 6d4h v1.23.17
[root@master231 scheduler-pods]#
[root@master231 scheduler-pods]# kubectl describe nodes | grep Taints -A 2
Taints: node-role.kubernetes.io/master:NoSchedule
Unschedulable: false
Lease:
--
Taints: <none>
Unschedulable: false
Lease:
--
Taints: node.kubernetes.io/unschedulable:NoSchedule
Unschedulable: true
Lease:
[root@master231 scheduler-pods]#
2.4 取消节点不可调度
[root@master231 scheduler-pods]# kubectl uncordon worker233
node/worker233 uncordoned
[root@master231 scheduler-pods]#
[root@master231 scheduler-pods]# kubectl get nodes
NAME STATUS ROLES AGE VERSION
master231 Ready control-plane,master 6d5h v1.23.17
worker232 Ready <none> 6d4h v1.23.17
worker233 Ready <none> 6d4h v1.23.17
[root@master231 scheduler-pods]#
2.5 扩大Pod副本数量测试验证worker233节点是否正常工作
[root@master231 scheduler-pods]# kubectl edit deployments.apps scheduler-taints-tolerations
节点下线
-
驱逐节点上的 Pod:
kubectl drain <node-name> --ignore-daemonsets
- 示例:
kubectl drain worker233 --ignore-daemonsets
- 示例:
-
停止 kubelet 组件:
systemctl disable --now kubelet
-
重置节点:
kubeadm reset -f
-
清理残留文件:
rm -rf /etc/cni/net.d/ ipvsadm --clear rm -f $HOME/.kube/config
-
重启系统:
init 0
-
从 Master 节点移除下线的节点信息:
kubectl delete nodes <node-name>
- 示例:
kubectl delete nodes worker233
- 示例:
节点的下线和上线流程
(1)节点下线
-
驱逐节点上的 Pod:
kubectl drain worker233 --ignore-daemonsets
-
标记节点不可调度:
kubectl cordon worker233
-
停止 kubelet 组件:
systemctl disable --now kubelet
-
重置节点:
kubeadm reset -f
-
清理残留文件:
rm -rf /etc/cni/net.d/ ipvsadm --clear rm -f $HOME/.kube/config
-
重启系统:
init 0
-
从 Master 节点移除下线的节点信息:
kubectl delete nodes worker233
(2)节点上线
-
标记节点可调度:
kubectl uncordon worker233
-
验证节点状态:
kubectl get nodes
节点加入集群
(1)在 Master 节点生成 token
kubeadm token create <token-name> --ttl 0 --print-join-command
- 示例:
kubeadm token create --print-join-command
(2)在 Worker 节点加入集群
kubeadm join <master-ip>:6443 --token <token-name> --discovery-token-ca-cert-hash sha256:<hash>
- 示例:
kubeadm join 10.0.0.231:6443 --token oldboy.cmyjason --discovery-token-ca-cert-hash sha256:72f9bf97faf36b7448822d2c32717cd9eb90b08020e76b8d415d187ed6d954be
(3)在 Master 节点验证节点是否加入成功
kubectl get nodes
总结
- 污点(Taints):用于标记节点,防止某些 Pod 调度到该节点。
- 容忍(Tolerations):允许 Pod 调度到带有特定污点的节点。
- 驱逐(Drain):将节点上的 Pod 驱逐到其他节点,通常用于节点维护或下线。
- 节点下线和上线:通过标记节点不可调度、驱逐 Pod、停止 kubelet 组件、重置节点等步骤完成节点的下线和上线操作。
- 节点加入集群:通过生成 token 和加入命令,将 Worker 节点加入 Kubernetes 集群。
8.10 亲和性
1.affinity概述
affinity的作用就是让Pod按照我们的日常需求进行倾向性调度。
affinity有三种实现方式:
nodeAffinity
让Pod更加倾向于哪些节点进行调度。
其功能和nodeSelector类似,但更加灵活。
podAffinity
可以基于拓扑域进行调度,当第一个Pod调度到该拓扑域后,则后续的所有Pod都会往该拓扑域调度。
为了方便大家理解,此处的拓扑域可以暂时理解为'机房'。
podAntiAffinity
和podAntiAffinity相反,,当第一个Pod调度到该拓扑域后,则后续的所有Pod都不会往该拓扑域调度。
9.1 nodeAffinity实战案例
[root@master-231 ~]# kubectl get nodes --show-labels |grep class
master-231 Ready control-plane,master 6d22h v1.23.17 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,class=cmy,kubernetes.io/arch=amd64,kubernetes.io/hostname=master-231,kubernetes.io/os=linux,node-role.kubernetes.io/control-plane=,node-role.kubernetes.io/master=,node.kubernetes.io/exclude-from-external-load-balancers=,school=oldboyedu
worker232 Ready <none> 6d22h v1.23.17 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,class=cmy,kubernetes.io/arch=amd64,kubernetes.io/hostname=worker232,kubernetes.io/os=linux
worker233 Ready <none> 16h v1.23.17 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,class=CMY,kubernetes.io/arch=amd64,kubernetes.io/hostname=worker233,kubernetes.io/os=linux
cat 08-nodeAffinity.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy-text-nodeaffinity
spec:
replicas: 5
selector:
matchLabels:
apps: text
template:
metadata:
labels:
apps: text
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: class
values:
- cmy
- CMY
# 声明key和values之间的关系,有效值为: In, NotIn, Exists, DoesNotExist. Gt, and Lt.
operator: In
tolerations:
- operator: Exists
containers:
- image: registry.cn-hangzhou.aliyuncs.com/cmy-k8s/apps:v1
name: c1
[root@master-231 /oldboyedu/manifests/scheduler]# kubectl apply -f 08-nodeAffinity.yaml
deployment.apps/deploy-text-nodeaffinity created
[root@master-231 /oldboyedu/manifests/scheduler]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
deploy-text-nodeaffinity-9c478f9c-fjnxm 1/1 Running 0 10s 10.100.140.68 worker233 <none> <none>
deploy-text-nodeaffinity-9c478f9c-fnpd8 1/1 Running 0 10s 10.100.209.42 master-231 <none> <none>
deploy-text-nodeaffinity-9c478f9c-k2jmh 1/1 Running 0 10s 10.100.203.134 worker232 <none> <none>
deploy-text-nodeaffinity-9c478f9c-kknnr 1/1 Running 0 10s 10.100.203.137 worker232 <none> <none>
deploy-text-nodeaffinity-9c478f9c-nc94x 1/1 Running 0 10s 10.100.140.67 worker233 <none> <none>
可以发现,与nodeselector对比,nodeAffinity更加灵活,可以调度节点到相同key不同value标签的节点
8.11 podAffinity实战案例
kubectl get nodes --show-labels | grep dc
master-231 Ready control-plane,master 6d22h v1.23.17 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,class=cmy,dc=beijing,kubernetes.io/arch=amd64,kubernetes.io/hostname=master-231,kubernetes.io/os=linux,node-role.kubernetes.io/control-plane=,node-role.kubernetes.io/master=,node.kubernetes.io/exclude-from-external-load-balancers=,school=oldboyedu
worker232 Ready <none> 6d22h v1.23.17 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,class=cmy,dc=shanghai,kubernetes.io/arch=amd64,kubernetes.io/hostname=worker232,kubernetes.io/os=linux
worker233 Ready <none> 17h v1.23.17 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,class=CMY,dc=shenzhen,kubernetes.io/arch=amd64,kubernetes.io/hostname=worker233,kubernetes.io/os=linux
cat 09-podAffinity.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy-text-podaffinity
spec:
replicas: 5
selector:
matchLabels:
apps: text
template:
metadata:
labels:
apps: text
spec:
affinity:
podAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
# 指定拓扑域
- topologyKey: dc
# 匹配对应的Pod
labelSelector:
matchLabels:
apps: text
tolerations:
- operator: Exists
containers:
- image: registry.cn-hangzhou.aliyuncs.com/cmy-k8s/apps:v1
name: c1
kubectl apply -f 09-podAffinity.yaml
deployment.apps/deploy-text-podaffinity created
kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
deploy-text-podaffinity-9b4c679ff-5qxmc 1/1 Running 0 8s 10.100.140.73 worker233 <none> <none>
deploy-text-podaffinity-9b4c679ff-5s8fr 1/1 Running 0 8s 10.100.140.72 worker233 <none> <none>
deploy-text-podaffinity-9b4c679ff-kj5xd 1/1 Running 0 8s 10.100.140.69 worker233 <none> <none>
deploy-text-podaffinity-9b4c679ff-lsns6 1/1 Running 0 8s 10.100.140.71 worker233 <none> <none>
deploy-text-podaffinity-9b4c679ff-qjfwz 1/1 Running 0 8s 10.100.140.70 worker233 <none> <none>
8.11 podAntiAffinity实战案例
kubectl get nodes --show-labels | grep dc
master-231 Ready control-plane,master 6d22h v1.23.17 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,class=cmy,dc=beijing,kubernetes.io/arch=amd64,kubernetes.io/hostname=master-231,kubernetes.io/os=linux,node-role.kubernetes.io/control-plane=,node-role.kubernetes.io/master=,node.kubernetes.io/exclude-from-external-load-balancers=,school=oldboyedu
worker232 Ready <none> 6d22h v1.23.17 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,class=cmy,dc=shanghai,kubernetes.io/arch=amd64,kubernetes.io/hostname=worker232,kubernetes.io/os=linux
worker233 Ready <none> 17h v1.23.17 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,class=CMY,dc=shenzhen,kubernetes.io/arch=amd64,kubernetes.io/hostname=worker233,kubernetes.io/os=linux
cat 10-podAntiAffinity.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy-text-podantiaffinity
spec:
replicas: 5
selector:
matchLabels:
apps: text
template:
metadata:
labels:
apps: text
spec:
affinity:
# 定义Pod的反亲和性
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- topologyKey: dc
labelSelector:
matchLabels:
apps: text
tolerations:
- operator: Exists
containers:
- image: registry.cn-hangzhou.aliyuncs.com/cmy-k8s/apps:v1
name: c1
kubectl apply -f 10-podAntiAffinity.yaml
deployment.apps/deploy-text-podantiaffinity created
[root@master-231 /oldboyedu/manifests/scheduler]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
deploy-text-podantiaffinity-64597f4865-2fcf4 1/1 Running 0 2s 10.100.140.74 worker233 <none> <none>
deploy-text-podantiaffinity-64597f4865-7lptf 0/1 Pending 0 2s <none> <none> <none> <none>
deploy-text-podantiaffinity-64597f4865-q7pcf 1/1 Running 0 2s 10.100.203.188 worker232 <none> <none>
deploy-text-podantiaffinity-64597f4865-qq79z 0/1 Pending 0 2s <none> <none> <none> <none>
deploy-text-podantiaffinity-64597f4865-zw488 0/1 ContainerCreating 0 2s <none> master-231 <none> <none>
8.11 nodeselector和nodeAffinity对比
在 Kubernetes 中,nodeSelector
和 Node Affinity
都用于控制 Pod 的调度位置,但它们在功能和使用方式上有显著区别。以下是两者的详细对比:
1. 功能对比
特性 | nodeSelector |
Node Affinity |
---|---|---|
基本功能 | 根据节点标签选择目标节点 | 基于节点标签的复杂规则(支持逻辑组合) |
灵活性 | 仅支持简单的键值匹配 | 支持 In 、NotIn 、Exists 、DoesNotExist 等复杂条件 |
逻辑组合 | 不支持多个条件的组合(OR/AND) | 支持通过 matchExpressions 实现复杂逻辑 |
软性规则 | 仅支持硬性规则(必须匹配) | 支持软性规则(PreferredDuringScheduling ) |
动态更新 | 需手动修改 Pod 的 nodeSelector |
可通过配置动态调整规则 |
2. 语法对比
(1) nodeSelector
-
语法简单,仅支持键值匹配:
spec: nodeSelector: disktype: ssd
-
硬性规则:Pod 必须调度到标签完全匹配的节点,否则调度失败。
(2) Node Affinity
-
支持复杂规则,例如:
affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: disktype operator: In values: - ssd - key: region operator: NotIn values: - us-west preferredDuringSchedulingIgnoredDuringExecution: - weight: 1 preference: matchExpressions: - key: env operator: In values: - production
-
支持逻辑组合:
matchExpressions
可以组合多个条件(AND 关系)。nodeSelectorTerms
是 OR 关系(满足任意一个即可)。
-
软性规则:
preferredDuringScheduling
允许设置权重(weight
),调度器会优先满足高权重的规则。
3. 使用场景对比
场景 | nodeSelector |
Node Affinity |
---|---|---|
简单标签匹配 | ✅ 适合(如 disktype=ssd ) |
⚠️ 可用,但过于复杂 |
多条件组合 | ❌ 不支持 | ✅ 支持(如 disktype=ssd AND region!=us-west ) |
软性调度偏好 | ❌ 不支持 | ✅ 支持(如优先调度到 env=production 的节点) |
动态调整规则 | ❌ 需手动修改 Pod | ✅ 可通过 ConfigMap 或 Operator 动态更新 |
4. 兼容性与演进
-
nodeSelector
是早期功能,简单但功能有限。 -
Node Affinity
是后续引入的增强版,兼容nodeSelector
的功能(可通过简单规则实现相同效果),并提供了更强大的能力。 - 推荐:在新项目中优先使用
Node Affinity
,除非需求非常简单。
5. 如何选择?
- 使用
nodeSelector
如果:- 只需简单的标签匹配(如
env=prod
)。 - 不需要复杂的逻辑组合或软性规则。
- 只需简单的标签匹配(如
- 使用
Node Affinity
如果:- 需要多条件组合(如
disktype=ssd AND region!=us-west
)。 - 需要软性规则(如优先调度到高性能节点,但不强制)。
- 需要动态调整调度策略。
- 需要多条件组合(如
6. 示例对比
(1) 简单场景(nodeSelector
足够)
# 使用 nodeSelector
spec:
nodeSelector:
disktype: ssd
等价于:
# 使用 Node Affinity 的简单形式
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: disktype
operator: In
values:
- ssd
(2) 复杂场景(必须用 Node Affinity
)
# 需求:调度到 disktype=ssd 且 region!=us-west 的节点,优先选择 env=production 的节点
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: disktype
operator: In
values:
- ssd
- key: region
operator: NotIn
values:
- us-west
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 1
preference:
matchExpressions:
- key: env
operator: In
values:
- production
9 HPA!!!
1.什么是hpa
hpa是k8s集群内置的资源,全称为"HorizontalPodAutoscaler"。
可以自动实现Pod水平伸缩,说白了,在业务高峰期可以自动扩容Pod副本数量,在集群的低谷期,可以自动缩容Pod副本数量。
9.1 验证水平伸缩
2.1 创建Pod
[root@master231 horizontalpodautoscalers]# cat 01-deploy-hpa.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy-stress
spec:
replicas: 1
selector:
matchLabels:
app: stress
template:
metadata:
labels:
app: stress
spec:
containers:
# - image: jasonyin2020/oldboyedu-linux-tools:v0.1
- image: harbor250.oldboyedu.com/oldboyedu-casedemo/oldboyedu-linux-tools:v0.1
name: oldboyedu-linux-tools
args:
- tail
- -f
- /etc/hosts
resources:
requests:
cpu: 0.2
memory: 300Mi
limits:
cpu: 0.5
memory: 500Mi
---
apiVersion: autoscaling/v1
kind: HorizontalPodAutoscaler
metadata:
name: stress-hpa
spec:
maxReplicas: 5
minReplicas: 2
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: deploy-stress
targetCPUUtilizationPercentage: 95
[root@master231 horizontalpodautoscalers]#
[root@master231 horizontalpodautoscalers]# kubectl apply -f 01-deploy-hpa.yaml
deployment.apps/deploy-stress created
horizontalpodautoscaler.autoscaling/stress-hpa created
[root@master231 horizontalpodautoscalers]#
2.2 测试验证
[root@master231 horizontalpodautoscalers]# kubectl get deploy,hpa,po -o wide # 第一次查看发现Pod副本数量只有1个
NAME READY UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTOR
deployment.apps/deploy-stress 1/1 1 1 11s oldboyedu-linux-tools harbor250.oldboyedu.com/oldboyedu-casedemo/oldboyedu-linux-tools:v0.1 app=stress
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
horizontalpodautoscaler.autoscaling/stress-hpa Deployment/deploy-stress <unknown>/95% 2 5 0 11s
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod/deploy-stress-5d7c796c97-rzgsm 1/1 Running 0 11s 10.100.140.121 worker233 <none> <none>
[root@master231 horizontalpodautoscalers]#
[root@master231 horizontalpodautoscalers]# kubectl get deploy,hpa,po -o wide # 第N次查看发现Pod副本数量只有2个
NAME READY UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTOR
deployment.apps/deploy-stress 2/2 2 2 51s oldboyedu-linux-tools harbor250.oldboyedu.com/oldboyedu-casedemo/oldboyedu-linux-tools:v0.1 app=stress
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
horizontalpodautoscaler.autoscaling/stress-hpa Deployment/deploy-stress 0%/95% 2 5 2 51s
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod/deploy-stress-5d7c796c97-f9rff 1/1 Running 0 36s 10.100.203.150 worker232 <none> <none>
pod/deploy-stress-5d7c796c97-rzgsm 1/1 Running 0 51s 10.100.140.121 worker233 <none> <none>
[root@master231 horizontalpodautoscalers]#
彩蛋:(响应式创建hpa)
[root@master231 horizontalpodautoscalers]# kubectl autoscale deploy deploy-stress --min=2 --max=5 --cpu-percent=95 -o yaml --dry-run=client
2.3 压力测试
[root@master231 ~]# kubectl exec deploy-stress-5d7c796c97-f9rff -- stress --cpu 8 --io 4 --vm 2 --vm-bytes 128M --timeout 10m
stress: info: [7] dispatching hogs: 8 cpu, 4 io, 2 vm, 0 hdd
2.4 查看Pod副本数量
[root@master231 horizontalpodautoscalers]# kubectl get deploy,hpa,po -o wide
NAME READY UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTOR
deployment.apps/deploy-stress 3/3 3 3 4m3s oldboyedu-linux-tools harbor250.oldboyedu.com/oldboyedu-casedemo/oldboyedu-linux-tools:v0.1 app=stress
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
horizontalpodautoscaler.autoscaling/stress-hpa Deployment/deploy-stress 105%/95% 2 5 2 4m3s
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod/deploy-stress-5d7c796c97-f9rff 1/1 Running 0 3m48s 10.100.203.150 worker232 <none> <none>
pod/deploy-stress-5d7c796c97-rzgsm 1/1 Running 0 4m3s 10.100.140.121 worker233 <none> <none>
pod/deploy-stress-5d7c796c97-zxgp6 1/1 Running 0 3s 10.100.140.122 worker233 <none> <none>
[root@master231 horizontalpodautoscalers]#
[root@master231 horizontalpodautoscalers]#
2.5 再次压测
[root@master231 ~]# kubectl exec deploy-stress-5d7c796c97-rzgsm -- stress --cpu 8 --io 4 --vm 2 --vm-bytes 128M --timeout 10m
stress: info: [6] dispatching hogs: 8 cpu, 4 io, 2 vm, 0 hdd
[root@master231 ~]# kubectl exec deploy-stress-5d7c796c97-zxgp6 -- stress --cpu 8 --io 4 --vm 2 --vm-bytes 128M --timeout 10m
stress: info: [7] dispatching hogs: 8 cpu, 4 io, 2 vm, 0 hdd
2.6 发现最多有5个Pod创建
[root@master231 horizontalpodautoscalers]# kubectl get deploy,hpa,po -o wide
NAME READY UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTOR
deployment.apps/deploy-stress 5/5 5 5 5m50s oldboyedu-linux-tools harbor250.oldboyedu.com/oldboyedu-casedemo/oldboyedu-linux-tools:v0.1 app=stress
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
horizontalpodautoscaler.autoscaling/stress-hpa Deployment/deploy-stress 249%/95% 2 5 5 5m50s
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod/deploy-stress-5d7c796c97-dnlzj 1/1 Running 0 34s 10.100.203.180 worker232 <none> <none>
pod/deploy-stress-5d7c796c97-f9rff 1/1 Running 0 5m35s 10.100.203.150 worker232 <none> <none>
pod/deploy-stress-5d7c796c97-ld8s9 1/1 Running 0 19s 10.100.140.123 worker233 <none> <none>
pod/deploy-stress-5d7c796c97-rzgsm 1/1 Running 0 5m50s 10.100.140.121 worker233 <none> <none>
pod/deploy-stress-5d7c796c97-zxgp6 1/1 Running 0 110s 10.100.140.122 worker233 <none> <none>
[root@master231 horizontalpodautoscalers]#
[root@master231 horizontalpodautoscalers]#
2.7 取消压测后
需要等待10min会自动缩容Pod数量到2个。
[root@master231 horizontalpodautoscalers]# kubectl get deploy,hpa,po -o wide
NAME READY UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTOR
deployment.apps/deploy-stress 2/2 2 2 20m oldboyedu-linux-tools harbor250.oldboyedu.com/oldboyedu-casedemo/oldboyedu-linux-tools:v0.1 app=stress
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
horizontalpodautoscaler.autoscaling/stress-hpa Deployment/deploy-stress 0%/95% 2 5 5 20m
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod/deploy-stress-5d7c796c97-dnlzj 1/1 Running 0 15m 10.100.203.180 worker232 <none> <none>
pod/deploy-stress-5d7c796c97-f9rff 1/1 Running 0 20m 10.100.203.150 worker232 <none> <none>
pod/deploy-stress-5d7c796c97-ld8s9 1/1 Terminating 0 14m 10.100.140.123 worker233 <none> <none>
pod/deploy-stress-5d7c796c97-rzgsm 1/1 Terminating 0 20m 10.100.140.121 worker233 <none> <none>
pod/deploy-stress-5d7c796c97-zxgp6 1/1 Terminating 0 16m 10.100.140.122 worker233 <none> <none>
[root@master231 horizontalpodautoscalers]#
[root@master231 horizontalpodautoscalers]#
[root@master231 horizontalpodautoscalers]# kubectl get deploy,hpa,po -o wide
NAME READY UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTOR
deployment.apps/deploy-stress 2/2 2 2 21m oldboyedu-linux-tools harbor250.oldboyedu.com/oldboyedu-casedemo/oldboyedu-linux-tools:v0.1 app=stress
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
horizontalpodautoscaler.autoscaling/stress-hpa Deployment/deploy-stress 0%/95% 2 5 2 21m
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod/deploy-stress-5d7c796c97-dnlzj 1/1 Running 0 16m 10.100.203.180 worker232 <none> <none>
pod/deploy-stress-5d7c796c97-f9rff 1/1 Running 0 21m 10.100.203.150 worker232 <none> <none>
[root@master231 horizontalpodautoscalers]#
10 pod健康检查
[[pod探针probe]]
11 Pod的优雅终止及容器的生命周期postStart和preStop
root@master231 pods]# cat 16-pods-lifecycle-postStart-preStop.yaml
apiVersion: v1
kind: Pod
metadata:
name: lifecycle-poststart-prestop-001
spec:
volumes:
- name: data
hostPath:
path: /oldboyedu-linux
# 在pod优雅终止时,定义延迟发送kill信号的时间,此时间可用于pod处理完未处理的请求等状况。
# 默认单位是秒,若不设置默认值为30s。
# terminationGracePeriodSeconds: 60
terminationGracePeriodSeconds: 3
containers:
- name: c1
image: registry.cn-hangzhou.aliyuncs.com/cmy-k8s/apps:v1
volumeMounts:
- name: data
mountPath: /data
# 定义容器的生命周期。
lifecycle:
# 容器启动(command)之后做的事情,如果此函数未执行完成,容器始终处于:' ContainerCreating'状态。
postStart:
exec:
# command: ["tail","-f","/etc/hosts"]
command:
- "/bin/sh"
- "-c"
- "sleep 30;echo \"postStart at $(date +%F_%T)\" >> /data/postStart.log"
# 容器停止之前做的事情,这个时间受限于: terminationGracePeriodSeconds
preStop:
exec:
command:
- "/bin/sh"
- "-c"
- "sleep 20;echo \"preStop at $(date +%F_%T)\" >> /data/preStop.log"
[root@master231 pods]#