先说一个背景:CentOS 7 进入维护尾声之后,很多团队的服务器基础系统都面临“换不换、换成什么”的问题。RHEL 本身要订阅,Oracle Linux 的生态又相对小众,Rocky Linux 出现在大家视野里的频率越来越高。原因不复杂——它是 RHEL 的二进制兼容发行版,定位就是 CentOS 的替代品,能用几乎一模一样的命令、包管理和运维习惯把服务跑起来。
我自己的习惯是:只要涉及企业级部署,先在 Docker 里把 Rocky Linux 的基础镜像跑通,再往上叠加中间件和应用。这样既能在开发环境里快速复现生产配置,又能把一套标准化环境沉淀成镜像,后续分发到任何一台装有 Docker 的机器上,很少出现“在我这明明是好的”这种尴尬。这篇内容就围绕怎么用 Docker 部署 Rocky Linux、搭建一套可复用的 RHEL 兼容基础镜像平台来写,适合正在做系统迁移评估的运维、需要在容器里复现 RHEL 环境的开发,以及刚接触 Rocky Linux 但对 Docker 不陌生的朋友。
1. 为什么是 Rocky Linux:从 CentOS 停更到 RHEL 兼容镜像
1.1 CentOS 停更后的生态缺口
CentOS 8 在 2021 年底停止维护,CentOS 7 也在 2024 年 6 月走到了生命周期终点。对大量中小团队来说,这意味着一件事:以前“免费且稳定”的 RHEL 下游发行版不再有长期免费版本。CentOS Stream 是滚动发行版,定位是 RHEL 的“上游预览”,生产环境用起来心理压力比较大。这时候 Rocky Linux 和 AlmaLinux 成为最常被提到的两个选项。
Rocky Linux 由 CentOS 创始人 Gregory Kurtzer 发起,目标很明确:保持与 RHEL 的高度兼容,按照 RHEL 的版本节奏发布,提供 10 年支持周期。它的构建方式是对 RHEL 源码重新编译,所以 RPM 包、内核参数、文件系统布局、SELinux 策略等层面都尽量向 RHEL 看齐。这意味着,过去写给 CentOS 的脚本、Ansible 角色、Dockerfile 基础镜像引用,大部分可以直接把centos:7换成rockylinux:9来用,改动成本很低。
1.2 二进制兼容到底意味着什么
“兼容 RHEL”不是嘴上说说。对企业用户来说,最直接的价值是:商业软件和第三方驱动通常会声明“支持 RHEL”,而 Rocky Linux 因为与 RHEL 的 ABI(应用二进制接口)兼容,往往能直接运行这些二进制包。比如 Oracle 数据库、部分安全厂商的 Agent、商业备份软件,官方只提供 RHEL 版 RPM,在 Rocky Linux 上安装通常没有问题。
我用 Docker 跑 Rocky Linux 还有一个额外好处:镜像本身就是一次兼容性验证。把某个商业软件的 RPM 包丢进容器里安装,依赖能否解析、glibc 版本够不够、缺哪些系统库,全部可以在镜像构建阶段暴露出来。这比在生产机器上反复试错要安全得多。容器镜像的不可变性让我们能沉淀一套“经过验证的 RHEL 兼容环境”,后续无论底层物理机是什么发行版,只要 Docker 能跑,往上叠加应用就有底气。
2. 环境准备:先让 Docker 在不同的宿主机上跑起来
在正式开始拉取 Rocky Linux 镜像之前,得先把 Docker 运行时搞定。这里涉及两类常见场景:Linux 服务器直接安装 Docker Engine,以及个人电脑上用 Docker Desktop 做验证。两类场景我踩过的坑不太一样,分开说。
2.1 Linux 服务器安装 Docker:Ubuntu 与 Rocky Linux 两种方式
Ubuntu 上我习惯用官方源安装,不建议直接用apt install docker.io,因为 Ubuntu 仓库里的 Docker 版本往往偏旧。官方推荐的方式是添加 Docker 的 apt 源再安装:
# 安装依赖 sudo apt-get update sudo apt-get install -y ca-certificates curl gnupg # 添加 Docker 官方 GPG 密钥 sudo install -m 0755 -d /etc/apt/keyrings curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg sudo chmod a+r /etc/apt/keyrings/docker.gpg # 添加仓库 echo \ "deb [arch="$(dpkg --print-architecture)" signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \ "$(. /etc/os-release && echo "$VERSION_CODENAME")" stable" | \ sudo tee /etc/apt/sources.list.d/docker.list > /dev/null # 安装 sudo apt-get update sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin如果宿主机本身就是 Rocky Linux,安装 Docker 的路径换成dnf:
# 添加 Docker 官方仓库 sudo dnf config-manager --add-repo=https://download.docker.com/linux/centos/docker-ce.repo # 安装 sudo dnf install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin # 启动并设为开机自启 sudo systemctl enable --now docker之所以用 Docker 官方仓库而不是 Rocky 自带的仓库,是因为 Rocky Linux 的默认源里可能没有打包 Docker,或者版本较老。我们既然要搭基础镜像平台,Docker 版本越新越好,至少能确保 BuildKit 和 Compose 插件正常工作。
2.2 Windows 安装 Docker Desktop 与常见启动报错
Windows 上跑 Docker 基本绕不开 Docker Desktop,它依赖 WSL2 后端。常见的报错是启动时提示Virtualization support not detected或类似信息。遇到这个问题,先按次序排查:
- 确认 BIOS 里开启了虚拟化(Intel VT-x 或 AMD-V)。任务管理器 -> 性能 -> CPU,里面能看到虚拟化是否已启用。
- 确认 Windows 功能里勾选了“适用于 Linux 的 Windows 子系统”和“虚拟机平台”,勾选后必须重启。
- 确认 WSL2 是当前默认版本,可以在 PowerShell 里执行
wsl --set-default-version 2。 - 某些安全软件会拦截虚拟化特性,试过前几步还不行,可以暂时退出安全软件再启动 Docker Desktop。
Docker Desktop 跑起来之后,建议在 Settings -> Resources -> WSL Integration 里,把需要和 Docker 联动的 WSL 发行版勾上。比如我们在 WSL 的 Ubuntu 里做开发,如果不勾选,WSL 内部是访问不到 Docker 命令的。
Windows 下还有一个容易被忽略的问题:Docker Desktop 默认给了 WSL2 动态内存,但有时候系统内存压力大,容器会明显变慢。如果同时跑 MySQL、Redis 和 GitLab 这几个容器,建议在 Resources 里把内存上限调到 6GB 或更高,避免容器被操作系统频繁回收内存。
3. 拉取并运行 Rocky Linux 基础镜像:从官方库到静态 IP 配置
3.1 选择合适的镜像版本:Rocky Linux 8 还是 9,镜像从哪里拉
Docker Hub 上有 Rocky Linux 官方镜像,仓库名是rockylinux。我们先把镜像拉下来看看:
docker pull rockylinux:9.5 docker pull rockylinux:8.10为什么两个版本都要?Rocky Linux 8 对应 RHEL 8 的生态,很多旧版商业软件和既有运维脚本依赖这个体系;Rocky Linux 9 则对应 RHEL 9,内核和系统库都更新,适合新项目。我们可以在同一台宿主机上同时保留两个标签的基础镜像,哪个应用需要哪个体系就基于哪个镜像构建,不用互相迁就。
顺便回应热搜词里“linux rocky 8.10镜像位置”这个问题:除了 Docker Hub,Rocky Linux 还提供官网的 ISO 和容器镜像仓库。容器场景直接docker pull rockylinux:8.10就行,不需要去官网找 ISO。如果你所在网络环境下访问 Docker Hub 不稳定,可以用阿里云、腾讯云等镜像加速器,或者在私有仓库里提前存一份。
启动一个基础容器验证一下:
docker run -it --name rocky9-dev rockylinux:9.5 /bin/bash进去之后执行cat /etc/rocky-release和dnf repolist,能看到发行版信息和默认的 AppStream、BaseOS 仓库。这个干净的 Bash 环境就是我们后续一切定制的基础。
3.2 容器内设置静态 IP:自定义网络与固定地址
很多人在容器里折腾 Rocky Linux 时会遇到一个问题:默认桥接网络下,容器每次重启 IP 都会变。虽然 Docker 的 DNS 机制可以让我们通过容器名互访,但有些老应用配置文件里写死了 IP,或者需要在宿主机上用特定 IP 访问容器,这时候就需要给容器设置静态 IP。
实现方式不是进容器改网卡,而是通过 Docker 自定义网络来控制。先创建一个子网:
docker network create --subnet=172.20.0.0/24 rocky-net然后启动容器时指定 IP:
docker run -it --name rocky9-static \ --network rocky-net \ --ip 172.20.0.10 \ rockylinux:9.5 /bin/bash这个方式在企业场景下非常实用。比如我们用 MySQL 容器固定 IP172.20.0.10,应用容器固定 IP172.20.0.11,再配合 docker-compose 文件把服务编排起来,网络拓扑就是确定的。即使容器重建,只要网络和 IP 不变,应用间的访问关系就不会失效。
如果坚持要在容器内部用nmcli设置 IP,也不是不行,但容器重建后设置会丢失,而且需要在启动容器时加--privileged或--cap-add=NET_ADMIN,安全性和可维护性都不好。我更推荐通过 Docker 网络层做固定 IP,这是更符合容器使用习惯的方案。
3.3 容器内安装软件:以 LibreOffice 为例
Rocky Linux 容器的一大用途是做构建环境或应用运行环境。比如热词里提到的“rocky linux安装libreoffice_7.4.7.2_linux_x86-64_rpm”,这种场景经常出现在企业文档转换服务里:容器内装 LibreOffice,接收 Office 文档请求,转换为 PDF。
安装前先更新软件源:
dnf update -y dnf install -y dnf-plugins-coreLibreOffice 在 Rocky Linux 9 的 AppStream 仓库里有现成包,直接装:
dnf install -y libreoffice完整版体积比较大,如果只需要转换文档,可以装精简版:
dnf install -y libreoffice-writer libreoffice-calc libreoffice-impress这里有两个容易踩的坑:第一,容器里跑 LibreOffice 往往需要中文字体支持,否则生成的 PDF 中文会变成方块。安装方式:
dnf install -y wqy-zenhei-fonts wqy-microhei-fonts第二,无图形环境下启动 LibreOffice 偶尔会缺字体缓存或 X 相关库,建议同时装一下dejavu-sans-fonts和fontconfig。我把自己常用的软件安装写进 Dockerfile 后,基本不会再出现中文乱码或启动失败的问题。
4. 把基础镜像做成平台:Dockerfile 定制、镜像提交与私有仓库
4.1 用 Dockerfile 定制基础镜像:规范目录与分层缓存
直接在运行中的容器里改环境,改完用docker commit生成镜像,这种方式能快速得到结果,但可追溯性很差。我更推荐把定制过程写成 Dockerfile,便于版本管理和自动化构建。
一个企业级 Rocky Linux 基础镜像的 Dockerfile 大概是这样的:
# 基础镜像锁定到小版本,避免意外漂移 FROM rockylinux:9.5 # 设置环境变量 ENV LANG=en_US.UTF-8 \ LC_ALL=en_US.UTF-8 \ TZ=Asia/Shanghai # 更新软件源并安装常用工具 RUN dnf update -y && \ dnf install -y \ vim \ curl \ wget \ tar \ unzip \ git \ procps-ng \ which \ sudo \ tzdata \ fontconfig \ && dnf clean all # 设置时区 RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime # 创建常用工作目录 WORKDIR /opt/app这里要重点解释两个细节。第一个是dnf clean all必须写,否则镜像里会残留大量缓存文件,直接导致镜像体积膨胀。企业级镜像平台讲究“干净”,基础镜像越小,后续分发和启动速度越快。第二个是时区和语言编码要显式写好,容器默认时区是 UTC,日志里的时间和国内运维习惯对不上,排障时很别扭。用ENV设置TZ=Asia/Shanghai再配合 tzdata 包,日志时间就和宿主机一致了。
构建命令:
docker build -t registry.internal/rocky/rocky9-base:9.5-20250115 .镜像是用registry.internal/rocky/rocky9-base这样的完整名,加上构建日期作为标签。为什么这样做?因为基础镜像一旦被多个应用依赖,就必须有清晰的版本追溯能力。看到标签就知道是哪个仓库、哪个发行版、哪一天构建的,出现问题时可以快速回滚。
4.2 用 docker commit 保存临时状态:适合探索与原型验证
Dockerfile 不是万能的。有些场景下,我们需要在容器里人工交互式操作,尝试各种包的安装和配置,这时候docker commit反而更高效。例如,测试某个 RPM 包在 Rocky Linux 9 上能否正常安装,直接写 Dockerfile 可能来回构建好几次,不如进容器里一步步试,试通了再 commit。
操作方式:
# 在容器里安装测试完成后,退出容器 docker commit rocky9-dev \ registry.internal/rocky/rocky9-with-oracle-client:1.0注意,docker commit只是把容器当前的文件系统状态保存成镜像,不会保留容器历史命令。所以提交前要在容器里尽量把临时文件清理干净,比如 dnf 缓存、日志、临时下载的安装包。否则镜像体积会膨胀,甚至会带入莫名的敏感信息。我自己一般会执行:
dnf clean all rm -rf /var/log/* history -c然后再 commit。这种方式用来做原型验证没问题,但一旦要推广成团队共同使用的基础镜像,还是要把已验证的步骤反哺到 Dockerfile 里,保证构建过程可重现、可审计。
4.3 搭建 Harbor 私有仓库:让基础镜像在企业内部流转
基础镜像构建好之后,下一个问题是怎么让团队其他人拿到。直接把镜像 tar 包传来传去,对协作效率和版本管理都不友好。企业场景下,我习惯用 Harbor 做私有镜像仓库。
Harbor 本身也跑在 Docker 里。部署方式很简单,下载 Harbor 的离线安装包,解压后修改harbor.yml里的 hostname 和端口,然后执行./install.sh即可。装好之后,我们在 Docker 客户端配置要访问的私有仓库地址:
docker tag registry.internal/rocky/rocky9-base:9.5-20250115 \ harbor.internal.com/rocky/rocky9-base:9.5-20250115 docker push harbor.internal.com/rocky/rocky9-base:9.5-20250115如果使用 HTTP 协议访问 Harbor,需要在/etc/docker/daemon.json里配置insecure-registries才能 push 成功:
{ "insecure-registries": ["harbor.internal.com"] }配置完要重启 Docker。这个过程有一步我经常忘:如果 Docker 已经设置了镜像加速器,修改 daemon.json 时要把加速器和 insecure-registries 放在同一个文件里,不要覆盖掉原来的配置。
Harbor 的好处不止是存镜像。它可以为不同项目分配独立项目空间,可以设置镜像扫描规则,还可以配置复制规则,把一个机房的镜像自动同步到另一个机房。基础镜像平台一旦跑起来,Harbor 就成了整个平台的“发行中心”。
5. 在 Rocky Linux 基础镜像之上搭建典型中间件
5.1 用 Docker 安装 MySQL 8.0 并配置数据持久化
基础镜像平台搭好了,最终还是要跑业务。MySQL 8.0 是容器化部署最常见的组件之一。直接拉官方镜像最省事,但如果要完全复现生产环境,可以基于我们定制的 Rocky Linux 基础镜像来构建 MySQL 容器。这里先用官方镜像演示基础操作:
docker run -d \ --name mysql8 \ --network rocky-net \ --ip 172.20.0.30 \ -p 3306:3306 \ -e MYSQL_ROOT_PASSWORD=YourStrongPass \ -v /data/mysql8:/var/lib/mysql \ mysql:8.0这里的关键点是-v /data/mysql8:/var/lib/mysql。容器是无状态的,一旦删除,容器内数据就没了。把 MySQL 数据目录挂载到宿主机,重建容器也不会丢数据。生产环境我还会把配置文件单独挂载出来:
-v /data/mysql8/conf/my.cnf:/etc/mysql/conf.d/my.cnf这样调max_connections、innodb_buffer_pool_size等参数不用重新构建镜像。
进入容器执行 SQL:
docker exec -it mysql8 mysql -uroot -p排查 MySQL 日志:
docker logs mysql8 --tail 200如果容器起不来,优先看日志,90% 的问题都能定位。比如日志里提示权限不足,多半是宿主机挂载目录的所有者和容器内 MySQL 用户不一致,可以用chown -R 999:999 /data/mysql8解决。
5.2 Docker 搭建 Redis 主从:一主一从的实用配置
Redis 的主从结构在容器里部署非常方便。先创建网络,让两个 Redis 容器可以互相通信:
docker network create redis-net启动主节点:
docker run -d \ --name redis-master \ --network redis-net \ -p 6379:6379 \ -v /data/redis-master:/data \ redis:7.2 --appendonly yes启动从节点:
docker run -d \ --name redis-slave1 \ --network redis-net \ -p 6380:6379 \ -v /data/redis-slave1:/data \ redis:7.2 --appendonly yes \ --replicaof redis-master 6379Redis 5.0 之后的命令参数是--replicaof,老版本的slaveof虽然还能用,但不推荐在新环境里使用。配置完之后,进入从节点验证:
docker exec -it redis-slave1 redis-cli info replication输出里能看到role:slave和master_link_status:up,说明主从同步正常。企业场景中主从架构一般是为了读写分离或高可用,如果只有一台机器,容器方式最能模拟多节点效果,因为每个容器都是独立网络命名空间,本质上和不同服务器上的部署差别不大。
5.3 用 Docker 部署 GitLab:完整的 DevOps 基础设施
GitLab 是典型的重量级容器应用,非常吃内存和磁盘。官方给出的最低配置是 4GB 内存,实际用起来最好给到 8GB。部署方式如下:
sudo mkdir -p /data/gitlab/config /data/gitlab/logs /data/gitlab/data docker run -d \ --name gitlab \ --restart always \ -p 80:80 \ -p 443:443 \ -p 2222:22 \ -v /data/gitlab/config:/etc/gitlab \ -v /data/gitlab/logs:/var/log/gitlab \ -v /data/gitlab/data:/var/opt/gitlab \ --shm-size=256m \ gitlab/gitlab-ce:latest这里有个细节:-p 2222:22是为了避免宿主机已经占用 22 端口(SSH 默认端口)。GitLab 的 SSH 克隆地址会变成ssh://git@宿主机IP:2222/group/project.git,需要在 GitLab 的 Admin Area -> Settings -> Network 里把 GitLab Server 的端口改成 2222,否则克隆地址不正确。
GitLab 第一次启动准备时间比较长,容器日志会持续输出70%、80%之类的进度,一定要等日志里出现GitLab ready再访问页面。我踩过的坑是以为容器 state 是 UP 就等于启动完成,实际 GitLab 内部初始化没结束,页面根本打不开。
GitLab 比较吃内存,如果和 MySQL、Redis 放在同一台宿主机,建议给 Docker 至少分配 8GB 内存。这也是为什么前面强调 Docker Desktop 或个人开发机要把资源上限调高。
6. 常见问题与排查技巧实录
这节整理我在搭建 Rocky Linux 容器环境时经常遇到的问题,多数情况下都能“照方抓药”解决。
| 问题现象 | 可能原因 | 排查与解决办法 |
|---|---|---|
| Docker Desktop 启动提示 Virtualization support not detected | BIOS 未开启虚拟化,或 Windows 功能未启用 | 重启进 BIOS 开启 VT-x/AMD-V,确保启用“虚拟机平台”和 WSL 后重启系统 |
Ubuntu 下apt install docker.io版本太旧 | Ubuntu 官方仓库的 Docker 包不跟随上游版本 | 改用 Docker 官方 apt 源安装 docker-ce |
Rocky Linux 容器内dnf makecache报错 | DNS 解析问题或镜像源不可达 | 检查容器内/etc/resolv.conf,用docker run --dns 223.5.5.5指定 DNS |
| 给容器固定 IP 后宿主机访问不到 | 使用了自定义网络但端口未映射 | 固定 IP 只能在 Docker 网络内部使用,宿主机访问仍需-p映射端口 |
| 容器内中文变方块 | 缺少中文字体 | dnf install -y wqy-zenhei-fonts wqy-microhei-fonts后重建镜像 |
| MySQL 容器启动后马上退出 | 挂载目录权限不足 | chown -R 999:999 /data/mysql8 |
| GitLab 页面长时间无法访问 | GitLab 初始化未完成 | docker logs -f gitlab等待出现GitLab ready |
| docker push 到 Harbor 报 http 错误 | Docker 未配置 insecure-registries | 编辑/etc/docker/daemon.json,加入仓库地址并重启 Docker |
还有两个不那么容易被搜索到的小技巧。第一,容器跑dnf install时偶尔会遇到“Could not resolve host”这类问题,往往不是网络断了,而是容器内/etc/resolv.conf被 Docker 自动设置的 DNS 指向了宿主机不可达的地址。启动容器时显式指定--dns 223.5.5.5或--dns 8.8.8.8会稳定很多。第二,基础镜像里尽量不要保留 root 用户作为唯一用户,企业规范一般要求创建普通用户并配置 sudo,避免应用容器被攻破后直接获得 root 权限。
7. 实操心得:如何持续维护一套 Rocky Linux 基础镜像平台
聊了这么多工具和配置,最后说一点关于“平台”的体会。基础镜像平台不是拉一次镜像、写一个 Dockerfile 就结束了,它需要持续维护。我对团队的建议是:每隔一两个月,基于最新的 Rocky Linux 小版本重新构建一次基础镜像,跑一遍现有应用的兼容性测试,再推送到 Harbor 的 nightly 版本目录里。这样做的好处是,安全问题能及时通过更新包修复,而不是等到生产环境被扫描出漏洞后才被动升级。
我个人踩过几次坑之后,养成了两个习惯。一个是给所有基础镜像打日期标签,绝对不用latest标签做生产基础镜像,因为latest是漂移的,今天构建和下周构建可能内容完全不同,谁也不知道线上镜像跟的是哪个版本。另一个习惯是维护一份“包清单”,每次构建基础镜像后,把当时安装的软件及版本导出成文本,随镜像一起保存。这样就算几个月后镜像出了问题,也能知道当时的环境里有哪个包。
Rocky Linux 在 Docker 环境下的表现,和当年 CentOS 容器非常接近,几乎不用改变团队已有的操作习惯。如果你正面临 CentOS 停更后的迁移问题,或者只是想在本地快速拥有一套 RHEL 兼容环境,用 Docker 跑 Rocky Linux 是一个很轻量又有长期价值的起步方案。先从拉一个基础镜像开始,跑通第一个容器,再逐步把你的中间件和业务应用往里面搬。等整个流程顺了,你会发现自己拥有的不只是一个容器,而是一套可以持续复制、分发、审计的企业级基础环境平台。