一、为什么要关注Docker Compose的版本差异?

很多开发者接触Docker时,都会用到Docker Compose这个工具——它能帮我们把好几个有依赖关系的容器(比如Web服务、数据库、缓存)一次性启动、停止、管理,不用一个个敲docker run命令。但最近不少人会发现,之前写的docker-compose up命令突然不好用了,或者官方文档里的示例变成了docker compose up,这其实就是V1和V2版本的差异导致的。

Docker Compose的V2是官方完全重写的版本,不是简单的小更新,核心逻辑和使用方式都有变化,而且官方已经宣布从2022年11月开始,停止对V1的维护,现在主流的Docker安装包(比如Docker Desktop、服务器端的Docker Engine)都已经默认集成V2,V1逐渐被淘汰。所以不管是新写配置,还是维护旧项目,搞懂两个版本的差异,才能避免踩坑。

二、核心差异1:命令兼容——从docker-compose到docker compose的变化

这是最直观的差异,也是很多人最先碰到的问题。V1的命令都是以docker-compose开头(中间有短横线),V2则改成了docker compose(中间是空格,没有短横线),相当于把Compose变成了Docker主命令的一个子命令,和docker run、docker ps这些命令整合到一起了。

2.1 命令的基础使用差异

先举个最常用的例子,启动所有容器: V1的写法:

# V1启动所有容器,-d表示后台运行
docker-compose up -d

V2的写法:

# V2启动所有容器,参数逻辑和V1完全一致
docker compose up -d

除了启动,停止、删除、查看日志这些常用命令的参数逻辑,V2和V1基本完全兼容,只是开头的命令前缀变了。

2.2 兼容模式:旧项目不用立刻改命令

很多人会担心,自己手里有一堆旧项目,全改成docker compose的命令太麻烦,有没有过渡方案?官方提供了兼容模式,只要给V2的docker compose命令加一个--compatibility参数,就能模拟V1的部分行为,比如:

# 兼容模式启动,临时适配旧项目的配置逻辑
docker compose --compatibility up -d

不过兼容模式不是万能的,它只能解决大部分基础场景的问题,一些复杂的配置(比如扩展配置、网络命名空间的特殊设置)还是会出问题,所以长期来看还是要迁移到V2的原生写法。

三、核心差异2:配置文件的变化——V2的新特性和限制

Docker Compose的配置文件是docker-compose.yml(V2也支持docker-compose.yaml),这个文件的语法是核心,V2对配置文件做了很多升级,也改了一些旧规则。

3.1 配置文件的版本支持变化

V1支持的配置文件版本有2、2.1、3等,V2则完全放弃了对V1配置文件中旧版本(比如2.x)的原生支持——如果你用V2启动一个版本号是2的配置文件,会直接报错,必须用兼容模式或者升级配置文件。

举个错误的例子,这是一个V1的旧配置文件:

# V1旧配置,版本号为2
version: '2'
services:
  web:
    image: nginx:alpine
    ports:
      - "8080:80"

用V2原生启动会报错:

# 报错:version '2' is not supported for the V2 format
docker compose up -d

解决方法要么加兼容模式,要么把版本号改成3.x(V2推荐的版本),修改后的正确配置:

# V2兼容的配置,版本号为3.8(3.x是V2支持的版本)
version: '3.8'
services:
  web:
    image: nginx:alpine
    ports:
      - "8080:80"

3.2 V2新增的实用配置特性

V2给配置文件加了很多新功能,能帮我们解决之前V1的痛点,这里举两个最常用的:

3.2.1 服务的依赖等待:depends_on的健康检查支持

V1的depends_on只是保证启动顺序,不保证服务真的可用——比如Web服务依赖MySQL,V1只会先启动MySQL,再启动Web,但可能MySQL还没完成初始化,Web就启动了,导致连接失败。

V2的depends_on新增了condition参数,可以指定依赖的服务必须处于什么状态才会启动当前服务,比如必须是健康状态(healthy)。举个完整的示例(技术栈:Nginx + MySQL):

# 技术栈:Nginx + MySQL,V2配置
version: '3.8'
services:
  mysql:
    image: mysql:8.0
    environment:
      MYSQL_ROOT_PASSWORD: 123456
      MYSQL_DATABASE: test_db
    # 配置健康检查:检查MySQL是否能正常连接
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root", "-p123456"]
      interval: 5s # 每5秒检查一次
      timeout: 3s # 每次检查超时3秒
      retries: 5 # 最多重试5次

  web:
    image: nginx:alpine
    ports:
      - "8080:80"
    # 依赖mysql服务,只有mysql健康后才启动web
    depends_on:
      mysql:
        condition: service_healthy

这个配置里,Web服务会等MySQL完全启动并能正常连接后,才会启动,避免了之前的连接失败问题。

3.2.2 扩展配置:extend的语法优化

V1的extend是用来复用配置的,比如多个服务有相同的环境变量、卷配置,V1的写法比较麻烦,V2做了简化。举个示例(技术栈:两个Nginx服务,复用相同的基础配置):

# 技术栈:Nginx,V2扩展配置示例
version: '3.8'
# 先定义一个基础服务模板
x-base:
  image: nginx:alpine
  volumes:
    - ./html:/usr/share/nginx/html

services:
  web1:
    extends:
      service: x-base # 继承基础模板
    ports:
      - "8081:80"

  web2:
    extends:
      service: x-base # 继承基础模板
    ports:
      - "8082:80"

这个配置里,web1和web2都复用了x-base里的image和volumes配置,不用重复写,V2的extends写法比V1更简洁,也支持跨文件复用(比如把基础模板放到另一个文件里)。

3.3 V2删除的旧特性

V2也删除了一些V1的特性,这些特性大多是不常用或者有更好的替代方案的:

  1. 网络模式的特殊配置:V1支持的--net=container:<容器名>的写法,V2改成了network_mode: service:<服务名>,逻辑更清晰;
  2. 旧的卷配置:V1的volumes_from已经被废弃,V2推荐用named volume或者bind mount来共享数据;
  3. 环境变量的旧写法:V1支持的env_file的相对路径写法,V2要求必须是相对于配置文件的路径,避免歧义。

四、核心差异3:架构和性能的变化

V2是用Go语言重写的(V1是Python写的),所以底层架构和性能都有很大变化:

  1. 启动速度:V2的启动速度比V1快很多,尤其是服务数量多的时候——比如一个包含10个服务的配置,V2启动可能只需要几秒钟,V1可能要十几秒甚至更长;
  2. 内存占用:V2的内存占用比V1低,因为Go语言的运行时比Python轻量;
  3. 兼容性:V2完全整合到Docker的核心架构里,和Docker CLI、Docker API的兼容性更好,不会出现V1和Docker版本不兼容的问题(比如旧的V1可能不支持新的Docker网络特性)。

五、迁移指南:从V1到V2的完整步骤

搞懂了差异,接下来就是具体的迁移步骤,不管是新写项目还是维护旧项目,都可以按这个流程来:

5.1 第一步:确认当前环境的Docker Compose版本

先检查自己的环境装的是V1还是V2,命令:

# 检查V1是否存在
docker-compose --version
# 检查V2是否存在
docker compose version

如果docker compose version能正常输出版本号(比如v2.20.0),说明环境已经支持V2;如果只有docker-compose能输出,说明是旧环境,需要先升级Docker(或者单独安装V2)。

5.2 第二步:迁移旧项目的配置文件

旧项目的配置文件如果是V1的版本(比如2.x),按以下步骤迁移:

  1. 把version改成3.x(推荐3.8及以上,兼容性最好);
  2. 检查depends_on的写法,如果原来的depends_on只是简单的顺序,改成带condition的写法(可选但推荐);
  3. 检查网络、卷的配置,改成V2的规范写法;
  4. 用兼容模式先测试,确认没问题后,去掉--compatibility参数。

举个完整的旧项目迁移示例(技术栈:Node.js + Redis):

旧的V1配置:

# V1旧配置,版本2
version: '2'
services:
  app:
    image: node:18-alpine
    ports:
      - "3000:3000"
    depends_on:
      - redis
    volumes:
      - ./app:/app
    working_dir: /app
    command: ["npm", "start"]

  redis:
    image: redis:alpine

迁移后的V2配置:

# 迁移后的V2配置,版本3.8
version: '3.8'
services:
  app:
    image: node:18-alpine
    ports:
      - "3000:3000"
    depends_on:
      redis:
        condition: service_healthy # 新增健康检查条件
    volumes:
      - ./app:/app
    working_dir: /app
    command: ["npm", "start"]

  redis:
    image: redis:alpine
    # 新增健康检查,确认Redis可用
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 5s
      timeout: 3s
      retries: 5

迁移后,用V2启动:

# 先测试兼容模式
docker compose --compatibility up -d
# 确认没问题后,去掉兼容模式
docker compose up -d

5.3 第三步:更新自动化脚本

如果项目里有启动、停止容器的脚本(比如shell脚本、CI/CD脚本),要把里面的docker-compose命令改成docker compose,比如原来的脚本:

# 旧的启动脚本
docker-compose down
docker-compose up -d

改成新的:

# 新的启动脚本
docker compose down
docker compose up -d

如果是CI/CD流程(比如GitHub Actions、GitLab CI),也要修改对应的命令,确保用V2启动。

六、应用场景、优缺点和注意事项

6.1 应用场景

Docker Compose V2适合所有需要管理多容器服务的场景,尤其是:

  1. 本地开发:多个服务(比如前端、后端、数据库、缓存)一起开发调试,不用单独启动每个服务;
  2. 测试环境:快速部署一套测试环境,方便测试人员验证功能;
  3. 小型生产环境:比如个人博客、小型API服务,用V2部署简单,维护方便;
  4. 容器编排的入门:V2的语法比K8s简单很多,适合新手学习容器编排的基础概念。

6.2 技术优缺点

优点:

  1. 命令更统一:整合到Docker主命令,和其他Docker命令的使用逻辑一致,学习成本低;
  2. 性能更好:启动速度快、内存占用低,适合服务数量多的场景;
  3. 功能更完善:新增的健康检查依赖、扩展配置等特性,解决了V1的很多痛点;
  4. 官方维护:V1已经停止维护,V2是官方唯一支持的版本,有问题能及时得到修复。

缺点:

  1. 旧项目迁移成本:如果旧项目的配置比较复杂,迁移可能需要花时间调整;
  2. 兼容模式有限:兼容模式不能解决所有V1的问题,一些特殊场景还是需要手动修改配置;
  3. 部分旧特性删除:一些不常用的V1特性被删除,需要用新的替代方案。

6.3 注意事项

  1. 升级Docker:如果环境还是旧的Docker版本,建议先升级到最新版,确保V2能正常运行;
  2. 配置文件的版本:尽量用3.8及以上的版本,兼容性最好;
  3. 健康检查的配置:使用depends_on的健康检查时,一定要配置合理的interval、timeout和retries,避免检查失败;
  4. 生产环境的验证:如果是生产环境的项目,迁移前一定要在测试环境充分验证,避免影响业务;
  5. 文档的更新:官方文档已经更新到V2的语法,遇到问题优先查官方文档,不要参考旧的V1文档。

七、总结

Docker Compose V2和V1的差异,本质上是官方对这个工具的重构和升级,从命令前缀的变化,到配置文件的语法升级,再到底层架构的优化,都是为了让这个工具更易用、更稳定、性能更好。

对于开发者来说,不管是新写项目还是维护旧项目,迁移到V2都是必要的——一方面V1已经停止维护,不再有安全更新;另一方面V2的新特性能帮我们解决很多之前的痛点,提高开发和部署的效率。

迁移的过程并不复杂,只要按步骤来:先确认环境,再迁移配置文件,最后更新脚本,大部分项目都能顺利迁移。如果遇到问题,官方的兼容模式和社区文档也能提供帮助。