如何用脚本自动运行Docker容器?

wen 实用脚本 2

如何用脚本自动运行Docker容器?从入门到生产级自动化部署

目录导读

  1. 为什么需要用脚本管理Docker容器?
  2. 基础脚本:启动、停止与重启容器
  3. 高级自动化:结合环境变量与日志记录
  4. 生产级实践:健康检查与自动重启策略
  5. 常见FAQ:脚本运行Docker的坑与解法

为什么需要用脚本自动运行Docker容器?

在开发或运维场景中,手动输入 docker run 命令虽然简单,但存在明显痛点:

如何用脚本自动运行Docker容器?

  • 每次启动需记忆大量参数(端口映射、卷挂载、环境变量)
  • 容器意外退出后无法自动恢复
  • 批量管理多容器时效率极低

脚本化的核心价值:将容器配置固化、实现自动化启停、支持定时任务与CI/CD流水线集成,根据Docker官方最佳实践,脚本自动化是容器运维的基础能力。


基础脚本:启动、停止与重启容器

1 单容器启动脚本示例

#!/bin/bash
# start_nginx.sh - 自动运行Nginx容器
CONTAINER_NAME="my-nginx"
IMAGE="nginx:alpine"
PORT_MAP="8080:80"
# 检查容器是否已存在,存在则删除重建
if [ "$(docker ps -aq -f name=$CONTAINER_NAME)" ]; then
    echo "停止并删除旧容器..."
    docker stop $CONTAINER_NAME
    docker rm $CONTAINER_NAME
fi
# 启动新容器
docker run -d \
    --name $CONTAINER_NAME \
    -p $PORT_MAP \
    --restart unless-stopped \
    $IMAGE
echo "Nginx已启动,访问 http://localhost:8080"

关键点

  • --restart unless-stopped 确保容器在故障或被守护进程重启时自动恢复
  • -d 后台运行,避免占用当前终端

2 批量停止所有运行中容器

#!/bin/bash
# stop_all.sh
for container in $(docker ps -q); do
    echo "停止容器: $(docker inspect --format='{{.Name}}' $container)"
    docker stop $container
done
echo "所有容器已停止"

高级自动化:结合环境变量与日志记录

1 使用.env文件动态配置

#!/bin/bash
# run_with_env.sh
# 加载.env文件中的变量
export $(grep -v '^#' .env | xargs)
docker run -d \
    --name app-$APP_ENV \
    -e "DB_HOST=$DB_HOST" \
    -e "DB_USER=$DB_USER" \
    -e "DB_PASS=$DB_PASS" \
    -v "$(pwd)/logs:/app/logs" \
    myapp:latest
# 记录启动日志
echo "$(date): 容器启动,环境: $APP_ENV" >> docker_run.log

设计要点

  • .env 文件存储敏感信息(需加入 .gitignore
  • 日志记录便于回溯容器启动历史

2 定时拉取镜像并重建

#!/bin/bash
# auto_update.sh - 每天凌晨3点检查镜像更新
IMAGE="myapp:latest"
docker pull $IMAGE 2>&1 | grep "Image is up to date"
if [ $? -ne 0 ]; then
    echo "发现新镜像,正在重建容器..."
    docker stop myapp || true
    docker rm myapp || true
    docker run -d --name myapp -p 3000:3000 $IMAGE
else
    echo "镜像已是最新"
fi

配合crontab使用:0 3 * * * /path/to/auto_update.sh


生产级实践:健康检查与自动重启策略

1 使用Docker Compose脚本化部署

docker-compose.yml 本身就是强大的声明式脚本:

version: '3.8'
services:
  web:
    image: nginx:alpine
    ports:
      - "8080:80"
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost"]
      interval: 30s
      timeout: 10s
      retries: 3
    restart: always

通过 docker-compose up -d 即可一次启动所有服务,并自动进行健康检查。

2 自定义Shell脚本监控+重启

#!/bin/bash
# health_monitor.sh
CONTAINER="myapp"
CHECK_INTERVAL=30
while true; do
    if [ "$(docker inspect -f '{{.State.Health.Status}}' $CONTAINER 2>/dev/null)" = "unhealthy" ]; then
        echo "$(date): 容器健康检查失败,执行恢复..."
        docker restart $CONTAINER
        sleep 60  # 避免频繁重启
    fi
    sleep $CHECK_INTERVAL
done

优势:可定制化通知(如发送钉钉/邮件告警),比Docker自带策略更灵活。

3 CI/CD中的自动化示例(GitLab CI)

# .gitlab-ci.yml
deploy:
  stage: deploy
  script:
    - docker build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA .
    - docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA
    - ssh deploy@server "cd /opt/app && ./deploy.sh $CI_COMMIT_SHORT_SHA"
  only:
    - main

deploy.sh 脚本负责拉取新镜像并更新容器。


常见FAQ:脚本运行Docker的坑与解法

Q1: 脚本中执行docker命令报“permission denied”?

A: 原因是当前用户未加入 docker 组,解决方案:

sudo usermod -aG docker $USER
newgrp docker  # 或重启终端

Q2: 如何让脚本在系统启动时自动运行?

A: 将脚本路径加入 /etc/rc.local 或使用systemd服务,推荐systemd方案:

[Unit]
Description=Docker Container Starter
After=docker.service
[Service]
ExecStart=/usr/local/bin/start_containers.sh
Restart=on-failure
[Install]
WantedBy=multi-user.target

Q3: 脚本中途失败如何保证原子性?

A: 使用 set -e 在脚本开头,或使用 trap 捕获错误。

#!/bin/bash
set -e
trap 'echo "脚本执行失败,请检查日志"; exit 1' ERR
# 你的docker命令...

Q4: 脚本中如何传递动态参数(如版本号)?

A: 通过命令行参数传入:./run.sh v1.2.3

#!/bin/bash
VERSION=${1:-latest}
docker run -d --name myapp myapp:$VERSION

Q5: 容器日志太大导致磁盘爆满?

A: 在 docker run 时添加日志限制:

docker run --log-opt max-size=10m --log-opt max-file=3 ...

或全局配置 /etc/docker/daemon.json

{ "log-driver": "json-file", "log-opts": { "max-size": "10m", "max-file": "3" } }

用脚本自动运行Docker容器,本质是将重复、易错的命令行操作固化为可靠、可复用的自动化流程,从简单的 docker run 包装,到结合健康检查、CI/CD、定时任务的完整解决方案,脚本化能大幅提升容器运维效率,建议初学者从基础钩子脚本入手,逐步引入错误处理和日志监控,最终建立满足生产需求的自动化体系。

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