前言
掌握 Pod 基础配置后,进阶能力才是保障 K8s 应用稳定运行的关键。想象一下:如果容器无节制占用 CPU 和内存,会导致其他服务崩溃;如果应用卡死但 K8s 不知情,会持续转发流量造成故障;如果容器启动时依赖未就绪或关闭时未保存数据,会引发业务异常。
这篇文章就用 “大白话 + 实操案例”,带你吃透 Pod 进阶配置——资源限制避免资源争用、健康探针实现自动自愈、生命周期钩子管理启停动作,让你的 K8s 应用既稳定又可控。
一、Pod 进阶配置
1.1 Pod 资源限制
集群资源就像公寓的水电,每个容器不能无限制使用。K8s 提供资源限制功能,给每个容器设定 “最低需求” 和 “最高上限”,避免资源浪费或争用。
1.1.1 核心概念
- requests(资源请求):容器启动的 “最低生活费”,是容器运行必需的最小资源。K8s 调度器会根据这个值,选择有足够剩余资源的节点部署 Pod。
- limits(资源限制):容器运行的 “消费上限”,是容器能使用的最大资源。超出这个限制后,CPU 会被限制使用(降速),内存会被强制终止(OOM 杀死)。
简单说:requests 决定 “能部署到哪个节点”,limits 决定 “最多能用多少资源”。
1.1.2 资源单位
- CPU 单位:用 “毫核(m)” 表示,1 核 CPU = 1000m。
- 500m = 0.5 核 CPU(半个核心);
- 250m = 0.25 核 CPU(四分之一核心);
- 支持小数,比如 0.5 核和 500m 是同一个意思。
- 内存单位:推荐用二进制单位(Gi、Mi、Ki),基于 1024 换算;也支持十进制单位(GB、MB),基于 1000 换算。
- 1Gi = 1024Mi,1Mi = 1024Ki;
- 注意:1Gi 比 1GB 大(约多 73MB),K8s 中优先用 Gi/Mi 避免数据丢失。
1.2 Pod 资源限制案例
下面通过两个实际配置,带你看懂资源请求和限制的配置逻辑。
示例 1:基础资源配置
apiVersion:v1kind:Podmetadata:name:frontendspec:containers:-name:app# 主应用容器image:images.my-company.example/app:v4resources:requests:memory:"64Mi"# 最少需要 64Mi 内存cpu:"250m"# 最少需要 0.25 核 CPUlimits:memory:"128Mi"# 最多能用 128Mi 内存cpu:"500m"# 最多能用 0.5 核 CPU-name:log-aggregator# 日志收集容器image:images.my-company.example/log-aggregator:v6resources:requests:memory:"64Mi"cpu:"250m"limits:memory:"128Mi"cpu:"500m"通俗分析:
- 每个容器的 “最低需求” 都是 0.25 核 CPU + 64Mi 内存;
- 每个容器的 “消费上限” 都是 0.5 核 CPU + 128Mi 内存;
- 整个 Pod 的总需求:0.5 核 CPU + 128Mi 内存(两个容器相加);
- 整个 Pod 的总上限:1 核 CPU + 256Mi 内存。
案例 1:不同容器差异化配置
apiVersion:v1kind:Podmetadata:name:frontendspec:containers:-name:web# Nginx web 容器image:nginxresources:requests:memory:"64Mi"# 需求低cpu:"250m"limits:memory:"128Mi"cpu:"500m"-name:db# MySQL 数据库容器image:mysqlresources:requests:memory:"512Mi"# 数据库需要更多内存,需求高cpu:"0.5"# 0.5 核 CPU(等同于 500m)limits:memory:"1Gi"# 上限 1Gi 内存cpu:"1"# 上限 1 核 CPU通俗分析:
- Web 容器(轻量):低需求、低上限;
- DB 容器(耗资源):高需求、高上限;
- Pod 总需求:0.75 核 CPU + 576Mi 内存;
- Pod 总上限:1.5 核 CPU + 1.128Gi 内存(1Gi + 128Mi)。
调度与资源分配
K8s 调度 Pod 时,只会看requests(最低需求),不会看limits。
Pod 调度实例:
- 执行命令部署 Pod:
kubectl apply -f pod2.yaml; - 查看 Pod 部署到哪个节点:
kubectl get pods -o wide; - 查看节点资源使用情况:
kubectl describe nodes 节点名(比如 node02)。
- 执行命令部署 Pod:
实际分配情况:
- 假设节点有 2 核 CPU,Pod 总 requests 是 0.75 核,就会占用节点 37.5% 的 CPU 资源;
- 节点资源不够时,K8s 会自动把 Pod 调度到其他有空闲资源的节点。
总结:
- 未设置 requests 时,K8s 会默认让它等于 limits;
- 多个容器的 requests 和 limits 会自动相加,作为 Pod 的总资源;
- 按容器角色差异化配置:数据库、缓存等耗资源组件,requests 和 limits 设高些;轻量组件设低些。
1.3 健康检查(探针 Probe)
K8s 里的 “健康医生”,定期检查容器状态,发现问题自动处理(比如重启容器、移出流量)。探针由 kubelet 执行,分 3 种类型,支持 3 种检查方法。
1.3.1 探针类型(重点)
| 探针类型 | 作用 | 失败处理方式 |
|---|---|---|
| livenessProbe(存活探针) | 检测容器是否 “活着”(正常运行) | 杀死容器,按重启策略重启 |
| readinessProbe(就绪探针) | 检测容器是否 “准备好”(能接收请求) | 从 Service 中移除 Pod,不转发流量 |
| startupProbe(启动探针) | 检测应用是否 “启动完成”(适用于慢启动) | 启动前屏蔽其他探针,失败则重启容器 |
小贴士:启动探针是 K8s 1.17 版本后新增的,比如 Java 应用启动慢,就用它避免其他探针误判。
1.3.2 检查方法
探针通过 3 种方式检查容器状态,按需选择:
- exec:在容器内执行命令,返回码为 0 表示成功(比如检查文件是否存在);
- httpGet:向容器的指定端口和路径发 HTTP 请求,状态码 200-399 表示成功;
- tcpSocket:尝试连接容器的指定端口,能建立 TCP 连接表示成功。
每次探测结果只有 3 种:成功、失败、未知(通信问题,不处理)。
二、Kubernetes 探针(Probe)实践
光懂理论不够,下面通过实操案例,带你玩转 3 种探针,看完就能上手。
2.1 存活探针(Liveness Probe)实践
存活探针的核心:容器 “死了” 就重启,保障应用持续运行。
2.1.1 Exec 方式:执行命令检测
示例 1:核心配置
apiVersion:v1kind:Podmetadata:name:liveness-execspec:containers:-name:liveness-containerimage:busybox# 容器启动后:创建 /tmp/live 文件 → 10 秒后删除 → 休眠 3600 秒command:["/bin/sh","-c","touch /tmp/live; sleep 10; rm -rf /tmp/live; sleep 3600"]livenessProbe:exec:command:["test","-e","/tmp/live"]# 检查 /tmp/live 文件是否存在initialDelaySeconds:1# 容器启动 1 秒后开始探测periodSeconds:3# 每 3 秒探测一次执行命令与结果:
- 创建 Pod:
kubectl create -f exec.yaml; - 实时查看状态:
kubectl get pods -w; - 结果:前 10 秒文件存在,探针成功;10 秒后文件删除,探针失败,K8s 重启容器(RESTARTS 次数增加)。
2.1.2 HTTP Get 方式:发送 HTTP 请求检测
案例 2:实操配置
apiVersion:v1kind:Podmetadata:name:liveness-httpgetspec:containers:-name:nginx-containerimage:soscscs/myapp:v1ports:-containerPort:80# Nginx 监听 80 端口livenessProbe:httpGet:port:80# 探测 80 端口path:/index.html# 探测路径 /index.htmlinitialDelaySeconds:1periodSeconds:3timeoutSeconds:10# 超时时间 10 秒执行命令与结果:
- 创建 Pod:
kubectl create -f httpget.yaml; - 模拟异常:删除 index.html 文件 →
kubectl exec -it liveness-httpget -- rm -rf /usr/share/nginx/html/index.html; - 查看状态:
kubectl get pods,发现 RESTARTS 增加(探针失败,重启容器)。
2.1.3 TCP Socket 方式:TCP 连接检测
案例 3:实操配置
apiVersion:v1kind:Podmetadata:name:probe-tcpspec:containers:-name:nginx-containerimage:soscscs/myapp:v1livenessProbe:tcpSocket:port:8080# 故意配错端口(Nginx 实际监听 80)initialDelaySeconds:5# 启动 5 秒后探测periodSeconds:10# 每 10 秒探测一次failureThreshold:2# 失败 2 次后重启执行命令与结果:
- 创建 Pod:
kubectl create -f tcpsocket.yaml; - 查看容器监听端口:
kubectl exec -it probe-tcp -- netstat -natp,发现只监听 80 端口; - 实时查看状态:
kubectl get pods -w,25 秒后(5 秒延迟 + 10 秒×2 次失败)容器重启,RESTARTS 增加; - 修复:把端口改成 80,重新应用配置 →
kubectl apply -f tcpsocket.yaml,Pod 不再重启。
2.2 就绪探针(Readiness Probe)实践
就绪探针的核心:容器 “没准备好” 就不接收流量,避免用户访问异常。
案例 4:就绪探针与存活探针协同
apiVersion:v1kind:Podmetadata:name:readiness-httpgetspec:containers:-name:app-containerimage:soscscs/myapp:v1ports:-containerPort:80readinessProbe:# 就绪探针:检测 /index1.htmlhttpGet:port:80path:/index1.htmlinitialDelaySeconds:1periodSeconds:3livenessProbe:# 存活探针:检测 /index.htmlhttpGet:port:80path:/index.htmlinitialDelaySeconds:1periodSeconds:3执行命令与结果:
- 创建 Pod:
kubectl create -f readiness-httpget.yaml; - 初始状态:
kubectl get pods,READY 为 0/1(/index1.html 不存在,未就绪); - 模拟就绪:创建 /index1.html →
kubectl exec -it readiness-httpget -- echo 123 > /usr/share/nginx/html/index1.html; - 查看状态:READY 变为 1/1(就绪,可接收流量);
- 模拟崩溃:删除 /index.html →
kubectl exec -it readiness-httpget -- rm -rf /usr/share/nginx/html/index.html; - 查看状态:存活探针失败,容器重启,READY 变回 0/1。
案例 5:就绪探针与 Service Endpoint 联动
核心逻辑:Service 只会把流量转发给 “就绪” 的 Pod,未就绪的 Pod 会被移出 Endpoint(服务端点)。
实操配置(含 3 个 Pod 和 1 个 Service):
# readiness-myapp.yamlapiVersion:v1kind:Podmetadata:name:myapp1labels:{app:myapp}spec:containers:-name:myappimage:soscscs/myapp:v1ports:[{containerPort:80}]readinessProbe:httpGet:{port:80,path:/index.html}initialDelaySeconds:5periodSeconds:5---apiVersion:v1kind:Podmetadata:name:myapp2labels:{app:myapp}spec:# 配置和 myapp1 一致,省略...---apiVersion:v1kind:Podmetadata:name:myapp3labels:{app:myapp}spec:# 配置和 myapp1 一致,省略...---apiVersion:v1kind:Servicemetadata:{name:myapp}spec:selector:{app:myapp}type:ClusterIPports:[{port:80,targetPort:80}]执行命令与结果:
- 创建资源:
kubectl create -f readiness-myapp.yaml; - 初始状态:
kubectl get pods,svc,endpoints -o wide,3 个 Pod 都就绪,Endpoint 包含 3 个 Pod 的 IP; - 模拟故障:删除 myapp1 的 index.html →
kubectl exec -it myapp1 -- rm -rf /usr/share/nginx/html/index.html; - 查看状态:myapp1 的 READY 变为 0/1,Endpoint 中移除 myapp1 的 IP(不再接收流量);
- 修复后:myapp1 重新就绪,Endpoint 自动添加其 IP。
三、容器生命周期钩子管理实践
生命周期钩子就像容器的 “自定义动作”,在启动后、关闭前执行指定操作,比如初始化配置、保存数据。
3.1 案例 6:初始化容器与生命周期钩子
核心配置:
apiVersion:v1kind:Podmetadata:name:lifecycle-demospec:# 初始化容器:主容器启动前执行initContainers:-name:init-containerimage:soscscs/myapp:v1command:["/bin/sh","-c","echo '初始化完成' >> /var/log/message"]volumeMounts:-name:log-volumemountPath:/var/log# 挂载存储卷,共享日志# 主容器containers:-name:main-containerimage:soscscs/myapp:v1lifecycle:postStart:# 主容器启动后执行exec:command:["/bin/sh","-c","echo '主容器启动' >> /var/log/message"]preStop:# 主容器关闭前执行exec:command:["/bin/sh","-c","echo '主容器关闭' >> /var/log/message"]volumeMounts:-name:log-volumemountPath:/var/log# 存储卷:共享日志文件volumes:-name:log-volumehostPath:path:/data/logtype:DirectoryOrCreate# 不存在则创建目录执行命令与结果:
- 创建 Pod:
kubectl create -f post.yaml; - 查看日志(验证执行顺序):
kubectl exec -it lifecycle-demo -- cat /var/log/message,输出:初始化完成 主容器启动 - 删除 Pod(触发 preStop):
kubectl delete pod lifecycle-demo; - 查看节点上的日志(存储卷挂载到节点):
输出:# 登录节点执行cat/data/log/message初始化完成 主容器启动 主容器关闭
核心逻辑总结
- 初始化容器(initContainers):主容器启动前执行,完成前置准备(如初始化配置、等待依赖);
- postStart:主容器启动后立即执行(可能和应用并行),用于启动后的自定义操作;
- preStop:主容器关闭前执行(同步操作,阻塞删除),用于优雅关闭(如保存数据、断开连接)。
四、Pod 与容器的状态说明
遇到问题时,Pod 和容器的状态是 “故障排查指南针”,下面用通俗的语言解释每种状态:
4.1 Pod 状态
- Pending:Pod 已被 K8s 认可,但容器还没启动(比如正在调度节点、拉取镜像);
- Running:Pod 已调度到节点,至少一个容器在运行(或启动中);
- Succeeded:所有容器正常终止,且不会重启(比如一次性任务执行完成);
- Failed:所有容器都终止了,且至少一个容器异常终止(退出码非 0 或被强制杀死);
- Unknown:无法获取状态(通常是 K8s 与节点通信失败)。
4.2 容器状态
- Waiting:容器正在启动中(如拉取镜像、执行初始化命令);
- Running:容器正常运行;
- Terminated:容器已终止(正常或异常,可通过退出码判断)。
小贴士:用
kubectl get pods看 Pod 状态,用kubectl describe pod 名称看详细事件,快速定位问题。
总结
这篇文章围绕 Pod 进阶配置的核心能力展开,关键要点可总结为 3 点:
- 资源限制:用 requests 保障容器 “最低需求”,用 limits 防止 “资源滥用”,按容器角色差异化配置,避免争用;
- 探针实践:存活探针保运行,就绪探针保可用,启动探针适配慢启动应用,3 种检查方法按需选择;
- 生命周期与状态:初始化容器做前置准备,postStart/preStop 实现自定义动作,状态信息帮你快速排查故障。
掌握这些能力,就能让你的 K8s 应用从 “能运行” 变成 “稳定运行、自动自愈、易于维护”