容器开机自启: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,一张表
| 场景 | always | unless-stopped |
|---|---|---|
| 容器异常退出 | 重启 | 重启 |
| Docker 守护进程重启 | 拉起 | 拉起 |
| 你手动 stop 后,机器重启 | 拉起(可能不是你想要的) | 保持停止 |
| 适用 | 基本不用 | 长期服务默认选它 |
和 Docker 开机自启是两回事
别搞混了,这是两层:
- Docker 守护进程开机自启:
sudo systemctl enable docker,保证 Docker 本体随机器启动。 - 容器自启:
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 了。小够每次配完都这么验,省得半夜被叫醒。生产机器别在白天高峰期做这个实验,找个夜深人静的时候。验证完顺手把验证过程记下来,下次换机器直接照做。