容器开机自启:restart 策略一次配好

VPS 半夜重启,早上发现网站挂了——因为容器没设自启。小够讲清 restart 四种策略怎么选、unless-stopped 和 always 的区别、容器启动顺序控制,以及验证方法。

我是小够,只推够用的 VPS。

VPS 重启是常事:商家维护、内核更新、你自己手滑。重启之后容器不会自己起来,除非你告诉 Docker。配一次,一劳永逸。

四种策略,一个一个说

services:
  web:
    image: nginx:alpine
    restart: unless-stopped

restart 有四个值:

no(默认):从不自动重启。容器退出了就是退出了,适合一次性任务、调试场景。你手动 docker run 跑个临时任务,不用配。默认值是 no,所以"没配 restart 的容器重启后没起来"不是 bug,是默认行为。

on-failure:只有非正常退出(退出码非 0)才重启。适合定时任务、批处理这类"跑完就该停"的场景。正常结束不打扰,报错了自动重试。还可以加次数限制:on-failure:5,重试 5 次还失败就放弃,别无限循环。

always:一直重启。容器挂了重启,Docker 守护进程重启也拉起来。听起来最省心,但有个讨厌的行为:你手动 docker stop 停掉想维护,机器一重启它又自己起来了,容易误事。半夜维护完忘了这事,第二天用户访问的是个半成品。

unless-stopped:和 always 一样,但"你手动停掉的就不再拉起"。网站、数据库这类长期服务,默认选它,这是小够的推荐。手动停的就是要停,机器重启别自作主张。

unless-stopped vs always,一张表

场景alwaysunless-stopped
容器异常退出重启重启
Docker 守护进程重启拉起拉起
你手动 stop 后,机器重启拉起(可能不是你想要的)保持停止
适用基本不用长期服务默认选它

和 Docker 开机自启是两回事

别搞混了,这是两层:

  1. Docker 守护进程开机自启:sudo systemctl enable docker,保证 Docker 本体随机器启动。
  2. 容器自启:restart: unless-stopped,保证容器随 Docker 启动。

两个都要配,缺一个重启后都是挂的。装 Docker 那篇里第一条已经配了,这里是第二条。检查守护进程自启状态:

sudo systemctl is-enabled docker   # 输出 enabled 就是开了

docker run 怎么配

不用 compose 的话,docker run 加参数:

docker run -d --restart unless-stopped --name web nginx:alpine

已经在跑的容器想补配,不用删了重建:

docker update --restart unless-stopped web

docker update 能在线改重启策略,重启容器后生效,应急很好用。同样能在线改的还有内存限制(--memory),排错那篇讲过。

启动顺序:数据库先起,应用后起

重启后所有容器几乎同时启动,应用可能比数据库先就绪,连不上就报错退出——好在有重启策略,它会重试几次最终连上。但优雅的做法是用 depends_on + healthcheck(进阶篇讲过),让应用真正等到数据库 ready。重启策略是兜底,健康检查是正道,两个都配最稳。

还有个细节:depends_on 的启动顺序在 Docker 守护进程重启时同样生效,Compose 会按依赖顺序拉起,不用你操心。

定时任务容器怎么配

跑 cron 这类定时任务的容器,用 on-failure 还是 unless-stopped?看任务性质:常驻的调度器(如 supercronic)用 unless-stopped;跑完就退的一次性任务用 no 或 on-failure。别给一次性任务配 unless-stopped,它跑完退出后你会发现它"又自己起来了",然后陷入困惑。

验证一下

配完别信感觉,实测:sudo reboot 重启机器,等两分钟,docker compose ps 看是不是都 Up 了。小够每次配完都这么验,省得半夜被叫醒。生产机器别在白天高峰期做这个实验,找个夜深人静的时候。验证完顺手把验证过程记下来,下次换机器直接照做。