调试时随手敲的一长串 docker run,验证可用后总想固化成 docker-compose.yml——可版本化、可复现、还能编排多个服务。大部分参数能机械对应,但有几类”转不过去”的,得手动处理。这篇把对照表和坑一次讲清。
为什么从 run 迁到 compose
| 维度 | docker run | docker-compose |
|---|---|---|
| 复现 | 命令散落各处,易漏 | 一份 YAML,提交进仓库 |
| 版本化 | 难 | 跟代码一起 diff/回滚 |
| 多服务 | 各起各的、手动连网络 | 一条 up 拉起整套 |
| 可读性 | 长命令难读 | 字段结构化、自解释 |
单容器临时跑用 run 很方便;只要涉及”长期维护”或”多个服务”,就该落到 compose。
常用参数映射对照
| docker run | docker-compose |
|---|---|
-p 8080:80 | ports: ["8080:80"] |
-v /data:/app:ro | volumes: ["/data:/app:ro"] |
-e KEY=VAL | environment: ["KEY=VAL"] |
--env-file .env | env_file: [.env] |
--name web | container_name: web |
--restart unless-stopped | restart: unless-stopped |
--network mynet | networks: [mynet] |
-w /app | working_dir: /app |
-u 1000:1000 | user: "1000:1000" |
--entrypoint /init | entrypoint: /init |
--health-cmd "curl -f localhost" | healthcheck.test |
| 镜像后的参数 | command: |
规整的命令基本能逐项机械转换。
转不过去的几类,要手动处理
这些在 run 和 compose 之间没有一一对应,转换工具会把它们单列在”需注意”里:
--rm:run 退出即删容器;compose 不会自动删。一次性任务用docker compose run --rm,长期服务则需自己管理生命周期。--gpus all:compose 要写成deploy.resources.reservations.devices,结构完全不同。-P(大写):发布所有暴露端口;compose 没有一键等价写法,得把端口逐个列进ports。--mount:比-v结构复杂,要拆成volumes的长语法(type/source/target)。--link:已废弃,用networks让容器同网互通替代。
反向:compose 转 run 的限制
把 compose 拆回 docker run 时,有两个字段天生转不了:
build::docker run不能构建镜像,只能用image占位,提示你先docker build。depends_on::表达启动顺序与健康依赖,run 没有等价物,需你手动先起依赖服务。
多服务的 compose 可以为每个服务各生成一条 run,但它们之间的网络、依赖、启动顺序要你自己串——这恰恰说明多服务本就该留在 compose 里。
迁移后检查清单
转换结果大多能直接用,落库前过一眼这几项:
- “需注意”里列出的无等价参数,逐条手动补全;
- 卷的宿主机路径、网络名是否和目标环境一致;
- 重启策略:单机
restart与编排模式deploy.restart_policy不是一回事; - Compose 版本差异:
mem_limit与deploy.resources.limits等字段在不同版本行为略有不同,在目标环境验证一次。
把一行命令变成结构化 YAML 的同时,顺手把这些”转不过去”的点确认掉,迁移就稳了。