接手一个还在用 docker-compose 的旧项目时,我通常不会直接动手改命令。因为 V1 和 V2 表面上是带不带横杠的区别,实际踩坑点集中在项目名、配置解析和依赖启动上。这篇记录会按照我平时排查的顺序来写:先确认环境,再处理容易误判的部分,最后给出一套可以回滚的迁移顺序。
要确认当前环境使用的是 Docker Compose V1 还是 V2,最直接的方法是执行 `docker compose version`。如果返回类似 `Docker Compose version v2.x.x` 的信息,说明已安装 V2 插件;如果提示找不到命令,则可能是旧版 V1。V1 的命令格式是 `docker-compose`(带横杠),而 V2 作为 Docker CLI 的插件,使用 `docker compose`(中间有空格)。在迁移时,首先需要将脚本和 CI 配置中的 `docker-compose` 全部替换为 `docker compose`,同时注意原 V1 中有些子命令参数在 V2 中可能已改名或废弃。例如 `docker-compose build --pull` 在 V2 …
项目名称在 Compose V1 和 V2 中的生成规则存在明显差异。V1 默认使用当前目录名作为项目名,但 V2 会先将目录名转换为小写,并删除或替换非字母数字字符(如点号、下划线)。例如名为 `MyApp_v2` 的目录,在 V1 中项目名通常是 `MyApp_v2`,到了 V2 可能变成 `myappv2`(具体规则与 Docker 版本有关)。这会影响容器名、网络名和卷名的前缀,导致迁移后旧容器无法识别。稳妥的做法是在 `docker-compose.yml` 或环境中明确设置 `COMPOSE_PROJECT_NAME`,或使用 `docker compose -p 项目名 up` 指定,确保前后一致。另外,`docker compose ls` 可以查看当前所有活跃项目的名称和状态,迁移时应先记录 …
先确认当前环境用的是哪个版本
要确认当前环境使用的是 Docker Compose V1 还是 V2,最直接的方法是执行 docker compose version。如果返回类似 Docker Compose version v2.x.x 的信息,说明已安装 V2 插件;如果提示找不到命令,则可能是旧版 V1。V1 的命令格式是 docker-compose(带横杠),而 V2 作为 Docker CLI 的插件,使用 docker compose(中间有空格)。在迁移时,首先需要将脚本和 CI 配置中的 docker-compose 全部替换为 docker compose,同时注意原 V1 中有些子命令参数在 V2 中可能已改名或废弃。例如 docker-compose build --pull 在 V2 …
这里有个容易误判的地方:docker-compose 命令在安装 V2 后可能依然存在,它可能是指向 Docker Compose 的兼容脚本。所以还要执行 docker-compose version,看输出是 docker-compose version 1.x 还是 Docker Compose version v2.x。如果同时存在两套命令,CI 脚本里最好写清楚完整路径,或者用 docker compose version 作为主判断。
项目名变化是迁移时最容易忽略的坑
项目名称在 Compose V1 和 V2 中的生成规则存在明显差异。V1 默认使用当前目录名作为项目名,但 V2 会先将目录名转换为小写,并删除或替换非字母数字字符(如点号、下划线)。例如名为 MyApp_v2 的目录,在 V1 中项目名通常是 MyApp_v2,到了 V2 可能变成 myappv2(具体规则与 Docker 版本有关)。这会影响容器名、网络名和卷名的前缀,导致迁移后旧容器无法识别。稳妥的做法是在 docker-compose.yml 或环境中明确设置 COMPOSE_PROJECT_NAME,或使用 docker compose -p 项目名 up 指定,确保前后一致。另外,docker compose ls 可以查看当前所有活跃项目的名称和状态,迁移时应先记录 …
我在迁移前会先跑一次 docker-compose ps -a 和 docker compose ls,把容器名和项目名记下来。如果旧项目名里包含点号或下划线,V2 自动生成的名称大概率不一样。这时候不要急着删旧容器,先用 docker compose -p 旧项目名 up -d 启动,再对照 docker network ls 里的网络名是否跟旧的一致。
脚本替换不是简单换个命令
将现有脚本从 V1 迁移到 V2,不能只做简单的命令替换。除了把 docker-compose 换成 docker compose,还需要留意几个隐藏差异。第一,V2 默认会使用 .env 文件,但 V1 需要显式指定 --env-file 才生效。如果你之前依赖于 .env 自动加载,V2 可能会改变某些变量的注入值。第二,docker-compose logs 在 V1 里不带服务名时输出全部日志,V2 的 docker compose logs 行为一致,但参数如 --tail 和 --follow 的短选项有所调整。第三,V2 在 docker compose run 执行时会自动为容器附加交互终端,除非用 -T 禁用它,这与 V1 中的默认行为不完全相同。建…
我的做法是,替换完命令后,对脚本里用到的每个子命令执行 docker compose 子命令 --help,逐项核对参数。例如 up 命令在 V2 里新增了 --wait 和 --wait-timeout,而 --remove-orphans 的默认行为也可能不同。对于 run,如果脚本里需要保持 V1 的非交互行为,记得加上 -T。另外,env_file 的相对路径在 V2 中是相对于 compose 文件所在目录,但 --env-file 是相对于当前工作目录,两者容易搞混。
建议的迁移顺序和验证
我通常按下面的顺序处理,每一步都留出回滚点:
- 先备份当前
docker-compose.yml和相关的.env文件。 - 运行
docker-compose config保存输出,再运行docker compose config对比差异。重点看name字段以及网络、卷的定义。 - 检查 compose 文件里有没有写死容器名或网络别名,如果有,改成变量或显式声明。
- 停掉旧环境的容器:
docker-compose stop(先别用down,这样容器和网络还在,方便回滚)。 - 用
docker compose -p 项目名 up -d --remove-orphans启动新环境。如果旧容器已经停止,这个命令会创建新容器。 - 执行
docker compose ps和docker compose ls确认状态,再对照docker network ls和docker volume ls里的名称。
验证时不要只看容器起来了,还要看日志里有没有连接错误。我习惯跑一次 docker compose logs --tail 200,如果有服务依赖数据库,确认数据库健康检查通过后再接入流量。
回滚与风险边界
迁移失败时,最直接的回滚方式是重新使用旧命令 docker-compose up -d。但前提是没有删除旧容器和旧命名卷。所以我把 down 拆成 stop 而不是直接 down,这样容器还在,网络和卷不会被自动移除。V2 对 depends_on 的依赖控制更严格,启动顺序不等于服务健康。如果旧环境里依赖数据库的服务一直正常,新环境却连接失败,需要给数据库服务加 healthcheck,然后在 depends_on 里用 condition: service_healthy。这是迁移后最常见的隐藏问题,不是命令差异导致的,而是容器启动时间变了。
另外,迁移期间不要同时用 V1 和 V2 对同一个项目目录执行命令。两个命令的锁机制不通用,可能产生两个互相冲突的容器组。.env 文件在 V2 中的加载顺序是:先读 .env,再读 compose 文件里的 env_file,最后读 shell 环境变量。如果发现某个变量没生效,按这个顺序排查。