☰
RockyLinux 10安装Docker Compose完整指南与排障实战
2026/10/14 4:33:18 网站建设 项目流程

最近在折腾容器化部署,发现 RockLinux 10 这个新版本跟以前的 CentOS 7、Rocky 8/9 有挺多不一样的地方。如果你正打算在这套系统上装 docker-compose,直接 yum 一个老教程去操作大概率会踩坑,因为 dnf 的行为变了,默认仓库的包名变了,甚至连 Python 环境都不一样。这篇文章我从头到尾记录了自己在 RockyLinux 10 上安装 docker-compose 的完整过程,里面包括环境检查、Docker Engine 的部署思路、两种安装 compose 的方式对比,还有我实际遇到过的各种报错和排障记录,希望对同样在准备新环境的人有点参考价值。

1. 动手之前先搞清楚环境差异

1.1 RockyLinux 10 和旧版本到底差在哪

RockyLinux 10 是从 RHEL 10 源码派生的发行版,包管理工具已经从 yum 全面切换到了 dnf5。默认情况下,直接执行yum install虽然还能通过兼容别名工作,但解析依赖的策略变了,输出的报错方式也变了,很多时候不再有以前那种“干脆直接告诉你缺哪个包”的提示。

另一个关键变化是默认软件源的构成。RHEL 系从 9 开始就大力推 Podman,系统源里虽然有 docker 相关的包,但那可能不是官方 Docker 维护的版本,而是发行版自行打的补丁包。我在新装的系统里试过一次直接dnf install docker-ce,结果提示找不到包,这才是正常现象,因为 Docker 官方仓库需要手动添加。如果你不知道这一点,很可能在这个阶段就卡住。

还有一个容易忽略的点是 SELinux 状态。RockyLinux 10 默认 SELinux 是 Enforcing 模式,Docker 启动容器时如果动作比较重,比如挂载了宿主机目录、改了端口映射、跑了特权容器,很可能被 SELinux 拦截。不是说装不了,而是装完你会发现有各种 permission denied,这些我会在后面问题排查里专门展开讲。

1.2 什么是 Docker Compose,为什么不能省

很多刚接触容器的人会误以为 docker run 就够用了,其实当服务从一个容器变成多个容器的时候,手工敲 docker run 就是灾难。Docker Compose 的作用简单说就是把多个容器的启动方式写在同一个 YAML 文件里,然后用一条命令把整个环境拉起来。我习惯这么打比方:Docker 是厨师,Compose 是厨师手边的排菜单,你先列好每道菜要什么配料、用什么锅、谁先下锅,后厨按单执行,出不了乱子。

Compose 还有一个非常实用的场景是把环境的可重复性带给了团队。同一个文件夹里只要包含 docker-compose.yml,新人拉下来直接docker-compose up -d就能得到一套跟生产环境一致的本地环境。这比在文档里写十条 docker run 命令靠谱太多,也大大降低了沟通成本。

1.3 安装前先想清楚的三个问题

第一个问题是版本选型。目前的 Docker Compose 有两条线:老版的 v1,命令是docker-compose,通过独立二进制或 Python 包安装;新版的 v2,命令是docker compose,以 Docker CLI 插件形式存在。如果是全新项目,我强烈建议直接用 v2;如果手上还有维护老项目、老脚本里写的都是docker-compose,那你可能需要把两个都装好。

第二个问题是要做成全局命令还是项目内使用。生产服务器上跑服务,一般需要全局可用,也就是把二进制放在/usr/local/bin并做软链。如果你只是自己的开发机用,那么 v2 插件模式就足够。

第三个问题是安装途径。dnf 装插件、官方二进制、PyPI 包,这三条路各有优劣。有人习惯 pip 一把梭,但在 RockyLinux 10 上 Python 环境相对保守,pip 安装的 compose 很容易因为依赖冲突或者 Python 版本问题被系统更新顺带破坏,这点我在后面详细对比。

2. 环境准备与 Docker Engine 部署

2.1 系统信息检查

在动手装 compose 之前,先把系统底子看清楚。我第一次没仔细检查就直接配置软件源,结果后发现版本标签对不上,白白折腾了十分钟。检查命令如下:

cat /etc/os-release uname -r df -h

重点看三样东西:系统大版本、内核版本、磁盘空间。RockyLinux 10 的 VERSION 字段显示是 10.x,内核版本一般是 6.x。Docker Engine 对内核版本要求不算高,但内核太老在某些文件系统挂载场景会有问题,6.x 内核完全够用。

磁盘空间这件事很多人会忽略。Docker 本身就是“磁盘怪兽”,镜像动辄几百 MB,一套 compose 服务跑起来日志更是吃空间。我的经验是系统盘剩余空间低于 20GB,后面编排服务就会很被动。

还需要检查一下是否已经装了旧版 docker 或 podman,避免冲突:

systemctl status docker --no-pager rpm -qa | grep -E 'docker|podman'

如果发现系统里已经预装了 podman 和有关的容器工具链,不用急着卸载,它们和 Docker 官方包冲突概率不是绝对的,但建议先把冲突的包清理干净再继续。

2.2 配置 Docker 官方仓库并安装引擎

RockyLinux 10 默认仓库不直接提供 docker-ce 包,所以第一件事是把 Docker 官方仓库加进来。因为 Rocky 保持 RHEL 系兼容,可以直接用 CentOS 路径。下面是我实际执行过的完整命令:

sudo dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo sudo dnf makecache sudo dnf install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

这里有个点值得说明:我一次性把 docker-buildx-plugin 和 docker-compose-plugin 也装上了。buildx 是 Docker Build Kit 的插件,用来自定义构建策略,在后面对镜像做复杂构建时很有用;docker-compose-plugin 则提供新版docker compose子命令。如果你只想要老式的独立docker-compose,不装这个插件也可以,但既然官方已经提供了插件,建议顺手装上,多一种调用方式总没有坏处。

安装完成后启动服务并验证:

sudo systemctl enable --now docker sudo systemctl status docker --no-pager sudo docker version

如果你希望不用sudo就能执行 docker 命令,可以把当前用户加进 docker 组:

sudo usermod -aG docker $USER newgrp docker

注意加组之后建议重新登录终端,别指望当前会话立即生效。我遇到过不止一个朋友配置完直接运行 docker 命令,结果报 permission denied,就是因为没有重新登录。

2.3 验证 Docker 基础功能

镜像拉取验证是判断 Docker 引擎是否正常的最直接方式:

docker run hello-world

如果正常,会看到 Hello from Docker! 提示。如果网络状况不佳,拉取可能卡住,这时候可以配置镜像加速或者稍后重试。这里我建议不要跳过验证步骤,哪怕慢一点也值得。因为 compose 本质上是在 Docker 引擎之上做编排,引擎如果没跑通,compose 装好了也是白搭。

另外,如果你的机器位于严格的网络代理环境里,需要在/etc/systemd/system/docker.service.d/http-proxy.conf这个目录下写代理配置,否则 Docker 守护进程不会读系统全局代理环境变量,这就是很多人配置了 HTTP_PROXY 但镜像拉取仍然超时的原因。

3. 三种安装路径的取舍

3.1 通过 dnf 安装官方插件

这是最省事的一种方式。前面安装 docker-compose-plugin 之后,直接就能用docker compose version查看版本。这条路径的优点是跟 Docker 引擎一起升级,引擎更新时插件也会同步更新,不容易出现版本断档的问题。

缺点也很明显:它提供的可执行文件是 v2 版本,命令是docker compose。如果你在脚本里写的是老式的docker-compose,这个插件帮不了你。如果你维护的项目里全是 pwd 写死的 v1 风格命令,只能再装独立二进制。

3.2 官方 GitHub 发布二进制

独立二进制的docker-compose其实就是早期官方做法。把编译好的可执行文件下载到系统里,配上执行权限就能跑。这条路径的好处是不依赖 Python 环境,也不会被系统的 dnf 包管理覆盖,对生产环境的可控性强。

坏处是升级要你自己去盯着,不会像 dnf 那样自动更新。我个人的做法是在服务器上用二进制装一份 v1,同时保留 dnf 的 v2 插件,两边互不干扰,旧命令有兼容入口,新命令又能享受 v2 的特性。

3.3 pip 安装的坑

pyPI 上到现在还有 docker-compose 的老版本,早期很多人会执行pip install docker-compose。在 RockyLinux 10 上这件事风险更高,因为系统默认 Python 版本较新,老版 docker-compose 依赖的某些旧库可能要被迫编译安装,很容易因为编译器版本或者缺少相关系统依赖而失败。

就算你侥幸装成功了,后续系统包管理器在更新 Python 相关组件时,也有可能把这个由 pip 安装的软件弄坏。这不是“一定会坏”,而是维护成本太高。所以我的结论非常明确:除非你在环境完全受控的 Python 虚拟环境里用,否则生产环境不要走 pip 这条路。

这三条路的对比,我在实践里总结过一个判断逻辑:叫“能走官方渠道走官方渠道,要兼容老命令就补二进制,实在被逼无奈才动 pip”。表格里列一下核心差异:

安装路径提供命令升级方式适用场景
dnf 插件docker compose系统更新自动升级新项目、个人开发、生产首选
官方二进制docker-compose手动下载替换维护老脚本、特殊版本要求
pipdocker-compose(老版本)手动管理,风险高仅适合隔离的纯 Python 环境

4. 二进制安装 docker-compose 的完整实操

4.1 确定版本与下载链接

如果你确实需要独立二进制版,就要去官方发布渠道查一下当时最新的版本号。这里我以 v2.27.0 为例,实际操作时建议查看当时的最新版本。下载命令如下:

sudo curl -SL "https://github.com/docker/compose/releases/download/v2.27.0/docker-compose-linux-x86_64" -o /usr/local/bin/docker-compose

先把文件下载到/usr/local/bin目录,命名成docker-compose。为什么要放在/usr/local/bin而不是/usr/bin?因为/usr/bin是发行版包管理器的主目录,系统升级或重装某个包时,如果该包声明了同名文件,可能会覆盖掉你手动放进去的文件。/usr/local/bin在设计上就是给系统管理员放自定义程序的地方,优先级通常也不低。

确定架构时要看清是 x86_64 还是 arm64。市面上大部分服务器是 x86_64,但如果你是在树莓派或者 ARM 服务器上跑,就得把链接里的linux-x86_64换成linux-aarch64,否则会直接遇到 exec format error。

4.2 赋予执行权限并建立全局软链

下载完成后需要手动添加执行权限:

sudo chmod +x /usr/local/bin/docker-compose

紧接着我建议做一步软链,命令是:

sudo ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose

可能有人觉得多此一举。但我实际遇到的情况是,部分 CI 环境或者由某用户启动的脚本,PATH 查找顺序会比较偏,如果你的用户 PATH 里没有/usr/local/bin,直接执行就会提示 command not found。软链到/usr/bin后,绝大多数环境的默认 PATH 都能直接找到它。

还有一种更稳妥的做法是直接修改/etc/profile.d/下的 PATH 变量,但我倾向于不做,因为这会影响系统里所有用户的全局环境,改动面太大。软链的方式最简单、最局部、也最容易回滚。

4.3 验证安装与卸载建议

验证命令:

docker-compose --version

如果看到类似Docker Compose version v2.27.0的输出,安装就成功了。

这时我建议顺手跑一下:

docker-compose version docker-compose --help

docker-compose version会显示更详细的版本信息,包括所属分支,--help能让你快速确认子命令是否齐全。如果 help 输出里寥寥几行,说明这个二进制可能被精简过,建议换一个完整版。

如果以后想卸载,直接删除二进制和软链即可:

sudo rm /usr/local/bin/docker-compose /usr/bin/docker-compose

因为是通过二进制方式安装的,没有注册到 RPM 数据库,卸载就是删文件这么简单,这也是很多人偏爱这种安装方式的原因之一。

5. 从安装到实战:启动一个最小编排项目

5.1 编写一份能跑的 compose 文件

安装只是第一步,真正让 compose 变得有价值的是写出一份清晰的 docker-compose.yml。我在这里提供一个最小可运行示例,包含 nginx 和 redis 两个服务:

version: "3.8" services: web: image: nginx:1.25-alpine container_name: demo-web ports: - "8080:80" volumes: - ./html:/usr/share/nginx/html:ro restart: unless-stopped networks: - demo-network cache: image: redis:7-alpine container_name: demo-cache command: redis-server --appendonly yes volumes: - cache-data:/data restart: unless-stopped networks: - demo-network volumes: cache-data: networks: demo-network: driver: bridge

这里./html:/usr/share/nginx/html:ro表示把当前目录下的 html 目录挂载到容器里,并以只读方式挂载,这样修改宿主机文件就能即时反映到容器内,适合本地调试。redis-server --appendonly yes则是开启 Redis 持久化,避免容器重启数据全丢。

我在文件开头仍然写了version: "3.8",虽然新版本 compose 已经不怎么强调这个字段,但对于很多老版本和现有工具链,写上没坏处。如果以后交给新版 docker compose 跑,这个字段会被忽略,不会有兼容性问题。

5.2 用 compose 启动与日常管理

在 docker-compose.yml 所在目录执行:

docker-compose up -d

看到容器状态为 Up 之后,再查看运行情况:

docker-compose ps docker-compose logs -f

logs -f是实时日志的入口。我在排查问题时第一反应就是打开这个输出,它能看到服务内部实际的报错信息,比看容器状态有价值得多。

停止一套环境并清除容器:

docker-compose down

如果需要连数据卷一起删掉,再加-v,但生产环境慎用,因为数据卷里的数据会一并消失。这个细节值得刻在脑子里:down不删卷,down -v删卷,而很多人根本没意识到后面那个指令会带走数据库文件。

5.3 更新服务时的正确姿势

比较常见的一个场景是:你改了 compose 文件或者镜像版本,想更新一个服务,怎么操作?正确做法是用:

docker-compose up -d --no-deps web

--no-deps表示不重新创建依赖服务,只更新 web。这样比直接up -d更精准,也不会造成数据库和其他无状态服务的意外重启。

如果是代码文件改动需要重新构建镜像,那就在项目目录执行:

docker-compose up -d --build

它会重新构建有构建上下文的镜像,然后再创建容器。我用这个命令的频率特别高,尤其是调试阶段。

6. 常见问题与排查技巧实录

6.1 permission denied while trying to connect to the Docker daemon

这个报错本质是当前用户不在 docker 组里,或者 docker 守护进程没启动。先执行systemctl status docker确认守护进程状态。如果守护进程正常,就把用户加进 docker 组,重新登录后就好了。

但要提醒一句:给用户加入 docker 组相当于授予了 root 权限,因为 Docker 可以挂载宿主机目录到容器内,获得 docker 组权限就能穿透访问宿主机文件。生产环境要谨慎分配。

6.2 拉取镜像超时

报错通常是Get https://registry-1.docker.io/v2/: net/http: request canceled。这个问题十有八九是网络原因。先检查 DNS,再考虑配置镜像加速。如果机器在代理环境里,需要单独给 Docker 守护进程配置代理,我前面提过/etc/systemd/system/docker.service.d/http-proxy.conf,这里再强调一次,因为代理出错在 compose 场景里特别常见。

6.3 出现提示 version is obsolete 或找不到命令

如果你写了老式 compose 文件,某些字段在新版本里已经被废弃,就会看到提示。大多数情况下可以无视,但如果工作和升级确实需要,可以用docker-compose config --quiet做文件校验,它会快速判断 compose 文件是否能被当前版本解析。

6.4 与 Podman 的环境冲突

RockyLinux 10 预装的 Podman 会在系统里注册 container 相关工具链,如果同时装上了 Docker 官方包,执行某些容器命令时,系统可能优先找到的仍是 Podman。我遇到的实际场景是docker-compose up时提示找不到 Docker 上下文,最后排查发现是命令被 alias 到了 podman。解决方法是检查别名配置:

alias | grep docker

如果有意外别名,去掉或者显式使用/usr/bin/docker-compose全路径即可。这类问题最隐蔽,因为报错很怪,但实际上只是命令优先级的问题。

6.5 容器启动后立刻退出

这个问题在 compose 项目里最常见。普遍规律是看一下 exit code:如果退出码是非 0,用docker-compose logs 服务名看错误日志;如果退出码是 0,往往是容器里的主进程执行完就直接退出了,例如命令行里使用了nginx而不是nginx -g "daemon off;"。很多官方镜像已经处理好了这个细节,但自定义镜像时很容易忽略,值得留意。

6.6 SELinux 挂载权限问题

RockyLinux 10 默认 SELinux Enforcing,如果 compose 里挂载了宿主机目录,容器内经常会报Permission denied或operation not permitted。最稳妥的临时做法是:

sudo chcon -Rt svirt_sandbox_file_t 宿主机目录

生产环境建议为对应目录配置合适的 SELinux 标签,而不是直接关闭 SELinux。关闭 SELinux 会让整体安全性下降,而且会影响系统后续升级时对策略的处理。

6.7 快速排查问题速查表

现象可能原因解决思路
permission denied while trying to connect用户未加入 docker 组 / 服务未启动检查服务状态,将用户加入 docker 组并重新登录
镜像拉取超时DNS 或网络问题测 DNS,配置镜像加速,配置 daemon 代理
提示找不到 docker-compose路径未在 PATH 中建立软链或使用全路径执行
容器频繁重启镜像内服务启动失败用 logs 查看服务日志,检查启动命令
SELinux 权限报错挂载目录上下文错误chcon 设置正确标签或调整策略

这些坑几乎人人都能遇到,尤其是长时间停留在老版本环境里的人,刚切到 RockyLinux 10 会感觉各种不舒服,但排查一遍之后就会发现底层逻辑并没有变,还是配置文件、权限、网络这三板斧。

7. 顺手记住的几个小经验

装完之后,最想说的是三件事:第一,Docker Compose 的安装不是一次性的事,它跟 Docker 引擎、系统镜像更新是绑定的,隔几个月就要回来看一眼版本号;第二,我建议每个项目目录里都放一个 README 说明,把 compose 启动命令和常用操作写清楚,这样半年后你自己回来看也知道当初怎么跑,效果比任何文档都好;第三,生产环境尽量用固定版本号,不要每次都是 latest,否则某天引擎自动升级后,旧的 compose 文件可能因为字段废弃直接无法启动。个人在实际操作里的习惯是既保留 dnf 的 docker compose 插件,也在 /usr/local/bin 放一份独立二进制,两把钥匙都有,遇到什么环境都能开锁。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询