☰
红帽系环境Docker CE安装全流程:从踩坑到离线部署
2026/10/23 7:01:39 网站建设 项目流程

红帽系环境上装 Docker,很多人第一反应是yum install docker就完事了,真上手才发现坑一个接一个:仓库配不上、SELinux 拦截、containerd.io 版本冲突,半天过去了容器还没跑起来。我最近在一批 RHEL 兼容系统上从零部署 Docker Engine,把安装到调优全流程走了一遍,有些教训值得记录下来。这篇文章会围绕红帽环境 + docker 安装这个主题,先解释清楚环境中容易被忽视的几个关键点,再给出一套可直接落地的 docker-ce 安装步骤、常见报错的排查方法,以及隔离内网环境下如何离线安装。适合正在接管红帽系服务器、或者在内部网络准备容器运行时的运维和开发同事参考。

1. 动手前先搞清楚:红帽环境到底哪里不一样

1.1 我们说的“红帽环境”通常指这些系统

日常聊天时说的红帽环境,一般包括 RHEL 本身,以及大量与其保持兼容的发行版,比如 CentOS 7/8/9、Rocky Linux、AlmaLinux。它们共享同一套 RPM 包管理体系和 systemd 启动方式,所以 Docker 官方提供的 docker-ce 源在里面基本是通用的。实际操作前先跑一下cat /etc/os-release,看清大版本号,因为 RHEL 7、8、9 的软件包依赖差异比较大,尤其是 SELinux policy、iptables 后端、cgroup 版本这些底层组件。

这里有一个容易让新手迷惑的地方:CentOS 和 RHEL 用的是同一套 yum/dnf 体系,但并不是说从 CentOS 复制来的命令就能原样套在 RHEL 上。RHEL 如果没注册订阅,连基础 yum 仓库都用不了;而 CentOS 7 已经停止维护,直接用官方源可能拿到的是旧包或失效源。所以我更推荐把 Rocky Linux 或 AlmaLinux 作为生产替代,它们在二进制层面兼容 RHEL,docker-ce 安装流程几乎不用改。

红帽系的内核版本跨度也很大。RHEL 7 是 3.10 内核,RHEL 8 是 4.18,RHEL 9 是 5.14。Docker Engine 要求内核不低于 3.10,所以这些版本在基础条件上都能支撑 docker-ce,但实际表现有差别。比如 overlay2 存储驱动在 RHEL 7 的 XFS 文件系统上需要特别注意目录项类型(d_type)是否开启,这一点后面会专门说。

1.2 系统自带 Podman,为什么还要专门装 Docker

红帽系默认带了一套容器工具链,命令行工具叫 Podman,另外还有 Buildah 和 Skopeo,这套体系跟 Docker 的思路并不完全一样。Podman 最明显的特性是没有守护进程,每个容器可以独立由 systemd 管理,安全性也确实不错。但现实工作里我们经常遇到要对接的 CI/CD 平台、日志采集器、监控组件只认/var/run/docker.sock,或者有人专门用了 docker-compose.yml 来定义编排,这时候 Podman 即使能模拟一部分 Docker CLI 行为,也难以做到百分百兼容。

另外,Docker CE 自带 docker-compose-plugin 和 docker-buildx-plugin。前者是现在主流的 Compose V2 版本,后者用于多架构镜像构建,都是持续集成的常客。如果你只是简单跑几个容器,Podman 完全够用;但如果团队现有工具链都建立在 Docker 之上,那就别跟生态对抗,直接装 docker-ce 更省心。装完之后 Podman 可以继续留着,两者不是非此即彼的关系。

还有一点要摆正心态:docker-ce 出自 Docker 官方仓库,不属于红帽发行版自带的软件仓库,所以出了问题更多要依靠 Docker 官方文档和社区资料,而不是遇到问题第一反应找系统厂商支持。生产环境里最好自己在内部再维护一套版本基线,别让业务容器建立在完全不受控的二进制包上。

1.3 动手前先回答自己的三个问题

我在部署前一般会强迫自己回答三个问题,这几个答案会直接影响安装步骤。

第一个问题:你是需要完整的 Docker 生态,还是只是要一个能跑容器的运行时?如果只需要跑容器,用 Podman 可能更符合红帽环境本身的维护节奏;如果需要 docker.sock、Compose、Buildx,那就直接走 docker-ce。

第二个问题:服务器能不能访问外网?这决定了你是走在线 yum 仓库,还是必须准备离线 rpm 包。很多红帽机器放在内网隔离区,只有代理或者根本没有外网,这种情况下提前把依赖包下载好能避免大量折腾。

第三个问题:容器数据准备放在哪,后续要升级怎么办?/var/lib/docker默认就在根分区,根分区不够大时容器一多就把磁盘打满。最好在安装前规划好独立数据盘,并在/etc/docker/daemon.json里把>cat /etc/os-release # 看发行版和大版本 uname -r # 看内核版本 uname -m # 看架构,x86_64 最常见 getenforce # 看 SELinux 状态 systemctl status firewalld # 看防火墙是否在运行

架构直接影响 rpm 包选择。Docker 官方仓库对 x86_64、aarch64、s390x 都有对应包,但离线下载时要严格按目标机架构选取,不能在 x86 机器上下包然后装到 arm 机器上。

如果你手上的是标准 RHEL 系统,还要确认订阅状态。RHEL 不注册订阅的话,很多系统基础的软件源是用不了的。虽然 docker-ce 官方仓库本身不依赖 RHEL 订阅,但安装 docker-ce 时可能依赖一些系统基础包,比如container-selinux,如果基础源不可用,后续补依赖就会很痛苦。检查命令是:

subscription-manager status

如果是 CentOS 或者 Rocky/Alma,这一步可以跳过,但要注意源是否配置正确,特别是旧 CentOS 已经迁移到 vault 源的环境。

2.2 内核参数、文件系统与存储驱动的关系

Docker 在 Linux 上的存储驱动默认是 overlay2,红帽系也推荐这个方案。overlay2 依赖内核的 overlay 文件系统支持,RHEL 7 之后默认都带了。它还有一个隐含要求:存放镜像和容器层的数据目录必须在支持 d_type 的文件系统上。XFS 文件系统如果创建时没有开启 ftype=1,环境就会比较尴尬,Docker 会报告 overlay2 不可用,让你换用 vfs,而 vfs 性能很差,磁盘占用也高。

检查方法:

xfs_info /var/lib/docker 2>/dev/null | grep ftype

如果ftype=1,放心用 overlay2;如果是ftype=0,要么改用 ext4,要么重新格式化分区。数据盘在安装前就要把格式搞对,等容器跑起来再迁移就费劲了。

另一个前置参数是 IPv4 转发。Docker 创建网桥和容器网络时要靠内核转发数据包,如果net.ipv4.ip_forward是 0,容器即使启动了也上不了网。检查方法:

cat /proc/sys/net/ipv4/ip_forward

输出应该是 1。如果不是,写入/etc/sysctl.conf:

net.ipv4.ip_forward = 1 sysctl -p

这一步完成后,再往后配置 Docker 的网络才会正常。

2.3 仓库和网络源选择

在线安装时,Docker 官方仓库是最省心的选择。仓库地址用的是 CentOS 路径,但红帽系所有衍生版本基本通用,Docker 官方文档也明确支持在 RHEL 上使用这套源。添加源之前,先确认yum-utils已经装上,因为后面要用的yum-config-manager命令由它提供。

如果你所在网络无法直接访问 Docker 官方仓库,可以考虑两类替代方案。一类是配置操作系统的代理,让 yum/dnf 通过代理访问外网;另一类是提前把仓库里的 repo 文件和 rpm 包同步到内网服务器,做成内部 yum 源。对长期运行的集群来说,内部源几乎是必需品,因为可以保证多台机器装到完全相同的版本,避免一台装一个版本最后行为不一致的问题。

仓库添加完之后,先执行一次yum makecache生成缓存,确认源可用再继续安装,避免在安装中途才发现仓库地址 404。

3. Docker 引擎安装实操:从删除旧装到跑通 hello-world

3.1 清理旧版本,避免残留配置干扰

红帽系环境下可能残留的旧 Docker 相关包包括:

docker docker-client docker-common docker-engine docker-selinux

如果从没装过,跳过这一步。如果机器上有旧版 Docker,建议先移除:

sudo yum remove -y docker docker-client docker-common docker-engine docker-selinux

注意docker-selinux是一个历史包名,现在对应的功能已经被container-selinux取代。卸载旧包时,/var/lib/docker目录里的数据默认不会删除,所以不用担心旧镜像丢失。如果是担心旧配置文件残留,可以在后续配置daemon.json时覆盖处理。

Podman 不用急着卸载。docker-ce 和 Podman 可以共存,命令层面也不会冲突,除非你安装了某个模拟 Docker CLI 的兼容包(比如podman-docker),那个包会提供/usr/bin/docker软链接,和真正的 docker CLI 抢路径,这种情况下才需要二选一。

3.2 添加 Docker 官方仓库并安装必要依赖

先安装基础工具包:

sudo yum install -y yum-utils device-mapper-persistent-data lvm2

其中device-mapper-persistent-data和lvm2在部分系统上是 Docker 存储驱动需要的底层库,装上有备无患。

然后添加 docker-ce 仓库:

sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo

添加后可以看一眼仓库文件内容:

cat /etc/yum.repos.d/docker-ce.repo

里面会有docker-ce-stable、docker-ce-test、docker-ce-nightly三个块。生产环境一般只用docker-ce-stable,如果仓库文件启用了 test 或 nightly,最好手动把 enabled 改为 0,免得某次yum update把不稳定的测试版拉进来。

刷新缓存:

sudo yum makecache

如果这里出现 GPG 密钥报错或者 404,多半是时间不同步或 DNS 解析问题。先检查系统时间:date,再确认能解析download.docker.com。

3.3 安装 Docker 引擎及相关插件

直接安装最新稳定版:

sudo yum install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

拆开看这几个包各自的作用:docker-ce是守护进程本体,docker-ce-cli是命令行工具,containerd.io是容器运行时,docker-buildx-plugin负责多架构镜像构建,docker-compose-plugin提供docker compose命令。装完这五个,日常开发和运维基本够用。

生产环境我更推荐锁定版本再装。先列出可用版本:

yum list docker-ce --showduplicates | sort -r

输出里会看到类似docker-ce.x86_64 3:27.6.2-1.el9 docker-ce-stable这样的行,注意前面的3:是 epoch 号,安装时必须带上。锁定版本安装示例:

sudo yum install -y docker-ce-3:27.6.2-1.el9 docker-ce-cli-3:27.6.2-1.el9 containerd.io

containerd.io 不指定版本时,yum 会挑选当前仓库里最合适的版本,一般没有问题。但如果你想整条链路都锁住,就先用yum list containerd.io --showduplicates | sort -r查出版本,再一起安装。

3.4 启动服务、设置自启并验证网络桥接

安装完成后,第一件事是启动守护进程并设置开机自启:

sudo systemctl start docker sudo systemctl enable docker sudo systemctl status docker

如果启动失败,先看日志:

journalctl -u docker -n 50 --no-pager

启动成功之后,系统里应该多出一个 docker0 网桥:

ip addr show docker0

看到172.17.0.1/16或类似地址,说明 Docker 网络组件初始化正常。如果网桥没出现,多半是 iptables 或者内核模块的问题,往下看常见问题部分。

这里也顺手确认一下存储驱动:

docker info | grep -i "storage driver"

正常情况下输出overlay2。如果输出了vfs,说明文件系统 d_type 有问题,需要回到分区格式那个话题去处理。

3.5 用 hello-world 验证完整生命周期

官方验证命令永远是:

sudo docker run hello-world

这条命令会从 Docker Hub 拉取 hello-world 镜像,创建容器,运行一个只有几 KB 的测试程序,然后退出。它能拉通整个链路:镜像下载、镜像解包、容器创建、进程启动、网络访问。

如果环境访问 Docker Hub 很慢或者超时,可以换成自己的内网镜像,比如:

sudo docker run --rm almalinux:9 echo "container ok"

关键在于验证容器能执行有输出的命令。跑通之后,执行docker ps -a能看到 hello-world 容器处于 Exited 状态,docker images能看到刚才拉下来的镜像,这套环境基本就能用了。

4. 安装路上的高发问题:依赖、SELinux、防火墙排查实录

4.1 containerd.io 版本冲突或依赖报错

不少人在执行安装命令时会看到类似这种提示:Package docker-ce requires containerd.io >= 1.x.y but none of the providers can be installed。这通常是因为机器上残留了旧版 containerd,或者仓库里 containerd.io 的可用版本比 Docker 要求的版本低。

处理方法比较简单,先把 containerd.io 单独更新到仓库里最新的稳定版:

sudo yum install -y containerd.io

如果机器上之前装的是操作系统自带的containerd包而不是containerd.io,两者重名但命名的来源不同,按官方仓库的统一性要求,应保留containerd.io并移除冲突的旧包。卸载前记得记录一下当前的 containerd 配置,通常配置文件在/etc/containerd/config.toml,重装后可能需要重新生成。

4.2 SELinux 导致的启动失败和权限异常

红帽环境的 SELinux 默认是 Enforcing,这是一个很多人又爱又恨的东西。Docker 本身对 SELinux 支持得不错,但它要求系统里已经安装好container-selinux这个策略包,否则启动时会碰到docker: failed to load module或容器启动被拒绝的问题。

先补上策略包:

sudo dnf install -y container-selinux

如果容器需要绑定非标准端口,比如要发布 8080 端口,SELinux 会拦截 Docker 的端口访问,这时候需要给端口打上允许的标签:

sudo semanage port -a -t http_port_t -p tcp 8080

这一条是经常被忽略的。很多容器映射端口后外部访问不了,不是防火墙问题,而是 SELinux 策略没放行对应端口。

还有一类问题是挂载宿主机目录时需要设置正确的标签。用-v挂载时,可以在挂载选项里加上:z或:Z后缀让 Docker 自动调整标签,或者提前手动给目录设置标签:

sudo chcon -Rt svirt_sandbox_file_t /data/appdata

我个人的态度是:不要为了省事setenforce 0然后写进 rc.local。生产系统关掉 SELinux 等于少了一层安全边界,而且很多审计要求会卡在这一点。按上面补策略包和标签的做法,既能让 Docker 正常工作,又能保住系统安全策略。

4.3 firewalld 与 Docker 端口映射打架

红帽系统跑着 firewalld 是很常见的情况,而 Docker 启动后会自动改写 iptables 规则,两条链路混在一起时典型症状是:容器起来了,端口在宿主机上ss -tlnp也能看到,但从外部就是访问不通。

原因通常是 firewalld 和 Docker 各自维护了一套 NAT/过滤规则,或者 firewalld reload 之后把 Docker 写进 FORWARD 链的规则给清掉了。排查时先看当前防火墙状态:

firewall-cmd --state firewall-cmd --list-all

一个比较省心的操作习惯是:先启动 firewalld,再启动 docker。顺序对了,Docker 会把自己需要的规则插到 nftables/iptables 对应链里,两者一般能共存。如果已经开了 Docker 又重启了 firewalld,把 Docker 也重启一次,让它重新生成规则:

sudo systemctl restart docker

另外,生产环境最好做一个简单划分:容器对外发布的端口交给 Docker 管理,不要再用firewall-cmd给同一个端口重复做端口转发,否则容易出现双重 NAT 和规则互相覆盖。如果内部还用了安全组或物理防火墙,需要把 Docker 所在宿主机作为转发节点来放行。

4.4 非 root 用户运行 Docker 的权限管理

刚装完 Docker 时,只有 root 用户或者 sudo 用户能执行docker命令。如果希望某个普通用户也能用,标准做法是把它加入 docker 组:

sudo usermod -aG docker <用户名> newgrp docker # 让组权限立即生效,或者退出重新登录

添加完之后,执行docker ps如果不再提示 permission denied,就说明生效了。

但这里必须泼一盆冷水:docker 组权限实际上等于 root 权限,因为用户可以挂载宿主机任意目录到容器里,然后通过容器读写宿主机文件。所以生产环境别为了省事随便把开发人员加进 docker 组,更稳妥的做法是给需要执行容器操作的账号配置受限的 sudo 规则,或者走统一的管理平台代发命令。

4.5 镜像拉不下来、DNS 解析超时的调优方法

镜像拉取慢是红帽内网环境最常碰到的痛点。外网访问受限时,Docker Hub 经常超时。解决的思路有两个方向:一是配置 registry mirror,二是配置 Docker 守护进程的 DNS。

编辑/etc/docker/daemon.json,设置镜像加速地址和内网 DNS:

{ "registry-mirrors": ["https://mirror.internal.example.com"], "dns": ["10.10.0.2", "8.8.8.8"] }

其中dns这一项专门解决容器内域名解析失败的问题。Docker 默认会读取宿主机/etc/resolv.conf,但有些红帽系统的 DNS 配置带有 search 域或使用的本地地址在容器网络里不可达,导致容器里curl域名报bad address。显式指定可用 DNS 后,重启 Docker 即可:

sudo systemctl restart docker

还要提醒一下:修改daemon.json后重启 Docker 是常规操作,但重启守护进程会短暂中断所有运行中的容器网络,排障窗口要选在业务低峰期。

5. 给隔离内网准备的离线安装方案

5.1 在有网机器上把 rpm 包全部下载下来

没有外网的红帽机器,离线安装是唯一出路。做法是找一台能访问外网、系统版本和目标机一致的机器,把 docker-ce 相关 rpm 包全部下载下来。

先在有网机器上配置好 docker-ce 源,然后创建一个下载目录,用 yum 的 downloadonly 能力:

sudo mkdir -p /tmp/docker-rpm sudo yum install --downloadonly --downloaddir=/tmp/docker-rpm \ docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

有时--downloadonly不会自动下载所有依赖,可以改用yumdownloader --resolve:

sudo yum install -y yum-utils sudo yumdownloader --resolve --destdir=/tmp/docker-rpm \ docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

下载完成后检查目录,里面应该包含所有依赖包,比如container-selinux、iptables、slirp4netns这些。把这些 rpm 包连同目标机的系统大版本一起打包拷回内网,就可以在目标机上安装:

sudo yum localinstall -y /tmp/docker-rpm/*.rpm

5.2 用本地 yum 仓库实现批量离线部署

如果只有一两台机器,直接yum localinstall就够了。但如果是一批机器,我更建议搭一个本地 yum 仓库,这样每台机器都可以用统一的yum install命令安装,后续补丁升级也能推送。

大致流程:把下载来的 rpm 包统一放到内网某台服务器的目录,比如/data/yum/docker-ce,然后在服务器上执行:

sudo yum install -y createrepo_c sudo createrepo /data/yum/docker-ce

再用 HTTP 或 Nginx 把这个目录发布成内网地址,比如http://repo.internal.example.com/docker-ce/。在其他机器上写一个仓库文件/etc/yum.repos.d/docker-ce-local.repo:

[docker-ce-local] name=Docker CE Local Repo baseurl=http://repo.internal.example.com/docker-ce/ enabled=1 gpgcheck=0

注意,这里gpgcheck=0只适用于完全可信的内网环境。如果对包完整性有要求,还是要把 GPG 公钥导入系统,或者把公钥文件一起放入仓库目录并开启 gpgcheck。

配置完成后执行:

sudo yum clean all sudo yum makecache sudo yum install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin

5.3 离线安装后的初始化收尾

离线安装成功之后,还需要做几件容易漏的事。

第一件事是确认 SELinux 策略已经齐了。很多离线机器会因为缺少container-selinux而启动不了 Docker,下载包的时候要特别留意这个包有没有进目录。如果没有,单独补下载一份。

第二件事是配置内部镜像仓库。离线环境里,业务镜像通常要放到内网 Harbor 或私有 Registry,而 Docker 默认还是去 Docker Hub 找镜像。要么在daemon.json里把registry-mirrors指到内网地址,要么在拉取镜像时显式带仓库域名,例如docker pull repo.internal.example.com/app/myimage:tag。

第三件事是处理证书。内网镜像仓库如果是自签名证书,Docker 不认识,需要在/etc/docker/certs.d/<仓库域名>/下放置 CA 证书,或者在/etc/docker/daemon.json中把该仓库加入insecure-registries。后者虽然省事,但只建议在完全可信、无外部暴露的测试环境里用,生产环境还是把证书配好。

6. 装完后必须做的日常养护与升级策略

6.1>{ "data-root": "/data/docker" }

如果 Docker 已经跑起来过,迁移前要先把服务和容器停掉:

sudo systemctl stop docker sudo rsync -avxP --xattrs /var/lib/docker/ /data/docker/

这里用--xattrs是必要的,Docker 的数据文件带有扩展属性,尤其是 SELinux 标签,漏掉会导致迁移后容器启动异常。迁移完成后删掉旧目录或者改名备份,再启 Docker,用docker info确认Docker Root Dir已经指向新路径。

生产环境的卷挂载也应该提前规划。容器里需要持久化的数据,比如数据库文件、日志、上传目录,尽量用命名卷或者独立目录映射,并做好标签和权限控制。不要放任容器写临时层,否则容器删除后数据也跟着没了。

6.2 日志轮转与临时镜像回收

Docker 默认的日志驱动是 json-file,如果不在daemon.json里做限制,单个容器的标准输出日志会无限增长,直到把磁盘撑满。建议一开始就设置日志大小:

{ "log-driver": "json-file", "log-opts": { "max-size": "10m", "max-file": "3" } }

这样每个容器最多保留 3 个 10MB 的日志文件,超过的会自动轮转。已经运行的容器需要重新创建才会应用新的日志参数,所以最好在业务上线前就配置好。

磁盘空间检查可以用:

docker system df

它会把镜像、容器、卷、构建缓存占用分别列出来。清理悬空镜像和停止的容器:

sudo docker system prune -f

注意,docker system prune默认不会删命名卷,但如果你在命令里加了--volumes,会把所有未被容器使用的卷一并删除,执行前务必想清楚。我见过有人手滑删掉了数据库卷,生产事故没跑了。

6.3 版本锁定和升级流程

对于已经稳定运行的红帽环境,动不动就yum update -y是非常危险的习惯。Docker 组件之间并不是完全独立:docker-ce、docker-ce-cli、containerd.io 这三个版本会有配合关系,单独升级其中一个,有时候会出现 API 不匹配或者运行时异常。

建议用 yum 的 versionlock 插件把 Docker 相关包锁定在已知稳定版本,等有明确的升级需求时再统一操作。安装插件:

sudo yum install -y yum-plugin-versionlock sudo yum versionlock docker-ce docker-ce-cli containerd.io

查看已锁版本:

sudo yum versionlock list

解锁升级:

sudo yum versionlock delete docker-ce docker-ce-cli containerd.io sudo yum install -y docker-ce docker-ce-cli containerd.io

升级前先在测试机验证,再上生产。升级过程中一定要有一个业务维护窗口,因为systemctl restart docker会中断所有容器的网络,即使是内部应用也会有一二十秒的抖动。

我个人在实际操作中的体会是:红帽环境装 Docker,真正决定后续运维质量的往往不是那几行安装命令,而是装之前有没有把存储位置、日志上限、版本锁定、SELinux 策略这些看似零碎的点想清楚。我见过太多环境装上之后能跑,但等到容器多起来再回头改配置,代价成倍增加。如果你也是第一次接触红帽系机器,建议按这篇文章的顺序把检查做完再动手,遇到问题直接对应章节里的现象去查,大部分坑都能避开。最后再分享一个小技巧:每次装完环境后,把daemon.json、docker-ce.repo、还有装的版本号一起备份到 Git 仓库里,下次扩容时直接复用,比临时翻历史命令靠谱得多。

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

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

立即咨询