docker-compose 安装与升级实战:覆盖 Linux、Windows 与离线环境
1. 装了这么久你可能还没搞懂 docker-compose 在装什么先聊点实在的。我这两年处理过不少部署事故最后排查下来相当一部分不是 yaml 写错了而是服务器上的 docker-compose 根本没装对。注意我说的是“装对”不只是“装上”。docker-compose 这个工具看起来很不起眼但它的安装方式、版本来源、命令入口水比很多人想象中深得多。老版本 docker-compose 1.x 用 Python 写的发布形态是独立二进制装完以后命令是docker-compose中间带横杠。2020 年以后Docker 官方用 Go 重写了 compose 能力改成 Docker CLI 的插件命令是docker compose中间是空格。这个变化是很多混乱的源头同一个服务器上可能两个命令同时存在但一个指向 v1、一个指向 v2跑出来的结果完全不一样。所以这篇文章不是一个单纯的“安装教程”我把安装选型、Windows 环境下的基础服务部署、版本升级、国内下载受限和离线环境部署这四条线整个过一遍。适合两类人看一类是刚入门、照着网上教程总是装不明白的另一类是在生产环境维护多台机器、经常被版本问题坑的。2. Linux 安装的三条路线别再只会 curl GitHub 了很多人一搜“docker-compose 安装”出来的教程千篇一律都是 GitHub Release 拉二进制。这条路本身没错但它不是唯一方案而且在部分网络环境下根本走不通。我按实用程度把三条路线讲清楚。2.1 官方二进制安装通用但要注意两个细节x86_64 的 Ubuntu 机器上官方最原始的方法是sudo curl -SL https://github.com/docker/compose/releases/download/v2.23.3/docker-compose-linux-x86_64 \ -o /usr/local/bin/docker-compose sudo chmod x /usr/local/bin/docker-compose执行完以后测试一下docker-compose version看到Docker Compose version v2.23.3就算成功。这里有两个容易被忽视的细节。第一个是架构。ARM 机器要把文件名换成docker-compose-linux-aarch64这个不搞清楚下载完一执行就会报Exec format error。判断架构用这个命令uname -m输出x86_64就下 x86_64输出aarch64就下 aarch64。第二个是插件目录。只把二进制扔进/usr/local/bin只能激活docker-compose这个横杠命令。如果你想docker compose空格版也能用得补一个软链接sudo mkdir -p /usr/local/lib/docker/cli-plugins sudo ln -sf /usr/local/bin/docker-compose /usr/local/lib/docker/cli-plugins/docker-compose很多教程不会讲这一步但实际维护中新版工具链比如一些 CI 脚本、Portainer 的栈调用的就是docker compose插件入口不补这个链接排查起来很抓狂。2.2 包管理器安装最省心但前置条件略多如果你的机器已经配置了 Docker 官方 apt 源安装 compose 变得极其简单sudo apt update sudo apt install docker-compose-plugin装完验证docker compose version这个包会自动把插件放到/usr/libexec/docker/cli-plugins/docker-compose路径不用你操心升级也用 apt 一把梭。CentOS 系对应命令是sudo yum install docker-compose-plugin但包管理器方案有个前置条件你得先有 Docker 官方源。很多人装 Docker 的时候用的是发行版自带源或者一堆第三方脚本这时候apt install docker-compose-plugin会直接报“找不到包”。碰到这种情况要么先配好官方源要么退回 2.1 的二进制方案。2.3 指定特定版本安装的三招“指定特定版本”这个需求我在排查问题时遇到最多。要么是项目文档明确要求 compose 2.23要么是生产环境不敢用最新版。这里给三个办法。第一二进制直接指定。GitHub Release 的 URL 结构是固定的把版本号换成v2.23.0、v2.23.3都可以sudo curl -SL https://github.com/docker/compose/releases/download/v2.23.0/docker-compose-linux-x86_64 \ -o /usr/local/bin/docker-compose第二apt 锁版本。先查可用版本apt-cache madison docker-compose-plugin输出会列出形如2.23.0-1~ubuntu.22.04~jammy的版本号然后安装指定版本sudo apt install docker-compose-plugin2.23.0-1~ubuntu.22.04~jammy第三用 Docker 镜像拉取指定 tag第五部分会展开适合 GitHub 访问不顺畅的场景。三种方式的取舍我列个表安装方式适用场景缺点GitHub 二进制所有 Linux最通用受网络限制需手动管升级包管理器已配官方源的 Debian/RHEL源没配好会找不到包Docker 镜像提取有 Docker 但拉不动 GitHub多一步容器文件拷贝3. Windows 11 部署 Redis、PostgreSQL 基础服务实测Windows 下搞 docker-compose 的场景这两年多了不少很多本地开发环境、测试环境直接跑在 Windows 11 上。热搜词里“win11 部署 docker-compose 基础服务 redis、postgre”正好戳中这个需求。我实测了一条完整链路。3.1 准备WSL2 Docker DesktopWindows 上不需要单独安装 composeDocker Desktop 里已经自带 compose v2。真正需要花心思的是 WSL2 后端。安装顺序别乱wsl --install装完重启确认 WSL 版本wsl --list --verbose确保版本显示是 2。如果显示 1执行wsl --set-version 发行版名 2升级。然后安装 Docker Desktop安装时保持默认的“Use WSL 2 based engine”勾选。开机后在 Settings - Resources - WSL Integration 里打开你要用的发行版开关。这里有个细节容易踩坑Docker Desktop 虽然默认集成 compose但一些历史版本默认关闭了老命令docker-compose的兼容入口。如果你的脚本里写的是横杠命令在 Docker Desktop 里老老实实升级到近一年内版本大概率就解决了。3.2 编写 redis PostgreSQL 的 compose 文件我直接给你一个能在 Windows 11 上跑起来的模板。新建一个目录比如dev-stack在里面创建docker-compose.ymlservices: redis: image: redis:7.2-alpine container_name: dev-redis ports: - 6379:6379 volumes: - redis-data:/data restart: unless-stopped command: redis-server --appendonly yes --requirepass ${REDIS_PASSWORD} networks: - dev-net postgres: image: postgres:15-alpine container_name: dev-postgres ports: - 5432:5432 environment: POSTGRES_USER: ${POSTGRES_USER} POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} POSTGRES_DB: ${POSTGRES_DB} volumes: - pg-data:/var/lib/postgresql/data restart: unless-stopped networks: - dev-net volumes: redis-data: pg-data: networks: dev-net:注意三个细节。第一我没有在文件顶部写version: 3.8。compose v2 已经不再需要这个字段写上反而可能触发个别版本的警告干脆删掉。第二Redis 的密码是通过command里${REDIS_PASSWORD}注入的PostgreSQL 的用户、密码、库名都来自环境变量不能真写死。所以同目录下必须建一个.env文件REDIS_PASSWORDdev-redis-pass-2025 POSTGRES_USERapp POSTGRES_PASSWORDdev-pg-pass-2025 POSTGRES_DBappdb第三卷我用的命名卷而不是./data这种本机路径。原因很现实Windows 下 bind mount 的 I/O 性能有明显损耗而且文件权限经常出幺蛾子Redis 容器往./data写文件时偶尔会报权限拒绝。命名卷由 Docker 自己管理省心太多。3.3 启动、验证、日常维护在dev-stack目录下执行docker compose config这个命令会渲染出最终生效的配置相当于“预检查”非常建议养成先 config 再 up 的习惯。确认没问题后docker compose up -d docker compose ps验证 Redisdocker exec -it dev-redis redis-cli -a dev-redis-pass-2025 ping看到PONG就通了。验证 PostgreSQLdocker exec -it dev-postgres psql -U app -d appdb -c select 1日常维护就三条命令docker compose logs -f看日志docker compose restart重启docker compose down -v连同卷一起清理。最后一个要慎重加了-v会把数据删光。4. 版本升级安全升到 2.23 的两个姿势和回滚方案很多开源项目部署时会检查 compose 版本我就见过官方安装脚本输出一行“需要 docker-compose 2.20当前版本过低”然后退出。这种场景下“升级到指定版本”就是硬需求。4.1 升级前先把基线搞清楚一上来就覆盖是不行的。我处理过的翻车事件里有一半是没分清自己机器上到底有几个 compose。先执行docker compose version docker-compose version which docker-compose如果两个命令输出的版本不同说明机器上同时存在多种安装。这时候别急着升先确定你的脚本到底调用哪个入口。这一步确定不了后边全白搭。4.2 姿势一二进制直接覆盖如果当前是二进制安装升级就是下载新版本覆盖旧文件sudo curl -SL https://github.com/docker/compose/releases/download/v2.23.3/docker-compose-linux-x86_64 \ -o /usr/local/bin/docker-compose sudo chmod x /usr/local/bin/docker-compose docker-compose version这里我想多提一句2.23 这个版本号在 GitHub Release 里实际上有v2.23.0、v2.23.1、v2.23.2、v2.23.3几个 patch 版本。如果项目文档只写了“2.23”我通常建议选最后一个 patch也就是v2.23.3。早期 patch 往往带着一些小毛病晚几周的版本稳定不少。4.3 姿势二apt 升级 docker-compose-plugin如果当初是用包管理器装的升级更简单sudo apt update sudo apt install --only-upgrade docker-compose-plugin注意--only-upgrade这个参数很重要。它告诉 apt 只升级这个包不要顺手把其他包也带上去。生产环境里批量升级依赖包风险不可控。升级完再看一眼版本docker compose version输出应该变成Docker Compose version v2.23.3之类的。4.4 回滚与版本锁定升级后如果发现新版本不兼容你的某个脚本回滚是绕不开的动作。apt 方式指定旧版本装回去就行sudo apt install docker-compose-plugin2.21.0-1~ubuntu.22.04~jammy二进制方式更简单下载一份旧版本覆盖即可。这里我建议生产环境把两个版本号都记下来一个是运行版本一个是安装包版本。以后不管是审计还是排障都有据可查。5. 国内下载源与离线部署从 GitHub 拉不动说起“docker-compose 国内下载源安装”是热搜词里很有信息量的一个。GitHub Releases 在国内网络环境下确实时好时坏这不是玄学就是现实。我自己的处理逻辑分三层先用包管理器再换镜像办法最后才考虑离线传输。5.1 从 Docker 镜像里“抠”出 compose 二进制如果你已经装了 Docker但 GitHub 下载弹窗一直转圈有一个很顺手的方案用 docker/compose 官方镜像。Docker Hub 拉镜像一般能配上加速器比直连 GitHub 稳得多。docker pull docker/compose:2.23.3 docker container create --name compose-tmp docker/compose:2.23.3 sudo docker cp compose-tmp:/usr/local/bin/docker-compose /usr/local/bin/docker-compose sudo docker rm compose-tmp简单解释一下docker/compose是官方维护的发行版镜像里面已经打包好了对应版本的二进制。docker container create只是创建一个容器但不启动它然后用docker cp从容器文件系统里把二进制拷出来。拷完之后容器删掉干干净净。这个思路也适用于离线环境下面详细说。5.2 离线部署的完整链路以国产化系统为例离线部署是很多运维同学头疼的事。尤其是部分国产化环境像麒麟这类系统默认软件源里不一定有 compose网络又隔离常规在线安装全失效。我实操过一套可行的链路这里分成三步。第一步准备一台同架构的联网机器。所谓“同架构”很关键。目标机器是 aarch64你在 x86_64 的机器上下载拷过去一样用不了。用uname -m先确认两边的架构一致。第二步在联网机器上拉镜像并打包docker pull docker/compose:2.23.3 docker save -o compose-2.23.3.tar docker/compose:2.23.3然后把这个 tar 文件通过 U 盘、内网共享或者其他合规方式传到目标机器。第三步在目标机器上导入镜像并提取二进制docker load -i compose-2.23.3.tar docker container create --name compose-extract docker/compose:2.23.3 sudo docker cp compose-extract:/usr/local/bin/docker-compose /usr/local/bin/docker-compose sudo docker rm compose-extract sudo chmod x /usr/local/bin/docker-compose docker-compose version如果目标机器连 Docker 也没有那就要连 Docker 引擎的离线安装包一起解决这就超出 compose 本身的范围了。至少目前这套方案覆盖了“有 Docker、没 compose”的常见情况。5.3 镜像加速器的配置注意点在线环境下进程范围内的加速可以通过/etc/docker/daemon.json配置镜像加速{ registry-mirrors: [ https://docker.m.daocloud.io, https://dockerproxy.com ] }配置后重启 Dockersudo systemctl daemon-reload sudo systemctl restart docker必须提醒的是第三方加速器的可用性变动很快新配置是否生效用docker info查看Registry Mirrors字段。如果某个加速器失效及时替换不要把 daemon.json 写死成单一源。6. 安装和运维中最常见的三个坑我都替你踩过了6.1 装完以后 command not found最经典的问题。症状docker-compose version提示命令找不到但文件明明在/usr/local/bin下。原因基本就是 PATH 不包含/usr/local/bin或者当前 shell 没有重新加载。临时验证export PATH$PATH:/usr/local/bin docker-compose version确认能跑以后把导出语句写进/etc/profile或~/.bashrc以后再开 shell 就不会丢了。6.2 项目自动命名导致的资源冲突compose v2 默认用目录名作为项目名。如果你在/opt/app-redis和/opt/dev-redis两个目录分别部署 Redis但端口都映射到宿主机 6379第二个up的时候就会因为端口冲突而失败。这时候要么改端口要么显式指定项目名docker compose -p dev up -d或者直接在 compose 文件顶层写name: dev这个name字段在 v2 才支持老版本不认识这也是为什么我建议新文件都直接写name。6.3 老版本 yaml 里的 version 字段网上大量旧教程的 compose 文件开头都写着version: 3.8。在 compose v2 里这个字段会被忽略不影响使用。但如果你同时混用了老版本 v1文件又声明了较高的 version旧版直接报语法错误。遇到历史遗留文件最稳妥的处理就是删掉version字段让工具自己判断。我自己的习惯是新项目从一开始就不写 version 字段也不指定旧版兼容参数。这样不管机器上是 v2.20 还是 v2.29行为都能保持一致。最后说一个和版本强相关的经验。我在生产环境的部署脚本里固定了一行检查docker compose version || { echo compose not found; exit 1; }这行代码看起来简单但它让我少接了很多“半夜部署失败”的救火电话。工具版本这种东西平时没人管出了问题全是坑。花十秒钟验证一下值。