Kubernetes Startup、Readiness、Liveness探针全过程
容器主进程存在,只能证明PID还在,不代表应用已经完成初始化、能接收新流量或能够从内部死锁中恢复。Kubernetes通过startupProbe、readinessProbe和livenessProbe,让kubelet周期判断容器处于启动、就绪还是需要重启的状态。
探针配置错误同样会制造事故:慢启动Java服务被liveness反复杀死、数据库抖动让所有Pod同时重启、Readiness过于敏感让Endpoint全部消失、固定返回200又把已经线程池耗尽的实例持续暴露。本页从kubelet执行机制讲到Service流量和容器重启结果。
学习目标
学完后应能:
- 区分Container Running、Started、Ready、Live和业务端到端可用。
- 解释探针由Node上的kubelet执行,而不是Deployment或Service执行。
- 解释startupProbe如何门控readiness/liveness。
- 计算initialDelay、period、timeout、failureThreshold和successThreshold的时间边界。
- 解释Readiness失败怎样写回Pod Condition并异步影响EndpointSlice。
- 解释Liveness/Startup失败怎样让kubelet重启单个容器,而不是迁移Pod。
- 区分HTTP、TCP、gRPC和Exec探测能证明与不能证明什么。
- 为Spring Boot设计不产生级联重启的Liveness/Readiness契约。
- 解释主端口与独立Management端口的可观测性取舍。
- 设计慢启动、线程池耗尽、依赖抖动和优雅终止场景。
- 根据Event、ContainerStatus、Restart Count和EndpointSlice排查误杀/摘流。
- 区分Kubernetes Probe、Docker Healthcheck、外部合成监控和业务Smoke。
一、先区分五个状态
| 状态 | 回答的问题 | 常见证据 |
|---|---|---|
| Running | 容器进程是否已经启动且当前未终止 | Container State |
| Started | 应用启动阶段是否通过startupProbe | ContainerStatus.started |
| Ready | 是否应该作为Service正常新流量后端 | Container Ready、Pod Condition |
| Live | 是否需要通过重启容器尝试恢复 | livenessProbe结果 |
| 业务可用 | 用户完整业务是否成功 | SLI、合成测试、业务指标 |
Running=true仍可能发生:
- Spring Context还在初始化。
- 数据库连接池未建立。
- 主线程/请求线程池死锁。
- Readiness失败。
- Service没有Ready Endpoint。
- Ingress/DNS/TLS故障。
- 下单核心链路失败。
二、三种探针的职责边界
| 探针 | 核心问题 | 失败达到阈值后的动作 | 不应该承担 |
|---|---|---|---|
| startupProbe | 本次容器是否完成启动 | kubelet终止并按策略重启容器 | 日常依赖抖动监控 |
| readinessProbe | 当前是否适合接收新流量 | Ready=False,端点异步摘除 | 自动重启修复 |
| livenessProbe | 当前容器是否陷入只能重启恢复的状态 | kubelet终止并重启该容器 | 检查共享数据库是否可用 |
三个Probe不是“同一个健康接口复制三份配置”。它们对应不同决策,健康条件应分别设计。
三、是谁执行探针
探针由运行Pod所在Node的kubelet负责调度和执行。Deployment Controller不发HTTP健康请求,Service也不主动探测应用。
flowchart TD
A["API Server保存PodSpec中的Probe"] --> B["Pod被Scheduler绑定Node"]
B --> C["Node kubelet创建容器"]
C --> D["kubelet按配置执行Probe"]
D --> E["结果更新Container/Pod状态"]
E --> F{"Probe类型和结果"}
F -- "Readiness失败" --> G["Ready=False并更新Endpoint条件"]
F -- "Liveness/Startup失败达阈值" --> H["kubelet终止并重启容器"]HTTP/TCP/gRPC探针通常从Node网络访问Pod IP;Exec探针通过容器运行时在容器内执行命令。这意味着探针成功不证明公网DNS、Ingress、TLS和Service ClusterIP正常。
四、容器启动后的探针状态机
flowchart TD
A["容器进程启动"] --> B{"是否配置startupProbe"}
B -- "是" --> C["只执行startupProbe"]
C --> D{"是否成功"}
D -- "未达失败阈值" --> C
D -- "失败达阈值" --> E["重启容器并重新开始"]
D -- "成功" --> F["容器标记Started"]
B -- "否" --> F
F --> G["启动readiness和liveness检查"]
G --> H{"Readiness是否成功"}
H -- "否" --> I["Ready=False,不接正常新流量"]
H -- "是" --> J["Ready=True,可进入Endpoint"]
G --> K{"Liveness是否连续失败达阈值"}
K -- "是" --> E
K -- "否" --> G配置startupProbe后,成功之前readiness和liveness不会正常接管,避免慢启动期间被liveness误杀。startupProbe一旦成功,一般不再继续执行,后续存活交给liveness。
五、Probe结果:Success、Failure和Unknown
kubelet内部会把单次探测归类为:
- Success:探测成功。
- Failure:明确失败、非成功状态、连接失败或超时。
- Unknown:执行本身无法得到有效结论等异常边界。
最终状态还要结合连续阈值,而不是一次失败就必然重启/摘除。具体Unknown处理和Event表现受实现/版本影响,应在目标集群故障注入验证。
六、六个时间参数
| 字段 | 常见默认值 | 含义 |
|---|---|---|
initialDelaySeconds | 0 | 容器启动后首次执行前等待 |
periodSeconds | 10 | 常规探测周期 |
timeoutSeconds | 1 | 单次探测允许时间 |
failureThreshold | 3 | 连续失败多少次判失败 |
successThreshold | 1 | 连续成功多少次恢复成功 |
terminationGracePeriodSeconds | 继承Pod或Probe级配置 | 探针失败后容器终止宽限期,版本支持有边界 |
默认 timeoutSeconds: 1 对高负载Java服务可能太激进;不能依赖默认值而不压测。
Probe级 terminationGracePeriodSeconds 主要适用于Startup/Liveness失败触发的容器终止,不能配置为Readiness“摘流量等待时间”;字段可用版本、最小值和继承行为必须在目标集群验证。
6.1 Liveness和Startup的successThreshold
Liveness和Startup的 successThreshold 必须为1;Readiness可以大于1,用于避免依赖刚恢复时立即反复接流量。
6.2 Readiness可能比period更积极
当容器NotReady时,kubelet可能在某些情况下比常规period更快执行Readiness,以便尽快恢复Ready。不能把period当严格定时任务SLA,准确行为按版本验证。
七、怎样估算Startup最大等待窗口
示例:
startupProbe:
httpGet:
path: /actuator/health/liveness
port: 8080
periodSeconds: 5
timeoutSeconds: 2
failureThreshold: 24粗略可理解为最多约:
24 × 5秒 = 120秒级启动窗口但实际时间还受首次调度、单次Probe执行耗时、kubelet负载和边界取整影响。若每次探测都跑满timeout,不能机械把所有字段相加当绝对精确时刻。
设计依据应来自:
- 冷启动P99。
- 镜像/类加载。
- Spring Bean初始化。
- 数据库迁移和缓存预热边界。
- CPU Limit/Throttle。
- 节点压力。
窗口过短会误杀;过长会让永远启动失败的版本占用资源很久并拖慢Rollout失败发现。
八、initialDelay不能替代startupProbe
只配置:
livenessProbe:
initialDelaySeconds: 120有两个问题:
- 快启动应用也要固定等120秒才开始存活保护。
- 慢于120秒时仍被误杀。
startupProbe根据实际成功结束启动保护:快则提前进入正常探针,慢则在有界窗口等待,更符合状态机语义。
九、Readiness失败后的完整链路
flowchart TD
A["kubelet执行readinessProbe"] --> B["连续失败达到failureThreshold"]
B --> C["该Container Ready=False"]
C --> D["Pod ContainersReady/Ready Condition变化"]
D --> E["状态写回API Server"]
E --> F["EndpointSlice Controller观察变化"]
F --> G["Endpoint ready条件更新"]
G --> H["kube-proxy/Ingress等数据面异步更新"]
H --> I["正常新连接不再选择该Pod"]这不是全局原子操作:
- 状态写回有延迟。
- EndpointSlice和数据面更新有延迟。
- 已建立Keep-Alive/gRPC/WebSocket连接不会自动迁移。
- 直接访问Pod IP不经过Service选择。
Readiness是流量准入信号,不是瞬时断网开关。
十、Readiness恢复怎样重新接流量
连续成功达到 successThreshold 后:
Container Ready=True
→ Pod Ready可能变True
→ EndpointSlice Ready更新
→ 数据面重新加入后端若依赖在好/坏之间抖动,Pod会反复进出Endpoint,造成连接重置和流量集中。可使用合理success/failureThreshold、依赖熔断和恢复稳定窗口,不能只把period调得很大掩盖。
十一、Liveness失败后的完整链路
flowchart TD
A["liveness连续失败达阈值"] --> B["kubelet按容器终止流程执行"]
B --> C["执行preStop并发送SIGTERM"]
C --> D{"宽限期内是否退出"}
D -- "否" --> E["SIGKILL"]
D -- "是" --> F["容器结束"]
E --> F
F --> G["按restartPolicy创建同Pod内新容器实例"]
G --> H["Restart Count增加,重新经历Startup"]重要边界:
- 默认是重启失败的容器,不是Scheduler把Pod迁移到另一个Node。
- Pod名称和UID通常不变,Container ID变化。
- 多容器Pod中,目标容器重启不等于所有Sidecar一起重启。
- 重启不能修复Node网络、共享数据库故障和错误配置。
- 反复失败会进入容器重启退避,表现为CrashLoopBackOff。
十二、探针失败与restartPolicy
长期服务通常使用Pod默认 restartPolicy: Always。Liveness/Startup失败导致容器终止后,kubelet按策略重启。
Job常使用Never或OnFailure。探针配置在Job中需要特别谨慎:批任务正常长时间计算不代表死锁,错误Liveness可能让同一任务重复执行并产生副作用。
十三、HTTP GET Probe执行原理
readinessProbe:
httpGet:
scheme: HTTP
path: /actuator/health/readiness
port: httpkubelet通常从Node侧向Pod IP和指定端口发起HTTP请求。HTTP状态码200到399通常视为成功,其他状态或连接/超时视为失败。
它通常不经过:
- Service ClusterIP。
- Ingress Controller。
- 公网DNS。
- 外部LoadBalancer。
所以即使Probe成功,Service targetPort、Ingress Host、TLS证书仍可能错误。
13.1 scheme
HTTP和HTTPS决定kubelet怎样连接。Kubernetes的HTTPS Probe通常跳过服务端证书校验,因此证书过期、SAN错误或链不完整时Probe仍可能成功;不要把它当外部TLS合成测试。公网证书必须通过带正确SNI、CA校验的独立监控验证。
13.2 host与Host Header
一般不要把 httpGet.host 写成Service域名;kubelet应直接访问Pod IP。需要虚拟Host时,使用 httpHeaders设置Host更符合意图:
httpHeaders:
- name: Host
value: internal-health.example但健康接口最好不依赖复杂虚拟主机和认证链。
13.3 Redirect边界
健康路径不应返回重定向。kubelet对同Host重定向有有限处理和警告边界,跨Host/过多重定向行为可能被视为成功或失败且随版本变化。最安全是直接返回明确200/503。
十四、TCP Socket Probe
livenessProbe:
tcpSocket:
port: 3306kubelet只尝试建立TCP连接。成功只能证明端口接受连接,不能证明:
- MySQL认证成功。
- SQL可执行。
- 数据未损坏。
- 应用线程池能处理请求。
- 协议响应正确。
适合没有标准健康协议、且“端口无法连接”足以判定局部故障的场景。若进程只accept但不处理,TCP Probe会假阳性。
十五、gRPC Probe
内置gRPC Probe使用gRPC Health Checking Protocol:
livenessProbe:
grpc:
port: 9090
service: order-api-liveness
periodSeconds: 10
timeoutSeconds: 2边界:
- 应用必须实现标准gRPC Health服务。
service可区分liveness/readiness语义。- 通常使用数字端口,不支持命名端口。
- 不提供任意认证/TLS参数,复杂安全链需其他方案。
- 内置gRPC Probe的稳定版本和timeout行为受Kubernetes版本/Feature Gate影响。
- 错误端口、未实现服务、超时都会失败。
不要在镜像中额外塞一个不受控 grpc-health-probe 二进制而不管理版本和供应链;现代版本优先评估内置能力。
十六、Exec Probe
readinessProbe:
exec:
command:
- /app/bin/check-readiness
- --timeout-ms=500
timeoutSeconds: 1kubelet通过Runtime在容器内执行新进程,退出码0成功,非0失败。
重要:
command数组默认不是Shell,不会自动解释管道、重定向和&&。- 需要Shell时必须显式
sh -c,但Distroless镜像可能没有Shell。 - 每次Probe启动进程,有CPU、PID和IO开销。
- 脚本若Fork后台进程或超时清理不当,可能泄漏进程。
- 脚本依赖外部命令,而精简镜像可能没有curl、grep、ps。
- Exec timeout执行边界受Runtime和Feature Gate历史影响,必须在目标版本故障注入。
高频Exec Probe执行Java命令或复杂SQL,可能反过来压垮容器。
十七、四种Probe方式对比
| 方式 | 能证明 | 不能证明 | 主要风险 |
|---|---|---|---|
| HTTP | 应用HTTP处理路径在本Pod可响应 | Service/Ingress/完整业务 | 同线程池拥塞、错误重定向 |
| TCP | 端口能建立连接 | 协议和业务正确 | accept假健康 |
| gRPC | 标准Health RPC可响应 | 外部网关和业务RPC | 版本、端口和安全限制 |
| Exec | 自定义命令退出码 | 外部流量路径 | 进程/资源开销、脚本依赖 |
选择最简单且能支持决策的探针,避免把完整业务交易塞进kubelet高频执行。
十八、参数怎样按故障预算设计
例如Readiness:
periodSeconds: 5
timeoutSeconds: 2
failureThreshold: 3
successThreshold: 2粗略语义:
- 连续约3次失败后摘流量,故障检测约10到15秒级,加单次执行/传播时间。
- 恢复后需要连续2次成功,约5到10秒级重新接流量。
这不是精确SLA。需考虑:
- 探测首次时间。
- 每次Probe耗时。
- kubelet调度延迟。
- 状态写回和Endpoint传播。
- Controller/数据面同步。
参数来自业务可容忍错误窗口、连接Drain和依赖恢复特征,而不是复制网上固定值。
十九、Liveness到底应该检查什么
Liveness只检查“重启当前容器是否有较大概率恢复”的本地不可恢复状态,例如:
- 事件循环/关键处理线程永久卡死。
- 应用内部状态机不可恢复。
- 主HTTP处理端口完全失去响应且重启可恢复。
不建议直接检查:
- 共享数据库。
- Redis集群。
- 外部支付接口。
- DNS上游。
- 全局配置中心。
因为依赖故障影响所有副本,若Liveness包含它:
数据库抖动
→ 所有Pod liveness失败
→ 全部容器重启
→ 连接风暴/冷启动
→ 数据库压力更大
→ 故障放大二十、Readiness应该检查哪些依赖
Readiness表示“这个实例现在接新流量是否比不接更安全”。可考虑:
- 应用初始化完成。
- 必需配置已加载。
- 关键本地资源可用。
- 必需连接池已建立到最低容量。
- 该实例无法处理任何请求的关键依赖状态。
但不能把所有下游都无脑加入:
- 某个非核心推荐服务故障时,订单API可能仍可降级。
- 所有Pod共享数据库,全部摘除会让入口直接503,可能比应用返回可解释降级更差。
- 每5秒从每个Pod对每个依赖做真实调用会形成探针流量风暴。
按功能分级:核心不可降级依赖、可降级依赖和仅告警依赖。
二十一、Spring Boot Availability State
Spring Boot Actuator提供:
LivenessState:应用内部存活状态。ReadinessState:是否接受流量。
常见路径:
/actuator/health/liveness
/actuator/health/readiness配置示意:
management:
endpoint:
health:
probes:
enabled: true
show-details: never
endpoints:
web:
exposure:
include: health,prometheus不要在公网暴露全部Actuator端点。健康响应不应包含数据库URL、用户名、磁盘路径、异常堆栈和Secret。
二十二、Spring Boot主端口还是Management端口
主业务端口
优点:能证明主Web Server、端口和部分请求处理链可用。缺点:业务线程池拥塞时健康也失败,Liveness可能重启形成风暴。
独立Management端口
优点:健康和指标不受主端口部分拥塞影响。缺点:Management端口健康时,主业务端口可能已经死锁/不监听,产生Liveness假阳性。
生产折中:
- Readiness/Liveness需要覆盖主服务是否能处理最小请求。
- 健康逻辑本身保持轻量、有界。
- 用应用指标/线程池饱和和外部合成监控补充。
- 对独立Management端口设置NetworkPolicy,不公网暴露。
二十三、完整Spring Boot商业Demo
apiVersion: apps/v1
kind: Deployment
metadata:
name: order-api
namespace: commerce
spec:
replicas: 3
minReadySeconds: 10
progressDeadlineSeconds: 300
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
selector:
matchLabels:
app: order-api
template:
metadata:
labels:
app: order-api
spec:
terminationGracePeriodSeconds: 45
containers:
- name: order-api
image: registry.example.com/order-api@sha256:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
ports:
- name: http
containerPort: 8080
startupProbe:
httpGet:
path: /actuator/health/liveness
port: http
periodSeconds: 5
timeoutSeconds: 2
failureThreshold: 24
readinessProbe:
httpGet:
path: /actuator/health/readiness
port: http
periodSeconds: 5
timeoutSeconds: 2
failureThreshold: 3
successThreshold: 2
livenessProbe:
httpGet:
path: /actuator/health/liveness
port: http
periodSeconds: 10
timeoutSeconds: 2
failureThreshold: 3
lifecycle:
preStop:
exec:
command: ["sh", "-c", "sleep 5"]
resources:
requests:
cpu: 250m
memory: 512Mi
limits:
cpu: "1"
memory: 1Gi示例 preStop要求镜像有Shell;Distroless镜像应依靠应用正确处理SIGTERM或使用受支持Hook。参数必须通过目标镜像冷启动压测和故障注入调整。
二十四、为什么Startup常使用Liveness路径
启动阶段只需证明应用内部已完成足够初始化并能进入正常检查;使用Liveness路径可以避免Readiness中外部依赖抖动阻止容器永远“启动”。
但如果应用进程在Spring Context完成前就让Liveness端点返回成功,startupProbe会过早放行。必须验证Availability State转换时机。
二十五、Readiness与Deployment滚动更新
新Pod必须Ready,并持续满足 minReadySeconds 后才成为Available。maxUnavailable: 0 时,新Pod不Ready会让旧Pod继续保留,Rollout卡住但服务可能仍可用。
新版本Readiness失败
→ 新Endpoint不接流量
→ 旧ReplicaSet不继续缩容
→ progressDeadline最终标记失败progressDeadlineSeconds不会自动业务回滚,流水线要检测并停止扩散。
二十六、Readiness和优雅终止
理想Drain:
- 应用开始拒绝新流量,Readiness变False。
- EndpointSlice和数据面传播。
- 已有连接/在途请求有时间完成。
- 收到SIGTERM并关闭Listener/消费者。
- 宽限期内退出。
但Pod删除、Endpoint更新、preStop和SIGTERM并非全局原子顺序。常用短preStop等待传播只是缓冲,不是绝对保证。应用必须处理SIGTERM、停止接新工作和幂等重试。
二十七、Readiness Gates
Pod可以声明额外Readiness Gate,让自定义Condition参与Pod Ready,例如云LB后端注册或平台准入:
spec:
readinessGates:
- conditionType: example.com/lb-registered只有内置容器Ready和自定义Condition都满足,Pod才整体Ready。负责写Condition的Controller故障会让Pod长期NotReady;必须监控该Controller和Condition Reason。
不要让业务应用随意伪造平台Readiness Condition,写status需要受控权限。
二十八、探针不能替代业务Smoke和合成监控
Probe通常只验证Node→Pod局部路径。外部合成监控应验证:
公网/企业DNS
→ LoadBalancer
→ TLS证书
→ Ingress Host/Path
→ Service/Endpoint
→ 应用
→ 关键只读业务依赖发布Smoke可以创建测试订单/查询并清理,但要有幂等、隔离测试账号和副作用控制。不要让kubelet每5秒执行真实下单。
二十九、Kubernetes Probe与Docker Healthcheck区别
| 能力 | Dockerfile HEALTHCHECK | Kubernetes Probe |
|---|---|---|
| 定义位置 | 镜像 | PodSpec |
| Startup/Ready/Live分工 | 通常单一Health状态 | 三种决策分离 |
| Service Endpoint联动 | 无K8s语义 | Readiness联动Pod/Endpoint |
| 重启动作 | 取决于运行/编排系统 | kubelet按Liveness/Startup重启 |
| 环境配置 | 镜像默认 | 可按环境配置 |
Kubernetes通常使用PodSpec Probe做编排决策;镜像Healthcheck是否被底层Runtime直接用于K8s决策,不能假设,需以集群实现为准。
三十、探针自身的资源开销
假设1000个Pod,每个配置两个5秒周期HTTP Probe:
约400次探测/秒(忽略启动、抖动和额外执行)如果每次探针都:
- 查询数据库。
- 执行Redis命令。
- 调用多个下游。
- 生成大JSON和堆栈。
会形成稳定背景压力。Exec还会创建进程并消耗PID。健康端点必须轻量、超时有界,并通过缓存/状态聚合避免探针风暴。
三十一、探针安全
- 健康端点不返回Secret和内部拓扑。
- Management端口用NetworkPolicy限制Node/监控来源。
- 不要求高权限Token才能Probe,否则轮换/认证故障导致误杀。
- Exec脚本不可由低权限配置任意覆盖,防命令注入。
- 不在URL Query中放密码。
- TLS与认证复杂性由外部合成监控补充。
Probe是高频自动调用面,也需要威胁建模。
三十二、场景一:Startup反复失败
证据:
kubectl describe pod <pod> -n commerce
kubectl get pod <pod> -n commerce -o yaml
kubectl logs <pod> -n commerce -c order-api --previous --tail=300 --timestamps检查:
- 路径/端口/scheme错误。
- 应用冷启动超过窗口。
- CPU Limit导致严重Throttle。
- 配置、Secret、数据库迁移失败。
- 健康端点在启动完成前不可用是否符合设计。
- 容器实际没有监听Pod IP。
不要只无限增大failureThreshold。若应用永远失败,窗口越大只会拖慢发布失败发现。
三十三、场景二:Liveness制造重启风暴
表现:
- Restart Count持续增加。
- Event反复
Liveness probe failed。 logs --previous显示应用正在初始化或依赖异常。- 所有副本在依赖抖动时同步重启。
处理:
- 保留Event、previous日志、配置和时间线。
- 暂停继续发布。
- 判断Probe失败是应用真死还是超时/依赖误判。
- 回退错误Probe或版本。
- 修复Liveness契约,而不是永久删除所有健康检查。
如果数据库被加入Liveness,先移除该外部依赖并设计Readiness/降级。
三十四、场景三:Readiness全部失败导致503
kubectl get pod -n commerce -l app=order-api
kubectl describe pod <pod> -n commerce
kubectl get endpointslice -n commerce \
-l kubernetes.io/service-name=order-api -o yaml检查:
- 所有Pod是否Ready=False。
- EndpointSlice是否没有Ready地址。
- Ingress 503是否因无Backend。
- Readiness是否检查共同依赖。
- 依赖能否降级而不是摘除全部流量。
不要把Readiness固定返回200作为止损,这可能把真正无法服务的实例放回流量。应恢复旧版本、修复依赖或启用经过验证的降级路径。
三十五、场景四:高峰期偶发Probe Timeout
关联:
- Probe latency和失败时间。
- Pod CPU Usage/Throttle。
- JVM GC/Safepoint。
- Web线程池和队列。
- Node CPU/IO压力。
- kubelet健康。
如果健康端点与业务共用线程池,Timeout可能真实反映服务饱和;简单调大timeout会延迟摘除。若只是Node/kubelet调度抖动,则应治理Node。用故障实验决定,而不是猜。
三十六、场景五:Probe成功但用户访问失败
因为Probe不覆盖:
- Service Selector/targetPort。
- CoreDNS。
- IngressClass/Host/Path/Rewrite。
- 公网DNS。
- TLS/SNI和证书。
- 外部LB/WAF。
- 完整业务依赖。
按 Service网络排查 和 Ingress七层排查 继续,不能据Probe成功关闭告警。
三十七、场景六:TCP Probe成功但请求挂死
端口accept成功不代表工作线程处理。改用轻量HTTP/gRPC健康协议,检查线程池、事件循环和锁。Liveness是否要通过主请求线程路径,需要在避免假阳性和避免重启风暴之间权衡。
三十八、场景七:Exec Probe超时或进程增长
kubectl top pod <pod> -n commerce --containers
kubectl exec <pod> -n commerce -- ps -ef精简镜像无ps时使用受控Debug Container。检查脚本是否:
- fork后台进程。
- 调用无超时网络命令。
- 每次生成临时文件。
- 依赖不存在的Shell/工具。
- 并发执行超过周期。
将检查改为应用内轻量状态或受控小程序,并验证超时能终止全部子进程。
三十九、场景八:Readiness反复抖动
观察Condition转换时间、Event和Endpoint变化,检查:
- 依赖阈值无滞后。
- successThreshold太低。
- 健康接口偶发超时。
- GC/CPU周期峰值。
- 依赖熔断器状态。
- 配置中心短暂断开。
加入恢复稳定窗口和本地状态聚合,而不是只把失败阈值调到很大,让坏实例长时间接流量。
四十、取证命令全集
kubectl get pod <pod> -n commerce -o wide
kubectl describe pod <pod> -n commerce
kubectl get pod <pod> -n commerce -o yaml
kubectl logs <pod> -n commerce -c order-api --tail=300 --timestamps
kubectl logs <pod> -n commerce -c order-api --previous --tail=300 --timestamps
kubectl get events -n commerce \
--field-selector involvedObject.name=<pod> \
--sort-by=.metadata.creationTimestamp
kubectl get endpointslice -n commerce \
-l kubernetes.io/service-name=order-api -o yaml
kubectl top pod <pod> -n commerce --containersContainerStatus摘要:
kubectl get pod <pod> -n commerce \
-o jsonpath='{range .status.containerStatuses[*]}name={.name}{" ready="}{.ready}{" started="}{.started}{" restarts="}{.restartCount}{" current="}{.state}{" last="}{.lastState}{"\n"}{end}'四十一、监控哪些Probe指标
- Probe成功/失败/Unknown次数。
- 按type、Pod、版本、Node的失败率。
- Probe执行耗时。
- Container Restart Count和原因。
- Pod Ready比例与Condition转换。
- Endpoint Ready数量。
- Rollout Available/Unavailable。
- 从NotReady到恢复的时间。
- Liveness重启后的恢复成功率。
告警需要版本、Node、Probe类型、错误消息和Runbook,不只写“Pod不健康”。
四十二、常见误区
- Running等于健康:进程存在不等于Ready/业务可用。
- 三个Probe用同一复杂接口:三者决策不同。
- initialDelay能完全替代startupProbe:固定等待不能适应快慢启动。
- Readiness失败会重启容器:它主要改变流量准入。
- Liveness失败会把Pod迁移Node:通常只在同Pod重启容器。
- Liveness检查数据库:共享依赖故障会造成重启风暴。
- TCP成功代表业务健康:只证明端口accept。
- Probe成功代表Ingress可用:通常不经过Service/Ingress。
timeoutSeconds默认足够:默认1秒可能误杀高负载Java应用。- sub-second精确执行:kubelet调度和传播有延迟。
- 调大所有阈值就稳定:会延迟真实故障发现。
- 固定返回200最安全:会制造假健康和错误流量。
四十三、面试标准回答
startup、readiness和liveness区别
startup判断本次容器是否完成启动,成功前门控readiness/liveness,失败达阈值会重启;readiness决定是否作为Service正常新流量后端,失败不重启;liveness判断当前容器是否需要重启恢复,失败达阈值由kubelet重启该容器,通常不迁移Pod。
Readiness失败后流量怎样摘除
kubelet把Container Ready和Pod Ready Condition写回API Server,EndpointSlice Controller更新Endpoint ready条件,kube-proxy/Ingress等数据面再异步同步。该过程不是原子的,已有长连接不会自动迁移,直接PodIP访问也不受Service选择控制。
为什么Liveness不应检查数据库
数据库是共享外部依赖,故障时重启应用通常不能修复;如果所有Pod都把数据库加入Liveness,会同步重启、制造冷启动和连接风暴,进一步压垮数据库。Liveness只检查重启本容器可能恢复的本地不可恢复状态。
HTTP、TCP、gRPC、Exec Probe区别
HTTP验证Pod内HTTP路径,TCP只验证端口可连接,gRPC调用标准Health协议,Exec在容器内执行命令看退出码。它们通常只覆盖Node到Pod或容器内部路径,不能证明Service、Ingress、TLS和完整业务可用;Exec还有进程和资源开销。
探针为什么会造成CrashLoopBackOff
Startup/Liveness路径、端口或超时错误,慢启动窗口不足,CPU Throttle或外部依赖误入Liveness,都可能让kubelet反复终止容器;重启退避后表现为CrashLoopBackOff。应看Event、previous日志、Container lastState和资源指标,不能只增大阈值。
独立Management端口做Liveness有什么风险
它可避免主业务线程池拥塞影响健康,但也可能在主业务端口已经死锁/关闭时仍返回成功,产生假阳性。需要让Probe覆盖主服务最小处理能力,并用线程池指标和外部合成监控补充。
四十四、学习实验与验收
实验一:慢启动误杀
让测试应用启动90秒,先只配过短Liveness复现重启,再加入120秒级startupProbe,观察Started、Restart Count和Event。
实验二:Readiness与EndpointSlice
切换应用Readiness状态,记录Pod Condition、EndpointSlice、Service新连接和已有Keep-Alive连接,证明传播和连接边界。
实验三:数据库故障重启风暴
在隔离环境把数据库检查加入Liveness并短暂阻断数据库,观察所有Pod重启;再改为降级/Readiness策略并比较恢复时间。不得在生产执行。
实验四:TCP假健康
编写只accept连接但不处理请求的测试服务,比较TCP Probe成功与HTTP业务超时,说明探针能力边界。
实验五:Exec资源开销
配置高频Exec脚本,测量PID、CPU和进程清理,再换成轻量HTTP状态,比较Node/Pod开销。
实验六:Probe成功但入口失败
保持HTTP Probe成功,故意写错Service targetPort或Ingress Host;按Pod→Service→Ingress逐层取证,证明局部健康不等于端到端可用。
验收清单
- 能区分Running、Started、Ready、Live和业务可用。
- 能画出kubelet探针状态机。
- 能计算Startup/Readiness粗略检测窗口。
- 能解释Readiness到EndpointSlice传播。
- 能解释Liveness重启对象和Restart Count。
- 能比较四种Probe方式的证据边界。
- 能设计Spring Boot Liveness/Readiness契约。
- 能权衡主端口和Management端口。
- 能识别依赖故障造成的重启风暴。
- 能设计Readiness、优雅终止和长连接Drain。
- 能使用Event、previous日志和状态排查误杀。
- 能用外部合成监控补齐Probe盲区。
