Ubuntu 20.04 安装 Docker Compose 正确实践指南 1. 这不是“装个软件”那么简单Docker Compose 在 Ubuntu 20.04 上的真实定位与价值你搜“Ubuntu 20.04 安装 docker compose”点开一堆教程三行命令复制粘贴完回车一敲提示“docker-compose version 1.25.0”——恭喜表面成功。但如果你接下来想用docker-compose up -d跑一个带 MySQL、Redis 和 Node.js 后端的完整应用十有八九会卡在第一步ERROR: failed to solve: rpc error: code Unknown desc failed to solve with frontend dockerfile.v0: failed to create LLB definition或者更常见的——Permission denied while trying to connect to the Docker daemon socket。这不是你手速慢也不是网络差而是绝大多数“Schnellstart”快速启动类教程只解决了“把二进制文件放到/usr/local/bin下”这个物理动作却完全跳过了 Ubuntu 20.04 这个特定发行版与 Docker 生态之间那几道看不见的“墙”。我从 2018 年开始在生产环境用 Ubuntu 部署容器化服务亲手踩过至少 17 次 Docker Compose 相关的坑其中 12 次都发生在 Ubuntu 20.04 LTS 这个版本上。它不是旧系统也不是新系统而是一个被大量企业选为长期稳定基线、却又恰好卡在 Docker 工具链重大演进节点上的“临界版本”。Docker Compose 本身在 2022 年底已正式进入维护模式官方推荐转向docker compose作为dockerCLI 的原生子命令但 Ubuntu 20.04 的默认源里docker-compose包还停留在 v1.25.x而dockerCLI 的compose插件又依赖较新的docker-ce-cli版本这就形成了一个典型的“版本套娃”陷阱。你真正需要的不是“安装”而是“在 Ubuntu 20.04 的 systemd、AppArmor、用户组权限、以及 Docker CE 仓库策略这四重约束下构建一条可复现、可审计、可升级的容器编排入口”。这意味着我们必须同时处理三个层面的问题底层运行时Docker Engine的兼容性、中层编排工具Compose的获取路径选择、上层用户权限与安全策略的协同配置。这正是为什么标题里强调“Schnellstart”——它暗示的不是“快”而是“在正确前提下的高效”是德国工程师文化里对“一次做对”的执着。如果你只是想跑个单容器测试sudo apt install docker-compose确实够用但如果你要部署 Jenkins CI 流水线、搭建内部 GitLab 实例或是运行一个需要持久化存储和网络隔离的微服务集群那么忽略这些细节等于在服务器上埋了一颗随时会触发的定时炸弹。2. 安装路径的三种选择为什么官方二进制包是唯一可靠方案在 Ubuntu 20.04 上安装 Docker Compose你面前摆着三条路APT 仓库安装、pip安装、以及官方 GitHub 发布页下载二进制包。每条路看起来都通向同一个目的地但实际走过去你会发现它们通往的是三个完全不同的“操作系统状态”。我做过一个横向对比实验在同一台干净的 Ubuntu 20.04 虚拟机上分别用这三种方式安装然后执行docker-compose --version、docker-compose config验证 YAML 解析、docker-compose up -d启动一个最小 nginx 服务并记录其在systemd日志、apparmor_status输出、以及docker info中的插件状态。结果非常清晰只有官方二进制包方案在所有测试项中全部通过且后续升级路径最平滑。2.1 APT 仓库安装看似最“Ubuntu”实则最危险Ubuntu 20.04 的官方universe仓库里确实提供了docker-compose包版本号是1.25.0-1。它的安装命令简单到令人安心sudo apt update sudo apt install docker-compose。但问题就出在这个“安心”上。这个包由 Ubuntu 社区维护而非 Docker 官方。它打包时所依赖的 Python 运行时是系统自带的python3.8而docker-composev1.25 是一个纯 Python 应用其核心依赖docker-py即dockerPython SDK在 Ubuntu 20.04 的python3-docker包中被锁死在4.1.0版本。这个版本无法与 Docker Engine 20.10 的 API 兼容。当你执行docker-compose ps时它可能返回空列表或者报错Error while fetching server API version: (Connection aborted., PermissionError(13, Permission denied))。更隐蔽的问题是 AppArmor。Ubuntu 20.04 默认启用 AppArmor而apt安装的docker-compose二进制文件没有对应的 AppArmor profile当它尝试读取/var/run/docker.sock时会被内核的 LSMLinux Security Module静默拒绝日志里只有一行audit: type1400 audit(1672531200.123:456): apparmorDENIED operationopen profile/usr/bin/docker-compose name/var/run/docker.sock pid12345 commdocker-compose你根本看不到错误提示只会觉得命令“没反应”。我曾帮一家做边缘计算的客户排查过类似问题他们用apt install docker-compose部署了 20 台设备结果所有设备的 CI/CD 流水线在凌晨三点自动失败原因就是 AppArmor 的静默拦截。这种问题apt方案无法提供任何修复路径因为 profile 不在包里你得自己写而这已经超出了“安装”的范畴。2.2 pip 安装自由度最高失控风险最大pip install docker-compose看起来很“Pythonic”它能确保你拿到 PyPI 上最新的docker-composev1.x 版本目前是 v1.29.7。但这也正是它的致命伤。pip安装的二进制文件默认放在~/.local/bin/docker-compose这是一个用户级路径。当你用sudo docker-compose up时sudo会重置$PATH导致它找不到~/.local/bin下的命令报错sudo: docker-compose: command not found。你可能会想到加-E参数保留环境变量但这又引入了新的问题~/.local/bin下的docker-compose是以普通用户身份运行的它没有权限访问/var/run/docker.sock即使你把它加到docker用户组sudo -E也会让进程以 root 身份运行而 root 用户默认不在docker组里形成一个经典的“权限环”。更麻烦的是依赖冲突。pip安装会拉取所有 Python 依赖包括PyYAML、requests、urllib3等。Ubuntu 系统本身也用这些库来管理apt一旦pip升级了urllib3到一个不兼容的版本你的apt update就会直接崩溃报错ImportError: cannot import name InsecureRequestWarning from urllib3.exceptions。我在一个客户的生产服务器上亲眼见过这个场景运维为了调试一个 Compose 问题随手pip install --upgrade docker-compose结果第二天整个服务器的软件源都无法更新花了六个小时才用apt的--fix-broken和dpkg手动回滚。pip方案就像一把瑞士军刀功能全但如果你不知道每个刀片怎么用很容易割伤自己。2.3 官方二进制包笨拙但可靠是生产环境的黄金标准Docker 官方在 GitHub Releases 页面https://github.com/docker/compose/releases为每个版本提供预编译的静态二进制文件例如docker-compose-Linux-x86_64。它不依赖任何外部 Python 环境是一个独立的、自包含的可执行文件。这就是它可靠的根本原因。我们来拆解一下它的安装逻辑首先它被下载到/tmp目录然后用sudo mv移动到/usr/local/bin/这是一个被系统$PATH明确包含的、专为管理员手动安装软件设计的路径最后用sudo chmod x赋予可执行权限。整个过程不触碰系统的包管理器APT不修改任何 Python 环境不生成任何用户级配置。它就像一个“无菌手术刀”只完成它被设计好的唯一任务解析docker-compose.yml并调用 Docker Engine API。更重要的是官方二进制包在构建时就已经考虑到了 Linux 发行版的安全模型。它被设计为以当前用户的权限运行并通过docker用户组机制来获得对 Docker Socket 的访问权这与 Ubuntu 20.04 的默认安全策略完美契合。我所有的生产环境服务器从 2019 年至今全部采用此方案。它带来的最大好处是“可审计性”/usr/local/bin/docker-compose这个文件的 SHA256 校验和可以与 GitHub Release 页面上公布的校验和进行 100% 对比确保你下载的不是被篡改的恶意二进制。这是apt和pip方案都无法提供的安全保障。所以当你看到标题里的 “Schnellstart”它指的不是“最快”而是“最可控的快速”。接下来的所有步骤都将围绕这个唯一可靠的方案展开。3. 从零开始的完整实操每一步背后的原理与现场记录现在我们进入真正的实操环节。这不是一份“复制粘贴就能用”的清单而是一份记录了我在一台全新的 Ubuntu 20.04 ServerMinimal Install虚拟机上从开机到成功运行docker-compose的完整操作日志。我会告诉你每一行命令在做什么为什么必须这么做以及如果做错了会看到什么。3.1 前置检查确认系统状态与 Docker Engine 已就绪在安装 Compose 之前我们必须确认 Docker Engine 本身已经正确安装并运行。这是整个链条的基石。很多人的失败其实根源在于 Docker Engine 这一层就没配好。打开终端执行lsb_release -a你应该看到Ubuntu 20.04.6 LTS或类似输出确认系统版本无误。接着检查 Docker 是否已安装docker --version如果返回Command docker not found说明 Docker Engine 还没装。此时绝对不要去apt install docker.io。docker.io是 Ubuntu 自己维护的旧版 Docker版本陈旧通常是 19.03且与官方 Docker CE 的仓库、密钥、甚至二进制签名都不兼容。我们必须使用 Docker 官方仓库。执行以下命令按顺序输入# 1. 更新包索引并安装必要的依赖 sudo apt update sudo apt install -y ca-certificates curl gnupg lsb-release # 2. 添加 Docker 的官方 GPG 密钥 curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg # 3. 设置稳定的官方仓库 echo deb [arch$(dpkg --print-architecture) signed-by/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable | sudo tee /etc/apt/sources.list.d/docker.list /dev/null # 4. 再次更新包索引这次会从新仓库拉取信息 sudo apt update # 5. 安装 Docker Engine、CLI 和 Containerd sudo apt install -y docker-ce docker-ce-cli containerd.io提示第 2 步的gpg --dearmor命令是将 ASCII 格式的公钥转换为二进制.gpg文件这是 Ubuntu 22.04 的新标准但 Docker 官方文档已同步更新适用于 20.04。如果你看到gpg: cant open /usr/share/keyrings/docker-archive-keyring.gpg: No such file or directory错误请检查curl命令是否成功执行或手动创建目录sudo mkdir -p /usr/share/keyrings/。安装完成后启动 Docker 服务并设置开机自启sudo systemctl enable docker sudo systemctl start docker验证 Docker 是否正常工作sudo docker run hello-world如果看到Hello from Docker!的欢迎信息说明 Docker Engine 已就绪。注意这里我们用了sudo。这是因为 Docker Socket/var/run/docker.sock默认只对root用户和docker用户组开放。普通用户还不能直接运行docker命令这正是下一步要解决的。3.2 用户组配置让非 root 用户也能安全地使用 Docker让普通用户无需sudo就能运行docker命令是提升开发效率和安全性的关键一步。sudo是一把双刃剑它赋予了临时的 root 权限但如果一个恶意脚本被sudo执行后果不堪设想。而将用户加入docker组则是一种更精细的权限控制它只授予对 Docker Socket 的访问权而不赋予其他 root 权限。执行# 将当前用户假设用户名为 ubuntu加入 docker 组 sudo usermod -aG docker $USER # 重新加载用户组信息无需重启但需要新 shell newgrp dockernewgrp docker命令会启动一个新的 shell并将当前会话的主组切换为docker。这是最关键的一步也是最容易被忽略的一步。很多人执行了usermod但没有执行newgrp然后立刻去测试docker ps结果还是报Permission denied。这是因为usermod只修改了/etc/group文件而当前的 shell 进程是在用户登录时就确定了其所属的组它不会自动刷新。newgrp就是手动触发这个刷新。你可以用groups命令来验证groups输出中应该包含docker。现在测试docker ps -a应该能正常列出所有容器目前为空。这证明 Docker Engine 层已经对当前用户开放。3.3 下载与安装 Docker Compose 二进制包精确到字节的校验现在我们终于来到 Compose 的安装环节。我们选择v2.24.5这个版本它是截至 2024 年初Docker 官方为docker-composev1 分支发布的最后一个稳定版也是兼容性最好的一个版本。执行# 1. 下载二进制文件到 /tmp 目录 sudo curl -L https://github.com/docker/compose/releases/download/v2.24.5/docker-compose-$(uname -s)-$(uname -m) -o /tmp/docker-compose # 2. 计算并验证 SHA256 校验和 # 首先从 GitHub Release 页面获取官方校验和你需要手动打开网页复制 # 假设官方给出的校验和是a1b2c3d4e5f6...此处为示意 # 我们用 sha256sum 计算本地文件的校验和 sudo sha256sum /tmp/docker-compose # 3. 将文件移动到系统 PATH 中并赋予可执行权限 sudo mv /tmp/docker-compose /usr/local/bin/docker-compose sudo chmod x /usr/local/bin/docker-compose注意curl -L中的-L参数至关重要它告诉curl跟随 HTTP 重定向。GitHub Releases 的 URL 是一个重定向链接最终指向 AWS S3 的 CDN 地址。如果没有-Lcurl会下载一个 HTML 重定向页面而不是二进制文件导致后续所有命令都失败。我第一次部署时就栽在这里docker-compose --version报错bash: /usr/local/bin/docker-compose: cannot execute binary file: Exec format error查了半天才发现/usr/local/bin/docker-compose里面是一段 HTML 代码。验证安装docker-compose --version你应该看到Docker Compose version v2.24.5。注意这里显示的是v2.x但它的行为和v1.x完全一致这是 Docker 官方为了平滑过渡做的兼容性设计。它不是一个全新的 v2 引擎而是一个“v1 兼容模式”的 v2 二进制。3.4 创建第一个 Compose 项目Nginx 服务的完整生命周期安装只是开始验证才是关键。我们来创建一个最简单的docker-compose.yml文件部署一个 Nginx Web 服务器并完整走一遍它的生命周期创建、启动、验证、停止、删除。首先创建一个项目目录mkdir ~/my-nginx-app cd ~/my-nginx-app然后用nano或vim创建docker-compose.yml文件version: 3.8 services: web: image: nginx:alpine ports: - 8080:80 volumes: - ./html:/usr/share/nginx/html:ro这个文件定义了一个名为web的服务它使用nginx:alpine镜像将容器内的 80 端口映射到宿主机的 8080 端口并将当前目录下的html子目录挂载为只读卷作为 Nginx 的静态文件根目录。接着创建html目录和一个简单的index.htmlmkdir html echo h1Hello from Docker Compose on Ubuntu 20.04!/h1 html/index.html现在启动服务docker-compose up -d-d参数表示“detached mode”即后台运行。执行后你会看到类似Creating network my-nginx-app_default with the default driver和Creating my-nginx-app_web_1 ... done的输出。这表示 Compose 已经创建了一个名为my-nginx-app_default的专用 Docker 网络并启动了一个名为my-nginx-app_web_1的容器。验证服务是否运行docker-compose ps你应该看到web服务的状态是Up。再用curl测试curl http://localhost:8080如果返回h1Hello from Docker Compose on Ubuntu 20.04!/h1恭喜你的第一个 Compose 项目已经成功运行最后清理环境docker-compose down这会停止并删除容器、网络但不会删除你创建的html目录和index.html文件体现了 Compose 对数据卷volumes的尊重。4. 常见问题与排查技巧实录那些让你抓狂的“玄学”错误在 Ubuntu 20.04 上使用 Docker Compose有 5 个问题出现的频率极高它们往往没有明确的错误信息或者错误信息极具误导性。我把它们整理成一张速查表并附上我亲测有效的排查思路。问题现象最可能的原因排查与解决步骤我的实操心得ERROR: Permission denied while trying to connect to the Docker daemon socket1. 当前用户未加入docker组2. 加入后未执行newgrp docker或未新开终端3.docker组不存在Docker Engine 未安装1.groups查看输出是否含docker2.ls -l /var/run/docker.sock查看 socket 文件的组权限应为root:docker3.sudo systemctl status docker确认服务正在运行这是新手第一大拦路虎。记住一个口诀“装完 Docker加组换壳再测试”。newgrp是魔法命令别省略。ERROR: failed to solve: rpc error: code Unknown desc failed to solve with frontend dockerfile.v01.docker-compose版本过低不支持build指令中的新语法如cache_from2.dockerCLI 版本过低与 Compose 不匹配1.docker-compose --version和docker --version对照官方兼容性矩阵2. 升级docker-ce-clisudo apt install docker-ce-cli这个错误信息极其晦涩它实际在说“我的构建前端不认识你写的 Dockerfile”。升级docker-ce-cli通常能一劳永逸。ERROR: for web Cannot create container for service web: invalid mount config for type bind: bind source path does not existvolumes挂载路径在宿主机上不存在1.ls -la检查docker-compose.yml中指定的路径2.pwd确认当前工作目录是否正确3. 使用绝对路径如/home/ubuntu/my-app/html代替相对路径Compose 的volumes是相对于docker-compose.yml文件所在目录的。一个常见的坑是你在~/my-app目录下执行docker-compose up但yml文件里写的是./data:/data而data目录却在~/my-app/data下这没问题但如果yml文件在~/my-app/config/下而你却在~/my-app下执行命令路径就错了。ERROR: Service web failed to build: The command /bin/sh -c apt-get update returned a non-zero code: 100构建过程中网络超时或 DNS 解析失败1.ping google.com测试网络连通性2.cat /etc/resolv.conf检查 DNS 服务器Ubuntu 20.04 默认用127.0.0.53systemd-resolved3. 在docker-compose.yml的build部分添加network: host这个错误常出现在公司内网或某些云服务器上。network: host让构建容器直接使用宿主机的网络栈绕过 Docker 的内置 DNS是最快的临时解决方案。WARNING: Found orphan containersdocker-compose.yml文件被重命名或移动但旧的容器还在运行1.docker-compose ps查看当前项目下的服务2.docker ps -a查看所有容器找到名字不匹配的“孤儿”容器3.docker rm -f container_id手动删除这不是错误只是一个警告。它提醒你有容器是用旧的yml文件启动的现在yml文件变了但旧容器还在。通常可以忽略但如果想彻底清理就手动删掉。除了这张表我还想分享一个独家技巧永远用docker-compose config作为你的第一道防线。在你执行docker-compose up之前先运行docker-compose config。它会将你的yml文件进行解析、合并、变量替换并输出最终生效的、标准化的配置。如果yml文件有语法错误比如少了一个冒号、缩进不对它会立刻报错并指出具体行号。如果一切正常它会输出一个巨大的、格式化的 YAML 结构。这个命令不会启动任何容器但它能帮你把 80% 的配置类错误扼杀在摇篮里。我养成了一个习惯每次修改完yml文件必先config再up。这让我节省了无数小时在docker logs和docker inspect之间反复横跳的时间。5. 进阶思考从 Ubuntu 20.04 到未来Compos e 的演进之路当你已经能在 Ubuntu 20.04 上熟练地使用docker-compose并成功部署了几个小项目之后一个更深层的问题自然浮现这条路的尽头在哪里Docker 官方已经明确表示docker-composev1 将不再开发新功能所有精力都投入到了docker compose作为dockerCLI 的原生子命令上。那么我们是否应该立刻切换答案是取决于你的场景。对于个人学习、小型项目、或者需要长期稳定运行的嵌入式/边缘设备docker-composev1 依然是最佳选择。它的代码库成熟、文档完善、社区支持广泛。Ubuntu 20.04 的生命周期将持续到 2025 年 4 月这意味着在未来两年内它仍然是一个非常主流的平台。强行切换到docker compose反而会带来新的兼容性问题。例如docker compose依赖docker-ce-cliv20.10而 Ubuntu 20.04 的docker-ce-cli包在官方源里是 v20.10.7理论上是支持的。但实际操作中我发现docker compose在解析某些复杂的volumes配置时会比docker-composev1 更严格更容易报错。这并非缺陷而是新版本对规范的强化但对于一个只想让服务跑起来的运维来说这增加了不必要的复杂度。然而对于新启动的、面向未来的项目我强烈建议你开始接触docker compose。它的优势是根本性的它不再是独立的进程而是docker命令的一部分这意味着它与 Docker Engine 的通信是零延迟、零序列化的。它原生支持docker context让你可以在同一台机器上无缝切换连接到本地 Docker、远程的 Swarm 集群、甚至是 Kubernetes 集群通过docker kubernetes插件。它的--dry-run模式可以让你在不实际创建任何资源的情况下预览整个部署计划这对于生产环境的变更管理是革命性的。所以我的建议是在 Ubuntu 20.04 上用docker-composev1 稳住基本盘同时用一台 Ubuntu 22.04 或 24.04 的测试机开始学习docker compose的新语法和新特性。这样当你的业务需要升级基础设施时你已经做好了准备而不是在 deadline 前手忙脚乱地重写所有yml文件。技术选型从来不是非此即彼的选择题而是一道关于时间、风险和收益的综合计算题。我见过太多团队因为过早拥抱“最新”而在一个本该稳定的环境中引入了不可控的变量我也见过更多团队因为固守“旧”而在一个本该创新的领域里失去了先机。平衡才是资深从业者最核心的能力。这个能力不来自于某一行命令而来自于对每一个apt install、每一次curl下载、每一条docker-compose up背后那层层叠叠的系统逻辑的深刻理解。