本文目录导读:

在Shell脚本中配置容器的优雅退出,主要涉及信号处理和资源清理两个核心方面,以下是完整的配置方法:
基础信号处理框架
#!/bin/bash
# 定义清理函数
cleanup() {
echo "[INFO] 开始优雅退出..."
# 停止子进程
if [ -n "$CHILD_PID" ]; then
echo "[INFO] 停止子进程 PID: $CHILD_PID"
kill -TERM "$CHILD_PID" 2>/dev/null
wait "$CHILD_PID"
fi
# 清理临时文件
rm -f /tmp/*.tmp 2>/dev/null
# 关闭数据库连接等
# mysql -e "SHOW PROCESSLIST" | awk '{print $1}' | xargs kill 2>/dev/null
echo "[INFO] 优雅退出完成"
exit 0
}
# 注册信号处理器
trap 'cleanup' SIGTERM SIGINT SIGQUIT
完整的生产级示例
#!/bin/bash
# ============ 配置变量 ============
GRACEFUL_TIMEOUT=30 # 优雅退出超时时间(秒)
CHILD_PID=""
LOG_FILE="/var/log/app.log"
# ============ 日志函数 ============
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_FILE"
}
# ============ 清理函数 ============
cleanup() {
local signal=$1
log "收到信号: $signal,开始优雅退出..."
# 1. 通知子进程
if [ -n "$CHILD_PID" ] && kill -0 "$CHILD_PID" 2>/dev/null; then
log "发送 SIGTERM 到子进程 $CHILD_PID"
kill -TERM "$CHILD_PID" 2>/dev/null
# 等待子进程退出(带超时)
local wait_time=0
while [ $wait_time -lt $GRACEFUL_TIMEOUT ]; do
if ! kill -0 "$CHILD_PID" 2>/dev/null; then
log "子进程 $CHILD_PID 已正常退出"
break
fi
sleep 1
wait_time=$((wait_time + 1))
done
# 超时后强制杀死
if kill -0 "$CHILD_PID" 2>/dev/null; then
log "子进程 $CHILD_PID 超时未退出,强制终止"
kill -9 "$CHILD_PID" 2>/dev/null
fi
fi
# 2. 清理资源
log "清理临时文件..."
rm -rf /tmp/app_* 2>/dev/null
# 3. 关闭文件描述符
exec 3>&- 2>/dev/null
# 4. 释放其他资源
# clean_database_connections
log "优雅退出完成"
exit 0
}
# ============ 注册信号处理 ============
trap 'cleanup SIGTERM' SIGTERM
trap 'cleanup SIGINT' SIGINT
trap 'cleanup SIGQUIT' SIGQUIT
trap '' SIGPIPE # 忽略 SIGPIPE
# ============ 健康检查接口 ============
health_check() {
if [ -n "$CHILD_PID" ] && kill -0 "$CHILD_PID" 2>/dev/null; then
echo "healthy"
return 0
else
echo "unhealthy"
return 1
fi
}
# ============ 主程序 ============
main() {
log "应用启动..."
# 启动子进程(示例:运行一个长时间的任务)
(
# 子进程逻辑
while true; do
log "应用运行中..."
sleep 10
done
) &
CHILD_PID=$!
log "子进程 PID: $CHILD_PID"
# 等待子进程
wait "$CHILD_PID"
# 如果子进程意外退出
log "子进程意外退出,退出码: $?"
exit 1
}
# ============ 启动应用 ============
main
Docker专用配置
#!/bin/bash
# Docker容器优雅退出配置
set -e
# 定义清理函数
docker_cleanup() {
echo "[Docker] 容器正在停止..."
# 停止所有后台服务
for service in nginx mysql redis; do
if command -v "$service" &>/dev/null; then
echo "[Docker] 停止 $service"
service "$service" stop || true
fi
done
# 等待所有进程退出
sleep 2
echo "[Docker] 容器停止完成"
exit 0
}
# 捕获Docker发出的信号
trap 'docker_cleanup' SIGTERM SIGINT
# 启动主服务(必须以exec在前台运行)
exec nginx -g "daemon off;"
多进程管理示例
#!/bin/bash
# 管理多个子进程的优雅退出
declare -A CHILD_PIDS
cleanup_multiple() {
echo "开始关闭所有子进程..."
# 发送 SIGTERM 到所有子进程
for name in "${!CHILD_PIDS[@]}"; do
pid=${CHILD_PIDS[$name]}
if kill -0 "$pid" 2>/dev/null; then
echo "停止进程: $name (PID: $pid)"
kill -TERM "$pid" 2>/dev/null
fi
done
# 等待所有进程退出
for name in "${!CHILD_PIDS[@]}"; do
pid=${CHILD_PIDS[$name]}
wait "$pid" 2>/dev/null || true
echo "进程 $name 已退出"
done
echo "所有进程已停止"
exit 0
}
# 启动多个子进程
start_processes() {
# 启动Web服务
python3 web_server.py &
CHILD_PIDS["web"]=$!
# 启动后台任务
python3 background_worker.py &
CHILD_PIDS["worker"]=$!
# 启动定时任务
cron -f &
CHILD_PIDS["cron"]=$!
}
trap 'cleanup_multiple' SIGTERM SIGINT
start_processes
# 等待所有子进程
for pid in "${CHILD_PIDS[@]}"; do
wait "$pid"
done
最佳实践
Dockerfile 配置
FROM alpine:3.18
# 安装 dumb-init 用于正确的信号处理
RUN apk add --no-cache dumb-init
COPY app.sh /app/app.sh
RUN chmod +x /app/app.sh
# 使用 dumb-init 作为 init 进程
ENTRYPOINT ["/usr/bin/dumb-init", "--"]
CMD ["/app/app.sh"]
# 设置健康检查
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD /app/healthcheck.sh
docker-compose 配置
version: '3.8'
services:
app:
build: .
stop_grace_period: 30s # 给予容器更多时间优雅退出
stop_signal: SIGTERM
healthcheck:
test: ["CMD", "/app/healthcheck.sh"]
interval: 30s
timeout: 10s
retries: 3
关键要点
- 使用
exec:在启动主进程时使用exec,确保信号直接传递给进程 - 设置超时:避免无限等待子进程
- 清理顺序:先停止子进程,再清理资源
- 日志记录:记录退出过程,便于故障排查
- 健康检查:提供健康检查接口,便于容器编排平台监控
这种配置确保容器能够优雅地处理停止信号,完成必要的清理工作,避免数据丢失或资源泄漏。
版权声明: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直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播