Shell脚本如何配置容器就绪探针

wen 实用脚本 1

Shell脚本如何配置容器就绪探针:从原理到实战的完整指南

目录导读

  1. 什么是容器就绪探针?为什么需要它?
  2. Shell脚本配置就绪探针的核心原理
  3. 实战:编写高可靠性的就绪检测Shell脚本
  4. 常见错误与优化策略(含问答)
  5. 不同场景下的Shell探针模板
  6. 与健康检查、存活探针的协同配置

什么是容器就绪探针?为什么需要它?

Q: 容器就绪探针(Readiness Probe)与健康检查有什么区别?
A: 就绪探针决定容器是否具备接收外部流量的能力,而健康检查(存活探针)决定容器是否需要重启,一个Web应用启动后需要加载缓存、连接数据库,若尚未就绪就接入流量,会导致503错误,Shell脚本作为探测工具,可以精确模拟应用的实际就绪条件。

Shell脚本如何配置容器就绪探针

就绪探针的典型使用场景包括:

  • 应用启动后需要初始化数据(如加载模型、同步配置)
  • 依赖外部服务(如Redis、数据库)尚未就绪
  • 应用内部处于“预热”或“冷却”阶段

Shell脚本配置就绪探针的核心原理

Kubernetes(简称K8s)允许通过三种方式配置就绪探针:HTTP GET、TCP Socket、Exec(Shell命令),其中Exec方式最灵活,通过编写Shell脚本返回0(就绪)或1(未就绪)决定容器状态。

关键配置参数(在Pod YAML中定义):

readinessProbe:
  exec:
    command:
    - /bin/sh
    - -c
    - /usr/local/bin/readiness-check.sh
  initialDelaySeconds: 5    # 启动延迟
  periodSeconds: 10         # 探测间隔
  timeoutSeconds: 3         # 超时时间
  failureThreshold: 3       # 失败阈值

Shell脚本的核心逻辑必须包含:

  1. 检查应用主进程是否存活(如PID文件或端口监听)
  2. 验证依赖服务是否可访问(如使用nc、curl或自定义脚本)
  3. 检测业务层面的就绪标志(如临时文件、API响应码)

实战:编写高可靠性的就绪检测Shell脚本

示例:检测Java应用是否就绪(含Redis依赖)

#!/bin/sh
# 文件位置:/usr/local/bin/readiness-check.sh
# 1. 检查应用进程是否存在
APP_PID=$(pgrep -f "java -jar app.jar" | head -1)
if [ -z "$APP_PID" ]; then
    echo "应用进程未运行"
    exit 1
fi
# 2. 检查应用端口是否监听(假设端口8080)
if ! ss -tln | grep -q ':8080 '; then
    echo "端口8080未监听"
    exit 1
fi
# 3. 检查API健康端点(假设应用有/health接口)
HEALTH_STATUS=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:8080/health 2>/dev/null)
if [ "$HEALTH_STATUS" != "200" ]; then
    echo "健康检查返回$HEALTH_STATUS"
    exit 1
fi
# 4. 检查Redis依赖是否连接正常
if ! redis-cli -h redis-service -p 6379 ping | grep -q "PONG"; then
    echo "Redis连接失败"
    exit 1
fi
# 5. 清理临时文件(可选)
exit 0

Q: 为什么不直接用curl的--fail参数?
A: --fail会在HTTP错误时使curl返回非零值,但Shell脚本中建议显式判断HTTP状态码,避免误判(如302跳转被当作成功)。

优化:使用锁文件防止竞态条件

# 在容器启动时创建就绪标志文件
APP_READY="/tmp/app-ready.flag"
if [ -f "$APP_READY" ]; then
    # 检查文件内容是否包含当前时间戳
    LAST_READY=$(cat $APP_READY)
    [ "$(date +%s)" -le "$((LAST_READY + 60))" ] || exit 1
else
    exit 1
fi

常见错误与优化策略(含问答)

Q: Shell脚本执行时间过长导致探针超时怎么办?
A: 建议设置timeoutSeconds(如3秒),并在脚本内部增加超时机制:

# 使用timeout命令限制子操作执行时间
TIMEOUT=2
result=$(timeout $TIMEOUT curl -s http://localhost:8080/health) || {
    echo "curl超时"
    exit 1
}

Q: 探针脚本应该放在容器镜像的哪个位置?
A: 推荐放在/usr/local/bin//opt/scripts/,并确保执行权限(chmod +x),同时避免放入/tmp,因为tmp可能被清空或挂载为临时卷。

典型错误排查表: | 现象 | 可能原因 | 解决方案 | |------|----------|----------| | 探针脚本无输出 | 脚本缺少exit 0/1 | 明确返回值 | | 容器始终未就绪 | 依赖服务未启动 | 添加initialDelaySeconds或使用预热脚本 | | 脚本执行报command not found | 镜像缺失命令(如curl) | 改为wget -q --spider或使用nc -z | | 探针日志无法查看 | 未启用容器日志 | 在脚本中添加echo输出到stderr |


不同场景下的Shell探针模板

Web应用(Nginx)

#!/bin/sh
# 检查Nginx主进程和反向代理后端
PID=$(pgrep -f "nginx: master process")
[ -z "$PID" ] && exit 1
# 检查后端应用响应(假设upstream为app:8080)
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" --connect-timeout 1 http://localhost:80)
[ "$HTTP_CODE" -eq 200 ] || exit 1
exit 0

数据库容器(PostgreSQL)

#!/bin/sh
# 验证PG是否可以接受连接
pg_isready -h 127.0.0.1 -p 5432 -U postgres >/dev/null 2>&1
if [ $? -eq 0 ]; then
    # 进一步检查数据库是否存在
    psql -h 127.0.0.1 -U postgres -d mydb -c "SELECT 1" >/dev/null 2>&1 || exit 1
    exit 0
else
    exit 1
fi

与健康检查、存活探针的协同配置

黄金法则:就绪探针(Readiness)和存活探针(Liveness)不要使用完全相同的脚本,否则可能导致循环依赖。

  • 存活探针:只检查进程是否存活(如pgrep或端口监听)
  • 就绪探针:检查更复杂的状态(如API响应、依赖服务)

升级实践:使用ConfigMap管理探针脚本,避免修改镜像:

apiVersion: v1
kind: ConfigMap
metadata:
  name: readiness-script
data:
  check.sh: |
    #!/bin/sh
    # 动态从环境变量读取配置
    SERVICE_HOST=${SERVICE_HOST:-127.0.0.1}
    SERVICE_PORT=${SERVICE_PORT:-8080}
    nc -zv $SERVICE_HOST $SERVICE_PORT 2>/dev/null

Shell脚本配置就绪探针的三大要点

  1. 聚焦业务就绪:不要只检查进程存在,要模拟外部流量能否正常访问
  2. 防御性编程:处理命令缺失、超时、权限不足等异常情况
  3. 性能与简洁平衡:避免在脚本中执行耗时操作(如大型SQL查询),优先使用轻量级检测手段(如nc -zcurl更轻)

通过本文的模板和策略,你可以在Kubernetes集群中构建可靠的容器就绪探针,确保服务在真正准备好后才接收流量,从而提升应用的稳定性和用户体验。

抱歉,评论功能暂时关闭!