五、pod从入门到实战
实验环境
| 角色 | IP | 主机名 | 组件 | 硬件 |
|---|---|---|---|---|
| 控制节点 | 192.168.128.11 | k8s-master-01 | apiserver controller-manager scheduler etcd containerd | CPU:4vcpu 硬盘:100g 内存:4g 开启虚拟化 |
| 工作节点 | 192.168.128.21 | k8s-node-01 | kubelet kube-proxy containerd calico coredns | CPU:2vcpu 硬盘:50g 内存:2g 开启虚拟化 |
| 工作节点 | 192.168.128.22 | k8s-node-02 | kubelet kube-proxy containerd calico coredns | CPU:2vcpu 硬盘:50g 内存:2g 开启虚拟化 |
1.pod的基本概念
1.pod是k8s中最小的调度单元、每一个pod都有一个特殊的被称为根容器的Pause容器、k8s通过定义一个pod的资源、然后在pod里面运行容器、容器需要指定镜像、这样就可以用来运行具体的服务。
2.k8s为每个pod都分配了唯一的ip地址、(靠网络插件calico/flannel/weave分配)称为pod IP、一个pod里的容器与另外主机上的pod容器能够直接通信、pod里的容器共享存储、网络等。
4.pod需要调度到k8s集群中的工作节点来运行、具体调度到哪个节点、是根据scheduler调度器实现的。同一个pod中的容器会自动的分配到同一个node上
5.创建pod的时候可以指定挂载的存储卷、pod中的所有容器都可以访问共享券、允许这个容器共享数据、pod只要挂载持久化数据券、pod重启之后数据依然存在。

node、pod、容器的关系
node包含pod、pod包含容器、数量不定

为什么k8s会设计一个全新的pod的概念并且pod有这样特殊的组成结构
1:在一组容器作为一个单元的情况下,我们难以简单地对“整体” 进行判断及有效地行动。比如,一个容器死亡了,此时算是整体死亡么?是N/M 的死亡率么?引入业务无关并且不易死亡的Pause容器作为Pod的根容器,以它 的状态代表整个容器组的状态,就简单、巧妙地解决了这个难题。
- :Pod里的多个业务容器共享Pause容器的IP,共享Pause容器挂 接的Volume,这样既简化了密切关联的业务容器之间的通信问题,也很好地解 决了它们之间的文件共享问题。
pod的类型
1.普通pod: 一旦被创建就会被放入etcd中存储,随后会被Kubernetes Master调度到某个具体的Node上并进行绑定(Binding),随后该Pod被对应的Node上的kubelet进程 实例化成一组相关的Docker容器并启动。在默认情况下,当Pod里的某个容器停止时,Kubernetes 会自动检测到这个问题并且重新启动这个Pod(重启Pod 里的所有容器),如果Pod所在的Node宕机,就会将这个Node上的所有Pod 重新调度到其他节点上 。
2.静态pod: 并没被存放在Kubernetes的etcd存储里,而是被存放在某个具体的Node 上的一个具体文件中,并且只在此Node上启动、运行 。
yaml文件对pod的定义
k8s中所有资源对象都可以采用YAML或者JSON格式的文件来定义或描述、下面是我们在之前的HelloWorld例子里用到的myweb这个Pod的资源定义文件
apiVersion: v1 # 必填字段,指定Kubernetes API 版本(Pod 属于核心 API 组)
kind: Pod # 资源类型为 Pod,代表最小可调度单元
metadata: # 元数据部分,定义 Pod 的标识和附加信息
name: myweb # Pod 名称,需在命名空间内唯一
labels: # 标签键值对,label标签前面讲过
name: myweb # 标签键为 "name",值为 "myweb"(通常推荐使用更具体的标签如 app、env)
spec: # 规格部分,定义 Pod 的期望状态
containers: # 容器列表,一个 Pod 可包含多个容器
- name: myweb # 容器名称,需在 Pod 内唯一
image: kubeguide/tomcat-app:v1 # 容器镜像地址及版本(需确保镜像仓库可访问)
ports: # 容器暴露的端口列表(仅声明用途,不强制监听)
- containerPort: 8080 # 容器监听的端口(Tomcat 默认端口)
env: # 环境变量列表,用于向容器传递配置
- name: MYSQL_SERVICE_HOST # 环境变量名称(用于定义 MySQL 服务地址)
value: 'mysql' # 环境变量值,此处为服务名(依赖 Service 资源 "mysql" 的 DNS 解析)
- name: MYSQL_SERVICE_PORT # 环境变量名称(定义 MySQL 服务端口)
value: '3306'
//关于Event(可以看作是pod的日志)
Event是一个事件的记录,记录了事件的最早产生时间、最后重现时间、重复次数、发起者、类型,以及导致
此事件的原因等众多信息。Event通常会被关联到某个具体的资源对象上,是排查故障的重要参考信息。
我们之前在排查错误的时候、使用kubectl describe pod xxx 、一般如果有错误就会在enent这里描述
Name: my-pod
Namespace: my-namespace
...
Containers:
my-container:
Container ID: container-id
Image: my-image:latest
...
Conditions:
Type Status
---- ------
Initialized True
Ready True
ContainersReady True
PodScheduled True
...
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 3m default-scheduler Successfully assigned my-namespace/my-pod to node-1
Normal Pulled 2m kubelet, node-1 Container image "my-image:latest" already present on machine
Normal Created 2m kubelet, node-1 Created container my-container
Normal Started 2m kubelet, node-1 Started container my-container
...
//看一下上面的示例输出Events部分、
1.成功将my-namespace/my-pod(pod)注册到node-1
2.容器镜像已经存在本地缓存(说明有这个镜像、如果没有的话会去拉取)
3.创建容器4.启动容器
这就说明这个pod没有报错、如果有错误的话就会显示类如
Failed to pull image "xxx":
Error: image xxx not found、镜像没找到这种
Events常见错误及解决方法可以在这个网页查看
https://blog.csdn.net/justlpf/article/details/131127456
2.查看k8s支持哪些api版本
//查看K8s支持哪些api版本
kubectl api-versions
admissionregistration.k8s.io/v1
apiextensions.k8s.io/v1
apiregistration.k8s.io/v1
apps/v1
authentication.k8s.io/v1
authorization.k8s.io/v1
autoscaling/v1
autoscaling/v2
batch/v1
certificates.k8s.io/v1
coordination.k8s.io/v1
crd.projectcalico.org/v1
discovery.k8s.io/v1
events.k8s.io/v1
flowcontrol.apiserver.k8s.io/v1beta2
flowcontrol.apiserver.k8s.io/v1beta3
networking.k8s.io/v1
node.k8s.io/v1
operator.tigera.io/v1
policy/v1
projectcalico.org/v3
rbac.authorization.k8s.io/v1
scheduling.k8s.io/v1
storage.k8s.io/v1
v1
//v1是核心群组、同一个组有多个版本、分组进行管理、
3.pod的工作方式
自主式pod(直接定义一个pod资源)
可以理解为这种Pod没人管,存活跟任何人没关系(简称“孤儿”)
方式一
// 创建目录、用于之后存放yaml文件
mkdir -p /etc/kubernetes/yaml
// 创建yaml文件
cd /etc/kubernetes/yaml/
vi pod-tomcat.yaml
apiVersion: v1
kind: Pod
metadata:
name: tomcat-test
namespace: default
labels:
app: tomcat # Label that can be used for selectors
spec:
containers:
- name: tomcat-java
ports:
- containerPort: 8080
image: tomcat
imagePullPolicy: IfNotPresent
//创建pod
kubectl create -f pod-tomcat.yaml
//获取pod信息(筛选了app=tomcat标签的pod)、需要一定时间创建(拉取镜像会消耗时间)
//可以通过kubectl get pods进行查看
kubectl get pods -o wide -l app=tomcat
//删除pod
kubectl delete pods tomcat-test
//再次查看pod是否存在、结果为空、已经被删除、不会重建
kubectl get pods-l app=tomcat
方式二:通过kubectl run命令在命令行创建pod(知道即可、不建议使用这种方式)
//创建一个nginx的pod
kubectl run nginx--image=nginx
//查看pod
kubectl get pods-o wide
//测试访问(这个地址是刚才查看pod获取的、注意替换)
curl 10.244.85.210
通过控制器管理的pod
控制器管理的Pod可以确保Pod始终维持在指定的副本数运行、删除会自动重建
常见的管理pod的控制器: Replicaset、Deployment、Job、CronJob、 Daemonset、Statefulset
//通过deployment管理pod、注意上面的kind是pod、这个kin是Deployment
//创建yaml文件
cd /etc/kubernetes/yaml
vi pod-test-nginx.yaml
apiVersion: apps/v1 # 指定 API 版本
kind: Deployment # 资源类型为 Deployment
metadata:
name: nginx-test # Deployment 名称,需唯一
labels: # Deployment 自身的标签(可选)
app: nginx-deploy # 标签键值对间需空格,如 "key: value"
spec:
replicas: 2 # 副本数,位于 spec 下(非 selector 内)
selector: # 标签选择器,匹配 Pod 标签
matchLabels:
app: nginx # 必须与 template.metadata.labels 一致
template: # Pod 模板定义
metadata:
labels: # Pod 标签,需与 selector.matchLabels 匹配
app: nginx # 键值对间需空格
spec:
containers: # 容器列表,每个容器以 "-" 开头并缩进
- name: my-nginx # 容器名称
image: nginx # 镜像名称
imagePullPolicy: IfNotPresent # 镜像拉取策略(默认值可省略)
ports: # 容器暴露端口列表
- containerPort: 80 # 容器监听端口,
//更新资源清单文件
kubectl create -f pod-test-nginx.yaml
//查看Deployment
kubectl get pods -o wide -l nginx-deploy
//查看Replicaset
kubectl get rs -l app=nginx
//查看pod
kubectl get pods -o wide -l app=nginx
//删除pod(名称注意替换、前面会查到)
kubectl delete pods nginx-test-75c685fdb7-9s95h
//再次查看一下、发现删除的pod又被重新创建
kubectl get pods -o wide -l app=nginx
这个例子可以看到、通过Deployment管理的pod、可以确保pod始终维持在指定的数量
4.k8s是如何创建、删除一个pod资源的


一、Pod 创建流程
步骤1:用户提交 Pod 定义
- 操作:通过
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">kubectl apply -f pod.yaml</font>或 API 客户端提交 YAML/JSON 配置文件1****7。 - 示例配置:
yaml
复制
apiVersion: v1
kind: Pod
metadata:
name: my-pod
spec:
containers:
- name: nginx
image: nginx:1.17.1
步骤2:API Server 接收并持久化配置
- 验证:API Server 检查语法、权限及资源配额。
- 存储:配置写入 etcd 集群,确保数据一致性与持久性。
- 状态:Pod 初始状态为
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">Pending</font>,等待调度。
步骤3:调度器(Scheduler)介入
- 监听:调度器通过 Watch 机制发现未绑定的 Pod。
- 预选(Filtering):过滤不满足条件的节点(如资源不足、污点未容忍)。
- 评分(Scoring):对剩余节点按负载均衡、亲和性等策略打分,选择最优节点。
- 绑定:调度器通过 API Server 更新 Pod 的
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">nodeName</font>字段,写入 etcd。
步骤4:kubelet 启动容器
- 节点监听:目标节点的 kubelet 检测到绑定指令后,调用容器运行时(如 containerd)。
- 容器创建:
- 拉取镜像(若本地不存在且
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">imagePullPolicy</font>非<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">Never</font>)。 - 调用 CRI(容器运行时接口)创建容器,挂载存储卷,配置网络(通过 CNI)。
- 拉取镜像(若本地不存在且
- 健康检查:执行
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">livenessProbe</font>和<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">readinessProbe</font>,确保容器就绪。
步骤5:状态同步
- 状态上报:kubelet 将 Pod 状态(如
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">Running</font>)上报至 API Server。 - 持久化:API Server 将最终状态写入 etcd,用户可通过
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">kubectl get pods</font>查看。
二、Pod 删除流程
步骤1:用户触发删除命令
- 操作:执行
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">kubectl delete pod my-pod</font>或通过 API 发送删除请求。 - 宽限期:默认 30 秒(可通过
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">terminationGracePeriodSeconds</font>自定义)。
步骤2:标记 Pod 为 Terminating
- API Server 更新状态:Pod 状态从
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">Running</font>变为<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">Terminating</font>。 - 端点控制器动作:从关联的 Service 端点列表中移除该 Pod,停止流量转发。
步骤3:优雅终止(Graceful Shutdown)
- preStop 钩子:若配置,kubelet 同步执行用户定义的清理命令(如保存数据、关闭连接)。
- SIGTERM 信号:向容器主进程发送终止信号,允许程序自行关闭。
- 超时处理:若宽限期结束仍有进程运行,发送 SIGKILL 强制终止。
步骤4:资源清理与状态更新
- 资源释放:kubelet 清理容器占用的存储卷、网络命名空间等资源。
- 状态持久化:API Server 更新 Pod 状态为
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">Terminated</font>,并从 etcd 中删除记录810。 - 容器创建:
- 拉取镜像(若本地不存在且
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">imagePullPolicy</font>非<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">Never</font>) - 调用 CRI(容器运行时接口)创建容器,挂载存储卷,配置网络(通过 CNI)
- 拉取镜像(若本地不存在且
- 健康检查:执行
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">livenessProbe</font>和<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">readinessProbe</font>,确保容器就绪
5.状态同步
- 状态上报:kubelet 将 Pod 状态(如
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">Running</font>)上报至 API Server - 持久化:API Server 将最终状态写入 etcd,用户可通过
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">kubectl get pods</font>查看
5.pod定义详解
apiVersion: v1 # 必选,API 版本固定为 v1[2,3](@ref)
kind: Pod # 必选,资源类型为 Pod[2](@ref)
metadata: # 必选,元数据定义
name: string # 必选,Pod 名称(需唯一且符合 DNS 规范)[2](@ref)
namespace: string # 可选,命名空间(默认 `default`)[2](@ref)
labels: # 可选,标签(用于资源筛选)
- name: string # 自定义标签键值对[3](@ref)
annotations: # 可选,注解(存储元信息如版本、监控配置)
- name: string # 自定义注解键值对[3](@ref)
spec: # 必选,Pod 规格定义
containers: # 必选,容器列表(至少一个容器)
- name: string # 必选,容器名称(需唯一)[2](@ref)
image: string # 必选,容器镜像(必须包含版本标签)[6](@ref)
imagePullPolicy: [Always | Never | IfNotPresent] # 可选,镜像拉取策略(默认 `IfNotPresent`)[2](@ref)
command: [string] # 可选,覆盖容器默认启动命令[6](@ref)
args: [string] # 可选,启动命令参数[2](@ref)
workingDir: string # 可选,容器工作目录(默认 `/`)[2](@ref)
volumeMounts: # 可选,存储卷挂载配置
- name: string # 必选,存储卷名称(需与 volumes 一致)
mountPath: string # 必选,挂载路径(绝对路径)
readOnly: boolean # 可选,是否只读(默认 `false`)[2](@ref)
ports: # 可选,容器暴露端口列表
- name: string # 可选,端口名称(如 `http`)
containerPort: int # 必选,容器监听端口[6](@ref)
hostPort: int # 可选,宿主机端口(**不推荐使用**)[6](@ref)
protocol: string # 可选,协议(默认 `TCP`)[2](@ref)
env: # 可选,环境变量列表
- name: string # 必选,变量名(推荐大写)
value: string # 可选,变量值[2](@ref)
resources: # 可选,资源限制与请求
limits: # 资源上限(防止耗尽节点资源)
cpu: string # CPU 限制(单位:`m`,如 `500m`)
memory: string # 内存限制(单位:`Mi`/`Gi`)[6](@ref)
requests: # 资源请求(调度依据)
cpu: string # CPU 请求(初始分配)
memory: string # 内存请求[6](@ref)
livenessProbe: # 可选,存活探针(健康检查)
exec: # 探针方式三选一:exec/httpGet/tcpSocket
command: [string] # 执行命令(如 `["cat", "/health"]`)[4](@ref)
httpGet:
path: string # HTTP 检查路径(如 `/healthz`)
port: number # 检查端口
host: string # 主机名(默认 Pod IP)
scheme: string # 协议(HTTP/HTTPS)[4](@ref)
tcpSocket:
port: number # TCP 检查端口[4](@ref)
initialDelaySeconds: 0 # 首次探测延迟(建议 15-30 秒)[6](@ref)
timeoutSeconds: 0 # 超时时间(默认 1 秒)[4](@ref)
periodSeconds: 0 # 探测间隔(默认 10 秒)[4](@ref)
successThreshold: 0 # 成功阈值(默认 1)[6](@ref)
failureThreshold: 0 # 失败阈值(默认 3)[6](@ref)
securityContext: # 可选,安全上下文
privileged: false # 是否启用特权模式(**慎用**)[6](@ref)
restartPolicy: [Always | Never | OnFailure] # 可选,重启策略(默认 `Always`)[2](@ref)
nodeSelector: obeject # 可选,节点标签选择器(调度至特定节点)[2](@ref)
imagePullSecrets: # 可选,镜像拉取密钥(私有仓库)
- name: string # Secret 名称[6](@ref)
hostNetwork: false # 可选,是否使用宿主机网络(默认 `false`)[6](@ref)
volumes: # 可选,存储卷定义
- name: string # 存储卷名称(如 `config-volume`)
emptyDir: {} # 临时目录卷(与 Pod 生命周期一致)[6](@ref)
hostPath: # **不推荐**:宿主机目录挂载
path: string # 宿主机路径(存在安全风险)[6](@ref)
secret: # 安全存储卷类型:Secret
secretName: string # Secret 名称
items:
- key: string # Secret 键
path: string # 挂载路径[6](@ref)
configMap: # 安全存储卷类型:ConfigMap
name: string # ConfigMap 名称
items:
- key: string # ConfigMap 键
path: string # 挂载路径[6](@ref)
| 字段路径 | 类型 | 是否必选 | 默认值 | 说明 | 最佳实践建议 |
|---|---|---|---|---|---|
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">apiVersion</font> | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">string</font> | 必选 | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">v1</font> | K8s APi版本 | 始终使用 <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">v1</font> |
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">kind</font> | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">string</font> | 必选 | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">Pod</font> | 资源类型 | 优先使用 <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">Deployment</font> 管理Pod |
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">metadata.name</font> | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">string</font> | 必选 | - | Pod 名称(需唯一且符合 DNS 子域名规范) | 名称需体现业务语义如<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">nginx-frontend</font> |
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">metadata.namespace</font> | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">string</font> | 可选 | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">default</font> | Pod 所属命名空间 | 按环境划分命名空间(如 <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">prd</font>、<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">dev</font> |
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">metadata.labels</font> | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">map<string,string></font> | 可选 | - | 自定义标签(用于资源筛选) | 定义统一标签体系(如 <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">app: nginx</font>、<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">env: prod</font> |
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">metadata.annotations</font> | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">map<string,string></font> | 可选 | - | 自定义注解(存储元信息) | 记录构建版本、监控配置等非调度信息 |
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">spec.containers[].name</font> | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">string</font> | 必选 | - | 容器名称 | 名称需唯一且有意义(如 <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">nginx-container</font> |
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">spec.containers[].image</font> | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">string</font> | 必选 | - | 容器镜像地址 | 必须指定版本标签(如 <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">nginx:1.23.1</font>),避免使用 <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">latest</font> |
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">spec.containers[].imagePullPolicy</font> | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">string</font> | 可选 | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">IfNotPresent</font> | 镜像拉取策略:<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">Always</font><font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">IfNotPresent</font><font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">Never</font> | 若镜像标签为 <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">latest</font>,默认值会变为 <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">Always</font> |
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">spec.containers[].command</font> | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">[]string</font> | 可选 | - | 覆盖容器默认启动命令 | 优先使用镜像默认命令,仅在特殊场景覆盖 |
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">spec.containers[].args</font> | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">[]string</font> | 可选 | - | 启动命令参数 | 参数需与 <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">command</font> 配合使用 |
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">spec.containers[].workingDir</font> | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">string</font> | 可选 | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">/</font> | 容器工作目录 | 仅在需要指定非根目录时配置(如日志目录 <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">/var/log</font>) |
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">spec.containers[].volumeMounts[].name</font> | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">string</font> | 必选 | - | 存储卷名称(需与 <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">volumes[]</font>中的定义一致) | 存储卷名称需简洁明确(如 <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">config-volume</font>) |
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">spec.containers[].volumeMounts[].mountPath</font> | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">string</font> | 必选 | - | 存储卷挂载路径 | 路径需符合容器文件系统规范(如 <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">/etc/nginx</font> |
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">spec.containers[].volumeMounts[].readOnly</font> | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">boolean</font> | 可选 | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">false</font> | 是否以只读模式挂载 | 敏感配置文件建议设置为 <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">true</font> |
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">spec.containers[].ports[].name</font> | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">string</font> | 可选 | - | 端口名称(用于 Service 关联) | 名称需体现协议用途(如 <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">http</font>、 <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">metrics</font> |
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">spec.containers[].ports[].containerPort</font> | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">int</font> | 必选 | - | 容器监听端口 | 必须与容器内应用实际监听端口一致 |
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">spec.containers[].ports[].hostPort</font> | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">int</font> | 可选 | - | 宿主机监听端口 | 避免使用,会导致同一节点无法启动多个副本;优先使用 Service 暴露端 |
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">spec.containers[].ports[].protocol</font> | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">string</font> | 可选 | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">TCP</font> | 端口协议(<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">TCP</font>、<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">UDP</font>) | 仅需在非 TCP 协议时显式指 |
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">spec.containers[].env[].name</font> | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">string</font> | 必选 | - | 环境变量名称 | 名称需大写并用下划线分隔(如 <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">DB_HOST</font> |
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">spec.containers[].env[].value</font> | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">string</font> | 可选 | - | 环境变量值 | 敏感数据应通过 <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">secret</font>注入 |
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">spec.containers[].resources.limits.cpu</font> | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">string</font> | 可选 | - | CPU 限制(单位:<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">m</font>,如 <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">500m</font>表示 0.5 核) | 生产环境必填,防止容器耗尽节点资源 |
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">spec.containers[].resources.limits.memory</font> | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">string</font> | 可选 | - | 内存限制(单位:<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">Mi</font>或 <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">Gi</font>,如 <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">512Mi</font>) | 建议与 <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">requests</font>保持相同以避免超卖 |
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">spec.containers[].resources.requests.cpu</font> | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">string</font> | 可选 | - | CPU 请求(初始分配 | 调度依据,需合理设置 |
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">spec.containers[].resources.requests.memory</font> | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">string</font> | 可选 | - | 内存请求(初始分配) | 建议与 <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">limits</font> 一致6 |
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">spec.dnsPolicy</font> | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">string</font> | 可选 | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">ClusterFirst</font> | DNS 策略:<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">None</font>、 <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">Default</font>、 <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">ClusterFirst</font>、 <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">ClusterFirstWithHostNet</font> | 使用 <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">ClusterFirst</font>优先集群 DNS |
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">spec.hostAliases</font> | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">[]Object</font> | 可选 | - | 容器内 hosts 解析配置 | 优先使用 Service 名称替代硬编码 IP |
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">spec.volumes[].hostPath.path</font> | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">string</font> | 可选 | - | 宿主机目录挂载路径 | 不推荐,改用 <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">configMap</font>或 <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">secret</font> |
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">spec.volumes[].secret.secretName</font> | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">string</font> | 必选 | - | 引用的 Secret 名称 | 敏感数据(如密码)必须通过 Secret 管理 |
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">spec.volumes[].configMap.name</font> | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">string</font> | 必选 | - | 引用的 ConfigMap 名称 | 通用配置(如环境变量)建议使用 ConfigMap |
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">spec.livenessProbe.initialDelaySeconds</font> | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">int</font> | 可选 | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">0</font> | 容器启动后首次探测的等待时间 | 建议设为 <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">15-30</font>秒,避免过早检查导致误判 |
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">spec.restartPolicy</font> | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">string</font> | 可选 | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">Always</font> | 重启策略:<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">Always</font>、 <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">OnFailure</font>、 <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">Never</font> | 生产环境优先使用 <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">Deployment</font>管理重启策略 |
6.静态pod
1.静态Pod是由kubelet进行管理的仅存在于特定Node上的Pod。它们不能 通过APIServer进行管理,无法与ReplicationController、Deployment或者 DaemonSet进行关联,并且kubelet无法对它们进行健康检查。静态Pod总是由 kubelet创建的,并且总在kubelet所在的Node上运行。
- 创建静态Pod有两种方式:配置文件方式和HTTP方式
**创建静态pod(****配置文件**方式)
2.kubelet会定期扫描该目录、并根据该目录下的.yaml或者.json文件进行创建操作。
实战演练:修改k8s-node-01的kubelet文件参数实现静态pod
//编辑kubelet主配置文件(默认路径)
sudo vi /var/lib/kubelet/config.yaml
//查看是否有以下参数
staticPodPath: /etc/kubernetes/manifests # 指定静态Pod配置目录
//创建静态Pod配置目录
sudo mkdir -p /etc/kubernetes/manifests
//编写静态Pod配置文件(containerd专用格式)
sudo vi /etc/kubernetes/manifests/static-web.yaml
apiVersion: v1
kind: Pod
metadata:
name: static-web
labels:
app: static-nginx
spec:
containers:
- name: nginx
image: docker.io/library/nginx:alpine # 必须包含完整镜像地址
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
//重启服务并验证
sudo systemctl daemon-reload
sudo systemctl restart kubelet
//查看静态pod
crictl pods | grep static-web
crictl ps -a | grep nginx
kubectl get pods -o wide | grep static-web
//如果需要删除的话、删除静态文件、再重启kubelet就可以了
# 进入静态 Pod 配置目录
cd /etc/kubernetes/manifests
# 删除配置文件(以 static-web.yaml 为例)
sudo rm -f static-web.yaml
#重启 kubelet 服务(强制生效)
sudo systemctl restart kubelet
**创建静态pod(****http**方式)
--manifest-url:指定访问的URL。(已弃用,应该通过kubelet的--config 指定配置文件设置此参数。)经测试1.28版本可以正常使用。
**实战演练: :修改k8s-node01的kubelet文件参数实现静态Pod **
# 修改 kubelet 配置文件(kubeadm 部署的集群路径)
sudo vi /var/lib/kubelet/kubeadm-flags.env
# 添加 --manifest-url 参数(替换为你的 HTTP 地址)(注意是追加在后面)
--manifest-url=http://[你的服务器IP]:[端口]/static-pod.yaml"
//安装web服务、创建yaml文件
yum -y install nginx
systemctl restart nginx
//在站点内创建yaml文件
cd /usr/share/nginx/html/
vi static-web.yaml
apiVersion: v1
kind: Pod
metadata:
name: http-static-web
labels:
app: http-static-nginx
spec:
containers:
- name: nginx
image: docker.io/library/nginx:alpine
ports:
- containerPort: 80
//验证是否能正常访问站点文件
curl http://192.168.0.11:80/static-web.yaml
//重启kubelet服务
systemctl daemon-reload
systemctl restart kubelet && sleep 2 && systemctl status kubelet
//测试
//node节点查看容器是否启动
ctr -n k8s.io containers ls | grep nginx
sudo crictl ps -a | grep nginx
kubectl get pods -A -o wide | grep http-static-web
//master节点查看pod是否运行
kubectl get pods
如果需要清理
# 删除 Web 服务器上的 YAML 文件
sudo rm /usr/share/nginx/html/static-web.yaml
# 重启 Nginx 使配置失效
sudo systemctl restart nginx
sudo vi /var/lib/kubelet/kubeadm-flags.env
# 删除或注释 --manifest-url 参数(网页1、网页6)
KUBELET_KUBEADM_ARGS="--container-runtime-endpoint=unix:///run/containerd/containerd.sock --pod-infra-container-image=registry.aliyuncs.com/google_containers/pause:3.9"
sudo systemctl daemon-reload
sudo systemctl restart kubelet
7.pod资源限制
Request: 容器使用的最小资源需求,作为容器调度时资源分配的判断依赖。 只有当节点上可分配资源量大于等于容器资源请求数时才允许将容器调度到该 节点。但Request参数不限制容器的最大可使用资源。
Limit:容器能使用资源的资源的最大值,设置为0表示使用资源无上限。
Request能够保证Pod有足够的资源来运行,而Limit则是防止某个Pod无限制地使用资源,导致其他Pod崩溃。(如果Limit为0表示不对资源进行限制, 这时可以小于Request )
- 对于CPU,如果pod中服务使用CPU超过设置的limits,pod不会被kill 掉但会被限制。如果没有设置limits,pod可以使用全部空闲的cpu资源。
2.对于内存,当一个pod使用内存超过了设置的limits,pod中container 的进程会被kernel因OOM(内存超限) kill掉。当container因为OOM被kill掉时,系统 倾向于在其原所在的机器上重启该container或本机或其他重新创建一个pod。
3.CPU单位换算:100mCPU、100milli(毫核)CPU和0.1CPU都相同。1000m CPU=1CPU。
实战演练
创建一个nginx pod容器组。该机器必须有CPU 100毫核、内存1G的 空间,才能运行此容器。该容器最大只能使用500毫核CPU、2G内存。
//创建yaml文件
vi resource_nginx.yaml
apiVersion: v1 # [必填] Kubernetes API 版本(核心 Pod 资源固定为 v1)[1,5](@ref)
kind: Pod # [必填] 资源类型为 Pod[1,5](@ref)
metadata: # [必填] 元数据定义[5](@ref)
name: resource-nginx # [必填] Pod 名称(需唯一且符合 DNS 子域名规范)[1,5](@ref)
namespace: default # [可选] 命名空间(默认值为 default)[5](@ref)
labels: # [可选] 标签(用于资源筛选)[1,5](@ref)
app: nginx # 标签键值对(建议使用业务语义化命名,如 app: frontend)[5](@ref)
spec: # [必填] Pod 规格定义[5](@ref)
containers: # [必填] 容器列表[1,5](@ref)
- name: resource-nginx # [必填] 容器名称(需唯一)[5](@ref)
ports: # [可选] 端口定义[5](@ref)
- containerPort: 80 # [必填] 容器实际监听端口(需与容器内应用一致)[5](@ref)
image: nginx:latest # [必填] 镜像地址(必须指定版本,如 nginx:1.25,禁止使用 latest)[1,5](@ref)
imagePullPolicy: IfNotPresent # [可选] 镜像拉取策略(若镜像有版本标签,默认值为 IfNotPresent)[5](@ref)
resources: # [可选] 资源限制与请求(生产环境必填)[7,8](@ref)
requests: # 资源请求量(调度依据)[7,8](@ref)
memory: "1024Mi" # 内存请求(单位:MiB,此处为 1GB)[7,8](@ref)
cpu: "100m" # CPU 请求(单位:m,此处为 0.1 核)[7,8](@ref)
limits: # 资源上限(防止节点资源耗尽)[7,8](@ref)
memory: "2048Mi" # 内存限制(2GB,超出将触发 OOM 终止)[7,8](@ref)
cpu: "500m" # CPU 限制(0.5 核,超出将触发 CPU 限流)[7,8](@ref)
//创建pod资源
kubectl apply -f resource_nginx.yaml
//查看创建的pod
kubectl get pods
//查看pod的详细信息
kubectl describe pods resource-nginx

可以看到我们已经对容器做了限制。运行该pod的node节点至少要有CPU 100 毫核、内存1G的空间。该pod最大只能使用500mCPU、2G内存资源。
在生产环境、我们只需要选择容器最大使用资源即可
8.Node节点选择器
在生产环境中、k8s集群的所有节点会配置不一、我们在创建pod资源的时候、pod会根据schduler调度器进行调度、会默认随机调度到一个节点上、但是有时候我们想将pod调度到指定节点、或者调度到一些具有某些特征的节点
可以使用pod中的nodeName或者nodeSelector字段指定要调度到的node节点
根据node名称进行调度
k8s中的nodename是指将pod强制调度到一个特定的节点、但是节点不可用的话、pod将无法被调度
实战演练:调度tomcat pod容器到k8s-node-02节点
//创建yaml文件
vi node02-tomcat.yaml
apiVersion: v1
kind: Pod
metadata:
name: node02-tomcat
labels:
name: tomcat
spec:
nodeName: k8s-node-02 # 修正此处
containers:
- name: static-tomcat
image: tomcat:8.5-jre8-alpine
ports:
- name: tomcat
containerPort: 8080
//更新资源清单文件
kubectl apply -f node02-tomcat.yaml
//查看pod调度到哪个节点
kubectl get pods -o wide
根据node标签进行调度
k8s中的nodeSelector是用于指定Pod调度节点的标签选择器, 可以确保将Pod调度到具有特定属性的节点上。
**实战演练:一个基于Java的Web应用,它需要运行在拥有很多内存和处理器的节点上,以便应用程序可以高效地执行。你的 Kubernetes 集群中有许多节点,但只有几个节点可以分配给这个Web应用。这个时候可以使用NodeSelector标签来标记那些有适合的硬件资源的节点,并在Pod YAML文件中指定节点选择器,以将该Pod分配给适合的节点。 **
//创建yaml文件
vi nodeSelector-node01.yaml
apiVersion: v1
kind: Pod
metadata:
name: java-web
labels:
name: tomcat
spec:
nodeSelector:
high-memory: "true"
high-cpu: "true"
containers:
- name: java-web
image: tomcat:8.5-jre8-alpine
ports:
- name: tomcat
containerPort: 8080
//对节点打标签
kubectl label nodes k8s-node-01 high-memory=true high-cpu=true
//查看节点标签
kubectl describe nodes k8s-node-01
//或者
kubectl get nodes k8s-node-01 --show-labels
//更新资源清单文件
kubectl apply -f nodeSelector-node01.yaml
//查看pod调度到哪个节点
kubectl get pods -o wide
//在这个示例中,Pod配置文件中的nodeSelector字段指定将Pod调度到拥有标有high-memory=true和high-cpu=true的标签的节点上。
需要注意的是,nodeSelector条件只有在全都匹配时才会将Pod调度到目标节点上。这意味着,如果节点上缺少某些标签,则该节点将无法用于Pod调度。
9.node节点亲和性
1.由nodeAffinity字段完成
- prefered 表示有节点尽量满足这个位置定义的亲和性,这不是一个必须的条件,软亲和性。
3.require 表示必须有节点满足这个位置定义的亲和性,这是个硬性条件,硬亲和性。
4.IgnoredDuringExecution 的意思是:如果一个 Pod所在的节点在Pod运行 期间标签发生了变更,不再符合该Pod的节点亲和性需求,则系统将忽略Node 上Label 的变化,该Pod能继续在该节点运行。
//查看node节点亲和性的解释
kubectl explain pods.spec.affinity.nodeAffinity
字段说明
| 字段路径 | 类型 | 说明 |
|---|---|---|
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">nodeAffinity</font> | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);"><Object></font> | 节点亲和性配置。 |
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">nodeAffinity.preferredDuringSchedulingIgnoredDuringExecution</font> | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);"><[]Object></font> | 软限制:调度器优先尝试满足规则,若无匹配节点仍会调度 Pod。 |
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">nodeAffinity.preferredDuringSchedulingIgnoredDuringExecution.weight</font> | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);"><integer></font> | 规则权重(1-100),优先级越高权重越大。 |
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">nodeAffinity.preferredDuringSchedulingIgnoredDuringExecution.preference</font> | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);"><Object></font> | 节点选择器配置,与权重关联。 |
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">nodeAffinity.preferredDuringSchedulingIgnoredDuringExecution.preference.matchExpressions</font> | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);"><[]Object></font> | 基于节点标签的匹配规则列表(如 <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">key: values</font>)。 |
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">nodeAffinity.preferredDuringSchedulingIgnoredDuringExecution.preference.matchFields</font> | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);"><[]Object></font> | 基于节点字段的匹配规则列表(如 <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">metadata.name</font>)。 |
2. requiredDuringSchedulingIgnoredDuringExecution(硬亲和性)
| 字段路径 | 类型 | 说明 |
|---|---|---|
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution</font> | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);"><Object></font> | 硬限制:调度器必须满足规则才会调度 Pod。 |
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution.nodeSelectorTerms</font> | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);"><[]Object></font> | 节点选择器条件列表(多个条件间为“或”关系)。 |
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution.nodeSelectorTerms.matchExpressions</font> | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);"><[]Object></font> | 基于节点标签的匹配规则列表(如 <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">key: values</font>)。 |
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution.nodeSelectorTerms.matchFields</font> | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);"><[]Object></font> | 基于节点字段的匹配规则列表(如 <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">metadata.name</font>)。 |
节点标签匹配操作符(Operator)对照表
| 操作符 | 示例规则 | 匹配条件 | 说明 |
|---|---|---|---|
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">In</font> | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">key: ["v1"]</font> | 节点标签 必须包含 <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">key: v1</font> | 精确匹配标签的 <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">key</font>和 <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">value</font> |
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">NotIn</font> | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">key: ["v1"]</font> | 节点标签 必须不包含 <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">key: v1</font> | 排除指定 <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">key</font>和 <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">value</font>的节点。 |
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">Exists</font> | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">key: []</font> | 节点 必须存在 <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">key</font>(值任意) | 仅检查 <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">key</font>是否存在,不限制 <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">value</font> |
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">DoesNotExist</font> | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">key: []</font> | 节点 必须不存在 <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">key</font> | 排除所有包含指定 <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">key</font>的节点。 |
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">Gt</font> | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">key: ["3"]</font> | 节点标签值 必须大于 <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">3</font>(数值或字母序) | 要求 <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">value</font>为数字或可比较的字符串。 |
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">Lt</font> | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">key: ["5"]</font> | 节点标签值 必须小于 <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">5</font>(数值或字母序) | 同上,但比较方向相反。 |
node节点硬亲和性实践

案例实战:匹配满足合适node节点key:value标签进行调度( (operator: In )
// 创建yaml文件
vi pod-nodeaffinity-httpd.yaml
apiVersion: v1 # API 版本
kind: Pod # 资源类型为 Pod
metadata:
name: pod-node-affinity-apache # Pod 名称
namespace: default # 所属命名空间
labels: # 自定义标签
app: apache # 应用标签
web: https # 网络协议标签
spec:
containers: # 容器配置
- name: apache # 容器名称
image: httpd:latest # 容器镜像
affinity: # 亲和性配置
nodeAffinity: # 节点亲和性
requiredDuringSchedulingIgnoredDuringExecution: # 硬性调度要求
nodeSelectorTerms: # 节点选择条件列表
- matchExpressions: # 标签匹配表达式
- key: web # 匹配的标签键
operator: In # 操作符:标签值必须在指定列表中
values: # 允许的标签值列表
- http # 允许值1
- https # 允许值2
//上面的yaml文件是硬性匹配、如果找不到匹配节点、pod会处于pending状态、节点的web必须是http或者https才能调度
//更新清单文件
kubectl apply -f pod-nodeaffinity-httpd.yaml
//查看pod状态
kubectl get pods
//查看pod详细信息(看一下node节点是否满足了硬性条件、label是否有http或者https、或者镜像是否拉取失败)
kubectl describe pods pod-node-affinity-apache
//看一下是否有报错、根据报错内容进行调整
//再次查看pid状态
kubectl get pods -o wide
**实例二: 匹配node节点拥有key标签时,进行pod调度(operator:Exists) **
//创建yaml文件
vi pod-nodeaffinity-nginx.yaml
apiVersion: v1 # Kubernetes API 版本声明
kind: Pod # 定义资源类型为 Pod
metadata:
name: pod-node-affinity-nginx # Pod 名称标识
namespace: default # 部署到默认命名空间
labels:
app: web-nginx # 应用标签,标识为 nginx 服务
spec:
containers:
- name: nginx # 容器名称
image: nginx:latest # 使用最新版 nginx 镜像
affinity: # 亲和性配置段
nodeAffinity: # 节点亲和性配置
requiredDuringSchedulingIgnoredDuringExecution: # 硬性调度规则(调度时必须满足)
nodeSelectorTerms: # 节点选择条件组(OR 逻辑)
- matchExpressions: # 标签匹配表达式组(AND 逻辑)
- key: zone # 目标节点标签键
operator: Exists # 操作符:节点必须存在 zone 标签
values: [] # Exists 操作符必须为空列表(语法要求)
//使用匹配表达式(matchExpressions)要求节点必须包含zone的标签,但是这个zone标签的值可以是空值。这里的Exists运算符表示只要存在zone标
签即可,而与其值是否为空无关。
//创建pod
kubectl apply-f pod-nodeaffinity-nginx.yaml
//查看pod状态
kubectl get pods
//查看pod详细信息
kubectl describe pods pod-node-affinity-apache
//看一下是否有报错、根据报错内容进行调整
//再次查看pid状态
kubectl get pods -o wide
node节点软亲和性实战
1、Pod1软亲和性策略为匹配key为zone,value为foo,满足条件的节点 为k8s-node02 节点。因此Pod1会调度到k8s-node02,若不满足条件,则随机调度。
2、Pod2 软亲和性策略为匹配key为zone1,value值为app或foo,没有能满足条件的节点。因此Pod2会进行随机调度,具体调度到哪个工作节点,我们没办法控制。

**案例实战:匹配满足合适node节点key:value标签进行pod调度(operator:In), 如果不满足,也可以随机调度到Node节点上。 **
//在master节点创建yaml文件
vi pod-node-affinity-demo-1.yaml
apiVersion: v1 # Kubernetes API 版本
kind: Pod # 资源类型为 Pod
metadata:
name: pod-node-affinity-demo-1 # Pod 名称
namespace: default # 部署到默认命名空间
labels: # Pod 标签
app: myapp # 应用标识
tier: frontend # 层级标识(前端)
spec:
containers:
- name: myapp # 容器名称
image: ikubernetes/myapp:v1 # 容器镜像地址
affinity: # 亲和性配置
nodeAffinity: # 节点亲和性设置
preferredDuringSchedulingIgnoredDuringExecution: # 软亲和性规则
- preference: # 偏好条件
matchExpressions: # 标签匹配表达式
- key: zone1 # 节点标签键
operator: In # 操作符:值必须在指定列表中
values: # 可接受的值列表
- foo1 # 可选值1
- bar1 # 可选值2
weight: 60 # 偏好权重(范围1-100)
//创建pod
kubectl apply pod-node-affinity-demo-1.yaml
//查看pod
kubectl get pods -o wide
//查看k8s-node-02节点标签、发现节点不符合单依然运行了pod
kubectl describe nodes k8s-node02
** 实例2:节点软亲和性权值值实战**
分析一下:pod是调度到node-01还是node-02
//给node节点打标签
kubectl label nodes k8s-node01 app=java
kubectl label nodes k8s-node02 app=go
//在master节点创建yaml文件
cat pod-node-affinity-demo-2.yaml
apiVersion: v1 # Kubernetes API 版本
kind: Pod # 资源类型为 Pod
metadata:
name: pod-node-affinity-demo-2 # Pod 名称
namespace: default # 部署到默认命名空间
spec:
containers:
- name: with-node-affinity # 容器名称
image: ikubernetes/myapp:v1 # 容器镜像
affinity: # 亲和性配置
nodeAffinity: # 节点亲和性设置
preferredDuringSchedulingIgnoredDuringExecution: # 软亲和性规则(多条件)
- weight: 1 # 规则1权重(低优先级)
preference:
matchExpressions:
- key: app # 匹配节点标签键
operator: In # 操作符:值在列表中
values: # 可接受的值
- java # 可选值1
- weight: 50 # 规则2权重(高优先级)
preference:
matchExpressions:
- key: app # 匹配节点标签键
operator: In
values:
- go # 可选值2
//创建pod
kubectl apply pod-node-affinity-demo-2.yaml
//查看pod、发现调度到了node-02、说明权重越大、优先级越高、我们go的权重是50、java的权重只有1
kubectl get pods-o wide
注意事项
●如果同时定义了nodeSelector和nodeAffinity,那么必须两个条件都 得到满足,Pod才能最终运行在指定的Node上。
● 如果nodeAffinity指定了多个nodeSelectorTerms,那么其中一个能 够匹配成功即可。
● 如果在nodeSelectorTerms 中有多个matchExpressions,则一个节点 必须满足所有matchExpressions才能运行该Pod。
10.pod节点亲和性
是由affinity字段来完成的
//查看相关语法
kubectl explain pods.spec.affinity
字
Pod亲和性(podAffinity)字段详解表
| 字段路径 | 字段类型 | 说明 | 示例或注意事项 |
|---|---|---|---|
**<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">podAffinity.preferredDuringSchedulingIgnoredDuringExecution</font> | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">[]Object</font> | 软亲和性规则:调度器优先尝试满足条件,但不强制。若条件不满足,仍会调度Pod。 | 权重范围 <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">1-100</font>,权重越高优先级越高 4 |
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">podAffinity.preferred...weight</font> | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">integer</font> | 权重值:表示该规则的优先级。调度器通过权重总和选择最优节点。 | 示例:<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">weight: 60</font>表示该规则的优先级为60 |
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">podAffinity.preferred...podAffinityTerm</font> | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">Object</font> | 亲和性条件:定义Pod需要满足的标签和拓扑规则。 | 必须包含 <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">labelSelecr</font>和 <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">topologyKey</font> |
**<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">podAffinityTerm.labelSelector</font> | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">Object</font> | 标签选择器:选择目标Pod的标签规则。 | 示例:<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">matchExpressions: {key: app, operator: In, values: ["web"]}</font> |
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">podAffinityTerm.namespaceSelector</font> | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">Object</font> | 命名空间选择器:通过标签选择目标Pod所在的命名空间。 | 若未指定,默认使用当前Pod的命名空间 |
**<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">podAffinityTerm.namespaces</font> | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">[]string</font> | 命名空间列表:直接指定目标Pod所在的命名空间。 | 与 <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">namespaceSelector</font>互斥,优先级更高 |
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">podAffinityTerm.topologyKey</font> | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">string</font> | 拓扑域键:定义“同一位置”的节点标签键。 | 示例:<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">kubernetes.io/hostname</font>(同一节点)、 <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">failure-domain.beta.kubernees.io/zone</font>(同一区域) |
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">podAffinity.requiredDuringSchedulingIgnoredDuringExecution</font> | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">[]Object</font> | 硬亲和性规则:必须满足的条件,否则Pod处于Pending状态。 | 示例:强制Pod调度到带有特定标签的节点 |
1. <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">topologyKey</font> 的核心作用**
- 定义“同一位置”:通过节点标签的键划分拓扑域。例如:
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">topologyKey: kubernetes.io/hostname</font>:同一节点视为同一位置。<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">topologyKey: failure-domain.beta.kubernetes.io/zone</font>:同一可用区视为同一位置。
- 多级拓扑域:支持自定义标签(如
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">rack</font>、<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">row</font>)实现多级调度策略。
2. <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">namespaceSelector</font> vs <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">namespaces</font>
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">namespaceSelector</font>:通过标签动态选择命名空间(如 <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">env: prod</font>)。
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">namespaces</font>:直接指定命名空间名称列表(如 <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">["default", "backend"]</font>)。
3. 软硬亲和性对比
| 类型 | 行为 | 典型场景 |
|---|---|---|
软亲和性**<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">preferred</font>** | 优先但不强制,调度失败仍继续。 | 优化性能(如优先同区域调度) |
硬亲和性**<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">required</font>** | 必须满足,否则Pod无法调度。 | 强合规性(如数据本地化、安全隔离) |
1.podAffinity硬亲和性实战

1、创建了一个名为mysql的pod容器,标签为app=mysql,在默认default 命名空间中创建。
2、当Web Pod进行调度时,是通过matchExpressions和namespaces进行 匹配的,这里用了强匹配,必须是default命名空间下的pod,pod标签必须是 app=mysql,如果找不到app=mysql标签,那么Web Pod将会是Pending状态。
3、当mysql pod容器调度到了k8s-node-01节点,如果web pod的yaml文 件中topologKey 的值,k8s-node01 节点标签中没有这个key,那么他们就不是 “同一位置”,那么也会无法调度,Web Pod将会是Pending状态
//创建第一个pod-编写yaml文件
vi pod-required-affinity-demo-1.yaml
apiVersion: v1
kind: Pod
metadata:
name: mysql
labels:
app: mysql
spec:
containers:
- name: mysql
image: nginx:latest
//创建pod
kubectl apply -f pod-required-affinity-demo-1.yaml
//查看pod
kubectl get pods -o wide
//确认topologykey关键字
kubectl get nodes --show-labels
//创建第二个pod、让第二个pod跟着第一个pod调度
vi pod-required-affinity-demo-2.yaml
apiVersion: v1
kind: Pod
metadata:
name: web # Pod 名称标识
labels:
app: web # Pod 标签,标识为 web 应用
spec:
containers:
- name: web # 容器名称
image: nginx:latest # 使用最新版 nginx 镜像
imagePullPolicy: IfNotPresent # 镜像拉取策略(本地存在则不拉取)
affinity: # 亲和性配置
podAffinity: # Pod 亲和性规则
requiredDuringSchedulingIgnoredDuringExecution: # 硬亲和性规则(必须满足)
- labelSelector: # 目标 Pod 的标签选择器
matchExpressions: # 标签匹配表达式
- key: app # 匹配标签键
operator: In # 操作符:包含在指定值列表中
values: ["mysql"] # 目标 Pod 必须包含标签 app=mysql
namespaces: ["default"] # 目标 Pod 所在的命名空间(默认不指定则为当前命名空间)
topologyKey: kubernetes.io/hostname # 拓扑域键(必须字段),定义「同一位置」的规则
//应用yaml文件
kubectl apply -f pod-required-affinity-demo-2.yaml
//查看pod
kubectl get pods -o wide
//定义了一个名为web的Pod,使用Nginx作为容器运行时的镜像。除此之外,配置文件中还指定了Pod对应的标签、拉取镜像的策略,以及Pod的调度策略。
特别地,Pod给出了亲和性规则,表明此Pod只应该部署在带有mysql标签的Pod所在的节点上。同时,只有命名空间为default的这些Pod所在的节点才会被考
虑为可行的部署节点。最后,使用kubernetes.io/hostname这个主机名作为节点的拓扑关键字进行调度
为什么要用kubernetes.io/hostname关键字?
每个节点都有“kubernetes.io/hostname=节点名”的标签,他们不是“同 一位置”,但是为什么还要用kubernetes.io/hostname呢? 假如node01节点有一个标签name=zhang,node02节点有一个标签name=zyf, 那么这两个节点不是“同一位置”;node01节点有一个标签name=zhang,node02 节点有一个标签name=zhang,那么这两个节点是“同一位置”。 在下面的yaml中指定“topologyKey:kubernetes.io/hostname”,这里只 指定了key,没有指定value,说明value可以是任意值。当pod调度到了node01 节点,那么topologyKey的value就是“kubernetes.io/hostname=k8s-node01”, 又使用了pod节点亲和性,那么就会跟随调度。
2.podAffinity软亲和性实战
目标: 创建一个mysql-1 pod,指定调度到k8s-node01节点。创建一 个mysql-2pod,指定调度到k8s-node02节点。创建webpod,使用podAffinity 软亲和性权重进行调度。

//创建第一个pod
vi pod-preferred-affinity-demo-1.yaml
apiVersion: v1
kind: Pod
metadata:
name: mysql-1
labels:
app: mysql-1
spec:
containers:
- name: mysql-1
image: nginx:latest
nodeName: k8s-node-01
//应用yaml文件
kubectl apply -f pod-preferred-affinity-demo-1.yaml
//查看pod
kubectl get pods -o wide
//创建第二个pod
vi pod-preferred-affinity-demo-2.yaml
apiVersion: v1
kind: Pod
metadata:
name: mysql-2 # Pod名称需符合DNS子域名规范(小写字母、数字、短横线)
labels: # 标签系统用于资源分类和服务发现
app: mysql-2 # 应用标识(建议配合tier标签如db/web)
# 建议补充标签(根据业务场景):
# tier: database # 层级标签(数据库层)
# environment: production # 环境标签(生产环境)
spec:
containers:
- name: mysql-2 # 容器名称(建议与镜像用途对应)
image: nginx:latest # 使用明确版本号代替latest(如nginx:1.23.4)
imagePullPolicy: IfNotPresent # 镜像拉取策略(默认值,本地存在则不拉取)
# 建议添加资源限制(参考网页1/3/6):
# resources:
# requests:
# memory: "512Mi" # 内存请求(调度依据)
# cpu: "500m" # CPU请求(500毫核)
# limits:
# memory: "1Gi" # 内存上限(防止OOM)
# cpu: "1000m" # CPU上限(避免资源耗尽)
nodeName: k8s-node02 # 硬性节点分配(需确保节点标签稳定性)
//应用yaml文件
kubectl apply -f pod-preferred-affinity-demo-2.yaml
//查看pod信息
kubectl get pods -o wide
//创建第三个pod、根据权重值进行调度
vi pod-preferred-affinity-demo-3.yaml
apiVersion: v1
kind: Pod
metadata:
name: web # Pod名称标识
labels:
app: web # 应用标签,标识为web服务
spec:
containers:
- name: web # 容器名称
image: nginx:latest # 使用最新版nginx镜像
imagePullPolicy: IfNotPresent # 镜像拉取策略(本地存在则不拉取)
affinity:
podAffinity:
preferredDuringSchedulingIgnoredDuringExecution: # 软亲和性规则(多条件)
- weight: 10 # 规则1权重(低优先级)
podAffinityTerm:
labelSelector:
matchExpressions:
- key: app # 匹配目标Pod的标签键
operator: In # 操作符:值必须在列表中
values: ["mysql-1"] # 目标Pod需有app=mysql-1标签
namespaces: ["default"] # 目标Pod需在default命名空间
topologyKey: kubernetes.io/hostname # 拓扑域:同一节点视为同一位置
- weight: 50 # 规则2权重(高优先级)
podAffinityTerm:
labelSelector:
matchExpressions:
- key: app
operator: In
values: ["mysql-2"] # 目标Pod需有app=mysql-2标签
namespaces: ["default"]
topologyKey: kubernetes.io/hostname
//应用yaml文件
kubectl apply -f pod-preferred-affinity-demo-3.yaml
//查看pod信息
kubectl get pods -o wide
yaml文件说明
创建一个名为web的Pod,并在其中运行基础设施容器nginx:latest。此外,该Pod 的亲和性设置还配置了两个podAffinityPreferred项:
●第一个podAffinityPreferred项指定希望将该Pod调度到一个节点上,该节点上 运行着具有标签app=mysql-1且位于命名空间default中的Pod。此外,该节点必须与 kubernetes.io/hostname拓扑键匹配,并且该项的权重为10。
●第二个podAffinityPreferred项指定希望将该Pod调度到一个节点上,该节点上 运行着具有标签app=mysql-2且位于命名空间default中的Pod。此外,该节点必须与 kubernetes.io/hostname拓扑键匹配,并且该项的权重为50。
使用这个Pod配置文件,Kubernetes调度器将在符合上述要求的节点中选择一个节点来运行web容器,如果都不满足,则随机调度。
3. podAntiAffinity硬亲和性实战

//对上面yaml文件的说明
//创建第一个pod
vi pod-required-antaffinity-demo-1.yaml
apiVersion: v1
kind: Pod
metadata:
name: mysql
labels:
app: mysql
spec:
containers:
- name: mysql
image: nginx:latest
//应用yaml文件
kubectl apply -f pod-required-antaffinity-demo-1.yaml
//获取pod信息
kubectl get pods -o wide
//创建第二个pod、让第二个pod跟着第一个pod反着走
vi pod-required-antaffinity-demo-2.yaml
//应用yaml文件
kubectl apply -f pod-required-antaffinity-demo-2.yaml
apiVersion: v1
kind: Pod
metadata:
name: web # Pod名称标识
labels:
app: web # 应用标签,标识为web服务
spec:
containers:
- name: web # 容器名称
image: nginx:latest # 使用最新版nginx镜像
imagePullPolicy: IfNotPresent # 镜像拉取策略(本地存在则不拉取)
affinity:
podAntiAffinity: # Pod反亲和性配置
requiredDuringSchedulingIgnoredDuringExecution: # 硬性反亲和规则(必须满足)
- labelSelector:
matchExpressions:
- key: app # 匹配目标Pod的标签键
operator: In # 操作符:值必须在列表中
values: ["mysql"] # 目标Pod需有app=mysql标签
namespaces: ["default"] # 目标Pod需在default命名空间
topologyKey: kubernetes.io/hostname # 拓扑域:同一节点视为同一位置
//获取pod信息
kubectl get pods -o wide
//对上面yaml文件的说明
1.创建一个名为web的Pod,并在其中运行基础设施容器nginx:latest。此外,该Pod的亲和性设置有一个podAntiAffinity项:
2.该podAntiAffinity项指定希望将该Pod调度到一个节点上,该节点上不运行具有标签app=mysql的Pod。此外,该节点必须与kubernetes.io/hostname拓扑键匹配。
3.使用这个Pod配置文件,Kubernetes调度器将不会将该Pod调度到运行着具有app=mysql标签的Pod的节点上,从而实现了Pod之间的最小化调度约束。
4. podAntiAffinity软亲和性实战
目标:创建一个mysql-1 pod,指定调度到k8s-node01节点。创建一 个mysql-2 pod,指定调度到k8s-node02节点。创建web pod,使用 podAntiAffinity软亲和性权重进行调度。

//创建第一个pod
vi pod-preferred-antaffinity-demo-1.yaml
apiVersion: v1
kind: Pod
metadata:
name: mysql-1
labels:
app: mysql-1
spec:
containers:
- name: mysql-1
image: nginx:latest
nodeName: k8s-node01
//应用yaml文件
kubectl apply-f pod-preferred-antaffinity-demo-1.yaml
//获取pod信息
kubectl get pods-o wide
//创建第二个pod
vi pod-preferred-antaffinity-demo-2.yaml
apiVersion: v1
kind: Pod
metadata:
name: mysql-2 # Pod名称(需符合DNS命名规范)
labels:
app: mysql-2 # 应用标签(建议增加tier/environment等业务标签)
spec:
containers:
- name: mysql-2 # 容器名称(建议与业务关联)
image: nginx:latest # 容器镜像(生产环境建议使用固定版本号)
imagePullPolicy: IfNotPresent # 镜像拉取策略(IfNotPresent|Always|Never)
# 建议添加资源限制(生产环境必选):
# resources:
# requests:
# cpu: "500m"
# memory: "512Mi"
# limits:
# cpu: "1000m"
# memory: "1Gi"
# 建议添加健康检查:
# livenessProbe:
# httpGet:
# path: /
# port: 80
# initialDelaySeconds: 15
nodeName: k8s-node02 # 硬性节点绑定(直接指定节点名称)
//应用yaml文件
kubectl apply -f pod-preferred-antaffinity-demo-2.yaml
//获取pod信息
kubectl get pods -o wide
//创建第三个pod、根据权重值进行调度
vi pod-preferred-antaffinity-demo-3.yaml
apiVersion: v1
kind: Pod
metadata:
name: web # Pod名称标识
labels:
app: web # 应用标签,标识为web服务
spec:
containers:
- name: web # 容器名称
image: nginx:latest # 使用最新版nginx镜像(生产建议指定版本号)
imagePullPolicy: IfNotPresent # 镜像拉取策略(本地存在则不拉取)
affinity:
podAntiAffinity: # Pod反亲和性配置
preferredDuringSchedulingIgnoredDuringExecution: # 软反亲和规则(优先但不强制)
- weight: 10 # 规则1权重(低优先级)
podAffinityTerm:
labelSelector:
matchExpressions:
- key: app # 匹配目标Pod的标签键
operator: In # 操作符:值必须在列表中
values: ["mysql-1"] # 避免与app=mysql-1的Pod共置
namespaces: ["default"] # 目标Pod需在default命名空间
topologyKey: kubernetes.io/hostname # 拓扑域:同一节点视为同一位置
- weight: 50 # 规则2权重(高优先级)
podAffinityTerm:
labelSelector:
matchExpressions:
- key: app
operator: In
values: ["mysql-2"] # 更强烈避免与app=mysql-2的Pod共置
namespaces: ["default"]
topologyKey: kubernetes.io/hostname
### 关键配置解析(表格说明)
| 配置项 | 说明 | 生产环境建议 |
|--------|------|--------------|
| **preferredDuringScheduling** | 软反亲和规则,调度器尽量但不强制满足 | 适合非关键业务场景 |
| **weight: 50** | 规则优先级高于weight:10的规则 | 权重差应设置明显(如10/50/100) |
| **topologyKey** | 定义"共置"范围,hostname=节点级隔离 | 跨可用区隔离应使用:<br>`failure-domain.beta.kubernetes.io/zone` |
| **matchExpressions** | 支持复杂标签匹配逻辑 | 可组合使用NotIn/Exists等操作符 |
### 典型调度场景
1. **权重优先调度**:
- 首先尝试避开有`mysql-2`的节点(权重50)
- 其次尝试避开有`mysql-1`的节点(权重10)
- 若无法避开仍会调度
2. **多层级隔离**:
```yaml
# 扩展案例:实现节点级+可用区级隔离
topologyKey: failure-domain.beta.kubernetes.io/zone
//应用yaml文件
kubectl apply -f pod-preferred-antaffinity-demo-3.yaml
//获取pod信息
kubectl get pods -o wide
//对于上面yaml文件说明
用于创建一个名为web的Pod,并在其中运行基础设施容器nginx:latest。此外,该
Pod的亲和性设置有两个podAntiAffinity的preferred项:
●第一个preferred项指定希望将该Pod调度到一个节点上,该节点上不运行具有标
签app=mysql-1的Pod。此外,该节点必须与kubernetes.io/hostname拓扑键匹配,并且
该项的权重为10。
●第二个preferred项指定希望将该Pod调度到一个节点上,该节点上运行着具有标
签app=mysql-2的Pod的节点上。此外,该节点必须与kubernetes.io/hostname拓扑键匹
配,并且该项的权重为50。
使用这个Pod配置文件,Kubernetes调度器将优先将该Pod调度到不运行mysql-2的
Pod的节点,其次调度到不运行mysql-1的Pod的节点上。如果条件都不满足,则随机调度
5. podAntiAffinity生产案例
目标: 当前有两个机房(beijing和shanghai),需要部署一个nginx产品,副本 为两个,为了保证机房容灾高可用场景,需要在两个机房分别部署一个副本
//给每个机房的节点打上标签
kubectl label nodes k8s-node01 type=beijing
kubectl label nodes k8s-node02 type=shanghai
//创建yaml文件
vi nginx.yaml
apiVersion: apps/v1
kind: Deployment #注意这种通过Deployment创建的pod删除后会自动重建
metadata:
name: nginx # 部署名称
labels:
app: nginx # 部署标签
spec:
replicas: 2 # 副本数量
selector:
matchLabels:
app: nginx # 选择器标签(必须匹配template中的标签)
template:
metadata:
labels:
app: nginx # Pod模板标签
spec:
containers:
- name: nginx # 容器名称
image: nginx # 容器镜像(生产环境建议指定版本号)
ports:
- containerPort: 80 # 容器暴露端口
affinity: # 亲和性配置
podAntiAffinity: # Pod反亲和性
requiredDuringSchedulingIgnoredDuringExecution: # 硬性反亲和规则
- labelSelector:
matchExpressions:
- key: app # 匹配标签键
operator: In # 操作符:值必须在列表中
values: ["nginx"] # 避免与同应用的Pod共置
topologyKey: "kubernetes.io/hostname" # 拓扑域:同一节点
nodeAffinity: # 节点亲和性
requiredDuringSchedulingIgnoredDuringExecution: # 硬性节点规则
nodeSelectorTerms:
- matchExpressions:
- key: type # 节点标签键
operator: In # 操作符:值必须在列表中
values: # 修正:列表格式标准化
- "beijing" # 注意:每个值需要单独列出并用引号包裹
- "shanghai" # 只调度到指定区域的节点
### 关键配置解析(表格说明)
| 配置项 | 说明 | 生产建议 |
|--------|------|----------|
| **podAntiAffinity** | 确保2个副本不会部署到同一节点 | 适合有状态服务 |
| **topologyKey** | 使用节点级隔离(hostname) | 高可用场景可用`failure-domain.beta.kubernetes.io/zone` |
| **nodeAffinity** | 限制部署到特定区域节点 | 建议配合节点标签管理系统使用 |
//更新清单文件
kubectl apply -f nginx.yaml
//查看pod信息
kubectl get pods -o wide
//对于yaml文件的说明
●该Deployment的副本数目为2。
● Pod的标签包含一个名为“app: nginx”的标签,以便与Selector和其他部分匹
配。
●在Pod规格中,该文件使用了Pod反亲和性和节点亲和性,以确保每个节点将只被
一个Pod分配,并将Nodes和Pods部署在不同的机房中(北京和上海)。
●在节点亲和性的规则中,将节点标签“type”指定为“beijing”或“shanghai”,
以确保只有具有这些标签的节点才能承载Pod。
使用这个Deployment配置文件,Kubernetes集群将保证在不同的机房(北京和上海)
中运行Pod的实例,每个Pod将运行在不同的节点上以确保高可用性。同时,该文件中的亲
和性设置确保避免了在同一节点或同一机房内运行多个Pod实例的情况
11.pod污点和容忍
1.Pod污点(Taint)是一个标记,表示一个Node具有一 些特殊的或者不可接受的特征,例如某些基础设施故障或者一些不允许部署的资源。
2.Pod容忍(Toleration)是指一个Pod在调度时可以容忍(或者接受)Node 上存在的一些污点,从而将其调度到该节点上进行运行。
1.污点和容忍应用的场景
1. 专用节点隔离
- 场景:将特定节点(如 GPU 节点、高内存节点)仅用于运行特定类型的 Pod(如机器学习任务或数据库)。
- 实现:
- 污点设置:通过
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">kubectl taint node node01 gpu=true:NoSchedule</font>标记节点为专用 - 容忍配置:为需要硬件的 Pod 添加匹配的容忍,例如容忍
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">gpu=true</font>,确保只有这些 Pod 能被调度到该节点1****8。
- 污点设置:通过
- 优势:避免普通 Pod 占用专用资源,优化硬件利用率。
2. 节点维护与升级
- 场景:临时下线节点进行维护或升级,同时避免服务中断。
- 实现:
- 污点设置:使用
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">NoExecute</font>污点驱逐节点上的现有 Pod(如<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">kubectl taint node node02 maintenance=yes:NoExecute</font>)358。 - 容忍配置:关键服务 Pod 添加容忍并设置
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">tolerationSeconds</font>(如 7200 秒),允许其在维护期间短暂运行后自动迁移3****8。
- 污点设置:使用
- 优势:实现优雅驱逐,减少服务中断风险。
3. 安全与合规性隔离
- 场景:在安全敏感环境中隔离敏感工作负载(如金融数据处理 Pod)。
- 实现:
- 污点设置:为安全节点添加污点(如
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">security=high:NoSchedule</font>)5****7。 - 容忍配置:仅允许通过安全审计的 Pod 添加对应容忍,限制未授权访问5****7。
- 污点设置:为安全节点添加污点(如
- 优势:构建逻辑隔离的安全边界,满足合规要求。
4. 多租户资源预留
- 场景:为不同团队或项目预留节点资源,避免资源争抢。
- 实现:
- 污点设置:按租户标签标记节点(如
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">team=alpha:NoSchedule</font>)4****7。 - 容忍配置:各团队 Pod 仅容忍所属租户的污点,确保资源独占性4****7。
- 污点设置:按租户标签标记节点(如
- 优势:实现资源配额管理,提升多租户集群的公平性。
5. 节点故障自动处理
- 场景:自动驱逐因硬件故障(如磁盘损坏)或资源耗尽(如内存不足)导致的异常节点上的 Pod。
- 实现:
- 污点设置:Kubernetes 自动为问题节点添加内置污点(如
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">node.kubernetes.io/disk-pressure:NoExecute</font>)8****9。 - 容忍配置:关键服务(如 DaemonSet 管理的网络插件)配置容忍,确保其不受驱逐影响8****9。
- 污点设置:Kubernetes 自动为问题节点添加内置污点(如
- 优势:提升集群自愈能力,减少人工干预。
6. 负载均衡与容量规划
- 场景:避免节点过载,分散高负载 Pod。
- 实现:
- 污点设置:为高负载节点添加
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">PreferNoSchedule</font>污点,降低调度优先级6****9。 - 容忍配置:非关键 Pod 不配置容忍,优先调度到低负载节点6****9。
- 污点设置:为高负载节点添加
- 优势:动态平衡集群负载,优化资源分配效率。
2. 污点和容忍语法说明
pod污点可以使用以下三种模式之一进行定义
1、NoSchedule:仅影响pod调度过程,当pod能容忍这个节点污点,就可 以调度到当前节点,后来这个节点的污点改了,加了一个新的污点,使得之前调 度的pod不能容忍了,已运行的pod不会被处理、新pod调度受限
2、PreferNoSchedule:表示仅当没有其他可用的Node时才可以被调度,与 NoSchedule 不同的是,他会更加倾向于不在该Node上调度Pod。
3、NoExecute:既影响调度过程,又影响现存的pod对象,如果现存的pod 不能容忍节点后来加的污点,这个pod就会被驱逐
4.pod容忍是使用tolerations字段来进行定义的、
//查看pod容忍相关语法
kubectl explain pods.spec.tolerations
字段说明
| 字段名 | 是否必填 | 描述 | 示例值 | 注意事项 |
|---|---|---|---|---|
**<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">key</font>** | 可选 | 匹配污点的键(Key)。若为空且 <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">operator=Exists</font>,则容忍所有键的污点。 | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">"gpu"</font> | - 当 <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">operator=Exists</font>时,无需指定 <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">value</font> |
**<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">operator</font>** | 必填 | 定义键值匹配规则: <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">Equal</font>(精确匹配值)或 <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">Exists</font>(仅匹配键存在)。 | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">"Equal"</font>或 <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">"Exists"</font> | - <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">Exists</font>忽略 <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">value</font>字段 3 。 |
**<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">value</font>** | 条件必填 | 污点的值(Value)。仅在 <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">operator=Equal</font>时必须指定。 | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">"nvidia"</font> | - 与污点的值严格匹配(区分大小写) 1 。 |
**<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">effect</font>** | 可选 | 指定匹配的污点效应: <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">NoSchedule</font>、 <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">PreferNoSchedule</font>、 <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">NoExecute</font>。若为空则匹配所有效应。 | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">"NoExecute"</font> | - 若未指定,容忍所有效应 3 。 |
**<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">tolerationSeconds</font>** | 可选 | 仅对 <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">effect=NoExecute</font>有效,表示 Pod 容忍驱逐前在节点上的存活时间(秒)。 | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">3600</font> |
节点污点管理
//查看节点定义的污点
kubectl describe nodes k8s-master-01
//查看所有节点的污点信息
kubectl describe nodes | egrep "Name:|Taints:"
//给节点打污点
kubectl taint nodes k8s-node-01 node-type=production:NoSchedule
//删除节点污点
kubectl taint nodes k8s-node-01 node-type=production:NoSchedule-
3.污点和容忍应用实战
目标:给k8s-node02节点打上node-type=production:NoSchedule污点, 创建一个能够调度到k8s-node02节点的pod。
//给k8s-node-02打上node-type=production:NoSchedule污点
kubectl taint nodes k8s-node-02 node-type=production:NoSchedule
//查看node的污点信息
kubectl describe nodes k8s-node-02 |grep Taints
//方式一、创建一个能够调度到k8s-node-02节点的pod
//编写yaml文件
vi taint-1.yaml
apiVersion: v1
kind: Pod
metadata:
name: nginx
namespace: default
labels:
app: nginx
spec:
nodeSelector:
kubernetes.io/hostname: k8s-node02 # 强制调度到指定节点(需确保节点标签存在)
containers:
- name: nginx
image: nginx:latest
tolerations: # 容忍规则:允许调度到含特定污点的节点
- key: "node-type" # 需匹配的污点键(必填)[3,7](@ref)
operator: "Equal" # 匹配规则:Equal(精确匹配值)或 Exists(仅匹配键存在)[3](@ref)
value: "production" # 污点的值(当 operator=Equal 时必须指定)[3](@ref)
effect: "NoSchedule" # 污点效应:NoSchedule/NoExecute/PreferNoSchedule(默认匹配所有)[3](@ref)
# tolerationSeconds: 3600 # 仅对 NoExecute 有效:容忍驱逐前的存活时间(默认永久)[3](@ref)
//operator的值是Equal的话,key值和value值必须要和污点的键值分别相等。effect表示要匹配的污点效果。
//应用yaml文件创建pod
kubectl apply -f taint-1.yaml
//查看pod
kubectl get pods -o wide
//方式二、创建一个能够调度到k8s-node-02节点的pod
//编写yaml文件
vi taint-2.yaml
apiVersion: v1
kind: Pod
metadata:
name: nginx
namespace: default
labels:
app: nginx
spec:
nodeSelector:
kubernetes.io/hostname: k8s-node-02 # 强制调度到名为 k8s-node02 的节点[2,8](@ref)
containers:
- name: nginx
image: nginx:latest
tolerations: # 容忍规则配置:允许调度到含特定污点的节点[1,3](@ref)
- key: "node-type" # 需匹配的污点键(必填,例如 node-type=production)[1,2](@ref)
operator: "Exists" # 匹配规则:Exists(仅需污点键存在,无需指定 value)[1,3](@ref)
effect: "NoSchedule" # 需匹配的污点效应(可选:NoSchedule/NoExecute/PreferNoSchedule)[1,3](@ref)
# tolerationSeconds: 3600 # 仅对 NoExecute 效应有效,定义容忍驱逐前的存活时间(默认永久)[1,5](@ref)
//operator的值是Exists的话,无须指定value。key值必须要和污点的键相等。effect表示要匹配的污点效果,空表示匹配所有污点效果。
//应用yaml文件创建pod
kubectl apply -f taint-2.yaml
//查看pod
kubectl get pods -o wide
//方式三、创建一个能够调度到k8s-node-02节点的pod
//编写yaml文件
vi taint-3.yaml
apiVersion: v1
kind: Pod
metadata:
name: nginx
namespace: default
labels:
app: nginx
spec:
nodeSelector:
kubernetes.io/hostname: k8s-node02 # 强制调度到名为 k8s-node02 的节点[5](@ref)
containers:
- name: nginx
image: nginx:latest
tolerations: # 容忍规则配置:允许调度到含特定污点的节点[1,3](@ref)
- key: "" # 空字符串表示匹配所有污点的键(需与 operator=Exists 配合)[3](@ref)
operator: "Exists" # 容忍所有污点(无论键或值是什么)[1,5](@ref)
effect: "NoSchedule" # 需匹配的污点效应:NoSchedule/NoExecute/PreferNoSchedule[1](@ref)
# tolerationSeconds: 3600 # 仅对 NoExecute 有效:容忍驱逐前的存活时间(默认永久)[1,5](@ref)
//operator的值是Exists的话,无须指定value。key值为空的话,则运算
符必须为Exists,这种组合表示匹配所有值和所有键。effect表示要匹配的污
点效果,空表示匹配所有污点效果
//应用yaml文件创建pod
kubectl apply -f taint-3.yaml
//查看pod
kubectl get pods -o wide
12.pod常见的状态和重启策略

第一阶段
●挂起(Pending)
1、正在创建Pod但是Pod中的容器还没有全部被创建完成,处于此状态的
Pod应该检查Pod依赖的存储是否有权限挂载、镜像是否可以下载、调度是否正
常等。
2、我们在请求创建pod时,条件不满足,调度没有完成,没有任何一个节
点能满足调度条件,已经创建了pod但是没有适合它运行的节点叫做挂起,调度
没有完成。
●失败(Failed)
Pod中的所有容器都已终止了,并且至少有一个容器是因为失败终止。也就
是说,容器以非0状态退出或者被系统终止。
●未知(Unknown)
未知状态,所谓pod是什么状态是apiserver和运行在pod节点的kubelet
进行通信获取状态信息的,如果节点之上的kubelet本身出故障,那么apiserver
就连不上kubelet,得不到信息了,就会看到Unknown状态。通常是由于与pod
所在的node节点通信错误。
● Error状态
Pod启动过程中发生了错误。
●成功(Succeeded)
Pod中的所有容器都被成功终止,并且不会再重启。即pod里所有的
containers均已terminated。
第二阶段
●运行中(Running)
Pod内部的容器已经被创建并且启动。
● Unschedulable
Pod不能被调度,scheduler没有匹配到合适的node节点
● PodScheduled
pod正处于调度中,在scheduler刚开始调度的时候,还没有将pod分配到
指定的node,在筛选出合适的节点后就会更新etcd数据,将pod分配到指定的
node。
● Initialized:所有pod中的初始化容器已经完成了。
● ImagePullBackOff:Pod所在的node节点下载镜像失败。
● InvalidImageName:无法解析镜像名称。
● ErrImageNeverPull:策略禁止拉取镜像。
● RegistryUnavailable:连接不到镜像中心。
● CreateContainerError:创建容器失败。
● RunContainerError:启动容器失败。
● ContainerCreating:容器创建中
● PodInitializing:pod初始化中
扩展
● Evicted
出现这种情况,多见于系统内存或硬盘资源不足,可df-h查看docker存
储所在目录的资源使用情况,如果百分比大于85%,就要及时清理下资源,尤其
是一些大文件、docker镜像。
● CrashLoopBackOff:容器曾经启动了,但可能又异常退出了。
● Error:Pod启动过程中发生了错误。
● Complete:完成状态
pod重启策略
k8s有3种不同的pod重启策略、Always、OnFailure、Never
1、Always:始终重启Pod。这意味着,如果容器结束,无论是以成功还是 以失败状态,Kubernetes都会立即重新启动此Pod。这是默认的重启策略。
2、OnFailure:仅在容器失败时重启Pod。如果容器以非0状态退出(即失 败),则Kubernetes将重启此Pod。否则,Kubernetes不会重启此Pod。这适 用于需要一些尝试才能成功的任务,例如处理可能会失败、但可以自动重试的消 息。
3、Never:不重启Pod。如果此策略用于Pod,则表示在容器退出后,将不 会重新启动Pod,将该Pod视为已完成。这在运行一次性任务时很有用,例如批 处理或数据转换作业。
4.需要注意的是、在使用任何pod重启策略时、还应该注意pod的资源要求和限制、如果资源不足、pod可能会在重启后继续失败哦
pod重启策略应用场景
1、Always:对于长期运行的服务和应用程序,例如Web服务器、数据库、 缓存服务等,始终重启Pod可以保持服务的稳定性和可用性。
2、OnFailure:对于需要重试的作业,例如处理消息或错误恢复,仅在容器 失败时重启Pod是最好的选择。此策略也可用于避免过度重启Pod。
3、Never:对于一次性任务,例如数据转换或批处理作业,不重启Pod是最 好的选择。此策略可确保一次性任务只运行一次,并避免重复执行。
项目实战
实例1:always重启策略
//创建yaml文件
vi pod-always.yaml
apiVersion: v1 # 必选,Kubernetes API 版本(Pod 使用 v1 版本)[3,4](@ref)
kind: Pod # 必选,资源类型为 Pod [3,4](@ref)
metadata:
name: pod-always # 必选,Pod 名称(需符合 DNS-1123 命名规范)[3,4](@ref)
namespace: default # 可选,默认命名空间,建议生产环境显式指定业务命名空间[4](@ref)
labels:
app: myapp # 标签用于服务发现和资源选择(建议配合 Deployment 使用)[4](@ref)
spec:
restartPolicy: Always # 容器重启策略(Always/OnFailure/Never)[3,6](@ref)
containers:
- name: tomcat # 必选,容器名称(建议体现业务功能)[3,4](@ref)
ports: # 声明容器暴露的端口(需配合 Service 使用才能实际暴露)[4](@ref)
- containerPort: 8080 # 容器监听端口(默认 TCP 协议)[3,4](@ref)
image: tomcat:8.5-jre8-alpine # 必选,镜像名称(建议避免 latest 标签)[6,8](@ref)
imagePullPolicy: IfNotPresent # 镜像拉取策略(Always/Never/IfNotPresent)[6,8](@ref)
//创建pod
kubectl apply -f pod-always.yaml
//正常停止容器里的tomcat服务
kubectl exec -it pod-always -c tomcat --bash
//查看pod状态
kubectl get pods
//当停止容器里的Tomcat服务,那么此容器的生命周期就结束了。因为我们设置了容器的重启策略为Always,Pod重启了一次,又恢复了正常。
//非正常停止容器里的tomcat服务
kubectl exec -it pod-always -c tomcat--bash
//查看pod状态
kubectl get pods
//可以看到容器终止了,并且又重启一次,重启次数增加了一次
//从上面测试结果可以得出,restartPolicy为Always的时候,当容器正常
结束生命周期时,容器会自动重启;当容器非正常结束生命周期时,容器一样会
自动重启。
实例2:never重启策略
//创建yaml文件
vi pod-never.yaml
apiVersion: v1 # 必选,Kubernetes API 版本(Pod 使用 v1 版本)[3,4](@ref)
kind: Pod # 必选,资源类型为 Pod [3,4](@ref)
metadata:
name: pod-never # 必选,Pod 名称(需符合 DNS-1123 命名规范)[3,4](@ref)
namespace: default # 可选,默认命名空间,建议生产环境显式指定业务命名空间[4](@ref)
labels:
app: myapp # 标签用于服务发现和资源选择(建议配合 Deployment 使用)[4](@ref)
spec:
restartPolicy: Never # 容器重启策略(Always/OnFailure/Never)[3,6](@ref)
containers:
- name: tomcat # 必选,容器名称(建议体现业务功能)[3,4](@ref)
ports: # 声明容器暴露的端口(需配合 Service 使用才能实际暴露)[4](@ref)
- containerPort: 8080 # 容器监听端口(默认 TCP 协议)[3,4](@ref)
image: tomcat:8.5-jre8-alpine # 必选,镜像名称(建议避免 latest 标签)[6,8](@ref)
imagePullPolicy: IfNotPresent # 镜像拉取策略(Always/Never/IfNotPresent)[6,8](@ref)
//创建pod
kubectl apply -f pod-never.yaml
//正常停止容器里的tomcat服务
kubectl exec -it pod-never -c tomcat --bash
//查看pod状态
kubectl get pods
//发现正常停止容器里的tomcat服务,pod正常运行,容器没有重启
//非正常停止容器里的tomcat服务
kubectl delete -f pod-never.yaml
kubectl apply -f pod-never.yaml
//进入容器、杀死主进程
kubectl exec -it pod-never -c tomcat --bash
//查看pod状态
kubectl get pods
//上面可以看到容器状态是error,并且没有重启,这说明重启策略是never,那么pod里容器服务无论如何终止,都不会重启
//从上面测试结果可以得出,restartPolicy为Never的时候,当容器正常结
束生命周期时,容器状态为Completed;当容器非正常结束生命周期时,容器状
态为Error。
实例3: onfailure 重启策略
//创建yaml文件
vi pod-never.yaml
apiVersion: v1 # 必选,Kubernetes API 版本(Pod 使用 v1 版本)[3,4](@ref)
kind: Pod # 必选,资源类型为 Pod [3,4](@ref)
metadata:
name: pod-never # 必选,Pod 名称(需符合 DNS-1123 命名规范)[3,4](@ref)
namespace: default # 可选,默认命名空间,建议生产环境显式指定业务命名空间[4](@ref)
labels:
app: myapp # 标签用于服务发现和资源选择(建议配合 Deployment 使用)[4](@ref)
spec:
restartPolicy: Never # 容器重启策略(Always/OnFailure/Never)[3,6](@ref)
containers:
- name: tomcat # 必选,容器名称(建议体现业务功能)[3,4](@ref)
ports: # 声明容器暴露的端口(需配合 Service 使用才能实际暴露)[4](@ref)
- containerPort: 8080 # 容器监听端口(默认 TCP 协议)[3,4](@ref)
image: tomcat:8.5-jre8-alpine # 必选,镜像名称(建议避免 latest 标签)[6,8](@ref)
imagePullPolicy: IfNotPresent # 镜像拉取策略(Always/Never/IfNotPresent)[6,8](@ref)
//创建pod
kubectl apply -f pod-never.yaml
//正常停止容器里的tomcat服务
kubectl exec -it pod-never -c tomcat --bash
//查看pod状态
kubectl get pods
//发现正常停止容器里的tomcat服务,pod正常运行,容器没有重启
//非正常停止容器里的tomcat服务
kubectl delete -f pod-never.yaml
kubectl apply -f pod-never.yaml
//进入容器、杀死主进程
kubectl exec -it pod-never -c tomcat --bash
//查看pod状态
kubectl get pods
//上面可以看到容器状态是error,并且没有重启,这说明重启策略是never,那么pod里容器服务无论如何终止,都不会重启
//从上面测试结果可以得出,restartPolicy为Never的时候,当容器正常结
束生命周期时,容器状态为Completed;当容器非正常结束生命周期时,容器状
态为Error。
13.Pod生命周期
pod 从开始创建到终止退出的时间范围称为Pod生命周期

pod声明周期的重要行为
1、在启动任何容器之前,先创建pause基础容器,它初始化Pod的环境并 为后续加⼊的容器提供共享的名称空间。
2、初始化容器(initcontainer) 一个pod可以拥有任意数量的init容器。init容器是按照顺序依次执行的, 并且仅当最后一个init容器执行完毕才会去启动主容器。
3、生命周期钩子 pod 允许定义两种类型的生命周期钩子,启动后(post-start)钩子和停止 前(pre-stop)钩子。 这些生命周期钩子是基于每个容器来指定的,和init容器不同的是,init 容器是应用到整个pod。而这些钩子是针对单个容器的,是在容器启动后和停止前执行的。
4、容器探测
对Pod健康状态诊断。分为三种:Startupprobe(启动探测)、Livenessprobe (存活性探测)、Readinessprobe(就绪性检测)
● Startup(启动探测):探测容器是否正常运行。
● Liveness(存活性探测):判断容器是否处于runnning状态,根据重 启策略决定是否重启容器。
● Readiness(就绪性检测):判断容器是否准备就绪并对外提供服务, 将容器设置为不可用,不接受service转发的请求。
5、容器的重启策略:定义是否重启Pod对象。
● Always:但凡Pod对象终止就重启,默认设置。
● OnFailure:仅在Pod出现错误时才重启。
● Never:从不。 注意:一旦Pod绑定到一个节点上,就不会被重新绑定到另一个节点上,要 么重启,要么终止。
6、pod的终止过程 终止过程主要分为如下几个步骤:
●(1)用户发出删除pod命令:kubectldeletepods、kubectldelete-fyaml。
●(2)Pod对象随着时间的推移更新,在宽限期(默认情况下30秒), pod被视为“dead”状态。
●(3)将pod标记为“Terminating”状态。
●(4)第三步同时运行,监控到pod对象为“Terminating”状态的同时 启动pod关闭过程。
●(5)第三步同时进行,endpoints控制器监控到pod对象关闭,将pod 与service匹配的endpoints列表中删除。
●(6)如果pod中定义了preStop钩子处理程序,则pod被标记为 “Terminating”状态时以同步的方式启动执行;若宽限期结束后,preStop仍 未执行结束,第二步会重新执行并额外获得一个2秒的小宽限期。
●(7)Pod内对象的容器收到TERM(宽限期)信号。
●(8)宽限期结束之后,若存在任何一个运行的进程,pod会收到SIGKILL 信号。SIGKILL信号:“用来立即结束程序的运行.本信号不能被阻塞、处理和 忽略”。
●(9)Kubelet请求APIServer将此Pod资源宽限期设置为0从而完成 删除操作。
14.Init Container(初始化容器)
Init 容器就是做初始化工作的容器。可以有一个或多个,如果多个按照定 义的顺序依次执行,只有所有的初始化容器执行完后,主容器才启动。
Init Container 和主容器共享相同的网络命名空间和存储卷。所以Init Container 里产生的数据可以被主容器使用到,Init Container可以在多种K8S资源里被 使用到,如Deployment、DaemonSet, StatefulSet、Job 等,但都是在Pod启动 时,在主容器启动前执行,做初始化工作。
Init 容器与普通的容器区别是:
1、Init 容器不支持Readiness,因为它们必须在Pod就绪之前运行完成。
2、每个Init容器必须运行成功,下一个才能够运行。
3、如果Pod的Init容器失败,Kubernetes会不断地重启该Pod,直到Init 容器成功为止,然而,如果Pod对应的restartPolicy值为Never,它不会重新 启动。
Init Container 可以完成以下任务:
1、文件下载:下载需要在主容器中使用的文件(如配置文件)。
2、数据填充:在主容器启动之前填充数据(如数据库初始化)。
3、网络设置:完成一些必要的网络设置。
4、等待依赖项:等待其他服务或资源准备就绪,以便主容器启动。
5、运行脚本或命令:在主容器启动之前执行初始化脚本或命令。
Init容器案例实战
实例1: 在生产环境中,我们有一套微服务项目部署在k8s集群中,微服务容器所使 用的镜像都是自己制作的,镜像存放在Harbor私有仓库中。我们这套业务Harbor 仓库是部署在k8s集群内的。 如果k8s集群在开机启动的时候,所有的Pod容器都会重启,那么这个时候 就会出现资源抢占,可能就会导致harbor容器启动的很慢,harbor如果没启动, 那么我们的微服务pod就会拉不到镜像,那么也会无法启动。所以我们对微服务pod增加Init初始化容器,让Init容器来判断harbor是否通信。如果通信那么就初始化完成,如果不通信,那么初始化容器就不断重启等待通信。
//创建yaml文件
vi init.yaml
apiVersion: v1
kind: Pod
metadata:
name: myapp-pod # Pod名称,需符合DNS命名规范
labels:
app: myapp # 标签,用于服务发现和选择器匹配
spec:
initContainers: # 初始化容器配置(主容器启动前运行)
- name: init-check-harbor # 初始化容器名称
image: rancher/curl:latest # 使用curl工具镜像(生产环境建议固定版本)
imagePullPolicy: IfNotPresent # 镜像拉取策略:本地存在则不拉取
command: # 执行的命令
- 'sh'
- '-c'
- |
until curl -I http://192.168.128.11:80; do # 持续检查Harbor仓库可用性
sleep 2; # 检查间隔2秒
echo 'Please wait...'; # 提示信息
sleep 3; # 等待3秒后重试
done;
containers: # 主容器配置
- name: myapp-container # 主容器名称
image: nginx:latest # 使用nginx镜像(生产环境建议固定版本)
imagePullPolicy: IfNotPresent # 镜像拉取策略:本地存在则不拉取
### 关键配置解析
1. **Init Container特性**
- 先于主容器运行,必须成功退出后才会启动主容器
- 本例用于检查Harbor仓库(192.168.128.11:80)可用性
- 检查逻辑:每5秒(2+3)尝试连接,直到返回HTTP头信息
2. **生产环境建议**
```yaml
# 建议优化点:
initContainers:
- name: init-check-harbor
image: rancher/curl:7.78.0 # 固定镜像版本
resources: # 添加资源限制
requests:
cpu: "100m"
memory: "64Mi"
containers:
- name: myapp-container
image: nginx:1.21.6 # 固定版本
ports: # 显式声明端口
- containerPort: 80
//这个Pod定义了两个容器:一个为初始化容器init-check-harbor,另一个为主容器
myapp-container。其中init-check-harbor使用了rancher/curl:latest镜像,并启动一
个shell命令,该命令会循环发送HTTP请求,直到能够成功访问http://192.168.128.11:80。
这个容器的目的是在主容器启动前检查服务是否可用。
myapp-container使用了nginx:latest镜像,其目的是运行一个NGINXWeb服务器。
//更新清单文件
kubectl apply -f init.yaml
//查看pod
kubectl get pods
//查看一下初始化容器的日志
kubectl logs -f myapp-pod -c init-check-harbor
//安装nginx并启动
yum -y install nginx
systemctl restart nginx
//再次检查pod
kubectl get pods -o wide
//测试访问pod(注意替换地址)
curl -I 10.244.58.206
**实例2: **目标:主容器运行nginx服务,初始化容器用来给主容器生成index.html 文件
//创建yaml文件
vi init-nginx.yaml
apiVersion: v1
kind: Pod
metadata:
name: init-nginx # Pod名称,需符合DNS命名规范(建议包含业务标识)
spec:
initContainers: # 初始化容器(主容器启动前运行)
- name: install # 初始化容器名称(建议体现功能)
image: busybox:latest # 轻量级工具镜像(生产环境建议固定版本)
imagePullPolicy: IfNotPresent # 镜像拉取策略:本地存在则不拉取
command: # 执行的命令(下载网页到共享目录)
- "wget" # 下载工具
- "-O" # 指定输出文件
- "/work/index.html" # 输出路径(挂载卷内)
- "https://www.baidu.com" # 下载目标URL
volumeMounts: # 卷挂载配置
- name: work # 引用下方定义的卷
mountPath: /work # 容器内挂载路径
containers: # 主容器配置
- name: nginx # 主容器名称
image: nginx # 官方nginx镜像(生产环境建议固定版本如nginx:1.25)
imagePullPolicy: IfNotPresent
ports: # 端口声明(需配合Service暴露服务)
- containerPort: 80 # 容器监听端口
volumeMounts: # 共享相同的卷
- name: work
mountPath: /usr/share/nginx/html # nginx默认站点目录
volumes: # 存储卷定义
- name: work # 卷名称
emptyDir: {} # 临时空目录卷(Pod删除时数据丢失)
### 关键配置解析
1. **初始化容器工作流**
- 先启动`install`容器下载百度首页到`/work/index.html`
- 通过共享卷`work`将文件传递给主容器
- 主容器nginx使用该文件作为网站根目录
2. **存储卷特性**
```mermaid
graph LR
A[initContainer] -- writes --> B[emptyDir]
B -- mounted --> C[nginxContainer]
//更新清单文件
kubectl apply -f init-nginx.yaml
//查看pod
kubectl get pods -o wide
//测试访问(注意替换地址)
curl 10.244.85.208
15.容器钩子:postStart和preStop
postStart:容器创建之后立刻执行,用于资源部署、环境准备等。
preStop:在容器被终止前执行,用于优雅关闭应用程序、通知其他系统等。
由 lifecycle字段来完成的
//查看相关语法
kubectl explain pods.spec.containers.lifecycle
字段介绍
| 字段名称 | 取值类型 | 说明 |
|---|---|---|
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">postStart</font> | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);"><Object></font> | Pod 启动后钩子 |
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">postStart.exec</font> | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);"><Object></font> | 通过命令方式执行 |
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">postStart.exec.command</font> | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);"><[]string></font> | 要执行的命令(数组形式) |
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">postStart.httpGet</font> | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);"><Object></font> | 通过 HTTP GET 请求探测 |
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">postStart.httpGet.host</font> | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);"><string></font> | 目标主机名(默认 Pod IP) |
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">postStart.httpGet.httpHeaders</font> | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);"><[]Object></font> | 自定义 HTTP 请求头 |
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">postStart.httpGet.httpHeaders.name</font> | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);"><string></font> | HTTP 头字段名 |
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">postStart.httpGet.httpHeaders.value</font> | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);"><string></font> | HTTP 头字段值 |
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">postStart.httpGet.path</font> | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);"><string></font> | HTTP 请求路径 |
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">postStart.httpGet.port</font> | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);"><string></font> | HTTP 请求端口 |
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">postStart.httpGet.scheme</font> | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);"><string></font> | 协议(HTTP/HTTPS,默认 HTTP) |
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">postStart.tcpSocket</font> | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);"><Object></font> | 通过 TCP 端口探测 |
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">postStart.tcpSocket.host</font> | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);"><string></font> | 目标主机名(默认 Pod IP) |
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">postStart.tcpSocket.port</font> | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);"><string></font> | TCP 探测端口 |
容器钩子实战
小节目标:创建一个nginxpod容器,在启动前创建一个测试web网页,在 容器关闭前优雅关闭nginx服务。
//创建yaml资源清单文件
vi nginx-pre.yaml
apiVersion: v1 # Kubernetes API版本声明
kind: Pod # 资源类型为Pod
metadata:
name: nginx-web # Pod名称,需符合DNS命名规范
spec:
containers:
- name: nginx-web # 容器名称
image: nginx:latest # 使用最新版nginx镜像(生产环境建议指定具体版本)
imagePullPolicy: IfNotPresent # 镜像拉取策略:本地存在则不拉取
lifecycle: # 生命周期钩子配置
postStart: # 容器启动后立即执行(非阻塞式)
exec: # 使用命令方式执行
command: # 要执行的命令(数组格式)
- "/bin/sh" # 调用shell
- "-c" # 执行命令模式
- "echo 'hello hook' > /usr/share/nginx/html/index.html" # 写入欢迎页面到nginx默认网站目录
preStop: # 容器终止前执行(优雅终止期触发)
exec:
command: # 优雅停止命令
- "/bin/sh"
- "-c"
- "nginx -s stop" # 向nginx主进程发送停止信号
### 关键配置解析
1. **postStart 钩子**
- 执行时机:容器启动后立即触发(与主进程并行执行)
- 典型用途:初始化配置文件、预热缓存等
- 注意事项:
- 若命令执行失败不会阻止容器启动
- 执行时间过长可能导致钩子超时(默认30秒)
2. **preStop 钩子**
- 执行时机:Pod收到终止信号(SIGTERM)后触发
- 典型用途:优雅关闭、数据持久化、服务注销
- 注意事项:
- 必须在terminationGracePeriodSeconds(默认30秒)内完成
//创建资源清单文件
kubectl apply -f nginx-pre.yaml
//检查pod
kubectl get pods -o wide
//连接测试
curl 10.244.58.208
16.容器探测
默认的健康检查
// vi check.yaml
apiVersion: v1 # Kubernetes API版本声明
kind: Pod # 资源类型为Pod
metadata:
name: check # Pod名称,需符合DNS命名规范
namespace: default # 部署到默认命名空间
labels:
app: check # 应用标签,用于服务发现和选择器匹配
spec:
containers:
- name: check # 容器名称
image: busybox:latest # 轻量级工具镜像(生产环境建议固定版本)
imagePullPolicy: IfNotPresent # 镜像拉取策略:本地存在则不拉取
command: # 容器启动命令(覆盖镜像默认ENTRYPOINT)
- /bin/sh
- -c
- "sleep 10; exit" # 睡眠10秒后退出(注意:exit会导致容器失败)
### 关键配置解析
1. **容器行为说明**
- 启动后执行`sleep 10`暂停10秒
- 执行`exit`命令主动退出(返回码0)
- 由于没有设置
//应用yaml文件
kubectl apply -f check.yaml
//获取pod信息
kubectl get pods -w
探针相关语法说明
livenessProbe、readinessProbe、startupProbe探测可以通过以下三种方式来 执行:
HTTP探针:发送HTTPGET请求来测试容器的活性。
TCP探针:对容器的特定TCP端口进行连接测试。
EXEC探针:在容器中执行特定命令,并验证返回码和输出文本。
1. livenessProbe(存活探针)
| 字段名称 | 取值类型 | 说明 |
|---|---|---|
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">livenessProbe</font> | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);"><Object></font> | 存活状态检测配置 |
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">livenessProbe.exec</font> | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);"><Object></font> | 通过执行命令检测(返回0表示健康) |
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">livenessProbe.httpGet</font> | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);"><Object></font> | 通过HTTP GET请求检测(2xx/3xx状态码表示健康) |
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">livenessProbe.tcpSocket</font> | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);"><Object></font> | 通过TCP端口检测(端口可连接表示健康) |
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">livenessProbe.failureThreshold</font> | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);"><integer></font> | 连续失败多少次判定为不健康(默认3次) |
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">livenessProbe.initialDelaySeconds</font> | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);"><integer></font> | 容器启动后延迟多少秒开始检测(默认0) |
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">livenessProbe.periodSeconds</font> | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);"><integer></font> | 检测间隔时间(秒,默认10) |
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">livenessProbe.successThreshold</font> | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);"><integer></font> | 连续成功多少次判定为健康(默认1次) |
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">livenessProbe.timeoutSeconds</font> | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);"><integer></font> | 检测超时时间(秒,默认1) |
2. readinessProbe(就绪探针)
| 字段名称 | 取值类型 | 说明 |
|---|---|---|
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">readinessProbe</font> | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);"><Object></font> | 就绪状态检测配置 |
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">readinessProbe.exec</font> | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);"><Object></font> | 同livenessProbe.exec |
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">readinessProbe.httpGet</font> | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);"><Object></font> | 同livenessProbe.httpGet |
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">readinessProbe.tcpSocket</font> | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);"><Object></font> | 同livenessProbe.tcpSocket |
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">readinessProbe.failureThreshold</font> | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);"><integer></font> | 同livenessProbe.failureThreshold |
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">readinessProbe.initialDelaySeconds</font> | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);"><integer></font> | 同livenessProbe.initialDelaySeconds |
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">readinessProbe.periodSeconds</font> | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);"><integer></font> | 同livenessProbe.periodSeconds |
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">readinessProbe.successThreshold</font> | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);"><integer></font> | 同livenessProbe.successThreshold |
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">readinessProbe.timeoutSeconds</font> | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);"><integer></font> | 同livenessProbe.timeoutSeconds |
3. startupProbe(启动探针)
| 字段名称 | 取值类型 | 说明 |
|---|---|---|
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">startupProbe</font> | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);"><Object></font> | 启动状态检测配置 |
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">startupProbe.exec</font> | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);"><Object></font> | 同livenessProbe.exec |
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">startupProbe.httpGet</font> | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);"><Object></font> | 同livenessProbe.httpGet |
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">startupProbe.tcpSocket</font> | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);"><Object></font> | 同livenessProbe.tcpSocket |
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">startupProbe.failureThreshold</font> | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);"><integer></font> | 允许的最大失败次数(默认3) |
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">startupProbe.initialDelaySeconds</font> | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);"><integer></font> | 同livenessProbe.initialDelaySeconds |
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">startupProbe.periodSeconds</font> | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);"><integer></font> | 同livenessProbe.periodSeconds |
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">startupProbe.successThreshold</font> | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);"><integer></font> | 同livenessProbe.successThreshold |
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">startupProbe.timeoutSeconds</font> | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);"><integer></font> | 同livenessProbe.timeoutSeconds |
三者的核心区别
| 探针类型 | 检测失败后果 | 典型应用场景 | 特殊说明 |
|---|---|---|---|
| livenessProbe | 重启容器 | 检测死锁/卡死 | 确保应用可用性 |
| readinessProbe | 从Service端点移除 | 检测初始化完成 | 控制流量接入时机 |
| startupProbe | 不重启容器 | 保护慢启动应用 | 仅在启动阶段生效 |
存活探针应用案例
案例1: 通过exec方式做健康探测
//创建yaml文件
vi liveness-exec.yaml
apiVersion: v1
kind: Pod
metadata:
name: liveness-exec # Pod名称
labels:
app: liveness # 应用标签(可用于Service选择器)
spec:
containers:
- name: liveness # 容器名称
image: busybox:latest # 轻量级工具镜像(生产环境建议固定版本)
args: # 容器启动参数(覆盖镜像默认CMD)
- /bin/sh
- -c
- "touch /tmp/healthy; sleep 30; rm -rf /tmp/healthy; sleep 600"
# 执行流程:
# 1. 创建健康标志文件
# 2. 等待30秒
# 3. 删除健康标志文件
# 4. 进入600秒休眠(模拟长时间运行)
livenessProbe: # 存活探针配置
initialDelaySeconds: 10 # 容器启动10秒后开始探测
periodSeconds: 5 # 每5秒检测一次
exec: # 通过执行命令检测
command:
- cat
- /tmp/healthy # 检测文件是否存在
# 返回码0表示成功(文件存在)
# 非0表示失败(触发容器重启)
### 关键行为说明
1. **容器生命周期**
- 0-10秒:容器启动,探针尚未开始(initialDelaySeconds)
- 10-40秒:`/tmp/healthy`文件存在,探针成功
- 40秒后:文件被删除,探针开始失败
- 连续3次失败(默认failureThreshold)后容器重启
2. **探针工作机制**
```mermaid
timeline
title 探针检测流程
section 容器启动
0s: 创建/tmp/healthy文件
10s: 首次探测(成功)
15s: 第二次探测(成功)
section 文件删除后
30s: 删除健康文件
35s: 探测开始失败
40s: 第二次失败
45s: 第三次失败(触发重启)
//容器启动色湖之执行的命令
/bin/sh -c "touch/tmp/healthy;sleep30;rm-rf/tmp/healthy;sleep600"
//容器在初始化后,首先创建一个/tmp/healthy文件,然后执行睡眠命令,
睡眠30秒,到时间后执行删除/tmp/healthy文件命令。而设置的存活探针检检
测方式为执行shell命令,用cat命令输出healthy文件的内容,如果能成功执
行这条命令,存活探针就认为探测成功,否则探测失败。在前30秒内,由于文
件存在,所以存活探针探测时执行cat /tmp/healthy命令成功执行。30秒后
healthy文件被删除,所以执行命令失败,Kubernetes会根据Pod设置的重启策
略来判断,是否重启Pod。
//更新资源清单文件
kubectl apply -f liveness-exec.yaml
//查看pod、发现容器已经重启了一次
kubectl get pods
//查看容器日志
kubectl describe pods liveness-exec
//重启次数过多就会变成CrashLoopBackOff
kubectl get pods
**案例2: 通过HTTP方式做健康探测 **
//创建yaml文件
vi liveness-http.yaml
apiVersion: v1
kind: Pod
metadata:
name: liveness-http # Pod名称
labels:
test: liveness # 标签(可用于监控或服务选择)
spec:
containers:
- name: liveness # 容器名称
image: nginx:latest # 使用最新版nginx镜像(生产环境建议固定版本)
livenessProbe: # 存活探针配置
initialDelaySeconds: 20 # 容器启动后20秒开始探测(考虑服务启动时间)
periodSeconds: 5 # 每5秒检测一次
timeoutSeconds: 10 # 单次探测超时时间(秒)
httpGet: # HTTP检测方式
scheme: HTTP # 使用HTTP协议(默认值,可省略)
port: 80 # 检测容器80端口
path: /index.html # 请求路径(需返回200-399状态码)
### 关键配置解析
1. **HTTP健康检查机制**
- 检测流程:
1. 向容器发送`GET /index.html`请求
2. 如果返回`2xx`或`3xx`状态码 -> 判定健康
3. 如果超时(10秒)或返回`4xx/5xx` -> 判定失败
- 连续3次失败(默认`failureThreshold`)后触发容器重启
2. **参数优化建议**
```yaml
livenessProbe:
failureThreshold: 5 # 增加失败容忍次数
successThreshold: 2 # 要求连续成功2次才认为健康
httpHeaders: # 自定义请求头
- name: Custom-Header
value: HealthCheck
//检查nginx的/index.html页面,存活探针可以使用HTTPGet方式向服务发
起请求,请求80端口的/index.html路径来进行存活判断:
●任何大于或等于200且小于400的代码表示探测成功。
●任何其他代码表示失败。
//创建pod
kubectl apply -f liveness-http.yaml
//查看pod
kubectl get pods
**案例3: 通过TCP方式做健康探测 **
//创建yaml文件
vi viliveness-tcp.yaml
apiVersion: v1
kind: Pod
metadata:
name: liveness-tcp # Pod名称,需符合DNS命名规范
labels:
app: liveness # 应用标签,可用于服务发现
spec:
containers:
- name: liveness # 容器名称
image: nginx # 使用官方nginx镜像(生产环境建议指定版本如nginx:1.25)
livenessProbe: # TCP存活探针配置
initialDelaySeconds: 15 # 容器启动后等待15秒开始检测
periodSeconds: 20 # 每20秒检测一次
tcpSocket: # TCP端口检测方式
port: 80 # 检测容器80端口
### 关键配置解析
1. **TCP探针工作机制**
- 检测流程:
1. 尝试与容器80端口建立TCP连接
2. 连接成功 -> 判定健康
3. 连接失败(超时或拒绝)-> 判定失败
- 连续3次失败(默认`failureThreshold`)后触发容器重启
2. **与HTTP探针的对比**
| 特性 | TCP探针 | HTTP探针 |
|---------------|----------------------------|-----------------------------|
| 检测维度 | 端口可连接性 | 应用层业务状态 |
| 资源消耗 | 低(传输层检测) | 较高(需解析HTTP协议) |
| 适用场景 | 数据库/中间件服务 | Web应用/API服务 |
| 配置复杂度 | 简单(只需端口) | 需定义path/scheme等参数 |
3. **生产环境建议**
```yaml
livenessProbe:
tcpSocket:
port: 80
initialDelaySeconds: 30 # 对于慢启动服务延长初始延迟
periodSeconds: 15 # 提高检测频率
timeoutSeconds: 3 # 显式设置超时时间
failureThreshold: 5 # 增加失败容忍次数
// TCP检查方式和HTTP检查方式非常相似,在容器启动initialDelaySeconds
参数设定的时间后,kubelet将发送第一个livenessProbe探针,尝试连接容器
的80端口,如果连接失败则将杀死Pod重启容器。
//创建pod
kubectl apply -f liveness-http.yaml
//查看pod
kubectl get pods
**就绪性探测 ReadinessProbe **
就绪性探测(ReadinessProbe)是在Kubernetes中用于确定Pod是否准备 好接收流量的机制。通过就绪性探测,Kubernetes可以在将流量发送到Pod之 前,检查Pod中的容器是否已经启动并准备好处理请求。如果探测失败, Kubernetes 将从 Service 的地址池中删除Pod,防止流量发送到未准备好的Pod 上。这可以帮助避免应用程序中的故障和请求失败,以及降低资源消耗。就绪性 探测通常通过HTTP或TCP探测的方式实现。
就绪性探测应用案例
实例1:
** 这里用一个nginx容器,设置ReadinessProbe探测nginx容器的80端口下 的/index.html 页面,如果探测成功则代表内部程序以及启动,就开放对外提供 接口访问,否则内部应用没有成功启动,暂不对外提供访问,直到就绪探针探测 成功 **
//编写yaml文件
vi readiness-http.yaml
apiVersion: v1
kind: Pod
metadata:
name: readiness-http # Pod名称,需符合DNS命名规范
namespace: default # 部署到默认命名空间
labels:
app: readiness-http # 应用标签,用于服务发现
spec:
containers:
- name: readiness-http # 容器名称
image: nginx:latest # 使用最新版nginx镜像(生产环境建议固定版本)
imagePullPolicy: IfNotPresent # 镜像拉取策略:本地存在则不拉取
ports:
- containerPort: 80 # 声明容器暴露端口(需配合Service使用)
readinessProbe: # 就绪探针配置
initialDelaySeconds: 20 # 容器启动后延迟20秒开始探测
periodSeconds: 10 # 每10秒检测一次
failureThreshold: 2 # 连续失败2次判定为未就绪
httpGet: # HTTP检测方式
scheme: HTTP # 使用HTTP协议(默认值)
port: 80 # 检测容器80端口
path: /index.html # 请求路径(需返回200-399状态码)
### 关键配置解析
1. **就绪探针工作机制**
```mermaid
timeline
title 就绪检测流程
section 容器启动
0s: 容器启动
20s: 首次探测(若失败则不会将Pod加入Service)
section 定期检测
30s: 第二次探测
40s: 第三次探测
section 故障处理
若连续2次失败: 从Service端点移除
//更新资源清单文件
kubectl apply -f readiness-http.yaml
//查看pod
kubectl get pods
实例2:
** 这里用一个nginx容器,设置ReadinessProbe探测nginx容器的80端口是 否启动,如果探测成功则代表内部程序以及启动,就开放对外提供接口访问,否 则内部应用没有成功启动,暂不对外提供访问,直到就绪探针探测成功。 **
//编写yaml文件
vi readiness-http.yaml
apiVersion: v1
kind: Pod
metadata:
name: readiness-http # Pod名称,需符合DNS命名规范
labels:
app: readiness # 应用标签,用于服务发现和监控
spec:
containers:
- name: readiness # 容器名称
image: nginx:latest # 使用最新版nginx镜像(生产环境建议固定版本)
ports: # 声明容器暴露端口(需配合Service使用)
readinessProbe: # 就绪探针配置
initialDelaySeconds: 20 # 容器启动后延迟20秒开始探测
periodSeconds: 5 # 每5秒检测一次(默认10秒)
timeoutSeconds: 10 # 单次探测超时时间(默认1秒)
tcpSocket: # TCP端口检测方式
port: 80 # 检测容器80端口
### 关键配置解析
1. **TCP就绪探针特性**
- 检测逻辑:尝试与容器80端口建立TCP连接
- 成功条件:端口可连接(三次握手成功)
- 失败处理:连续失败达到阈值后,从Service端点移除
2. **参数优化说明**
| 参数 | 默认值 | 当前值 | 作用 |
|------|--------|--------|------|
| `periodSeconds` | 10 | 5 | 提高检测频率 |
| `timeoutSeconds` | 1 | 10 | 延长超时时间(适合高延迟环境) |
| `failureThreshold` | 3 | 未设置(使用默认) | 连续失败3次判定未就绪 |
3. **与HTTP探针对比**
```mermaid
graph LR
A[TCP探针] -->|检测端口连通性| B[网络层]
C[HTTP探针] -->|检测业务逻辑| D[应用层]
//更新资源清单文件
kubectl apply -f readiness-http.yaml
//查看pod
kubectl get pods
存活性探针与就绪性探针的区别
Kubernetes 中的存活性探测(Liveness Probe)和就绪性探测(Readiness Probe)都是用于监测Pod的健康状态的机制,但它们的目的略有不同。
存活性探测用于检测容器是否仍在运行,并在容器不健康时重启容器。通常, 存活性探测采用的是HTTP或TCP的探测方式,在容器执行进程或服务时定期发 送检查请求。如果容器无法正常响应请求或服务失败,则Kubernetes会认为容 器不健康,尝试重启容器。
就绪性探测则用于检测容器是否准备好接收流量,可以在容器启动时进行, 或在容器运行时进行。如果就绪性探测失败,Kubernetes会将容器从服务的终 端点列表中删除,以防止流量被发送到未准备好的容器上。就绪性探测通常使用 HTTP 或TCP 的探测方式进行,以确保容器已准备好接收请求。
综上所述,存活性探测和就绪性探测在监测容器状态方面具有不同的功能, 分别用于容器的运行状态和接收流量的准备状态
启动探测
启动探测(startupProbe)是Kubernetes中的一种探测方式,用于在容器 启动时检测容器内的应用程序是否已经准备好接受流量。它与Kubernetes中的 其他两种探测方式(存活探测和就绪探测)不同。存活探测用于检测容器是否正 在运行,而就绪探测用于检测应用程序是否已经准备好处理流量。启动探测在容 器启动时启动,并且仅在容器启动期间运行。在容器启动期间,应用程序可能需 要时间来初始化和启动,此时可以使用启动探测来检测容器是否已经启动并准备好
启动探测应用案例(无需操作)
**案例1:web pod依赖mysql pod场景 假设应用程序使用 MySQL 数据库,可以使用以下YAML文件来定义启动探测: **
apiVersion: v1
kind: Pod
metadata:
name: myapp # Pod名称,需符合DNS命名规范
spec:
containers:
- name: app # 容器名称
image: myapp:latest # 使用最新版应用镜像(生产环境建议固定版本)
ports:
- containerPort: 80 # 声明容器暴露端口
startupProbe: # 启动探针配置(Kubernetes 1.16+)
exec: # 通过执行命令检测
command:
- sh
- -c
- "mysqladmin ping -h db -u root -prootpasswd" # 检测MySQL可用性
failureThreshold: 30 # 允许的最大失败次数(30 * 10=300秒超时窗口)
periodSeconds: 10 # 每10秒检测一次
timeoutSeconds: 1 # 单次命令执行超时时间
### 关键配置解析
1. **启动探针特性**
- 专为慢启动服务设计(如数据库依赖型应用)
- 在探针成功前不会触发存活/就绪探针
- 本例检测MySQL服务可用性(需能连接并认证成功)
2. **参数优化说明**
| 参数 | 计算值 | 效果 |
|------|--------|------|
| `failureThreshold: 30` × `periodSeconds: 10` | 300秒 | 允许最长5分钟启动时间 |
| `timeoutSeconds: 1` | - | 单次检测超过1秒即失败 |
//在上述示例中,启动探测使用了exec命令,检查MySQL数据库是否可用。如
果数据库已启动并准备好接受连接,则启动探测将返回成功。如果在30次尝试
后仍然失败,则容器将被认为无法启动。 该探测将每10秒执行一次,并在1
秒后超时。在容器成功启动并准备好接受流量之前,该探测将一直运行。
案例2:
** 在k8s中,通过控制器管理pod,如果更新pod的时候,会创建新的pod, 删除老的pod,但是如果新的pod创建了,pod里的容器还没完成初始化,老的 pod 就被删除了,会导致访问service或者ingress时候,访问到的pod是有问 题的,所以k8s就加入了一些存活性探针:livenessProbe、就绪性探针 readinessProbe 以及这节课要介绍的启动探针startupProbe。 **
** 生产场景: 在微服务场景中,我们的微服务组件启动都需要依赖nacos注册中心,那么 我们的微服务组件可以增加启动探针,去检测nacos注册中心是否正常。(初始 化容器也可以实现相同功能,不过此方法需要额外启动一个容器)。 **
//安装并重启nginx
yum -y install nginx
systemctl restart nginx
//创建yaml为念
vi startup-check-nacos.yaml
apiVersion: v1
kind: Pod
metadata:
name: myapp # Pod名称,需符合DNS命名规范
spec:
containers:
- name: app # 容器名称
image: nginx:latest # 使用最新版nginx镜像(生产环境建议固定版本)
ports:
- containerPort: 80 # 声明容器暴露端口(需配合Service使用)
# 启动探针配置(Kubernetes 1.16+)
startupProbe:
exec: # 通过执行命令检测
command:
- sh
- -c
- "curl -I 192.168.128.11" # 检测外部服务可用性(建议使用Service域名)
failureThreshold: 30 # 最大允许失败次数(30 * 20=600秒检测窗口)
periodSeconds: 20 # 每20秒检测一次
timeoutSeconds: 1 # 单次命令超时时间(秒)
# 存活探针配置
livenessProbe:
initialDelaySeconds: 20 # 容器启动20秒后开始检测
periodSeconds: 20 # 每20秒检测一次
tcpSocket: # TCP端口检测方式
port: 80 # 检测容器80端口连通性
# 就绪探针配置
readinessProbe:
initialDelaySeconds: 20 # 容器启动20秒后开始检测
periodSeconds: 20 # 每20秒检测一次
tcpSocket: # TCP端口检测方式
port: 80 # 检测容器80端口连通性
### 三维健康检查体系解析
1. **启动探针 (startupProbe)**
```mermaid
timeline
title 启动阶段检测流程
0s: 容器启动
0-600s: 持续检测外部服务(192.168.128.11)
成功: 激活liveness/readiness探针
失败: 容器重启(根据restartPolicy)
//更新yaml配置
kubectl apply -f startup-check-nacos.yaml
//查看pod
kubectl get pods -w
三种探针的启动顺序问题
在Kubernetes 中,startupProbe 和 LivenessProbe、ReadinessProbe 都是 用于监测Pod容器状态的探测机制。就它们的启动顺序而言,startupProbe通 常先启动,然后才是LivenessProbe和ReadinessProbe。
因为startupProbe 主要用于检测容器是否已经启动和应用程序是否已经准 备就绪。如果startupProbe失败,Kubernetes会等待重试时间,直到重试次数 到达上限,然后将Pod标记为失败,同时记录相关事件。
在startupProbe 已启动且成功后,Kubernetes会同时进行LivenessProbe 和ReadinessProbe 的探测。LivenessProbe 用于检测容器是否仍在运行, ReadinessProbe 则用于检测容器是否准备好接收流量
17.pod优先级和抢占式调度
优先级抢占调度策略的核心行为分别是: 驱逐(Eviction) 抢占(Preemption )
驱逐(Eviction):驱逐是kubelet进程的行为,即当一个Node出现资源 不足的情况时,该节点上的kubelet进程会执行驱逐动作,此时Kubelet会综合 考虑Pod的优先级、资源申请量与实际使用量等信息来计算哪些Pod需要被驱逐; 当同样优先级的Pod需要被驱逐时,实际使用的资源量超过申请量最大倍数的高 耗能Pod会被首先驱逐。
抢占(Preemption): 抢占则是Scheduler 执行的行为,当一个新的Pod 因为资源无法满足而不能被调度时,Scheduler可能(有权决定)选择驱逐部分 低优先级的Pod实例来满足此Pod的调度目标,这就是抢占机制。
Scheduler可能会驱逐Node A上的一个Pod以满足Node B 上的一个新Pod的调度任务。比如下面的这个例子:
一个低优先级的PodA在NodeA(属于机架R)上运行,此时有一个高优先 级的Pod B等待调度,目标节点是同属机架R的Node B,他们中的一个或全部 都定义了antiaffinity规则,不允许在同一个机架上运行,此时Scheduler只 好“丢车保帅”,驱逐低优先级的Pod A以满足高优先级的Pod B的调度。
**PriorityClass 资源字段说明 **
//查看描述
kubectl explain PriorityClass
字段介绍
| 字段名称 | 取值类型 | 说明 |
|---|---|---|
| apiVersion | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);"><string></font> | API 版本,固定值:<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">scheduling.k8s.io/v1</font> |
| description | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);"><string></font> | 优先级类的描述信息(可选) |
| globalDefault | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);"><boolean></font> | 是否作为集群默认优先级类: - <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">true</font>:当 Pod 未指定优先级类时自动使用 - <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">false</font>(默认):不作为默认类 ⚠️ 多个类设置此字段时,只有最后创建的生效 |
| kind | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);"><string></font> | 资源类型,固定值:<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">PriorityClass</font> |
| metadata | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);"><Object></font> | 元数据(名称、标签等) |
| preemptionPolicy | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);"><string></font> | 抢占策略: - <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">Never</font>:禁止抢占其他 Pod - <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">PreemptLowerPriority</font>(默认):允许抢占低优先级 Pod |
| value | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);"><integer></font> | 优先级数值(必须指定): - 范围:1 - 1亿(系统保留值需 >1亿) - 值越大优先级越高 |
pod优先级和抢占式调度实战
** 目标: **
**1、创建两个个优先级配置low-priority和high-priority。 **
**2、创建一个使用low-priority并且带有标签app=web的Pod,指定Pod调 度到k8s-node01节点。 **
**3、创建一个Pod指定调度到k8s-node01节点,使用high-priority和 podAntiAffinity不与拥有app=web标签的Pod在同一节点,看是否能把低优先 级的Pod挤走。 **
**4、检查high-priority的Pod是否将low-priority的Pod“挤走”。 **
//创建两个个优先级配置low-priority和high-priority
//编写yaml文件
vi priority.yaml
# 低优先级配置类(适用于后台任务等非关键Pod)
apiVersion: scheduling.k8s.io/v1 # Kubernetes调度API版本
kind: PriorityClass # 资源类型为优先级类
metadata:
name: low-priority # 类名称(Pod通过此名称引用)
value: 100 # 优先级数值(范围1-1亿,数值越大优先级越高)
globalDefault: false # 非全局默认类(需显式指定才会生效)
description: "低优先级Pod" # 用途说明(显示在kubectl describe中)
---
# 高优先级配置类(适用于核心业务Pod)
apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
name: high-priority # 类名称
value: 10000 # 较高优先级数值(比low-priority高100倍)
globalDefault: false # 非全局默认类
description: "高优先级Pod" # 业务说明
//应用yaml文件
kubectl apply -f priority.yaml
//获取PriorityClass
kubectl get PriorityClass
//创建一个使用low-priority的Pod
//编写yaml文件
vi nginx-low.yaml
apiVersion: v1
kind: Pod
metadata:
name: nginx-low # Pod名称,需符合DNS命名规范
labels:
app: web # 应用标签,可用于Service选择器
spec:
priorityClassName: low-priority # 使用预定义的优先级类(value=100)
containers:
- name: nginx # 容器名称
image: nginx # 使用官方nginx镜像(生产环境建议固定版本如nginx:1.25)
nodeSelector: # 节点选择器(硬性调度约束)
kubernetes.io/hostname: k8s-node01 # 指定调度到node01节点
### 关键配置解析
1. **优先级控制**
- `priorityClassName: low-priority` 表示:
- 该Pod优先级数值为100(参见前文PriorityClass定义)
- 可能被`high-priority`(value=10000)的Pod抢占资源
- 适合用于后台任务等非关键业务
2. **节点调度约束**
```mermaid
graph LR
A[Pod] -->|nodeSelector| B[k8s-node01]
B --> C[必须运行在指定节点]
//应用yaml文件
kubectl apply -f nginx-low.yaml
//获取pod信息
kubectl get pods -o wide
//创建一个使用high-priority的Pod
//编写yaml文件
vi nginx-high.yaml
apiVersion: v1
kind: Pod
metadata:
name: nginx-high # Pod名称(高优先级服务标识)
spec:
priorityClassName: high-priority # 使用高优先级类(value=10000)
containers:
- name: nginx # 容器名称
image: nginx # 官方镜像(生产环境建议固定版本如nginx:1.25)
nodeSelector: # 硬性节点选择
kubernetes.io/hostname: k8s-node-01 # 必须调度到node01节点
affinity: # 亲和性配置
podAntiAffinity: # Pod反亲和性(避免同类Pod共置)
requiredDuringSchedulingIgnoredDuringExecution: # 硬性规则
- labelSelector:
matchExpressions:
- key: app # 匹配标签键
operator: In # 操作符:值在列表中
values: ["web"] # 避免与app=web的Pod同节点
topologyKey: kubernetes.io/hostname # 拓扑域:节点级隔离
//应用yaml文件
kubectl apply -f nginx-high.yaml
//获取pod信息、调度器因为找不到满足条件的节点无法将低优先级的pod调度到其他节点、所以低优先级的pod
nginx-low被驱逐后移除了
kubectl get pods -w
通过控制器代理用户创建指定数量的pod副本,并确保pod副 本一直处于满足用户期望的数量,并且还具有自动扩容缩容等机制。
主要有三个部分组成:
1、用户期望的pod副本数:用来定义由这个控制器管控的pod副本有几个
2、标签选择器:选定哪些pod是自己管理的,如果通过标签选择器选到的 pod 副本数量少于我们指定的数量,需要用到下面的组件。
3、pod 资源模板:如果集群中现存的pod数量不够我们定义的副本中期望 的数量怎么办,需要新建pod,这就需要pod模板,新建的pod是基于模板来创 建的。
三个控制器的区别
Replicase:需要手动替换pod
Deployment:在Replicase上面加了一层、基于Replicase、提供声明式更新、滚动升级和回滚、渐进式更新
Daemonset:确保每个节点(或满足条件的节点)运行一个指定的 Pod 副本。适合节点级别的pod、如日志收集、监控代理。
实验环境:一主两从
| 角色 | ip | 主机名 | 组件 | 硬件 |
|---|---|---|---|---|
| 控制节点 | 192.168.0.11 | k8s-master-01 | apisercer controll-manager schedule etcd containerd | **硬盘:50G ** **内存:4GB ** 4核 **开启虚拟化 ** |
| 工作节点 | 192.168.0.21 | k8s-node-01 | lubelet kube-proxy containerd calico coredns | **硬盘:25G ** **内存:2GB ** 2核 **开启虚拟化 ** |
| 工作节点 | 192.168.0.22 | k8s-node-02 | kubelet kube-proxy containerd calico coredns | **硬盘:25G ** **内存:2GB ** 2核 **开启虚拟化 ** |
1.Replicase
| 属性名称 | 取值类型 | 取值说明 |
|---|---|---|
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">apiVersion</font> | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">string</font> | 固定值 <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">apps/v1</font>(表示使用的 API 版本)。 |
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">kind</font> | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">string</font> | 固定值 <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">ReplicaSet</font>(资源类型)。 |
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">metadata</font> | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">Object</font> | 元数据,包含名称、标签、注解等(如 <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">metadata.name</font>指定 ReplicaSet 名称)。 |
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">spec</font> | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">Object</font> | ReplicaSet 的核心配置。 |
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">spec.replicas</font> | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">integer</font> | 期望的 Pod 副本数量(默认值为 1)。 |
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">spec.selector</font> | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">Object</font> | 必需,标签选择器(<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">matchLabels</font>或 <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">matchExpressions</font>),用于匹配 Pod。 |
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">spec.template</font> | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">Object</font> | 必需,Pod 模板(定义 Pod 的 <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">metadata</font>和 <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">spec</font>)。 |
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">spec.minReadySeconds</font> | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">integer</font> | Pod 启动后视为“就绪”的最小等待时间(秒,默认 0)。 |
<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">status</font> | <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">Object</font>(只读) | 当前状态信息(如 <font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(243, 243, 243);">status.readyReplicas</font>显示已就绪的 Pod 数量)。 |
实战一:创建Replicase资源
//创建yaml文件
vi nginx-replicaset.yaml
apiVersion: apps/v1 # 固定值,使用 apps/v1 API 版本
kind: ReplicaSet # 资源类型为 ReplicaSet
metadata:
name: nginx # ReplicaSet 名称
labels:
app: nginx # 为 ReplicaSet 添加标签(非必须)
spec:
replicas: 3 # 期望的 Pod 副本数量为 3
selector:
matchLabels:
app: web # 必须与 template 中的 labels 匹配,否则无法关联 Pod
template: # Pod 模板定义
metadata:
labels:
app: web # Pod 标签,必须与 selector.matchLabels 一致
spec:
containers:
- name: nginx # 容器名称
image: nginx:latest # 使用的镜像
imagePullPolicy: IfNotPresent # 镜像拉取策略(本地有则跳过拉取)
//应用yaml文件
kubectl apply -f nginx-replicaset.yaml
//查看replicase资源
kubectl get replicaset
● DESIRED:预期要管理的Pod
● CURRENT:当前启动的Pod
● READY:就绪的Pod
//查看replicase创建出来的pod
kubectl get pods
实战二:实现动态扩容(缩容把副本数改小就好了)
方法一:编辑yaml文件实现扩容(推荐方法)
//创建yaml文件
vi nginx-replicaset.yaml
//更改replicas值为4(这个字段控制pod的数量)
replicas: 4
//应用yaml文件
kubectl apply -f nginx-replicaset.yaml
//查看replicase资源
kubectl get replicaset
● DESIRED:预期要管理的Pod
● CURRENT:当前启动的Pod
● READY:就绪的Pod
//查看replicase创建出来的pod
kubectl get pods
方法二:编辑控制器实现扩容(不推荐)
//查看rs资源的名称
kubectl get rs
//编辑re资源(注意替换名称)
kubectl edit rs nginx
//编辑好之后、wq保存会立即生效
//查看replicase资源
kubectl get replicaset
● DESIRED:预期要管理的Pod
● CURRENT:当前启动的Pod
● READY:就绪的Pod
//查看replicase创建出来的pod
kubectl get pods
实战三:Replicase实现pod的动态更新
这里需要注意一下、rs在更新镜像的时候、不是自动的、你需要先把原来的给删除、新创建的pod才是新版本
//查看pod
kubectl get pods -o wide
//访问pod(地址上一步能查出来)
curl 10.244.58.200
//查看rs
kubectl get rs
//编辑yaml文件或者修改re控制器
vi nginx-replicaset.yaml
kubectl edit rs nginx
//可以另外开一个窗口通过kubectl get pods -w来观察pod状态
//发现pod没有更新、需要手动删除旧pod、新pod会自动创建、新创建的pod才会更新
//删除旧pod(注意替换名称)
kubectl delete pods nginx-6rlgb
//查看pod、发现新pod被创建出来
kubectl get pods -o wide
//再次访问、发现新pod更新
curl 10.244.85.198:8080
2.Deployment
Deployment更新方式:渐进式更新、先创建新的pod再删除旧pod、保证pod一直可用
所以、deployment新增了参数去控制渐进式更新时、新创建的pod数量。分别是 spec.strategy.type 、 spec.strategy.rollingU pdate.maxSurge 、 spec.strategy.rollingU pdate.maxUnavailable
spec.strategy.type : Recreate /RollingUpdate 新建一个删除一个也叫滚动更新/自定义更新时新建几个删除几个的数量
spec.strategy.rollingU pdate.maxSurge : 它有两种取值方式,第一种直接给定数量,第二种根据 百分比。 假设原本是5个,最多可以超出20%,那就允许多一个,那就是滚动更新了 最多可以超过40%,那就允许多两个
spec.strategy.rollingU pdate.maxUnavailable : 最多允许几个不可用。 假设有5个副本,最多一个不可用,就表示最少有4个 可用。
实战一:通过Deployment实现动态扩容(缩容的话把replicas值改小就可以了)
方式一:编辑yaml文件实现扩容(推荐)
//修改yaml文件
vi deploy-demo.yaml
apiVersion: apps/v1 # 固定值,使用 apps/v1 API 版本
kind: Deployment # 资源类型为 Deployment
metadata:
name: myapp # Deployment 名称
spec:
replicas: 3 # 期望的 Pod 副本数量为 3
selector:
matchLabels:
app: myapp # 必须与 template 中的 labels 匹配
version: v1 # 版本标签,可用于滚动更新
template: # Pod 模板定义
metadata:
labels:
app: myapp # Pod 标签,必须与 selector.matchLabels 一致
version: v1 # 版本标签,可用于区分不同版本
spec:
containers:
- name: myapp # 容器名称
image: janakiramm/myapp:v1 # 使用的镜像
imagePullPolicy: IfNotPresent # 镜像拉取策略(本地有则跳过拉取)
ports:
- containerPort: 80 # 容器监听的端口
//更新pod
kubectl apply -f deploy-demo.yaml
//查看创建的pod
kubectl get pods
//查看deployment管理的资源
kubectl get deployment
//编辑yaml文件、修改
replicas: 4
//更新pod
kubectl apply -f deploy-demo.yaml
//查看创建的pod
kubectl get pods
//查看deployment管理的资源
kubectl get deployment
方式二:编辑控制器实现扩容(跟replicase一样)
//修改deployment参数
kubectl edit deploy myapp
//编辑好之后wq保存、会立即生效
//查看创建的pod
kubectl get pods
//查看deployment管理的资源
kubectl get deployment
**实战二: Deployment实现pod的滚动升级 **
//查看正在运行的pod的页面信息
kubectl get pods -o wide
//访问pod(地址上一步能查出来)
curl 10.244.58.200
//查看rs
kubectl get rs
//编辑yaml文件或者修改re控制器
vi nginx-replicaset.yaml
kubectl edit rs nginx
//应用yaml文件(如果是通过yaml文件更新的)
kubectl apply -f deploy-demo.yaml
//可以另外开一个窗口通过kubectl get pods -w来观察pod状态
//查看pod、发现新pod被创建出来、发现不需要手动删除就能自动更新
kubectl get pods -o wide
//查看rs、发现有两个、一个是旧的、一个是新的、可以回滚
kubectl get rs
//再次访问、发现新pod更新
curl 10.244.85.198:8080
**实战三: Deployment实现pod的回滚 **
//查看pod对象的历史版本
kubectl rollout history deployment myapp
//回滚myapp的历史版本为1
kubectl rollout undo deployment myapp --to-revision=1
//查看Deployment myapp对象的历史版本
kubectl rollout history deployment myapp
//查看rs控制器、发现旧rs资源回来了、新的rs资源消失了
kubectl get rs
实战四、自定义滚动更新策略
前面讲过、滚动更新只能一个pod一个pod的渐进式更新、我们可以自定义数量、适用于pod数量比较多的情况、下面是maxSurge和maxUnavailable对于更新的影响、建议配置1、0、就是有点慢。
1. 默认策略(快速更新)
yaml
spec:
strategy:
rollingUpdate:
maxSurge: 25% # 允许临时超出期望副本数的 25%(向上取整)
maxUnavailable: 25% # 允许最多 25% 的 Pod 不可用(向下取整)
场景:
假设当前有 4 个 Pod,更新时会:
新增 1 个新 Pod(4 × 25% = 1,向上取整)。
允许 1 个旧 Pod 被终止(4 × 25% = 1,向下取整)。
效果:同时存在 5 个 Pod(4 旧 + 1 新)→ 逐步替换,更新速度较快。
2. 零宕机更新(先扩容再缩容)
yaml
spec:
strategy:
rollingUpdate:
maxSurge: 100% # 允许临时超出 100% 副本数(即翻倍)
maxUnavailable: 0 # 不允许任何 Pod 不可用
场景:
当前有 3 个 Pod,更新时会:
先创建 3 个新 Pod(总数变为 6:3 旧 + 3 新)。
等待新 Pod 就绪后,再逐步删除旧 Pod。
效果:全程保持 3 个可用 Pod,零宕机,但需要双倍资源。
3. 保守更新(最小影响)
yaml
spec:
strategy:
rollingUpdate:
maxSurge: 0 # 不允许超出期望副本数
maxUnavailable: 1 # 每次只允许 1 个 Pod 不可用
场景:
当前有 5 个 Pod,更新时会:
每次终止 1 个旧 Pod,并创建 1 个新 Pod。
同一时间最多 4 个 Pod 可用(5 - 1)。
效果:更新速度慢,但对资源无额外需求,适合低配集群。
4. 快速替换(激进更新)
yaml
spec:
strategy:
rollingUpdate:
maxSurge: 1 # 允许超出 1 个 Pod
maxUnavailable: 1 # 允许 1 个 Pod 不可用
场景:
当前有 3 个 Pod,更新时会:
先终止 1 个旧 Pod(剩余 2 旧)。
同时创建 1 个新 Pod(总数变为 3:2 旧 + 1 新)。
重复此过程直到全部替换。
效果:平衡速度与稳定性,适合大多数场景。
5. 大规模集群的平滑更新
yaml
spec:
strategy:
rollingUpdate:
maxSurge: 20% # 按比例控制扩容规模
maxUnavailable: 10% # 按比例控制不可用比例
场景:
当前有 100 个 Pod,更新时会:
最多新增 20 个新 Pod(100 × 20% = 20)。
最多 10 个旧 Pod 不可用(100 × 10% = 10)。
效果:适合大规模部署,避免瞬时资源激增。
下面是代码演示
//创建yaml文件
vi deploy-demo.yaml
apiVersion: apps/v1 # 固定值,使用 apps/v1 API 版本
kind: Deployment # 资源类型为 Deployment
metadata:
name: my-deploy # Deployment 名称
spec:
replicas: 2 # 期望的 Pod 副本数量为 2
selector:
matchLabels:
app: my-app # 必须与 template 中的 labels 匹配
template: # Pod 模板定义
metadata:
labels:
app: my-app # Pod 标签,必须与 selector.matchLabels 一致
spec:
containers:
- name: my-container # 容器名称
image: janakiramm/myapp:v1 # 使用的镜像(版本 v1)
ports:
- containerPort: 80 # 容器监听的端口
strategy: # 滚动更新策略配置
type: RollingUpdate # 使用滚动更新(默认策略)
rollingUpdate:
maxSurge: 50% # 允许临时超出 50% 的副本数(即最多 3 个 Pod)
maxUnavailable: 0 # 不允许任何 Pod 不可用(零宕机更新)
//maxSurge: 50%:当前 2 个副本时,允许临时新增 1 个 Pod(2 × 50% = 1),总数最多 3 个(2 旧 + 1 新)。
//maxUnavailable: 0:确保更新过程中始终有 2 个可用 Pod(零宕机)。
//应用yaml文件
kubectl apply -f deploy-demo.yaml
//另开一个窗口、对pod状态进行观察
kubectl get pods -w
//更新pod配置文件、更新了镜像
kubectl set image deployment/my-deploy my-container=janakiramm/myapp:v2
实战五:pod中添加域名解析和DNS配置
hostAliases字段用于将一些主机别名映射到Pod内的IP地址,以便Pod 内的容器可以通过这些别名来访问主机上的服务
添加域名解析
//在master节点创建yaml文件
vi nginx-hosts.yaml
apiVersion: apps/v1 # 固定值,使用 apps/v1 API 版本
kind: Deployment # 资源类型为 Deployment
metadata:
name: nginx-hosts # Deployment 名称
labels:
app: web # 为 Deployment 添加标签(可选)
spec:
replicas: 2 # 期望的 Pod 副本数量为 2
selector:
matchLabels:
app: web # 必须与 template 中的 labels 匹配
template: # Pod 模板定义
metadata:
labels:
app: web # Pod 标签,必须与 selector.matchLabels 一致
spec:
containers:
- name: nginx-hosts # 容器名称
image: nginx:latest # 使用的镜像
imagePullPolicy: IfNotPresent # 镜像拉取策略(本地有则跳过拉取)
hostAliases: # 自定义主机名映射(添加到 Pod 的 /etc/hosts)
- ip: "192.168.128.11" # 目标 IP 地址
hostnames: # 要映射的主机名列表
- "zyf.qq.com" # 第一个域名
- "zyf.test.com" # 第二个域名
//添加下划线的部分是我们新增的参数、用于主机名映射
//应用yaml
kubectl apply -f nginx-hosts.yaml
//查看创建的pod
kubectl get pods
//进入pod查看域名解析是否添加成功、正常会显示出我们的配置
kubectl exec -it nginx-hosts-c49499bfd-jvxq7 --cat/etc/hosts
添加dns配置
//在master节点创建yaml文件
vi nginx-dns.yaml
apiVersion: apps/v1 # 固定值,使用 apps/v1 API 版本
kind: Deployment # 资源类型为 Deployment
metadata:
name: nginx-dns # Deployment 名称
labels:
app: web # 为 Deployment 添加标签(可选)
spec:
replicas: 2 # 期望的 Pod 副本数量为 2
selector:
matchLabels:
app: web # 必须与 template 中的 labels 匹配
template: # Pod 模板定义
metadata:
labels:
app: web # Pod 标签,必须与 selector.matchLabels 一致
spec:
containers:
- name: nginx-dns # 容器名称
image: nginx:latest # 使用的镜像
imagePullPolicy: IfNotPresent # 镜像拉取策略(本地有则跳过拉取)
hostAliases: # 自定义主机名映射(添加到 Pod 的 /etc/hosts)
- ip: "192.168.128.11" # 目标 IP 地址
hostnames: # 要映射的主机名列表
- "zyf.qq.com" # 第一个域名
- "zyf.test.com" # 第二个域名
dnsPolicy: None # 自定义 DNS 策略(不使用默认配置)
dnsConfig: # 自定义 DNS 配置(当 dnsPolicy=None 时生效)
nameservers: # 自定义 DNS 服务器列表
- 192.168.128.254 # 主 DNS 服务器
- 192.168.128.1 # 备用 DNS 服务器
searches: # DNS 搜索域列表
- xiaozhang.svc.cluster.local # 第一个搜索域
- my.dns.search.xiaozhang # 第二个搜索域
//添加下划线的部分是我们新增的参数、用于域名解析
//应用yaml
kubectl apply -f nginx-dns.yaml
//查看创建的pod
kubectl get pods
//进入pod查看域名解析是否添加成功、正常会显示出我们的配置
kubectl exec -it nginx-dns-55c976dcf6-k4zxq --cat/etc/resolv.conf
**实战六: 、Deployment控制器创建一个web站点 **
deployment是一个三级结构,deployment管理replicaset,replicaset 管理pod。
//在master节点创建yaml文件
vi deploy-demo.yaml
apiVersion: apps/v1 # 固定值,使用 apps/v1 API 版本
kind: Deployment # 资源类型为 Deployment
metadata:
name: myapp # Deployment 名称
spec:
replicas: 2 # 期望的 Pod 副本数量为 2
selector:
matchLabels:
app: myapp # 必须与 template 中的 labels 匹配
version: v1 # 版本标签,可用于滚动更新
template: # Pod 模板定义
metadata:
labels:
app: myapp # Pod 标签,必须与 selector.matchLabels 一致
version: v1 # 版本标签,可用于区分不同版本
spec:
containers:
- name: myapp # 容器名称
image: janakiramm/myapp:v1 # 使用的镜像(版本 v1)
imagePullPolicy: IfNotPresent # 镜像拉取策略(本地有则跳过拉取)
ports:
- containerPort: 80 # 容器监听的端口
//更新清单文件
kubectl apply -f deploy-demo.yaml
//查看deploy状态
kubectl get deploy
NAME:列出名称空间中deployment的名称。
READY:显示deployment有多少副本数。它遵循ready/desired的模式。
UP-TO-DATE:显示已更新到所需状态的副本数。
AVAILABLE:显示你的可以使用多少个应用程序副本。
AGE:显示应用程序已运行的时间。
//查看rs
kubectl get rs
NAME:列出名称空间中ReplicaSet资源
DESIRED:显示应用程序的所需副本数,这些副本数是在创建时定义的。这
是所需的状态。
CURRENT:显示当前正在运行多少个副本。
READY:显示你的用户可以使用多少个应用程序副本。
AGE:显示应用程序已运行的时间。
//查看创建的pod
kubectl get pods
3.Daemonset
在每个Node上运行一个 Pod 的副本。它确保在Kubernetes集群的每个节点上都存在一个Pod副本,并 且这个Pod副本可以执行一些特定的任务,例如监控、日志收集、节点维护等
当一个新的节点加入Kubernetes集群时,DaemonSet会自动在这 个节点上启动一个Pod副本,当一个节点从集群中删除时,该节点上的Pod副本 也会被删除
DaemonSet 控制器常用于部署一些系统级别的服务或应用程序,如fluentd、 kube-proxy 和 Node Exporter。
Deployment控制器通常会使用“滚动升级”等策略来更新和 升级应用程序。即创建一组新的Pod,逐步替换旧的Pod,以便在不影响现有服 务的情况下,实现平滑的升级 DaemonSet通常会使用“替换升级”策略,即通过删除旧Pod和创建新Pod的方式来更新DaemonSet,因为DaemonSet通常只 有一个Pod,只需要将旧Pod替换为新的Pod,就可以完成升级
Daemonset的应用场景
1、日志收集器:DaemonSet可以在每个节点上运行日志收集器,例如Fluentd 或者Filebeat,从而收集所有节点的日志数据,并将其发送到中心日志服务器 进行存储和分析。
2、监控代理:DaemonSet可以在每个节点上运行监控代理,例如Prometheus Node Exporter,从而收集所有节点的运行状态数据,并将其发送到中心监控服 务器进行分析和展示。
3、网络代理:DaemonSet可以在每个节点上运行网络代理,例如kube-proxy 或者Istio Sidecar,从而负责节点之间的网络通信和流量管理。
4、安全代理:DaemonSet可以在每个节点上运行安全代理,例如SysdigFalco 或者AquaSecurity,从而检测所有节点的安全事件,并及时报警或者进行防御。
DaemonSet 适用于需要在每个节点上运行一组Pod的场景,可以使集 群中的服务更加健壮和可靠
**实战一: 部署日志收集组件fluentd(先不用管这个组件是什么) **
//在master节点创建yaml文件
vi daemonset.yaml
apiVersion: apps/v1 # 固定值,使用 apps/v1 API 版本
kind: DaemonSet # 资源类型为 DaemonSet
metadata:
name: fluentd # DaemonSet 名称
namespace: logging # 部署到 logging 命名空间
labels:
log: fluentd # 为 DaemonSet 添加标签(可选)
spec:
selector:
matchLabels:
name: fluentd # 必须与 template 中的 labels 匹配
template: # Pod 模板定义
metadata:
labels:
name: fluentd # Pod 标签,必须与 selector.matchLabels 一致
spec:
tolerations: # 容忍度配置(允许调度到控制平面节点)
- key: node-role.kubernetes.io/control-plane
operator: Exists # 容忍所有带此污点的节点
effect: NoSchedule # 仅容忍 NoSchedule 污点
containers:
- name: fluentd # 容器名称
image: fluentd:latest # 使用的镜像
resources: # 资源配额配置
limits: # 资源上限
memory: 1024Mi # 内存上限 1GB
cpu: 500m # CPU 上限 0.5核
requests: # 资源请求(调度依据)
memory: 100Mi # 最小内存需求 100MB
cpu: 50m # 最小 CPU 需求 0.05核
//更新资源清单文件、如果报错、看看是不是污点的问题
kubectl apply -f daemonset.yaml
//查看新创建的daemonset控制器
kubectl get daemonset fluentd -n logging
//查看创建的pod
kubectl get pods -n kube-system -o wide -l name=fluentd
//可以发现k8s的每个节点都创建了fluentd这个pod
实战二:基于Daemonset的滚动更新
//修改上面的yaml配置文件、增加更新策略、蓝色部分为添加的配置
cat daemonset.yaml
apiVersion: apps/v1 # 固定值,使用 apps/v1 API 版本
kind: DaemonSet # 资源类型为 DaemonSet
metadata:
name: fluentd # DaemonSet 名称
namespace: logging # 部署到 logging 命名空间
labels:
log: fluentd # 为 DaemonSet 添加标签(可选)
spec:
updateStrategy: # 更新策略配置
type: RollingUpdate # 使用滚动更新(默认策略)
rollingUpdate:
maxSurge: 1 # 允许临时创建 1 个新 Pod(超出节点数)
maxUnavailable: 0 # 不允许任何 Pod 不可用(零宕机更新)
selector:
matchLabels:
name: fluentd # 必须与 template 中的 labels 匹配
template: # Pod 模板定义
metadata:
labels:
name: fluentd # Pod 标签,必须与 selector.matchLabels 一致
spec:
tolerations: # 容忍度配置(允许调度到控制平面节点)
- key: node-role.kubernetes.io/control-plane
operator: Exists # 容忍所有带此污点的节点
effect: NoSchedule # 仅容忍 NoSchedule 污点
containers:
- name: fluentd # 容器名称
image: fluentd:latest # 使用的镜像
resources: # 资源配额配置
limits: # 资源上限
memory: 1024Mi # 内存上限 1GB
cpu: 500m # CPU 上限 0.5核
requests: # 资源请求(调度依据)
memory: 100Mi # 最小内存需求 100MB
cpu: 50m # 最小 CPU 需求 0.05核
//上面表示rollingUpdate更新策略只支持maxUnavailabe,先删除在更新
因为我们不支持一个节点运行两个pod,因此需要先创建一个,再删除一个。
方法二:直接在命令行更新
kubectl set image daemonsets fluentd fluentd=nginx:latest-nlogging