本文目录导读:

在Shell脚本中配置容器终止宽限期(Graceful Shutdown),主要有以下几种方式:
Docker/Kubernetes 环境下的配置
Docker run 命令
# 使用 --stop-grace-period 参数(单位:秒) docker run --stop-grace-period=30 -d nginx # 或者使用时间格式 docker run --stop-grace-period=1m30s -d nginx
Docker Compose
version: '3.8'
services:
myapp:
image: myapp:latest
stop_grace_period: 30s # 设置30秒宽限期
# 或者
stop_grace_period: 1m30s
Kubernetes Pod
apiVersion: v1
kind: Pod
metadata:
name: mypod
spec:
terminationGracePeriodSeconds: 60 # 60秒宽限期
containers:
- name: myapp
image: myapp:latest
Shell脚本处理退出信号
#!/bin/bash
# 设置宽限期(秒)
GRACE_PERIOD=30
# 捕获退出信号
cleanup() {
echo "接收到终止信号,开始优雅退出..."
# 执行清理操作
echo "保存数据..."
# sync 或其他保存操作
echo "关闭连接..."
# 关闭数据库连接、网络连接等
echo "正在等待后台任务完成..."
# 等待子进程结束
wait
echo "优雅退出完成"
exit 0
}
# 注册信号处理函数
trap cleanup SIGTERM SIGINT SIGHUP
# 模拟主程序运行
echo "应用启动,PID: $$"
echo "宽限期: $GRACE_PERIOD 秒"
# 主循环
while true; do
echo "应用运行中..."
sleep 5
done
高级宽限期管理脚本
#!/bin/bash
# 配置参数
GRACE_PERIOD=60
CHECK_INTERVAL=2
PID_FILE="/var/run/app.pid"
# 状态变量
CLEANUP_COMPLETE=false
# 智能清理函数
smart_cleanup() {
local start_time=$(date +%s)
local current_time=$start_time
local elapsed_time=0
echo "[$(date)] 开始优雅退出,宽限期: ${GRACE_PERIOD}s"
# 阶段1: 停止新请求(5秒)
echo "阶段1: 停止接受新请求..."
sleep 5
elapsed_time=$(( $(date +%s) - start_time ))
echo "已用时: ${elapsed_time}s"
# 阶段2: 完成正在处理的请求
if [ $elapsed_time -lt $GRACE_PERIOD ]; then
remaining=$(( GRACE_PERIOD - elapsed_time ))
echo "阶段2: 等待当前请求完成(最多等待 ${remaining}s)..."
# 检查是否有活跃连接
while [ $elapsed_time -lt $GRACE_PERIOD ]; do
if check_active_connections; then
echo "仍有活跃连接,等待中..."
sleep $CHECK_INTERVAL
else
echo "所有连接已关闭"
break
fi
elapsed_time=$(( $(date +%s) - start_time ))
done
fi
# 阶段3: 保存状态和清理
if [ $elapsed_time -lt $GRACE_PERIOD ]; then
echo "阶段3: 保存应用状态..."
save_state
echo "清理临时文件..."
cleanup_temp_files
echo "关闭日志..."
close_logs
fi
CLEANUP_COMPLETE=true
echo "[$(date)] 优雅退出完成(用时: ${elapsed_time}s)"
}
# 检查活跃连接
check_active_connections() {
# 根据实际应用实现
# 示例:检查网络连接
local connections=$(ss -tn | grep -c "ESTAB")
[ $connections -gt 0 ]
return $?
}
# 保存状态
save_state() {
# 模拟状态保存
echo "保存应用状态到文件..."
# 实际保存逻辑
}
# 清理文件
cleanup_temp_files() {
echo "清理 /tmp/app_* 文件"
rm -f /tmp/app_* 2>/dev/null
}
# 关闭日志
close_logs() {
echo "关闭日志文件句柄..."
# 实际日志清理逻辑
}
# 主信号处理
handle_signal() {
smart_cleanup
if [ "$CLEANUP_COMPLETE" = true ]; then
echo "正在关闭进程..."
kill -TERM $$ 2>/dev/null
exit 0
else
echo "宽限期不足,强制关闭"
exit 1
fi
}
trap handle_signal SIGTERM SIGINT
# 写入PID
echo $$ > $PID_FILE
# 主程序逻辑
echo "应用启动,PID: $$"
echo "宽限期配置: ${GRACE_PERIOD}s"
# 模拟运行
while true; do
# 应用主逻辑
echo "处理请求中... ($(date))"
sleep 10
done
Docker 容器内的专门脚本
# Dockerfile FROM alpine:latest # 安装 tini 作为 init 进程 RUN apk add --no-cache tini # 复制启动脚本 COPY docker-entrypoint.sh /usr/local/bin/ RUN chmod +x /usr/local/bin/docker-entrypoint.sh # 使用 tini 作为入口 ENTRYPOINT ["/sbin/tini", "--", "/usr/local/bin/docker-entrypoint.sh"]
#!/bin/sh
# docker-entrypoint.sh
# 宽限期配置(可以通过环境变量覆盖)
TERMINATION_GRACE_PERIOD=${TERMINATION_GRACE_PERIOD:-30}
# 信号处理
cleanup() {
echo "Docker容器接收到SIGTERM信号"
echo "开始${TERMINATION_GRACE_PERIOD}秒的优雅关闭..."
# 通知应用停止
kill -TERM $child 2>/dev/null
# 等待子进程或超时
for i in $(seq 1 $TERMINATION_GRACE_PERIOD); do
if ! kill -0 $child 2>/dev/null; then
echo "子进程已优雅退出"
break
fi
sleep 1
done
# 如果超时,强制终止
if kill -0 $child 2>/dev/null; then
echo "宽限期结束,强制终止进程"
kill -KILL $child 2>/dev/null
fi
exit 0
}
trap cleanup SIGTERM SIGINT
# 启动主应用
exec /usr/local/bin/your-app &
child=$!
# 等待子进程
wait $child
配置示例:不同环境的设置
生产环境脚本
#!/bin/bash
# 生产环境配置
GRACE_PERIOD=${PROD_GRACE_PERIOD:-60}
# 检查应用状态
check_app_healthy() {
# 健康检查逻辑
curl -f http://localhost:8080/health
}
# 优雅关闭
graceful_shutdown() {
local start_time=$(date +%s)
echo "开始生产环境优雅关闭..."
# 1. 从负载均衡器移除
echo "从负载均衡器移除..."
kubectl label pod $(hostname) routeable=false
# 2. 等待现有请求完成
while [ $(($(date +%s) - start_time)) -lt $GRACE_PERIOD ]; do
if ! check_app_healthy; then
echo "应用健康检查失败,准备关闭"
break
fi
echo "等待请求完成..."
sleep 2
done
# 3. 执行最终清理
cleanup_resources
echo "生产环境优雅关闭完成"
}
trap graceful_shutdown SIGTERM
# 启动应用
echo "生产环境应用启动..."
while true; do
sleep 10
done
测试宽限期配置
#!/bin/bash
# 测试脚本 - 验证容器宽限期
test_graceful_shutdown() {
container_name="test-graceful-$RANDOM"
# 创建测试容器
docker run -d --name $container_name \
--stop-grace-period=30 \
alpine sh -c "trap 'echo 接收到信号; sleep 10; exit 0' SIGTERM; while true; do sleep 1; done"
# 测试1: 正常关闭
echo "测试1: Docker正常关闭"
time docker stop $container_name
# 测试2: 强制关闭(超出宽限期)
echo "测试2: Docker强制关闭"
container_name2="test-graceful-force-$RANDOM"
docker run -d --name $container_name2 \
--stop-grace-period=5 \
alpine sh -c "trap 'echo 接收到信号; sleep 30; exit 0' SIGTERM; while true; do sleep 1; done"
time docker container kill $container_name2
# 清理
docker rm -f $container_name $container_name2
echo "测试完成"
}
test_graceful_shutdown
调试和监控脚本
#!/bin/bash
# 监控容器关闭过程
monitor_shutdown() {
local container=$1
local pid=$(docker inspect -f '{{.State.Pid}}' $container)
echo "监控容器: $container (PID: $pid)"
echo "开始时间: $(date)"
# 监控进程状态变化
while docker ps -q --filter "name=$container" | grep -q .; do
local status=$(docker inspect -f '{{.State.Status}}' $container)
local exit_code=$(docker inspect -f '{{.State.ExitCode}}' $container)
echo "状态: $status, 退出码: $exit_code, 时间: $(date)"
# 检查超时
if [ "$status" = "exited" ]; then
break
fi
sleep 1
done
echo "关闭过程完成"
echo "结束时间: $(date)"
}
# 使用示例
monitor_shutdown "myapp-container"
最佳实践建议
-
合理的宽限期设置
- Web应用:30-60秒
- 数据库:60-120秒
- 批处理:根据任务大小调整
-
信号处理
- 处理 SIGTERM(15)信号
- 避免使用 SIGKILL(9)
-
监控和日志
- 记录关闭过程
- 设置告警
-
测试验证
- 定期测试优雅关闭
- 验证数据完整性
这些脚本和配置可以根据具体应用需求进行调整,重要的是确保关闭过程中的数据完整性和服务稳定性。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播