
健康检查与资源管理Part 1探针与健康检查概念引入你在一家餐厅当经理。你需要知道三件事厨师还活着吗— 如果厨师晕倒了你需要换人重启 Pod厨师准备好接单了吗— 厨师活着但还在热锅这时候别给他派单暂停流量新厨师上手了吗— 新来的厨师需要培训时间别在他还没学会的时候就说他不行启动保护期K8s 的探针就是这三件事。它们是 K8s 用来自动检查 Pod 健康状态的体检工具。K8s 探针失败失败成功失败成功 Liveness你还活着吗✅ Readiness你准备好接单了吗 Startup你启动好了吗重启 Pod停止发送流量恢复流量继续等待激活 L R 探针原理讲解三种探针探针问什么失败时 K8s 做什么什么时候用Liveness“你还活着吗”杀掉 Pod 并重启应用可能死锁、卡住Readiness“你准备好接流量了吗”从 Service 端点中移除 Pod应用启动需要加载数据Startup“你启动好了吗”等待不杀也不加流量慢启动应用如 Java/Spring探针的检查方式K8s 支持三种方式来做健康检查检查方式HTTP GET发 HTTP 请求2xx/3xx 健康TCP Socket尝试建 TCP 连接连上 健康Exec Command在容器内执行命令exit 0 健康方式适用场景示例HTTP GETWeb 应用GET /healthz返回 200 表示健康TCP Socket数据库、缓存连接 3306 端口连上表示健康Exec任意应用cat /tmp/healthy文件存在表示健康探针的关键参数livenessProbe:httpGet:path:/healthzport:8080initialDelaySeconds:10# Pod 启动后等 10 秒再开始检查periodSeconds:5# 每 5 秒检查一次timeoutSeconds:3# 检查超时时间failureThreshold:3# 连续失败 3 次才算不健康successThreshold:1# 连续成功 1 次才算恢复PodK8sPodK8sinitialDelaySeconds: 等 10 秒failureThreshold 达到检查 1 (periodSeconds: 5s)✅ 成功检查 2❌ 失败 (1/3)检查 3❌ 失败 (2/3)检查 4❌ 失败 (3/3)杀掉并重启Liveness vs Readiness一个常见误区⚠️不要把 Readiness 检查的逻辑放到 Liveness 里Liveness 失败 重启 Pod。如果你的 Liveness 探针检查数据库连接当数据库临时不可用时K8s 会重启所有 Pod——但这解决不了问题数据库还是不可用反而引发雪崩。Readiness 失败 暂停流量。同样的场景Readiness 失败只会让 Pod 暂停接收请求等数据库恢复后自动恢复。检查内容该用哪个为什么应用进程是否存在Liveness进程死了需要重启数据库连接是否正常ReadinessDB 不可用时暂停流量不要重启缓存是否加载完成Readiness加载期间不接流量应用是否完成初始化Startup慢启动需要保护期动手实验配套实验位于docs/labs/beginner/probes/步骤 1部署带健康检查的应用cddocs/labs/beginner/probesbashsetup.sh步骤 2观察 Readiness 探针# 查看 Pod 状态 — 注意 READY 列kubectl get pods-lapphealth-demo-w你会看到 Pod 从0/1变成1/1说明 Readiness 探针通过了。步骤 3触发 Liveness 探针失败# 模拟应用死锁删除健康检查文件kubectlexecdeploy/health-demo --rm/tmp/healthy# 观察 Pod 重启kubectl get pods-lapphealth-demo-w# 预期RESTARTS 计数增加Pod 经历 CrashLoopBackOff → Running步骤 4观察 Readiness 对 Service 的影响# 触发 Readiness 失败kubectlexecdeploy/health-demo --rm/tmp/ready# Pod 还在运行但 READY 变为 0/1kubectl get pods-lapphealth-demo-w# 预期READY 0/1STATUS Running# 查看 Service 端点 — Pod 被移除kubectl get endpoints health-svc# 预期Endpoints 为空# 恢复 Readinesskubectlexecdeploy/health-demo --touch/tmp/ready# Pod 重新出现在端点中kubectl get endpoints health-svc步骤 5清理bashteardown.shPart 2资源请求与限制概念引入想象你和室友合租房。你跟房东说“我最少需要一间卧室request最多用两间limit。” 房东根据你的 request 给你分配房间但如果你偷偷用了三间房东就会把你赶出去OOMKilled。K8s 的资源管理就是这个逻辑requests你对调度器说我至少需要这么多资源——调度器据此选择节点limits你对内核说我最多用这么多——超了就被杀Pod 声明调度器据此选择节点内核据此强制限制超出 limitrequestscpu: 0.5memory: 256Milimitscpu: 1memory: 512MiSchedulercgroup 限制☠️ OOMKilled原理讲解requests vs limits维度requestslimits谁用Scheduler调度器kubelet 内核 cgroup作用调度时保证节点有足够资源运行时限制容器不能超过的上限超出后果Pod 无法调度Pending容器被 OOMKilled 或 CPU 被 throttle可以超卖✅ 节点上所有 Pod 的 requests 总和可以 节点容量超卖❌ limits 是硬上限三种 QoS 等级K8s 根据 Pod 的 requests 和 limits 设置自动给 Pod 分配QoSQuality of Service等级。当节点资源不足时K8s 按 QoS 从低到高驱逐 PodQoS 等级从最安全到最危险 Guaranteedrequests limits最后被驱逐 Burstable至少一个容器设了 request中间被驱逐 BestEffort什么都没设最先被驱逐QoS 等级条件驱逐优先级建议场景Guaranteed所有容器都设了 requests limits最低最后被驱逐核心业务数据库、APIBurstable至少一个容器设了 requests 或 limits中间普通 Web 应用BestEffort所有容器都没设 requests 和 limits最高最先被驱逐临时任务、测试 Pod最佳实践生产环境的所有 Pod 都应该设 requests 和 limits。不设就是 BestEffort节点一紧张你的 Pod 就第一个被杀。OOMKilled内存超限当容器使用的内存超过 limits时Linux 内核的 OOM Killer 会杀掉容器中的进程。Pod 状态会显示OOMKilled。# 这个 Pod 声明了 128Mi 的内存 limit# 如果应用试图用 200Mi就会被 OOMKilledresources:requests:memory:64Milimits:memory:128Mi# 硬上限超过即杀CPU ThrottleCPU 超限CPU 和内存不同——CPU 超 limits 不会被杀而是被限速throttle。就像高速公路上限速你不会被抓但跑不快了。resources:limits:cpu:500m# 最多用 0.5 核超过会被限速怎么设置合理的 requests 和 limits1. 不设置跑应用观察实际资源使用2. 设 requests P50 使用量50%的时间够用3. 设 limits P99 使用量 × 1.5留足峰值余量4. 持续观察根据 Grafana调优动手实验配套实验位于docs/labs/beginner/resource-limits/步骤 1部署不同 QoS 的 Podcddocs/labs/beginner/resource-limitsbashsetup.sh步骤 2查看 QoS 等级# 查看五个 Pod 的 QoSkubectl get pods-ocustom-columns\NAME:.metadata.name,\QOS:.status.qosClass,\CPU_REQ:.spec.containers[0].resources.requests.cpu,\MEM_REQ:.spec.containers[0].resources.requests.memory,\CPU_LIM:.spec.containers[0].resources.limits.cpu,\MEM_LIM:.spec.containers[0].resources.limits.memory预期输出NAME QOS CPU_REQ MEM_REQ CPU_LIM MEM_LIM besteffort BestEffort none none none none burstable Burstable 50m 64Mi 200m 256Mi cpu-throttle-demo Burstable 50m none 100m none guaranteed Guaranteed 100m 128Mi 100m 128Mi oom-demo Burstable none 20Mi none 50Mi步骤 3触发 OOMKilled# 这个 Pod 的内存 limit 是 50Mi我们让它吃超过 50Mi 的内存kubectlexecoom-demo --sh-cdd if/dev/zero of/dev/null bs60M count1# 等几秒查看 Pod 状态kubectl get pod oom-demo# 预期RESTARTS 增加# 查看 OOMKilled 详情Last State 显示 OOMKilledkubectl describe pod oom-demo|grep-A5Last State步骤 4观察 CPU Throttle CPU 和内存不同——内存超限会被 OOMKilled但 CPU 超限只是被限速throttlePod 不会被杀。# 1. 部署 Metrics Serverkubectl apply-fhttps://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml# 2. 为 Kind 环境打补丁重要kubectl patch deployment metrics-server-nkube-system\--typejson\-p[{op:add,path:/spec/template/spec/containers/0/args/-,value:--kubelet-insecure-tls}]# 3. 等待并验证kubectl get pod-nkube-system-lk8s-appmetrics-server-w# cpu-throttle-demo Pod 里跑的是死循环 while true; do :; done# 它会尽力吃掉所有 CPU但 limit100m 把它限制在 0.1 核kubectltoppod cpu-throttle-demo# 预期输出CPU 约 100m不会超过 limit# NAME CPU(cores) MEMORY(bytes)# cpu-throttle-demo 100m 1Mi注意kubectl top显示的是被限速后的实际用量不是 throttling 次数。如果要确认是否真的在被 throttle需要看 cgroup 的nr_throttled计数器kubectlexeccpu-throttle-demo --cat/sys/fs/cgroup/cpu.stat2/dev/nullnr_throttled就是该容器从启动到现在被 CPU throttle 的总次数。步骤 5清理bashteardown.sh自检问题Liveness 探针和 Readiness 探针失败时K8s 分别做什么查看答案 **Liveness 失败**K8s 杀掉 Pod 并根据 restartPolicy 决定是否重启。**Readiness 失败**K8s 不会杀 Pod但会从 Service 的 Endpoints 中移除它不再给它发流量。等 Readiness 恢复后Pod 自动重新加入 Endpoints。为什么慢启动的应用如 Java Spring Boot需要 Startup 探针查看答案 Java/Spring Boot 启动可能需要 30-60 秒加载类、初始化 Bean。如果没有 Startup 探针Liveness 探针会在应用还没启动完时就判定失败并反复重启导致应用永远起不来。Startup 探针提供一个启动保护期——只有 Startup 探针通过后才激活 Liveness 和 Readiness。requests 和 limits 的区别是什么各在什么阶段起作用查看答案 **requests** 在**调度阶段**起作用——调度器根据 requests 选择有足够资源的节点。**limits** 在**运行阶段**起作用——通过 cgroup 限制容器的资源上限。内存超 limits 会被 OOMKilledCPU 超 limits 会被 throttle限速但不杀。一个 Pod 的 requests 设为 100m CPUlimits 设为 500m CPU。当这个 Pod 实际只用 50m CPU 时节点上多出来的 CPU 资源能被其他 Pod 用吗查看答案 **可以。** CPU 资源是**可压缩资源**当 Pod 实际用量低于 requests 时空闲的 CPU 可以被同一节点上的其他 Pod 使用。但如果所有 Pod 同时需要 CPU调度器保证每个 Pod 至少能拿到 requests 声明的量。内存是**不可压缩资源**不能动态分享。下一步你的应用会自我体检、有资源保障了。接下来认识两种特殊的控制器→ 08. 高级工作负载DaemonSet、StatefulSet、Job、CronJob本文来自 K8s Guide—— 开源免费的 Kubernetes 中文学习指南️ 初学者轨道 面试轨道从零基础到拿 Offer 一站式覆盖 每篇文章配套 Kind 实验脚本本地一键运行 本文源码docs/beginner/12-probes.md / docs/beginner/13-resource-limits.md⭐如果对你有帮助欢迎 Stargithub.com/callmebg/k8s-guide