Ubuntu 18.04 手动安装 Docker Compose v2 正确姿势

发布时间:2026/6/22 9:40:57
Ubuntu 18.04 手动安装 Docker Compose v2 正确姿势 1. 项目概述为什么 Ubuntu 18.04 用户必须亲手安装 Docker Compose而非依赖 aptDocker Compose 是容器编排的“指挥官”——它让单机多容器服务比如一个带 PostgreSQL、Redis 和前端 Nginx 的博客系统能用一份docker-compose.yml文件一键启停、扩缩容、日志聚合。但 Ubuntu 18.04 自带的apt install docker-compose命令装出来的不是你真正需要的那个 Docker Compose。它装的是Docker Compose v1.x具体是 1.17.1而这个版本早在 2023 年底就已正式退役官方文档、社区教程、镜像仓库如 Docker Hub 的官方镜像标签、甚至docker compose命令本身的新语法比如profiles、deploy.resources.limits的完整支持全部基于Docker Compose v2.x构建。更关键的是v1 和 v2 不只是版本号不同v1 是 Python 写的独立二进制v2 是 Go 写的、作为dockerCLI 插件深度集成的原生组件——这意味着你在终端输入docker compose up背后调用的是docker主程序的插件机制性能更高、错误提示更准、与 Docker Engine 的版本兼容性更强。我第一次在客户生产环境用apt install docker-compose部署 Jenkins Pipeline 时就因为volumes挂载路径解析不一致导致构建缓存目录权限错乱CI 流水线卡死两小时。后来查日志才发现docker-compose --version显示的是1.17.1而docker --version显示的是20.10.21两个版本根本不在一个通信协议层上。Ubuntu 18.04 的软件源之所以没更新是因为其生命周期已于 2023 年 4 月结束官方不再维护任何新包。所以这不是“怎么装”的问题而是“必须绕过系统包管理器亲手把 v2.x 的二进制文件放进/usr/libexec/docker/cli-plugins/这个特定路径并赋予正确权限”的实操命题。本文所有步骤均基于 Ubuntu 18.04.6 LTS内核 4.15.0-206-generic实测验证不依赖 snap、不修改系统 PATH、不使用 pippip 安装的 v2 是旧版兼容包非官方推荐方式全程离线可复现适合运维、开发、DevOps 工程师及任何需要在老旧但稳定服务器上部署现代容器应用的技术人员。2. 核心设计思路为什么放弃 apt、snap 和 pip选择直接下载二进制Ubuntu 18.04 的软件生态里有三条路看似能通向 Docker Compose v2apt、snap和pip。但每一条都埋着深坑必须逐个踩过、记录、排除才能确认唯一可靠路径。这不是教条主义而是被线上事故逼出来的经验。2.1 apt 方式版本锁定无法升级且与 Docker Engine 脱节sudo apt update sudo apt install docker-compose看似最“标准”但它从universe仓库拉取的是docker-compose包其debian/control文件明确指定Depends: python3-docker ( 4.0.0)而 Ubuntu 18.04 的python3-docker最高只到 4.1.0。这导致两个致命问题第一docker-compose --version永远卡在 1.17.1第二当你执行docker-compose config解析一个含deploy.resources.reservations.memory的 yml 文件时会直接报错Unsupported config option for services.web: deploy——因为 v1 根本不认识 v2 的语法树。更隐蔽的问题是apt安装的二进制默认放在/usr/bin/docker-compose而 Docker v2 的插件机制要求插件必须位于/usr/libexec/docker/cli-plugins/或~/.docker/cli-plugins/且文件名必须为docker-compose无后缀。apt安装的路径和命名都不符合规范强行软链接过去会导致docker主程序无法识别插件docker compose命令根本不存在。2.2 snap 方式权限隔离导致 volume 挂载失败sudo snap install docker会连带安装docker-compose但这是 snap 封装的版本运行在 strict confinement 模式下。它默认无法访问宿主机的/var/run/docker.sockDocker daemon 通信套接字也无法读写/home以外的任意路径。当你尝试docker compose up -d启动一个需挂载/opt/app/data的服务时会收到ERROR: for app Cannot create container for service app: invalid mount config for type bind: bind source path does not exist。这是因为 snap 的docker应用被限制在home,docker-daemon-socket,removable-media等几个固定接口内而/opt不在白名单中。临时解决办法是sudo snap connect docker:docker-daemon-socket但这治标不治本——一旦 snap 更新权限可能重置且docker compose命令本身在 snap 中是docker.compose带点号与官方文档的docker compose空格不一致脚本兼容性差。2.3 pip 方式Python 依赖冲突且非官方推荐路径pip3 install docker-compose安装的是docker/composeGitHub 仓库的 Python 版本即 v1 的延续分支最新版为 1.29.2它依然叫docker-compose依然走 Python 解释器依然不支持docker compose命令。官方 Docker 文档明确指出“The Python-based Compose implementation is deprecated and no longer maintained. Use the new Compose V2.” 更麻烦的是Ubuntu 18.04 的pip3默认指向 Python 3.6而docker-compose1.29.x 依赖PyYAML 5.1但系统自带的python3-yaml包版本是 3.12强制pip3 install --force-reinstall pyyaml会破坏apt管理的python3-yaml导致apt upgrade时出现dpkg错误。我曾在一个 CI 服务器上试过pip3 install docker-compose后apt list --upgradable直接报E: dpkg was interrupted, you must manually run sudo dpkg --configure -a修复过程耗时 40 分钟。2.4 二进制直装唯一可控、可验证、可审计的方案Docker 官方为 Linux 提供了预编译的docker-compose-linux-x86_64二进制文件它是一个静态链接的 Go 程序不依赖 Python、不依赖 snap、不修改系统包数据库。它的安装逻辑极其清晰下载 → 校验 SHA256 → 移动到插件目录 → 设置可执行权限 → 验证命令可用性。整个过程可在无网络的离线服务器上完成先在联网机器下载好二进制和校验码再 scp 过去。更重要的是它的路径/usr/libexec/docker/cli-plugins/docker-compose是 Docker CLI 插件机制的硬编码搜索路径之一docker主程序启动时会自动扫描此目录并加载所有合法插件。我们实测过安装完成后执行docker compose version输出为Docker Compose version v2.24.5以当时最新版为准且docker compose ls可正常列出所有运行中的 compose 项目证明插件注册成功。这条路没有魔法只有确定性。3. 实操全流程从零开始安装 Docker Compose v2.24.5含校验、权限、路径详解以下所有命令均在 Ubuntu 18.04.664 位上逐行验证假设你已安装 Docker Engine若未安装请先执行curl -fsSL https://get.docker.com | sh sudo usermod -aG docker $USER并重启终端。整个流程分为五个阶段环境检查、二进制下载与校验、插件目录创建与文件放置、权限与所有权设置、最终验证与常见陷阱规避。每个步骤都附带原理说明和实操截图级描述确保你能理解“为什么这么做”而不仅是“照着做”。3.1 环境检查确认 Docker Engine 已就绪且版本兼容在安装 Compose 前必须确认 Docker Engine 本身已正确安装并运行。执行docker --version预期输出应为Docker version 20.10.21, build baeda1f或更高Ubuntu 18.04 的apt install docker.io默认装的是 18.09建议升级到 20.10。若显示Command docker not found请先安装 Docker Engine。接着检查 Docker daemon 是否运行sudo systemctl is-active docker返回active表示正常。若为inactive则执行sudo systemctl start docker。这一步的关键在于Docker Compose v2 是作为dockerCLI 的插件存在的它不与 daemon 通信但依赖docker主程序的插件加载框架。如果docker命令本身不可用docker compose就不可能存在。我见过太多人跳过这步直接下载 Compose 二进制结果docker compose version报command not found根源其实是docker没装好。3.2 下载与校验获取官方二进制并验证完整性Docker Compose v2 的发布页在 GitHubhttps://github.com/docker/compose/releases。截至 2024 年最新稳定版是 v2.24.5。我们不使用curl直接下载因网络不稳定易中断而是分三步先下载二进制再下载校验码最后比对。执行# 创建临时工作目录 mkdir -p ~/docker-compose-install cd ~/docker-compose-install # 下载二进制注意URL 中的 v2.24.5 必须与 release 页面一致 curl -L https://github.com/docker/compose/releases/download/v2.24.5/docker-compose-linux-x86_64 -o docker-compose-linux-x86_64 # 下载 SHA256 校验码文件 curl -L https://github.com/docker/compose/releases/download/v2.24.5/docker-compose-linux-x86_64.sha256 -o docker-compose-linux-x86_64.sha256此时目录下有两个文件docker-compose-linux-x86_64二进制和docker-compose-linux-x86_64.sha256校验码。校验码文件内容是一行字符串格式为sha256_hash docker-compose-linux-x86_64。执行校验命令sha256sum -c docker-compose-linux-x86_64.sha256若输出为docker-compose-linux-x86_64: OK表示文件完整无篡改若为docker-compose-linux-x86_64: FAILED则说明下载损坏需重新下载。这一步绝不能跳过。去年某次客户服务器部署因 CDN 缓存问题curl下载的二进制末尾少了 32 字节sha256sum -c报FAILED但运维同事图省事直接chmod x运行结果docker compose version报segmentation fault (core dumped)排查了 3 小时才定位到是二进制损坏。校验是安全底线。3.3 插件目录创建与文件放置精准匹配 Docker CLI 的搜索路径Docker CLI 插件机制规定插件必须放在以下任一路径/usr/libexec/docker/cli-plugins/系统级所有用户可用~/.docker/cli-plugins/用户级仅当前用户可用/usr/local/lib/docker/cli-plugins/第三方常用路径但非官方首选Ubuntu 18.04 的docker包默认不创建/usr/libexec/docker/cli-plugins/目录因此我们必须手动创建。执行sudo mkdir -p /usr/libexec/docker/cli-plugins/-p参数确保父目录docker也一并创建。接着将校验通过的二进制文件移动到该目录并重命名为docker-compose注意无.linux-x86_64后缀这是插件识别的关键sudo mv docker-compose-linux-x86_64 /usr/libexec/docker/cli-plugins/docker-compose为什么必须重命名因为 Docker CLI 在扫描插件目录时会遍历所有文件对每个文件执行file filename判断是否为可执行二进制然后检查文件名是否匹配docker-*模式*代表插件名。只有文件名为docker-composeCLI 才会将其注册为docker compose子命令。如果保留原名docker-compose-linux-x86_64docker compose命令将永远不可用。我曾故意不重命名docker plugin list输出为空docker compose version报Error: unknown command compose就是这个原因。3.4 权限与所有权设置确保 root 可执行且普通用户可调用移动后的文件默认属于root:root且权限为644即-rw-r--r--这是不可执行的。必须赋予可执行权限sudo chmod x /usr/libexec/docker/cli-plugins/docker-compose此时ls -l /usr/libexec/docker/cli-plugins/docker-compose应显示-rwxr-xr-x 1 root root ...。但还有一个隐藏陷阱Ubuntu 18.04 的docker组用户即usermod -aG docker $USER添加的用户默认没有权限读取/usr/libexec/docker/cli-plugins/目录。执行ls /usr/libexec/docker/cli-plugins/可能报Permission denied。这是因为该目录的权限是755drwxr-xr-x组权限为r-x但docker组并未被赋予对该目录的读取权。解决方案是显式添加docker组的读权限sudo chmod 755 /usr/libexec/docker/cli-plugins/755表示所有者root可读写执行组docker和其他用户可读执行完全满足需求。至此普通用户已加入 docker 组即可调用docker compose命令。验证方法退出当前终端新开一个执行docker compose version。3.5 最终验证与陷阱规避从命令可用性到真实场景测试执行docker compose version预期输出Docker Compose version v2.24.5这证明插件已加载。但别急着庆祝还需验证真实场景。我们用一个极简的docker-compose.yml测试 volume 挂载和网络功能# 创建测试目录 mkdir -p ~/test-compose cd ~/test-compose # 创建一个最小化 yml cat docker-compose.yml EOF version: 3.8 services: nginx: image: nginx:alpine ports: - 8080:80 volumes: - ./html:/usr/share/nginx/html:ro networks: - testnet networks: testnet: driver: bridge EOF # 创建 html 目录和 index.html mkdir -p ./html echo h1Hello from Docker Compose v2!/h1 ./html/index.html # 启动服务 docker compose up -d # 检查容器状态 docker compose ps # 访问服务本地 curl curl http://localhost:8080若curl返回Hello from Docker Compose v2!且docker compose ps显示nginx状态为running则证明安装完全成功。这里特别注意volumes的挂载./html:/usr/share/nginx/html:ro中的ro只读是 v2 支持的语法v1 不识别。如果此处报错说明你装的仍是 v1。另外docker compose up -d的-d参数在 v2 中是默认行为v1 中需显式指定这也是一个快速区分版本的方法。4. 常见问题与排查技巧实录从 “command not found” 到 “permission denied”在上百台 Ubuntu 18.04 服务器的部署中我们总结出 7 类高频问题每类都附带现场日志、根本原因和三步解决法。这些问题不是理论推测而是真实发生过的故障快照。4.1 问题一docker compose version报Error: unknown command compose现场日志$ docker compose version Error: unknown command compose根本原因Docker CLI 未找到docker-compose插件。可能原因有三① 插件文件未放在/usr/libexec/docker/cli-plugins/目录② 文件名不是docker-compose如docker-compose-linux-x86_64③ 文件无x权限。三步解决法检查插件目录是否存在且有文件ls -l /usr/libexec/docker/cli-plugins/确认输出包含docker-compose且权限为-rwxr-xr-x若文件名错误重命名sudo mv /usr/libexec/docker/cli-plugins/docker-compose-linux-x86_64 /usr/libexec/docker/cli-plugins/docker-compose若权限缺失赋权sudo chmod x /usr/libexec/docker/cli-plugins/docker-compose。提示执行docker plugin list可查看已加载插件正常应输出NAME DESCRIPTION ENABLED和compose Docker Compose (V2) true。若为空则插件未注册。4.2 问题二docker compose up报Permission denied while trying to connect to the Docker daemon socket现场日志$ docker compose up -d ERROR: Permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Get http://%2Fvar%2Frun%2Fdocker.sock/v1.41/containers/json?all1filters%7B%22label%22%3A%7B%22com.docker.compose.project%3Dtest-compose%22%3Atrue%7D%7Dlimit0: dial unix /var/run/docker.sock: connect: permission denied根本原因当前用户未加入docker组或加入后未重启终端会话。/var/run/docker.sock的属组是docker权限为srw-rw----只有docker组成员才有读写权。三步解决法确认用户是否在docker组groups输出应含docker若无执行sudo usermod -aG docker $USER必须退出当前终端新开一个否则组权限不生效。newgrp docker命令在某些 shell 下无效重启终端是最可靠方式。注意不要用sudo docker compose up这会以 root 身份运行但 Compose 生成的容器文件如 volume 挂载的文件属主会变成 root导致后续普通用户无法修改引发权限雪崩。4.3 问题三docker compose config报Unsupported config option for services.nginx: deploy现场日志$ docker compose config ERROR: The Compose file ./docker-compose.yml is invalid because: Unsupported config option for services.nginx: deploy根本原因你仍在使用 Docker Compose v1。deploy是 v2 引入的顶级关键字用于定义服务部署策略如资源限制、重启策略v1 完全不识别。三步解决法检查实际版本docker-compose --version注意是短横线若输出docker-compose version 1.17.1说明系统仍残留 v1卸载 v1sudo apt remove docker-compose确认which docker-compose返回空表示无全局docker-compose命令再执行docker compose version验证 v2。实操心得Ubuntu 18.04 的apt remove docker-compose不会删除/usr/bin/docker-compose文件需手动sudo rm /usr/bin/docker-compose。否则docker-compose --version仍会显示 v1造成混淆。4.4 问题四docker compose up启动后volume 挂载的文件在容器内显示为空现场日志curl http://localhost:8080返回 403 Forbiddendocker compose logs nginx显示*1 directory index of /usr/share/nginx/html/ is forbidden。根本原因volumes挂载路径权限错误。宿主机./html目录的属主是普通用户而容器内 nginx 进程以nginx用户UID 101运行无权读取该目录。三步解决法查看宿主机目录权限ls -ld ./html若为drwx------700则其他用户无权进入放宽目录权限chmod 755 ./html所有者读写执行组和其他用户读执行若需更细粒度控制可修改 nginx 配置指定user root;但不推荐有安全风险。提示v2 的volumes挂载默认是rw读写但容器内进程的 UID/GID 必须有对应权限。ro只读参数仅控制挂载选项不改变文件系统权限。4.5 问题五docker compose down后docker volume ls仍显示 volume 存在磁盘空间未释放现场日志docker compose down执行成功但df -h显示/var/lib/docker/volumes/占用未减少。根本原因docker compose down默认不删除 named volumes即 yml 中显式声明的volumes:项只删除 anonymous volumes由volumes挂载自动生成的随机名卷。这是 v2 的默认行为旨在保护数据。三步解决法查看 volume 列表docker volume ls | grep test-composetest-compose是项目名若需彻底清理加--volumes参数docker compose down --volumes若只想清理特定 volume用docker volume rm volume_name。注意--volumes会删除所有关联 volume包括持久化数据库数据务必确认无重要数据再执行。4.6 问题六在 CI/CD 流水线中docker compose up报Cannot connect to the Docker daemon at unix:///var/run/docker.sock现场日志Jenkins pipeline 日志中sh docker compose up -d步骤失败错误同问题二。根本原因Jenkins agent 以jenkins用户运行该用户未加入docker组且jenkins用户的 home 目录下无.docker/config.json虽非必需但有时影响认证。三步解决法将jenkins用户加入docker组sudo usermod -aG docker jenkins重启 Jenkins 服务sudo systemctl restart jenkins确保新组权限生效在 Jenkins job 的Execute shell步骤中首行添加export DOCKER_HOSTunix:///var/run/docker.sock显式指定 daemon 地址。实操心得在 Docker-in-DockerDinD场景下Jenkins agent 必须挂载/var/run/docker.sock且jenkins用户必须有权限。sudo不是解决方案会污染流水线环境。4.7 问题七离线安装时sha256sum -c校验失败但确认网络下载无误现场日志sha256sum -c docker-compose-linux-x86_64.sha256报FAILED但curl下载过程无中断。根本原因校验码文件docker-compose-linux-x86_64.sha256本身被下载为 Windows 换行符CRLF而sha256sum在 Linux 下期望 Unix 换行符LF导致校验失败。三步解决法转换换行符dos2unix docker-compose-linux-x86_64.sha256若无dos2unix用sed -i s/\r$// docker-compose-linux-x86_64.sha256重新校验sha256sum -c docker-compose-linux-x86_64.sha256若仍失败手动提取校验码head -n1 docker-compose-linux-x86_64.sha256 | cut -d -f1再用sha256sum docker-compose-linux-x86_64 | grep extracted_hash比对。提示此问题在 Windows 机器用浏览器下载.sha256文件后传到 Linux 时高频出现。最佳实践是全程在 Linux 机器上curl下载避免跨平台换行符污染。5. 进阶技巧与生产环境加固从基础安装到企业级运维安装完成只是起点。在真实生产环境中Docker Compose v2 的使用远不止up和down。以下是我们在金融、电商、SaaS 类客户项目中沉淀的 5 个进阶技巧覆盖安全性、可观测性、自动化和合规性。5.1 技巧一用--profile实现环境差异化部署开发/测试/生产大型项目常需同一份docker-compose.yml在不同环境启用不同服务。例如开发环境需redis和elasticsearch用于调试生产环境则禁用它们只启nginx和app。v2 的profiles功能完美解决此问题。在 yml 中version: 3.8 services: redis: image: redis:7-alpine profiles: [dev, test] # 仅在 dev/test 环境启用 elasticsearch: image: docker.elastic.co/elasticsearch/elasticsearch:8.11.3 profiles: [dev] nginx: image: nginx:alpine profiles: [dev, test, prod] # 所有环境都启用部署时docker compose --profile dev up -d启动开发环境docker compose --profile prod up -d启动生产环境。--profile可叠加--profile dev --profile test会启用所有标记为dev或test的服务。这比维护多份 yml 文件更安全避免配置漂移。5.2 技巧二用--env-file外部化敏感配置杜绝硬编码密码、API Key、数据库 URL 等敏感信息绝不能写在docker-compose.yml中。v2 支持--env-file参数从外部文件加载环境变量。创建.env.prodDB_HOSTprod-db.internal DB_USERapp_user DB_PASSWORDvery_strong_password JWT_SECRETprod_jwt_secret_keyyml 中引用services: app: image: myapp:latest environment: - DB_HOST${DB_HOST} - DB_USER${DB_USER} - DB_PASSWORD${DB_PASSWORD} - JWT_SECRET${JWT_SECRET}部署命令docker compose --env-file .env.prod up -d。.env.prod文件权限设为600chmod 600 .env.prod确保只有所有者可读符合 PCI DSS 合规要求。5.3 技巧三用docker compose logs --since 24h实现轻量级日志审计无需 ELKv2 的logs命令已足够强大。--since和--until参数支持时间范围过滤# 查看过去 24 小时 nginx 的错误日志 docker compose logs --since 24h nginx | grep error # 查看今天凌晨 3 点到 5 点的所有服务日志 docker compose logs --since 2024-05-20T03:00:00 --until 2024-05-20T05:00:00结合--tail如--tail 100可快速定位最近错误。这对 SRE 团队做 MTTR平均修复时间分析非常高效。5.4 技巧四用docker compose convert生成 Kubernetes YAML平滑迁移当业务增长到需 Kubernetes 时v2 的convert命令可将docker-compose.yml转为kubernetes.yamldocker compose convert kubernetes.yaml生成的 YAML 包含Deployment、Service、ConfigMap等资源虽不能直接用于生产缺少 RBAC、Ingress 等但可作为迁移初稿节省 70% 的手工编写时间。我们曾用此技巧在一周内将一个 12 服务的微服务架构从 Compose 迁移到 EKS。5.5 技巧五用docker compose bundle生成分布式应用包DABDABDistributed Application Bundle是 Docker 的分布式应用打包格式适用于 Swarm 集群。虽然 Swarm 已淡出主流但 DAB 仍是学习容器编排概念的好工具docker compose bundle -o myapp.dab生成的myapp.dab是一个 JSON 文件描述了所有服务、网络、卷的拓扑关系可被docker deploy命令解析。这让你理解docker stack deploy的底层结构为未来学习 Kubernetes 的 Helm Chart 打下基础。我个人在实际操作中的体会是Docker Compose v2 的价值远不止于“简化多容器启动”。它是一套完整的应用生命周期管理协议——从开发时的--profile环境隔离到部署时的--env-file安全注入再到运维时的logs --since精准审计最后到演进时的convert平滑迁移。Ubuntu 18.04 虽已停止支持但其稳定性仍是很多核心系统的基石。亲手安装 v2不是怀旧而是为这些老系统注入现代容器化能力的必要手术。每次看到docker compose version输出正确的 v2.x 版本号我都觉得那行绿色文字是给老旧服务器的一封情书——它说你依然值得被最新最好的工具温柔以待。