容器开机自启动

容器开机自启动

面试题

如何让 Docker 容器在宿主机启动时自动运行?有哪些配置方式?

标准答案

容器开机自启动涉及两个层面:Docker Daemon 自启动容器自启动。两者缺一不可。

第一步:Docker Daemon 开机自启

# 确保 Docker 服务跟随系统启动
systemctl enable docker

# 验证
systemctl is-enabled docker
# enabled

# 检查 Docker 服务的启动状态
systemctl status docker
# ● docker.service - Docker Application Container Engine
#    Loaded: loaded (/lib/systemd/system/docker.service; enabled; vendor preset: enabled)

第二步:容器自启动

方法 1:–restart 策略(最常用)

# 创建容器时设置
docker run -d --restart always --name web nginx
docker run -d --restart unless-stopped --name app my-app

# 容器已经运行,更新配置
docker update --restart always my-existing-container

# 批量设置所有运行中的容器
docker update --restart unless-stopped $(docker ps -q)

# 批量设置所有容器(包括停止的)
docker update --restart always $(docker ps -aq)

不同策略对开机自启的影响

# always:Daemon 重启时自动拉回所有设置了 always 的容器
# unless-stopped:Daemon 重启时拉回,但如果是手工 stop 过的则不拉
# on-failure:只在异常退出时重启,Daemon 重启时也会拉回

# 验证开机自启效果
sudo reboot            # 重启宿主机
# 重启后
docker ps              # 设置了 --restart always/unless-stopped 的容器自动运行

方法 2:使用 systemd 管理容器

对于更精细的控制,可以用 systemd 来管理容器:

# 创建一个 systemd service
cat > /etc/systemd/system/my-web-app.service << 'EOF'
[Unit]
Description=My Web App Container
Requires=docker.service
After=docker.service

[Service]
Restart=always
ExecStart=/usr/bin/docker start -a my-web-app
ExecStop=/usr/bin/docker stop -t 10 my-web-app
ExecStartPre=-/usr/bin/docker rm my-web-app
ExecStartPre=/usr/bin/docker run --name my-web-app my-app:latest

[Install]
WantedBy=multi-user.target
EOF
# 另一种更简单的方案:使用 docker run 的重启特性
cat > /etc/systemd/system/docker-container@.service << 'EOF'
[Unit]
Description=Docker Container %I
Requires=docker.service
After=docker.service

[Service]
Restart=always
ExecStart=/usr/bin/docker start -a %i
ExecStop=/usr/bin/docker stop -t 10 %i
ExecStartPre=-/usr/bin/docker rm %i
ExecStartPre=/usr/bin/docker run --name %i --restart no (此处省略完整参数)

[Install]
WantedBy=multi-user.target
EOF

方法 3:docker-compose + restart

# docker-compose.yml
version: '3'
services:
  web:
    image: nginx
    restart: always          # ← 开机自启

  app:
    image: my-app
    restart: unless-stopped  # ← 手动停过就不自启

  db:
    image: mysql:8
    restart: always
    volumes:
      - mysql-data:/var/lib/mysql

  redis:
    image: redis:alpine
    restart: always          # ← 开机自启

启动:

docker-compose up -d

# 宿主机重启后,这些容器会自动启动

容器启动顺序控制

# Docker 自身不保证依赖顺序
# 可以通过以下方式控制

# 方案 1:在启动脚本中等待
#!/bin/bash
# start-containers.sh
docker start db || docker run -d --name db --restart always mysql:8

# 等数据库就绪
sleep 10

docker start app || docker run -d --name app --restart always my-app
# 方案 2:docker-compose depends_on
version: '3'
services:
  db:
    image: mysql:8
    restart: always

  app:
    image: my-app
    restart: always
    depends_on:
      - db                # 启动时先启动 db
# 方案 3:健康检查保证顺序
docker run -d --name db --restart always \
  --health-cmd="mysqladmin ping" \
  --health-interval=5s \
  mysql:8

docker run -d --name app --restart always \
  --health-cmd="curl -f http://localhost/health" \
  --health-interval=5s \
  my-app

自启动的常见问题

问题 1:容器冲突

# 同名容器冲突导致无法启动
docker run -d --restart always --name web nginx

# 重启后,如果已有同名容器(可能挂在其他设备上),新容器创建会失败

# 解决:使用 --rm 配合 restart 需要在编排中处理

问题 2:网络依赖

# 重启时网络可能还未就绪
# 解决方法:使用自定义 network-mtu 或健康检查

docker network create mynet
docker run -d --restart always --net mynet --name web nginx

问题 3:依赖顺序

# 数据库还没就绪,应用已经启动
# 解决方法:应用层做重试

# Node.js 示例
const connectWithRetry = async () => {
  try {
    await sequelize.authenticate();
    console.log('DB connected');
  } catch {
    console.log('Retrying in 5s...');
    setTimeout(connectWithRetry, 5000);
  }
};

生产环境建议

# 1. 统一管理:用 docker-compose 管理所有需要自启的容器
# 2. 测试自启:手动重启宿主机,确认所有容器按预期启动
# 3. 监控:配置容器健康检查,自启失败时发出告警
# 4. 文档:记录哪些容器设置了自启

# 检查哪些容器设置了自启
docker ps -a --format "{{.Names}}: {{.HostConfig.RestartPolicy.Name}}" \
  | grep -v "no"

# 输出示例
# web: always
# app: unless-stopped
# db: always
# redis: always

面试官追问

问:Docker Daemon 重启后,always 和 unless-stopped 的区别?

答:always:Daemon 重启后,无论容器之前什么状态,只要存在就拉起来。unless-stopped:如果容器之前被 docker stop 手动停过,Daemon 重启后不会自动启动。但如果是崩溃退出的会自启。

问:系统重启后,Docker 容器启动有顺序吗?

答:Docker Daemon 本身不保证容器启动顺序。它会尝试并发启动所有设置了自启的容器。如果需要顺序,需要使用 docker-compose 的 depends_on 或者在应用层面做重试等待。

问:CRON 定时任务中如何启动容器?

# 在 crontab 中检查并启动
*/5 * * * * docker ps | grep my-critical-app || docker start my-critical-app

总结

容器开机自启的核心配置就是 --restart always--restart unless-stopped,配合 Docker 服务本身的 systemctl enable docker。建议优先使用 unless-stopped,避免运维人员手动停止容器后又被自动拉起。生产环境推荐用 docker-compose 统一管理所有容器的自启策略。

© 版权声明
THE END
喜欢就支持一下吧
点赞11 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容