Docker使用笔记:容器保活、快速起 MySQL、密码管理器部署三件事
版本说明
本文命令在 Docker 24.x / 25.x 下验证通过,docker run 参数多年未变,可放心用于任意近期版本。
# 1. 容器为什么会"跑着跑着就退出了"
刚上手 Docker 最常踩的坑:docker run 起一个基础镜像(比如 alpine、ubuntu)想进去调试,结果容器秒退。原因是 Docker 容器的生命周期绑定的是容器内 PID 1 进程——PID 1 退出,容器立刻停止,不管你有没有 -d。基础镜像的默认命令往往是一次性任务(比如打印完就退出的 shell),没有一个"一直不退出"的前台进程。
# 2. 两种保活方式,怎么选
给容器一个不会退出的 PID 1,常见两种写法:
# 方式一:sleep infinity
docker run -d IMAGE sleep infinity
# 方式二:tail -f /dev/null
docker run -d IMAGE tail -f /dev/null
2
3
4
5
infinity 是 GNU coreutils 的 sleep 特有参数,表示"睡到天荒地老",不会像 sleep 999999 那样最终到期。tail -f /dev/null 则是监听一个永远不会有新内容的空设备,效果等价,但 tail 在 Alpine 精简镜像(busybox 版)里也保证存在,兼容性略好。
预期输出:起完用 docker ps 能看到容器 STATUS 是 Up,而不是几秒前的 Exited (0)。
为什么不用 docker run -d IMAGE(不加保活命令)直接期待它常驻:如果镜像本身没有定义长驻的 CMD/ENTRYPOINT(比如纯工具镜像),容器会在默认命令跑完后立刻退出,这不是 bug,是设计如此——Docker 认为"容器 = 一个进程的生命周期",不是"容器 = 一台常开的虚拟机"。需要常驻调试环境时才需要手动补一个保活命令。
坑:sleep infinity / tail -f /dev/null 本身几乎不占资源(休眠/阻塞态),但如果你开了几十个这样的"僵尸调试容器"忘记清理,累积的容器元数据和日志文件依然会占磁盘。定期 docker ps -a --filter status=exited + docker container prune 清理。
# 3. 最简单起一个 MySQL 容器
不装机器上的 MySQL,直接拉镜像跑起来,用于本地开发或临时验证:
docker run --name some-mysql \
-e MYSQL_ROOT_PASSWORD=<PASSWORD> \
-v /docker/mysql/conf:/etc/mysql/conf.d \
-v /docker/mysql/logs:/logs \
-v /docker/mysql/data:/var/lib/mysql \
-p 3306:3306 \
-d mysql:latest
2
3
4
5
6
7
三个挂载对应配置、日志、数据三类文件,目的是让容器可以随意删掉重建而不丢数据——这是容器化部署有状态服务的核心原则:容器本身是一次性的,状态必须落在宿主机的卷上。
验证:
docker logs some-mysql --tail 20 # 看到 "ready for connections" 才算真正起来
docker exec -it some-mysql mysql -uroot -p<PASSWORD> -e "select 1"
2
坑:mysql:latest 会随时间指向不同大版本(比如某天从 8.0 跳到 8.4),生产环境务必锁定具体 tag(如 mysql:8.0.34),否则重建容器时可能因为大版本跳变导致数据目录不兼容、容器起不来。
# 4. 用密码管理器(Vaultwarden)验证"数据库分离部署"模式
在真实场景中会更进一步:容器只跑应用本身,数据库是外部独立服务(自建或云数据库),这样应用容器可以随意重建、扩缩容,数据库单独维护备份策略。以开源密码管理器 Vaultwarden(Bitwarden 兼容后端)为例:
docker run -d --name vaultwarden \
-e DATABASE_URL='mysql://user:password@db-host:3306/vaultwarden' \
-p 8088:80 \
-v /data/vaultwarden:/data/ \
vaultwarden/server:1.25.1
2
3
4
5
这里 DATABASE_URL 指向的是一个外部 MySQL(可以就是上一节起的那个容器,也可以是独立数据库主机),-v /data/vaultwarden:/data/ 只保留应用侧的附件/图标缓存这类非核心数据。这种"应用容器 + 外部数据库"的组合是容器化部署最常见的模式:应用层无状态、可随时 docker rm 重建;数据层有状态、独立管理生命周期。
为什么锁定镜像版本号(1.25.1 而不是 latest):密码管理器这类涉及加密格式的服务,大版本升级可能伴随数据库 schema 变更,锁版本号能保证"这次部署跑的就是我验证过的那个版本",升级是主动决策而不是意外发生。
验证:访问 http://<host>:8088 能看到 Vaultwarden 登录页;docker logs vaultwarden 里出现数据库连接成功且无 migration 报错。
# 5. 可复用要点
- 容器退出往往不是故障,是 PID 1 进程正常退出——需要常驻就显式给一个不退出的前台命令(
sleep infinity/tail -f /dev/null)。 - 任何有状态服务(数据库、密码管理器)都用
-v把状态挂到宿主机卷,容器本身当一次性资源对待。 - 生产环境永远锁定镜像 tag 到具体版本号,
latest只适合临时验证。 - "应用容器 + 外部数据库"是比"全部塞进一个容器"更容易维护和扩展的默认模式。
- 02
- ORDER BY 配合 LIMIT 触发的索引选择陷阱 原创08-07
- 03
- Nginx 运维知识地图:从配置基础到反向代理实战 原创07-29