我会为您提供几种自动重启异常容器的脚本方案,适用于不同的使用场景。

Shell脚本 + Docker(基础版)
#!/bin/bash
# restart-unhealthy-containers.sh
# 定义检查间隔(秒)
CHECK_INTERVAL=60
# 日志文件
LOG_FILE="/var/log/container-restart.log"
while true; do
# 获取所有异常状态的容器
UNHEALTHY_CONTAINERS=$(docker ps --filter "health=unhealthy" --format "{{.Names}}")
if [ -n "$UNHEALTHY_CONTAINERS" ]; then
echo "$(date) [INFO] 发现异常容器: $UNHEALTHY_CONTAINERS" >> "$LOG_FILE"
for CONTAINER in $UNHEALTHY_CONTAINERS; do
echo "$(date) [ACTION] 重启容器: $CONTAINER" >> "$LOG_FILE"
docker restart "$CONTAINER"
if [ $? -eq 0 ]; then
echo "$(date) [SUCCESS] 容器 $CONTAINER 重启成功" >> "$LOG_FILE"
else
echo "$(date) [ERROR] 容器 $CONTAINER 重启失败" >> "$LOG_FILE"
fi
done
fi
sleep "$CHECK_INTERVAL"
done
监控退出状态码(兼容性更强)
#!/bin/bash
# restart-exited-containers.sh
LOG_FILE="/var/log/container-restart.log"
MAX_RESTART_ATTEMPTS=3
check_and_restart() {
# 查找状态为exited的容器(排除手动停止的)
local EXITED_CONTAINERS=$(docker ps -a --filter "status=exited" --filter "name=!" --format "{{.ID}} {{.Names}} {{.ExitCode}}")
while IFS= read -r line; do
[ -z "$line" ] && continue
CONTAINER_ID=$(echo $line | awk '{print $1}')
CONTAINER_NAME=$(echo $line | awk '{print $2}')
EXIT_CODE=$(echo $line | awk '{print $3}')
# 排除正常退出的容器(exit code 0)
if [ "$EXIT_CODE" != "0" ]; then
RESTART_COUNT=$(docker inspect "$CONTAINER_NAME" --format '{{.RestartCount}}' 2>/dev/null || echo 0)
if [ "$RESTART_COUNT" -lt "$MAX_RESTART_ATTEMPTS" ]; then
echo "$(date) [ACTION] 重启异常退出的容器: $CONTAINER_NAME (退出码: $EXIT_CODE)" >> "$LOG_FILE"
docker start "$CONTAINER_ID" >> "$LOG_FILE" 2>&1
else
echo "$(date) [WARN] 容器 $CONTAINER_NAME 已达到最大重启次数: $MAX_RESTART_ATTEMPTS" >> "$LOG_FILE"
fi
fi
done <<< "$EXITED_CONTAINERS"
}
# 持续监控
while true; do
check_and_restart
sleep 30 # 每30秒检查一次
done
Docker Compose环境自动修复
#!/bin/bash
# docker-compose-auto-heal.sh
COMPOSE_FILE="docker-compose.yml"
PROJECT_NAME="myapp"
LOG_FILE="/var/log/compose-heal.log"
# 检查服务状态并重启异常服务
fix_unhealthy_services() {
# 获取所有服务的健康状态
docker-compose -f "$COMPOSE_FILE" -p "$PROJECT_NAME" ps --format "{{.Name}} {{.Status}}" | while read SERVICE LINE; do
if echo "$LINE" | grep -q "unhealthy\|exit\|dead"; then
echo "$(date) [ACTION] 修复异常服务: $SERVICE" >> "$LOG_FILE"
# 尝试重启特定服务
docker-compose -f "$COMPOSE_FILE" -p "$PROJECT_NAME" up -d --no-deps "$SERVICE" >> "$LOG_FILE" 2>&1
# 如果失败,尝试重新创建
if [ $? -ne 0 ]; then
echo "$(date) [INFO] 尝试重新创建服务: $SERVICE" >> "$LOG_FILE"
docker-compose -f "$COMPOSE_FILE" -p "$PROJECT_NAME" rm -f -s "$SERVICE" >> "$LOG_FILE" 2>&1
docker-compose -f "$COMPOSE_FILE" -p "$PROJECT_NAME" create "$SERVICE" >> "$LOG_FILE" 2>&1
docker-compose -f "$COMPOSE_FILE" -p "$PROJECT_NAME" start "$SERVICE" >> "$LOG_FILE" 2>&1
fi
fi
done
}
# 主循环
echo "$(date) [START] 启动Docker Compose自动修复服务" >> "$LOG_FILE"
while true; do
fix_unhealthy_services
sleep 60 # 每分钟检查一次
done
高级版(带通知和重试策略)
#!/bin/bash
# advanced-container-restart.sh
# 配置
LOG_FILE="/var/log/container-restart.log"
NOTIFY_CMD="" # 通知命令,如: curl -X POST https://api.telegram.org/...
MAX_RETRIES=3
CHECK_INTERVAL=30
# 初始化日志
[ ! -f "$LOG_FILE" ] && touch "$LOG_FILE"
log() {
local LEVEL=$1
local MESSAGE=$2
echo "$(date '+%Y-%m-%d %H:%M:%S') [$LEVEL] $MESSAGE" | tee -a "$LOG_FILE"
}
send_notification() {
local MESSAGE=$1
if [ -n "$NOTIFY_CMD" ]; then
$NOTIFY_CMD "$MESSAGE" &
fi
}
check_container_health() {
local CONTAINER=$1
# 支持健康检查的容器
local HEALTH_STATUS=$(docker inspect "$CONTAINER" --format '{{.State.Health.Status}}' 2>/dev/null)
# 不支持健康检查的容器,检查进程存活
if [ -z "$HEALTH_STATUS" ] || [ "$HEALTH_STATUS" = "<nil>" ]; then
local RUNNING=$(docker inspect "$CONTAINER" --format '{{.State.Running}}')
if [ "$RUNNING" != "true" ]; then
return 1 # 异常
fi
return 0 # 正常
fi
# 有健康检查配置
if [ "$HEALTH_STATUS" = "unhealthy" ]; then
return 1 # 异常
fi
return 0 # 正常
}
restart_container_with_retry() {
local CONTAINER=$1
local ATTEMPT=0
while [ $ATTEMPT -lt $MAX_RETRIES ]; do
ATTEMPT=$((ATTEMPT + 1))
log "ACTION" "尝试重启容器 $CONTAINER (第 $ATTEMPT 次)"
if docker restart "$CONTAINER" > /dev/null 2>&1; then
log "SUCCESS" "容器 $CONTAINER 重启成功"
# 等待容器启动并检查状态
sleep 5
if check_container_health "$CONTAINER"; then
log "SUCCESS" "容器 $CONTAINER 健康检查通过"
return 0
else
log "WARN" "容器 $CONTAINER 重启后仍不健康"
fi
else
log "ERROR" "容器 $CONTAINER 重启失败"
fi
sleep 3
done
log "CRITICAL" "容器 $CONTAINER 经过 $MAX_RETRIES 次尝试仍无法恢复"
send_notification "关键告警: 容器 $CONTAINER 无法自动恢复,请手动检查"
return 1
}
# 主监控循环
log "INFO" "启动容器自动修复服务"
log "INFO" "检查间隔: ${CHECK_INTERVAL}s, 最大重试: ${MAX_RETRIES}"
while true; do
# 获取所有容器
ALL_CONTAINERS=$(docker ps -a --format "{{.Names}}" 2>/dev/null)
if [ -n "$ALL_CONTAINERS" ]; then
while IFS= read -r CONTAINER; do
[ -z "$CONTAINER" ] && continue
if ! check_container_health "$CONTAINER"; then
log "WARN" "发现异常容器: $CONTAINER"
send_notification "容器 $CONTAINER 状态异常,开始自动修复"
restart_container_with_retry "$CONTAINER"
fi
done <<< "$ALL_CONTAINERS"
fi
sleep "$CHECK_INTERVAL"
done
使用说明
- 基础使用(方案一):
# 保存脚本 sudo nano /usr/local/bin/restart-unhealthy-containers.sh sudo chmod +x /usr/local/bin/restart-unhealthy-containers.sh
运行
sudo nohup /usr/local/bin/restart-unhealthy-containers.sh &
2. **作为Systemd服务运行**:
```ini
# /etc/systemd/system/container-restart.service
[Unit]
Description=Container Auto Restart Service
After=docker.service
Requires=docker.service
[Service]
ExecStart=/usr/local/bin/advanced-container-restart.sh
Restart=always
User=root
[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload sudo systemctl enable container-restart.service sudo systemctl start container-restart.service
- 使用Docker的restart策略(推荐先使用Docker原生功能):
# docker-compose.yml services: web: image: nginx restart: unless-stopped healthcheck: test: ["CMD", "curl", "-f", "http://localhost"] interval: 30s timeout: 10s retries: 3
注意事项
- Docker原生restart策略是最简单的方式,优先使用
- 健康检查配置能更精确地识别容器是否正常
- 避免重启循环:设置最大重试次数和冷却时间
- 日志记录:记录所有操作以便排查问题
- 通知机制:关键故障时发送告警通知
选择适合您场景的方案,建议先从方案一或Docker原生restart策略开始。