如何用脚本自动重启异常容器?

wen 实用脚本 1

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

如何用脚本自动重启异常容器?

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

使用说明

  1. 基础使用(方案一):
    # 保存脚本
    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
  1. 使用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

注意事项

  1. Docker原生restart策略是最简单的方式,优先使用
  2. 健康检查配置能更精确地识别容器是否正常
  3. 避免重启循环:设置最大重试次数和冷却时间
  4. 日志记录:记录所有操作以便排查问题
  5. 通知机制:关键故障时发送告警通知

选择适合您场景的方案,建议先从方案一或Docker原生restart策略开始。

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