piapia123
zh

Compose 与 docker run 互转

网络

所有处理都在浏览器本地完成,数据不上传服务器

输入
把文件拖到这里可直接载入
输出

两个方向都能转:粘 compose 的 `services:` 段得到 `docker run` 命令,粘一条 `docker run` 得到 compose 片段(类型自动识别)。 ⚠️ 但这两个格式的表达能力并不对等,所以转换不可能完整。 这是用这个工具之前最该知道的一件事: · `depends_on`、`deploy`(副本数、资源限制)、`profiles`、`extends` —— compose 有,`docker run` 里没有对应物。副本数尤其:`docker run` 就是跑一个容器,没有「3 个副本」这个说法。 · `${VAR}` 插值、`env_file` 与 `.env` 的合并顺序、相对路径的基准目录(compose 是文件所在目录,`docker run` 是当前目录)—— 转换之后语义会变,而结果看起来完全合理。 所以这里的做法是:能一一对应的就转,转不了的逐条列出来并说明为什么。静默丢掉一个 `deploy` 会让人以为那条命令等价于原来的服务,而它不等价。 ⚠️ 另一个容易踩的地方是 `docker run` 的参数位置:镜像之后的 `-` 开头的词不是 docker 选项,是容器里那条命令的参数(`docker run nginx -g "daemon off;"` 里的 `-g` 属于 nginx)。这里按位置切开,所以命令会原样保留。全部在浏览器本地完成。 需要规划 Docker 的地址池与子网(`daemon.json` 的 `default-address-pools` / `bip`)?那是另一个工具:「Docker 地址池规划」。

功能

  • 两个方向自动识别:compose 的 services 段 ↔ 完整的 docker run 命令
  • image、container_name、ports、volumes、environment、env_file、command、entrypoint、restart、network_mode、working_dir、user、hostname
  • 开关型:privileged、read_only、tty、stdin_open
  • healthcheck 的 test 数组转成 --health-cmd,连同 interval / timeout / retries
  • 端口的短写法与长写法(target / published / protocol)都认,非 tcp 加后缀
  • 卷的长写法(source / target / read_only)转成 `-v src:dst:ro`
  • ⚠️ depends_on、deploy、profiles、extends 逐条列出,并说明为什么没有对应物
  • ⚠️ build、多网络、命名卷、`KEY=` 空值这些语义会变的地方单独标出来
  • ⚠️ 认不出的 docker 选项如实报出来,不塞进结果里假装转过了
  • ⚠️ 正确处理行尾的续行符 —— `docker ps` 与文档里复制出来的命令都带
  • ⚠️ 镜像之后的参数按位置切分为命令,不会把 `-g` 之类的当成 docker 选项丢掉
  • 全部在浏览器本地完成

使用方法

  1. 把 compose 文件的 services 段或一条 docker run 命令粘进去
  2. 需要时在选项里指定只转哪一个服务
  3. 先看命令或片段,再看「没转过来的东西」与「语义会变的地方」两块

常见问题

为什么有些配置没有转过来?
因为它们在 `docker run` 里没有对应物。最典型的是 `deploy`:它配置的是副本数、资源限制、滚动更新策略,属于编排层,而 `docker run` 只启动一个容器 —— 「3 个副本」这个说法在单条命令里根本不存在(那要用 `docker service` 或编排器)。`depends_on`(启动顺序)与 `profiles`(开关)同理。把转不了的东西悄悄丢掉,会让人以为那条命令等价于原来的服务,而它不等价,于是拿着它去部署才发现少了东西。
转换之后为什么相对路径可能不对?
因为两者的基准目录不同:compose 里的相对路径是相对compose 文件所在目录解析的,而 `docker run` 的命令行参数是相对当前工作目录。`./site:/usr/share/nginx/html` 这一条,在 compose 文件位于 `/srv/app/docker-compose.yml` 时指的是 `/srv/app/site`,而在别处执行 `docker run` 时指的是你当时所在的目录。转换出来的命令看起来一模一样,跑起来却挂载到了别的地方。
`-d` 与 `--rm` 转换后为什么不见了?
因为它们在 compose 里不是 service 定义的一部分。`-d`(后台运行)对应的是 `docker compose up -d` 这个命令级的开关,写在任何一个服务上都说不通;`--rm`(退出后删除容器)在 compose 的 service 键里也没有对应的写法。所以转换时它们会消失 —— 这是正确的,因为 compose 的语义里本来就不该有它们。
镜像后面的 `-g` 为什么没被当成选项丢掉?
因为 docker 的语法是 `docker run [选项] 镜像 [命令]`,镜像之后的一切都是容器里要跑的命令。`docker run nginx -g "daemon off;"` 里的 `-g` 是 nginx 的参数,不是 docker 的开关。按位置切开之后它原样保留在 command 里;不按位置切的话,它会被当成一个不认识的 docker 选项丢掉,而 compose 文件看起来还是完整的。
能转 Podman 或 Kubernetes 吗?
不能,这里只做 compose 与 `docker run`。转 Kubernetes 是另一个量级的事情:一个 Deployment 加上 Service、ConfigMap、Secret 的拆分方式取决于你的集群怎么组织,不是一个一一对应的映射,硬做出来的 YAML 能跑但很难维护。
daemon.json 的地址池规划在哪里?
在另一个工具「Docker 地址池规划」里。这里只做 compose 与 `docker run` 的互转:一边是服务编排文件、一边是单条运行命令。地址池(`default-address-pools`)与 docker0 的 `bip` 是 daemon 级别的配置,和单个容器的启动命令没有对应关系,所以拆成两个工具,免得在一页里混淆两件事。

相关工具