跳到正文
Docker Compose:为什么我不手敲一串 docker run
Docker Compose:为什么我不手敲一串 docker run

Docker Compose:为什么我不手敲一串 docker run

真实项目很少只有一个容器。这篇不讲 Compose 语法大全,讲我用手敲 docker run 翻过什么车、为什么把整套服务写进一个 yml,以及那条差点把数据删没了的教训。

速读#

Compose 解决的不是少敲几条命令,而是把整套服务环境写成可提交、可复现、可 diff 的文件。这篇真正要记住三件事:环境该是代码,有状态服务必须有命名卷,启动顺序不等于服务就绪。

手敲的问题:下次很难和上次一样#

拿这个博客说:WordPress、数据库、Redis 三个服务。一个个 docker run,命令又长又容易错——漏环境变量、端口写反,排半天。

更早做 Django + Redis + Celery,光本地环境搭起来就半小时。手敲最大的问题不是慢,是下次重建,大概率和上次不一样

环境该是代码#

Compose 把整套服务写进一个 compose.yml。选择它的理由就一句:环境该是代码——可提交、可复现、可 diff。

这三个「可」各自值钱:可提交,环境的每次变动都有记录,坏了能回到任何一版;可复现,换机器一句 docker compose up -d 拉起,和原来一样;可 diff,改动在提交前就能看清动了哪一行——手敲命令行时代,这三样一样都没有。而且 up 是幂等的:改完 yml 再执行,只重建发生变化的服务,敢反复跑。

services:
app:
build: .
depends_on: [db]
environment:
DB_HOST: db
db:
image: mysql:8
volumes:
- db_data:/var/lib/mysql
volumes:
db_data:

差点删没数据:破坏性藏在 -v#

有状态服务必须有命名卷。 容器的文件系统跟着容器走,容器删了就没了;命名卷独立于容器存在,容器怎么换,数据都在。一句话:容器可以扔,数据不能跟着扔。我曾经没挂卷,删容器把数据全弄丢过。

Terminal window
docker compose down # 默认保留命名卷
docker compose down -v # 连数据卷一起删
命令数据卷
down保留
down -v删除

看上去只是「停服务」,加个 -v 就把数据带走。破坏性命令绝不盲执行:删卷前先 docker volume ls,想清楚卷里有没有要留的东西。

有状态的服务(容器里存了数据的),必须有命名卷兜底,否则别上线。数据不是配置,删了恢复不回来。

服务名就是主机名#

DB_HOST: db——app 用服务名 db 连库。Compose 起服务时会自动建一个内部网络,并带内部 DNS 把服务名解析成容器地址;不用手动建网络,更不用查容器 IP——容器重建后 IP 会变,服务名不会。

这个机制的适用范围比想象大:后来我把 cloudflared 和应用放进同一个 Compose 网络,隧道配置里直接写 app:8080 连容器,一样成立。同一 Compose 网络里,服务名即主机名——记住这一条,容器间互连基本不用再碰 IP。

depends_on 只管启动顺序#

depends_on 让 db 先起、app 后起。但要清醒:

进程起了 ≠ 依赖就绪。 db 容器起来了,不代表 MySQL 已经能接连接。app 可能在库还没 ready 时去连,直接失败。

概念含义
启动顺序容器谁先 start
就绪进程内服务是否真能接请求

要让 depends_on 真等到「能接连接」,得给依赖配 healthcheck,再声明等它健康:

db:
image: mysql:8
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
interval: 5s
retries: 10
app:
depends_on:
db:
condition: service_healthy

就算配了这个,应用侧最好也带连接重试——healthcheck 只保证启动那一刻就绪,不保证之后 db 不重启。两道兜底不是重复,是各管一段时间窗。

这篇留下的不是 Compose 语法表,是三件事:

  1. 环境该是代码
  2. 有状态服务必须有卷
  3. 启动顺序 ≠ 就绪

三者一起,才支撑「换机器一键复现,且数据不丢」。

版权许可

CC BY-NC-SA 4.0 本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。

相关文章

s1oopX

登录 s1oopX