EKS Pod 健康检查与生命周期管理
📅 撰写日期: 2025-10-15 | 修改日期: 2026-02-14 | ⏱️ 阅读时间: 约 28 分钟
📌 参考环境: EKS 1.30+, Kubernetes 1.30+, AWS Load Balancer Controller v2.7+
1. 概述
Pod 健康检查与生命周期管理是服务稳定性和可用性的基础。正确配置 Probe 并实现 Graceful Shutdown 可以确保以下几点:
- 零停机部署: 在滚动更新期间防止流量丢失
- 快速故障检测: 自动隔离和重启不健康的 Pod
- 资源优化: 防止启动缓慢的应用被过早重启
- 数据完整性: 在关闭期间安全完成正在处理的请求
本文档涵盖了 Pod 的完整生命周期,从 Kubernetes Probe 的工作原理,到各语言的 Graceful Shutdown 实现、Init Container 的使用方法以及容器镜像优化。
- Probe 调试: 请参阅 EKS 故障排查与事件响应指南 中的"Probe 调试与最佳实践"章节
- 高可用设计: 请参阅 EKS 高可用架构指南 中的"Graceful Shutdown"、"PDB"和"Pod Readiness Gates"章 节
2. Kubernetes Probe 深入指南
2.1 三种 Probe 类型及工作原理
Kubernetes 提供三种类型的 Probe 来监控 Pod 状态。
| Probe 类型 | 目的 | 失败时的行为 | 激活时机 |
|---|---|---|---|
| Startup Probe | 验证应用初始化是否完成 | 重启 Pod(达到 failureThreshold 时) | Pod 启动后立即执行 |
| Liveness Probe | 检测应用死锁/挂起状态 | 重启容器 | Startup Probe 成功后 |
| Readiness Probe | 验证是否准备好接收流量 | 从 Service Endpoints 中移除(不重启) | Startup Probe 成功后 |
Startup Probe:保护启动缓慢的应用
Startup Probe 会延迟 Liveness/Readiness Probe 的执行,直到应用完全启动。它对于 Spring Boot、JVM 应用和 ML 模型加载等启动缓慢的应用至关重要。
工作原理:
- Startup Probe 运行期间,Liveness/Readiness Probe 被禁用
- Startup Probe 成功 → 激活 Liveness/Readiness Probe
- Startup Probe 失败(达到 failureThreshold) → 重启容器
Liveness Probe:检测死锁
Liveness Probe 检查应用是否存活。失败时,kubelet 会重启容器。
使用场景:
- 检测无限循环和死锁状态
- 不可恢复的应用错误
- 由于内存泄漏导致的无响应状态
注意事项:
- 不要在 Liveness Probe 中包含外部依赖(DB、Redis 等)
- 外部服务故障可能导致所有 Pod 同时重启的级联故障
Readiness Probe:控制流量接收
Readiness Probe 检查 Pod 是否准备好接收流量。失败时,Pod 从 Service 的 Endpoints 中移除,但容器不会重启。
使用场景:
- 验证依赖服务连接(DB、缓存)
- 确认初始数据加载完成
- 部署期间的渐进式流量接收
2.2 Probe 机制
Kubernetes 支持四种 Probe 机制。
| 机制 | 描述 | 优点 | 缺点 | 最适合 |
|---|---|---|---|---|
| httpGet | HTTP GET 请求,检查 200-399 响应码 | 标准,实现简单 | 需要 HTTP 服务器 | REST API、Web 服务 |
| tcpSocket | 检查 TCP 端口连通性 | 轻量快速 | 无法验证应用逻辑 | gRPC、数据库 |
| exec | 在容器内执行命令,检查退出码是否为 0 | 灵活,可自定义逻辑 | 开销较高 | 批处理 Worker、基于文件的检查 |
| grpc | 使用 gRPC Health Check Protocol(K8s 1.27+ GA) | 原生 gRPC 支持 | 仅适用于 gRPC 应用 | gRPC 微服务 |
httpGet 示例
livenessProbe:
httpGet:
path: /healthz
port: 8080
httpHeaders:
- name: X-Custom-Header
value: HealthCheck
scheme: HTTP # 或 HTTPS
initialDelaySeconds: 30
periodSeconds: 10
tcpSocket 示例
livenessProbe:
tcpSocket:
port: 5432 # PostgreSQL
initialDelaySeconds: 15
periodSeconds: 10
exec 示例
livenessProbe:
exec:
command:
- /bin/sh
- -c
- test -f /tmp/healthy
initialDelaySeconds: 5
periodSeconds: 5
grpc 示例(Kubernetes 1.27+)
livenessProbe:
grpc:
port: 9090
service: myservice # 可选
initialDelaySeconds: 10
periodSeconds: 5
gRPC 服务必须实现 gRPC Health Checking Protocol。Go 语言使用 google.golang.org/grpc/health,Java 使用 grpc-health-check 库。
2.3 Probe 时间设计
Probe 时间参数决定了故障检测速度和稳定性之间的平衡。
| 参数 | 描述 | 默认值 | 建议范围 |
|---|---|---|---|
initialDelaySeconds | 容器启动到首次 Probe 的等待时间 | 0 | 10-30s(使用 Startup Probe 时可设为 0) |
periodSeconds | Probe 执行间隔 | 10 | 5-15s |
timeoutSeconds | Probe 响应等待时间 | 1 | 3-10s |
failureThreshold | 判定失败前的连续失败次数 | 3 | Liveness: 3, Readiness: 1-3, Startup: 30+ |
successThreshold | 判定成功前的连续成功次数(仅 Readiness 可 >1) | 1 | 1-2 |
时间设计公式
最大检测时间 = failureThreshold × periodSeconds
最短恢复时间 = successThreshold × periodSeconds
示例:
failureThreshold: 3, periodSeconds: 10→ 最多 30 秒后检测到故障successThreshold: 2, periodSeconds: 5→ 至少 10 秒后判定恢复(仅 Readiness)
按工作负载类型的建议时间
| 工作负载类型 | initialDelaySeconds | periodSeconds | failureThreshold | 理由 |
|---|---|---|---|---|
| Web 服务(Node.js、Python) | 10 | 5 | 3 | 启动快,需要快速检测 |
| JVM 应用(Spring Boot) | 0(使用 Startup Probe) | 10 | 3 | 启动慢,由 Startup Probe 保护 |
| 数据库(PostgreSQL) | 30 | 10 | 5 | 初始化时间长 |
| 批处理 Worker | 5 | 15 | 2 | 周期性任务,检测要求宽松 |
| ML 推理服务 | 0(Startup: 60) | 10 | 3 | 模型加载时间长 |
2.4 按工作负载的 Probe 模式
模式 1:Web 服务(REST API)
apiVersion: apps/v1
kind: Deployment
metadata:
name: rest-api
spec:
replicas: 3
selector:
matchLabels:
app: rest-api
template:
metadata:
labels:
app: rest-api
spec:
containers:
- name: api
image: myapp/rest-api:v1.2.3
ports:
- containerPort: 8080
protocol: TCP
resources:
requests:
cpu: 200m
memory: 256Mi
limits:
cpu: 500m
memory: 512Mi
# Startup Probe:验证在 30 秒内完成启动
startupProbe:
httpGet:
path: /healthz
port: 8080
failureThreshold: 6
periodSeconds: 5
# Liveness Probe:仅内部健康检查(排除外部依赖)
livenessProbe:
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 10
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
# Readiness Probe:可以包含外部依赖
readinessProbe:
httpGet:
path: /ready
port: 8080
initialDelaySeconds: 5
periodSeconds: 5
timeoutSeconds: 3
failureThreshold: 2
successThreshold: 1
lifecycle:
preStop:
exec:
command:
- /bin/sh
- -c
- sleep 5 && kill -TERM 1
terminationGracePeriodSeconds: 60
健康检查端点实现(Node.js/Express):
// /healthz - Liveness:仅检查应用 自身状态
app.get('/healthz', (req, res) => {
// 仅检查内部状态(内存、CPU 等)
const memUsage = process.memoryUsage();
if (memUsage.heapUsed / memUsage.heapTotal > 0.95) {
return res.status(500).json({ status: 'unhealthy', reason: 'memory_pressure' });
}
res.status(200).json({ status: 'ok' });
});
// /ready - Readiness:包括外部依赖的检查
app.get('/ready', async (req, res) => {
try {
// 验证 DB 连接
await db.ping();
// 验证 Redis 连接
await redis.ping();
res.status(200).json({ status: 'ready' });
} catch (err) {
res.status(503).json({ status: 'not_ready', reason: err.message });
}
});
模式 2:gRPC 服务
apiVersion: apps/v1
kind: Deployment
metadata:
name: grpc-service
spec:
replicas: 3
selector:
matchLabels:
app: grpc-service
template:
metadata:
labels:
app: grpc-service
spec:
containers:
- name: grpc-server
image: myapp/grpc-service:v2.1.0
ports:
- containerPort: 9090
name: grpc
resources:
requests:
cpu: 300m
memory: 512Mi
limits:
cpu: 1
memory: 1Gi
# gRPC 原生探针(K8s 1.27+)
startupProbe:
grpc:
port: 9090
service: myapp.HealthService # 可选
failureThreshold: 30
periodSeconds: 10
livenessProbe:
grpc:
port: 9090
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
readinessProbe:
grpc:
port: 9090
periodSeconds: 5
timeoutSeconds: 3
failureThreshold: 2
terminationGracePeriodSeconds: 45
gRPC 健康检查实现(Go):
package main
import (
"context"
"google.golang.org/grpc"
"google.golang.org/grpc/health"
"google.golang.org/grpc/health/grpc_health_v1"
)
func main() {
server := grpc.NewServer()
// 注册健康检查服务
healthServer := health.NewServer()
grpc_health_v1.RegisterHealthServer(server, healthServer)
// 设置服务状态为 SERVING
healthServer.SetServingStatus("myapp.HealthService", grpc_health_v1.HealthCheckResponse_SERVING)
// 依赖检查后可以更改为 NOT_SERVING
// healthServer.SetServingStatus("myapp.HealthService", grpc_health_v1.HealthCheckResponse_NOT_SERVING)
// 启动 gRPC 服务器
lis, _ := net.Listen("tcp", ":9090")
server.Serve(lis)
}
模式 3:Worker/批处理
批处理 Worker 没有 HTTP 服务器,因此使用 exec Probe。
apiVersion: apps/v1
kind: Deployment
metadata:
name: batch-worker
spec:
replicas: 2
selector:
matchLabels:
app: batch-worker
template:
metadata:
labels:
app: batch-worker
spec:
containers:
- name: worker
image: myapp/batch-worker:v3.0.1
resources:
requests:
cpu: 500m
memory: 1Gi
limits:
cpu: 2
memory: 4Gi
# Startup Probe:验证 Worker 初始化
startupProbe:
exec:
command:
- /bin/sh
- -c
- test -f /tmp/worker-ready
failureThreshold: 12
periodSeconds: 5
# Liveness Probe:检查心跳文件
livenessProbe:
exec:
command:
- /bin/sh
- -c
- find /tmp/heartbeat -mmin -2 | grep -q heartbeat
initialDelaySeconds: 10
periodSeconds: 30
failureThreshold: 3
# Readiness Probe:验证作业队列连接
readinessProbe:
exec:
command:
- /app/check-queue-connection.sh
periodSeconds: 10
failureThreshold: 3
terminationGracePeriodSeconds: 120
Worker 应用(Python):
import os
import time
from pathlib import Path
HEARTBEAT_FILE = Path("/tmp/heartbeat")
READY_FILE = Path("/tmp/worker-ready")
def worker_loop():
# 标记初始化完成
READY_FILE.touch()
while True:
# 定期更新心跳
HEARTBEAT_FILE.touch()
# 处理作业
process_jobs()
time.sleep(5)
def process_jobs():
# 实际作业逻辑
pass
if __name__ == "__main__":
worker_loop()
模式 4:启动缓慢的应用(Spring Boot、JVM)
JVM 应用启动可能需要 30 秒或更长时间。使用 Startup Probe 进行保护。
apiVersion: apps/v1
kind: Deployment
metadata:
name: spring-boot-app
spec:
replicas: 4
selector:
matchLabels:
app: spring-boot
template:
metadata:
labels:
app: spring-boot
spec:
containers:
- name: app
image: myapp/spring-boot:v2.7.0
ports:
- containerPort: 8080
resources:
requests:
cpu: 1
memory: 2Gi
limits:
cpu: 2
memory: 4Gi
env:
- name: JAVA_OPTS
value: "-Xms1g -Xmx3g"
# Startup Probe:最长等待 5 分钟(30 x 10s)
startupProbe:
httpGet:
path: /actuator/health/liveness
port: 8080
failureThreshold: 30
periodSeconds: 10
# Liveness Probe:Startup 成功后激活
livenessProbe:
httpGet:
path: /actuator/health/liveness
port: 8080
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
# Readiness Probe:包含外部依赖
readinessProbe:
httpGet:
path: /actuator/health/readiness
port: 8080
periodSeconds: 5
timeoutSeconds: 3
failureThreshold: 2
terminationGracePeriodSeconds: 60
Spring Boot Actuator 配置:
# application.yml
management:
endpoints:
web:
exposure:
include: health
health:
livenessState:
enabled: true
readinessState:
enabled: true
endpoint:
health:
probes:
enabled: true
show-details: when-authorized
模式 5:Sidecar 模式(Istio Proxy + App)
在 Sidecar 模式中,应为主容器和 Sidecar 都配置 Probe。
apiVersion: apps/v1
kind: Deployment
metadata:
name: app-with-sidecar
spec:
replicas: 3
selector:
matchLabels:
app: myapp
template:
metadata:
labels:
app: myapp
spec:
containers:
# 主应用容器
- name: app
image: myapp/app:v1.0.0
ports:
- containerPort: 8080
startupProbe:
httpGet:
path: /healthz
port: 8080
failureThreshold: 10
periodSeconds: 5
livenessProbe:
httpGet:
path: /healthz
port: 8080
periodSeconds: 10
readinessProbe:
httpGet:
path: /ready
port: 8080
periodSeconds: 5
# Istio sidecar(Istio 在自动注入时会自动添加 Probe)
# 手动配置示例:
- name: istio-proxy
image: istio/proxyv2:1.22.0
ports:
- containerPort: 15090
name: http-envoy-prom
startupProbe:
httpGet:
path: /healthz/ready
port: 15021
failureThreshold: 30
periodSeconds: 1
livenessProbe:
httpGet:
path: /healthz/ready
port: 15021
periodSeconds: 10
readinessProbe:
httpGet:
path: /healthz/ready
port: 15021
periodSeconds: 2
terminationGracePeriodSeconds: 90
当 Istio 使用自动注入(istio-injection=enabled 标签)时,Istio 会自动为 Sidecar 添加适当的 Probe,无需手动配置。
2.4.6 Windows 容器 Probe 注意事项
EKS 支持基于 Windows Server 2019/2022 的 Windows 节点,Windows 容器与 Linux 容器相比具有不同的 Probe 行为特征。
Windows 与 Linux Probe 行为差异
| 项目 | Linux 容器 | Windows 容器 | 影响 |
|---|---|---|---|
| 容器运行时 | containerd | containerd (1.6+) | 相同运行时,不同 OS 层 |
| exec Probe 执行 | /bin/sh -c | cmd.exe /c 或 powershell.exe | 脚本语法差异 |
| httpGet Probe | 相同 | 相同 | 无差异 |
| tcpSocket Probe | 相同 | 相同 | 无差异 |
| 冷启动时间 | 快(几秒) | 慢(10-30 秒) | 需要增加 Startup Probe failureThreshold |
| 内存开销 | 低(50-100MB) | 高(200-500MB) | 需要增加 Resource request |
| Probe 超时 | 通常 1-5 秒 | 建议 3-10 秒 | 需考虑 Windows I/O 延迟 |
Windows 工作负载 Probe 配置示例
IIS/.NET Framework 应用:
apiVersion: apps/v1
kind: Deployment
metadata:
name: iis-app
namespace: windows-workloads
spec:
replicas: 2
selector:
matchLabels:
app: iis-app
template:
metadata:
labels:
app: iis-app
spec:
nodeSelector:
kubernetes.io/os: windows
kubernetes.io/arch: amd64
containers:
- name: iis
image: mcr.microsoft.com/windows/servercore/iis:windowsservercore-ltsc2022
ports:
- containerPort: 80
resources:
requests:
cpu: 500m
memory: 512Mi
limits:
cpu: 2000m
memory: 2Gi
# Startup Probe:考虑 Windows 冷启动
startupProbe:
httpGet:
path: /
port: 80
scheme: HTTP
initialDelaySeconds: 10
periodSeconds: 5
timeoutSeconds: 5
failureThreshold: 12 # 是 Linux 的 2 倍(最长 60 秒)
successThreshold: 1
# Liveness Probe:IIS 进程状态
livenessProbe:
httpGet:
path: /healthz
port: 80
initialDelaySeconds: 30
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
# Readiness Probe:ASP.NET 应用就绪
readinessProbe:
httpGet:
path: /ready
port: 80
initialDelaySeconds: 15
periodSeconds: 5
timeoutSeconds: 5
failureThreshold: 3
successThreshold: 1
terminationGracePeriodSeconds: 60
ASP.NET Core 健康检查端点实现:
// Program.cs (ASP.NET Core 6+)
using Microsoft.AspNetCore.Diagnostics.HealthChecks;
using Microsoft.Extensions.Diagnostics.HealthChecks;
var builder = WebApplication.CreateBuilder(args);
// 添加健康检查
builder.Services.AddHealthChecks()
.AddCheck("self", () => HealthCheckResult.Healthy())
.AddSqlServer(
connectionString: builder.Configuration.GetConnectionString("DefaultConnection"),
name: "sqlserver",
tags: new[] { "ready" }
);
var app = builder.Build();
// /healthz - Liveness:仅检查应用自身
app.MapHealthChecks("/healthz", new HealthCheckOptions
{
Predicate = check => check.Tags.Contains("self") || check.Tags.Count == 0
});
// /ready - Readiness:包括外部依赖
app.MapHealthChecks("/ready", new HealthCheckOptions
{
Predicate = _ => true // 所有健康检查
});
app.Run();
Windows 工作负载 Probe 超时注意事项
Windows 容器可能出现较长的 Probe 超时,原因如下:
- Windows 内核开销: 较重的 Windows OS 层导致系统调用延迟
- 磁盘 I/O 性能: NTFS 文件系统元数据开销
- .NET Framework 预热: CLR JIT 编译和程序集加载时间
- Windows Defender: 实时扫描导致进程启动延迟
建议的 Probe 时间(Windows):
startupProbe:
timeoutSeconds: 5-10 # Linux: 3-5s
periodSeconds: 5
failureThreshold: 12-20 # Linux: 6-10
livenessProbe:
timeoutSeconds: 5-10 # Linux: 3-5s
periodSeconds: 10-15 # Linux: 10s
failureThreshold: 3
readinessProbe:
timeoutSeconds: 5-10 # Linux: 3-5s
periodSeconds: 5-10 # Linux: 5s
failureThreshold: 3
CloudWatch Container Insights for Windows(2025-08)
AWS 于 2025 年 8 月宣布 CloudWatch Container Insights 支持 Windows 工作负载。
在 Windows 节点上安装 Container Insights:
# CloudWatch Agent ConfigMap(Windows)
kubectl apply -f - <<EOF
apiVersion: v1
kind: ConfigMap
metadata:
name: cwagentconfig-windows
namespace: amazon-cloudwatch
data:
cwagentconfig.json: |
{
"logs": {
"metrics_collected": {
"kubernetes": {
"cluster_name": "my-eks-cluster",
"metrics_collection_interval": 60
}
}
},
"metrics": {
"namespace": "ContainerInsights",
"metrics_collected": {
"statsd": {
"service_address": ":8125"
}
}
}
}
EOF
# 部署 Windows DaemonSet
kubectl apply -f https://raw.githubusercontent.com/aws-samples/amazon-cloudwatch-container-insights/latest/k8s-deployment-manifest-templates/deployment-mode/daemonset/container-insights-monitoring/cwagent/cwagent-daemonset-windows.yaml
验证 Container Insights 指标:
# Windows 节点指标
aws cloudwatch get-metric-statistics \
--namespace ContainerInsights \
--metric-name node_memory_utilization \
--dimensions Name=ClusterName,Value=my-eks-cluster Name=NodeName,Value=windows-node-1 \
--start-time 2026-02-12T00:00:00Z \
--end-time 2026-02-12T23:59:59Z \
--period 300 \
--statistics Average
# Windows Pod 指标
aws cloudwatch get-metric-statistics \
--namespace ContainerInsights \
--metric-name pod_cpu_utilization \
--dimensions Name=ClusterName,Value=my-eks-cluster Name=Namespace,Value=windows-workloads \
--start-time 2026-02-12T00:00:00Z \
--end-time 2026-02-12T23:59:59Z \
--period 60 \
--statistics Average
混合集群(Linux + Windows)统一监控策略
1. 基于 Node Selector 的分离:
apiVersion: v1
kind: Service
metadata:
name: unified-app
spec:
selector:
app: unified-app # 与 OS 无关
ports:
- port: 80
targetPort: 8080
---
# Linux Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: unified-app-linux
spec:
replicas: 3
selector:
matchLabels:
app: unified-app
os: linux
template:
metadata:
labels:
app: unified-app
os: linux
spec:
nodeSelector:
kubernetes.io/os: linux
containers:
- name: app
image: myapp:linux-v1
readinessProbe:
httpGet:
path: /ready
port: 8080
periodSeconds: 5
timeoutSeconds: 3
---
# Windows Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: unified-app-windows
spec:
replicas: 2
selector:
matchLabels:
app: unified-app
os: windows
template:
metadata:
labels:
app: unified-app
os: windows
spec:
nodeSelector:
kubernetes.io/os: windows
containers:
- name: app
image: myapp:windows-v1
readinessProbe:
httpGet:
path: /ready
port: 8080
periodSeconds: 10 # Windows:较长间隔
timeoutSeconds: 10 # Windows:较长超时
2. CloudWatch Logs Insights 统一查询:
-- 同时搜索 Linux 和 Windows Pod 日志
fields @timestamp, kubernetes.namespace_name, kubernetes.pod_name, kubernetes.host, @message
| filter kubernetes.labels.app = "unified-app"
| sort @timestamp desc
| limit 100
3. Grafana Dashboard 集成:
# Prometheus 查询(混合集群)
# Linux + Windows Pod CPU 利用率
sum(rate(container_cpu_usage_seconds_total{namespace="default", pod=~"unified-app-.*"}[5m])) by (pod, node, os)
# 按 OS 聚合
sum(rate(container_cpu_usage_seconds_total{namespace="default", pod=~"unified-app-.*"}[5m])) by (os)
- 镜像大小: Windows 镜像有几个 GB(Linux 是几十 MB)
- 许可证成本: 适用 Windows Server 许可证费用(包含在 EC2 实例费用中)
- 节点启动时间: Windows 节点启动较慢(5-10 分钟)
- 特权容器: Windows 不支持 Linux
privileged模式 - HostProcess 容器: 从 Windows Server 2022(1.22+)开始支持