CentOS 7 Docker离线安装全流程:内网环境下的RPM包搬运与踩坑实践
2026/9/18 7:44:00 网站建设 项目流程

公司新上的服务器全在内网,客户一句话“需要用Docker部署”,我就知道麻烦来了。内网环境没有外网权限,yum install直接打水漂,更别提什么在线拉镜像。那段时间我连续折腾了两天,才把离线安装 Docker 的整套流程跑通。这篇就是记录我在 CentOS 7 上做 Docker 离线安装的完整过程,包括下载、搬运、安装、验证,以及那些只有真正踩过坑才会注意到的细节。如果你也在做私有化部署、内网交付,或者公司网络严禁连接外网,这篇可以直接当操作手册用。

1. 什么场景非逼你走离线安装这条路

1.1 一次现场交付的教训

我接过一个项目,客户的服务器放在隔离机房,物理上就不通公网。业务方要求在这台机器上跑容器化应用,第一反应是先把 Docker 环境拉起来。正常情况下,CentOS 7 上一条命令就完事:

yum install -y yum-utils yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo yum install -y docker-ce docker-ce-cli containerd.io

但在内网机器上,这几条命令走到第二步就挂了——仓库地址解析不了,yum一直在报网络超时。当时我还没太当回事,以为换个国内的镜像源就行,结果发现内网连所有公网域名都做了白名单限制,不是换源能解决的。最后只能绕回最原始的思路:在外网找一台同架构的机器,把所有安装包下载好,再搬到内网手动安装。

这个经历让我意识到一件事:离线安装不是“备用方案”,而是很多内网交付场景里的唯一方案。你没法指望客户给你开临时外网权限,也没法在等审批上耗时间。

1.2 离线安装的底层逻辑:把“安装过程”拆成“搬运过程”

很多人一听“离线安装”就觉得难,其实拆开看很简单。在线安装之所以省心,是因为yum会自动处理依赖下载、版本冲突这些问题。离线安装的本质,是提前把依赖和主包全部备齐,再在目标机器上做一次“无网络参与的安装”。

可以这样理解:在线安装是在新家下单买齐家具,等着送货上门;离线安装是你提前把所有家具打包好,一趟车拉过去,到了新家只负责拆包摆放。

所以整个流程就三个环节:

  1. 准备环节:找一台和目标机器系统、架构一致的联网机器。
  2. 下载环节:下载 Docker 主程序包以及所有依赖包。
  3. 安装环节:把 RPM 包全部拷贝到内网机器,本地安装。

听起来简单,但实际操作里最容易翻车的恰恰是第一步“准备环节”。有人图省事,在一台 CentOS 8 的机器上下载 RPM 包,结果带到 CentOS 7 的目标机上装,依赖库版本对不上,一堆报错。系统版本和 CPU 架构必须匹配,这是离线安装的第一条铁律。

2. 动手前先确认三件事:系统版本、依赖关系、下载工具

2.1 目标机的系统版本和内核要摸清楚

在下载任何安装包之前,我建议你先到目标机上跑三条命令:

cat /etc/redhat-release uname -r uname -m
  • cat /etc/redhat-release看发行版版本,比如 CentOS Linux release 7.9.2009。
  • uname -r看内核版本,CentOS 7 一般是3.10.0-xxx.el7.x86_64之类的。
  • uname -m看系统架构,主流是x86_64,但也有不少 ARM 架构的机器(aarch64)。

为什么非得先看这些?因为 RPM 包是区分发行版和架构的。el7的包不能装到el8上,x86_64的包不能装到aarch64上。这个错一旦犯,安装阶段会直接报wrong ELF class或者依赖解析失败。

另外要注意内核版本。Docker 官方要求 CentOS 7 内核不低于 3.10,绝大多数 CentOS 7 即装即用,但如果你遇到的是定制过内核的老系统,就要多留个心眼。后面我会专门讲内核和存储驱动的坑。

2.2 docker-ce 的依赖包没有你想象中那么少

很多人以为只要下载一个docker-ce.rpm就够了,实际执行rpm -ivh docker-ce.rpm的时候会弹出一堆Failed dependencies,这才发现 Docker 依赖了那么多包。

以我在 CentOS 7 上安装 Docker 20.10.x 为例,核心安装包和依赖通常包括:

包名作用
docker-ceDocker 主程序包,包含 daemon 和 client
docker-ce-cliDocker 命令行工具,单独拆分出来的
containerd.io容器运行时,Docker 依赖它来管理容器生命周期
docker-compose-pluginCompose V2 插件,建议一起装,后面编排会用
container-selinuxSELinux 策略扩展包,不装可能起不了服务
pigz并行压缩工具,部分镜像解压会用到
device-mapper-libs早期存储驱动相关依赖,老版本会需要
audit-libs-python / libsemanage-python / policycoreutils-python安装 container-selinux 时的依赖链

如果缺少这些,rpm -Uvh会给出很明确的报错,但问题是你在内网没法执行yum install去补依赖,只能重新去外网下载再传进来,一来一回非常浪费时间。所以下载阶段就要把所有依赖全部拉齐。

2.3 用 yumdownloader 自动解析依赖,别手动一个个找

面对这么多依赖,手动去 rpmfind 网站一个个下载不是不行,但效率极低,还可能下错版本。我的做法是用yumdownloader配合--resolve参数,让 yum 自动把依赖关系解析好,一次性下载到位。

yumdownloader需要先安装yum-utils

yum install -y yum-utils

然后在联网机器上,把 Docker 官方仓库加进来:

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

如果你要指定版本而不是装最新的,可以先看仓库里有哪些可用版本:

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

确定版本号之后,创建下载目录:

mkdir -p /root/docker-offline cd /root/docker-offline

最后执行下载命令,关键是--resolve

yumdownloader --resolve docker-ce-20.10.24 docker-ce-cli-20.10.24 containerd.io docker-compose-plugin --destdir=/root/docker-offline

这条命令会把所有依赖的 RPM 包全部下载到/root/docker-offline目录。下载完成后,用ls -lh看一下包的数量和大小,我那次大概拉了十几个 RPM,总大小在 80MB 到 100MB 左右。

这个阶段有个小技巧:container-selinux单独确认一下。有时候yumdownloader --resolve会因为系统里已经装过 SELinux 相关策略包而跳过某些依赖,到了离线机器上反而缺。保险起见,可以手动补一条:

yumdownloader --resolve container-selinux pigz --destdir=/root/docker-offline

多花几秒钟,省得后面来回折腾。

3. 完整离线安装流程:从下载到上线的五步操作

3.1 在联网机器上拉取全部 RPM 包

接上一节,当所有 RPM 包都躺在/root/docker-offline目录里之后,先别急着打包,整理一下目录内容,明确装了什么。我当时整理出来的文件类似这样:

docker-ce-20.10.24-3.el7.x86_64.rpm docker-ce-cli-20.10.24-3.el7.x86_64.rpm containerd.io-1.6.22-3.1.el7.x86_64.rpm docker-compose-plugin-2.24.1-1.el7.x86_64.rpm container-selinux-2.119.2-1.911c772.el7_8.noarch.rpm pigz-2.3.4-1.el7.x86_64.rpm ...

这里想提醒一句:如果目标机之前装过旧版本 Docker,不建议直接用这些包做升级实验。离线环境下的版本升级比全新安装更麻烦,容易出现配置残留、旧依赖清理不干净的问题。生产环境里我倾向于保持版本一致,避免在离线场景引入额外变量。

3.2 打包、传输与校验

下载好的 RPM 包如果数量多,我一般先打包再传输,减少文件数量,避免漏传:

cd /root tar czvf docker-offline-rpms.tar.gz docker-offline/*.rpm

打包完成后,用scp传到内网目标机:

scp /root/docker-offline-rpms.tar.gz root@<内网IP>:/root/

如果内网无法直连,可以通过跳板机操作:

scp -oProxyJump=跳板机用户@跳板机IP /root/docker-offline-rpms.tar.gz root@<内网IP>:/root/

传输完成之后,建议在目标机上做个校验。虽然scp本身有完整性校验,但我在实际操作中遇到过传输过程中文件损坏的情况,后来养成了习惯:在联网机器上先算好 MD5,到目标机再核对:

# 联网机器上 md5sum /root/docker-offline-rpms.tar.gz # 内网目标机上 md5sum /root/docker-offline-rpms.tar.gz

两个值一致再继续解压,否则重新传。这一步看着多余,但能帮你屏蔽掉最诡异的一类问题——安装报错并不是因为你操作错,而是因为包文件本身坏了。

解压:

mkdir -p /root/docker-offline tar xzvf /root/docker-offline-rpms.tar.gz -C /root/docker-offline

3.3 在目标机上执行安装

进入 RPM 包目录后,我建议先用rpm -qa确认目标机上没有装过老的 Docker 包:

rpm -qa | grep docker

如果输出为空,说明是干净环境,直接安装:

cd /root/docker-offline rpm -Uvh *.rpm

rpm -UvhU是升级安装,如果是全新环境,和-ivh效果一样,它会按照 RPM 包自身的依赖元数据自动处理。但是要注意,rpm -Uvh *.rpm并不保证安装顺序正确,只是把所有包一次性交给 rpm 处理,rpm 会根据依赖关系自行判断顺序。

如果安装过程中出现Failed dependencies,大概率是某个依赖包没下载全。此时把报错信息里的包名记下来,回联网机器上补下:

yumdownloader --resolve <缺失的包名> --destdir=/root/docker-offline

补完再传输、再安装。

如果遇到的是已经存在的包版本冲突,比如系统自带的podmanrunc与 Docker 冲突,可以用rpm -e把冲突包先移除,但操作前要小心,最好确认一下这个包没有其他关键依赖。

3.4 配置开机自启并启动 Docker 服务

安装完成后,先配置开机自启,再启动服务:

systemctl enable docker systemctl start docker

执行systemctl start docker后不要急着跑容器,先用systemctl status docker看一眼状态是否active (running)。如果启动失败,用journalctl -u docker查日志,重点看有没有failed to start daemonError starting daemon之类的字眼。

在我印象里,新装 Docker 启动失败最常见的原因有三个:

  1. containerd.io没装上或者版本不匹配。
  2. SELinux 相关策略没有正确安装,导致container-selinux相关的报错。
  3. 内核模块缺失,比如overlaybr_netfilter没有加载。

这三个问题都会在后面专门讲。

3.5 用 docker version 和 docker info 确认安装状态

Docker 启动之后,验证命令非常关键。很多人只敲一句docker --version,看能输出版本号就以为大功告成。实际上docker --version只能证明 client 端命令存在,真正要确认服务端可用,必须看docker versiondocker info

docker version

正常输出应该分两段:ClientServer。如果只有ClientServer段报错,说明 Docker daemon 没起来,问题还大着呢。

接着看docker info

docker info

重点看这几个字段:

  • Storage Driver:正常应该是overlay2。如果你看到devicemapper,说明系统不支持 overlay2,存在性能隐患。
  • Cgroup Driver:默认是cgroupfs,如果以后要接 Kubernetes,这里最好是systemd,不然后面会踩坑。
  • Server Version:确认服务端版本。

到这一步,Docker 离线安装基本算成功了。但你别急着高兴,因为还有一个绕不开的问题等着你:内网环境里没有镜像,Docker 装好了却拉不了镜像,相当于买了车却没有油。

4. 离线装完 Docker 后,镜像怎么带进内网

4.1 不要在内网执行 docker pull,先把镜像导出

装好 Docker 之后,很多人习惯性地敲一句docker pull nginx:1.25,然后发现卡在connect: network is unreachable。这是离线环境的常态,不用慌。

正确的思路是:在联网机器上先把镜像拉下来,导出成文件,再把文件搬到内网导入。整个链路和 RPM 包离线安装如出一辙:

# 联网机器上 docker pull nginx:1.25 docker save -o nginx-1.25.tar nginx:1.25

docker save会把镜像连同它的历史层、元数据全部打包进一个 tar 文件。这里有个细节:docker save默认不会压缩,镜像越大,tar 文件越大。如果镜像超过几百 MB,建议打包后用 gzip 压缩:

docker save nginx:1.25 | gzip > nginx-1.25.tar.gz

传到内网之后解压再导入,或者直接在导入时解压:

docker load -i nginx-1.25.tar.gz

docker load支持 gzip 压缩的 tar 文件,会先解压再导入,所以我倾向于直接用压缩包传输。

4.2 单机导入的 docker save / docker load 操作实录

实际操作中,内网机器往内网机器传镜像文件,和 RPM 包传输一样使用scp

scp nginx-1.25.tar.gz root@<内网IP>:/root/

到内网机器上执行:

docker load -i nginx-1.25.tar.gz

输出会显示每一层镜像加载的过程,最后出现Loaded image: nginx:1.25就算成功。再用docker images确认镜像已经在本地列表里。

有一点特别提醒:docker save保存的是当前机器平台架构对应的镜像。如果你在 x86_64 的机器上docker pull nginx:1.25,导出的镜像也是 x86_64 架构的;拿到 aarch64 的目标机上 load 也能加载,但运行时爆炸的概率极高。所以下载镜像前,先确认目标机架构,再在对应架构的联网机器上拉取,或者用docker pull --platform指定平台拉取。

4.3 想长久解决镜像分发:内网镜像仓库的搭建思路

如果内网机器多,一台台scp镜像文件再docker load不是不行,但效率低。上线一个容器要传一个 tar,十几个应用就是十几个 tar,而且镜像文件版本混乱后特别难管理。

更好的做法是在内网搭建一个私有镜像仓库,比如跑一个 Registry 容器,然后让所有离线机器从内网仓库拉镜像。但这里有一个先有鸡还是先有蛋的问题:内网还没有 Docker 环境,怎么跑 Registry 容器?

我的做法是:先按前面步骤在一台机器上装好 Docker,用docker save/loadregistry:2镜像导入,然后启动 Registry 容器:

docker run -d -p 5000:5000 --name registry --restart=always \ -v /data/registry:/var/lib/registry registry:2

之后其他机器只需要在/etc/docker/daemon.json里配置insecure-registries(内网 HTTP 或无信任证书时):

{ "insecure-registries": ["192.168.1.100:5000"] }

然后就能直接从内网仓库 push/pull 镜像了。

这个方案的收益很直观:以后任何镜像变更,只需要在一台机器上docker pulldocker tag到私仓地址,再docker push,其他机器从私仓拉取,不用再传 tar 包。做私有化交付时,这套组合拳非常省事。

5. 离线安装高频踩坑记录与排查方法

5.1 依赖包版本不对导致安装中途报错

我早期踩得最多的坑,就是版本错位。比如docker-ce是 20.10.24,而containerd.io是另一个较老的版本,安装时 rpm 会报:

Error: Package: docker-ce-20.10.24-3.el7.x86_64 Requires: containerd.io >= 1.6.0

这个报错已经算仁慈了,因为它直接告诉你缺什么。最烦的是某些依赖版本满足报错条件,但实际运行时行为异常。所以我后来固定动作是:yumdownloader --resolve时指定相同版本号,尽量让主包、CLI、containerd 版本处于一个发布周期内。

5.2 内核过老导致存储驱动回退

CentOS 7 默认内核 3.10,用 Docker 20.10 一般没问题。但如果遇到一些被裁剪过的定制内核,overlay2驱动不可用,Docker 会自动回退到devicemapper,性能下降一截之外,容器挂载行为也怪。

可以先检查内核模块:

lsmod | grep overlay lsmod | grep br_netfilter

如果没加载,手动加载一下:

modprobe overlay modprobe br_netfilter

确认模块存在后,最好设置开机自动加载。新建/etc/modules-load.d/docker.conf

overlay br_netfilter

然后把桥接流量转发到 iptables 的配置写入/etc/sysctl.d/docker.conf

net.bridge.bridge-nf-call-ip6tables = 1 net.bridge.bridge-nf-call-iptables = 1

执行sysctl -p /etc/sysctl.d/docker.conf生效。这些配置在做 Kubernetes 节点时尤其重要,离线环境里没外网,出了问题排查成本更高,前置做好能省心很多。

5.3 cgroup 驱动不一致,前期没感觉后期带出大问题

docker info里有一项Cgroup Driver,默认值是cgroupfs。如果这台机器以后要加入 Kubernetes 集群,而 kubelet 的 cgroup 驱动是systemd,两者不一致会直接导致 kubelet 报错,容器生命周期管理混乱。

解决方法是提前配置/etc/docker/daemon.json

{ "exec-opts": ["native.cgroupdriver=systemd"], "log-driver": "json-file", "log-opts": { "max-size": "100m", "max-file": "3" }, "storage-driver": "overlay2" }

改完重启 Docker:

systemctl daemon-reload systemctl restart docker

在这里多说一句:daemon.json 最好在 Docker 刚装好、还没有跑任何容器的时候配置,因为 cgroup 驱动切换需要重启 Docker,这一重启,所有运行中的容器都会受影响。生产环境里没人愿意为了改一个配置去挪一堆容器。

5.4 传输损坏和磁盘空间不足的隐蔽坑

RPM 包传输损坏的问题前面提过,镜像 tar 包同样有这个风险。比如内网网络质量差,scp一个 2GB 的镜像包,传到 90% 的时候断了,硬着头皮继续用,结果docker load提示archive/tar: invalid tar header。这时候别怀疑操作步骤,先重新传一遍,或者校验一下 md5。

另一个隐蔽的坑是磁盘空间。离线安装本身占不了多少空间,但容器运行起来之后,镜像、容器层、日志全往/var/lib/docker里塞,如果这个目录所在分区空间不足,Docker daemon 会非常奇怪地报错,比如no space left on device或者更隐晦的failed to mount local volume

所以装好 Docker 之后,第一件事就是检查/var/lib/docker所在分区的剩余空间:

df -h /var/lib/docker

如果空间不够,建议在daemon.json里修改>{ "data-root": "/data/docker" }

这个配置同样要在跑容器之前改好,否则迁移数据目录的复杂度会直线上升。

5.5 时间不同步导致的奇怪问题

内网机器时间飘了,是离线环境里最容易被忽略的“隐形杀手”。Docker 在拉取镜像、获取镜像元数据时经常要验证时间戳,如果本地时间和实际时间相差太大,会报证书过期、签名验证失败这类莫名其妙的错误。我之前有一次在内网搭 Registry,镜像 push 过去一切正常,pull 的时候却报x509: certificate has expired or is not yet valid,查了半天才发现是机器时间慢了三个小时。

离线环境访问不了公网 NTP 服务,解决办法是配置内网 NTP 服务器:

yum install -y ntpdate ntpdate <内网NTP服务器IP>

如果内网没有 NTP 服务器,也可以在计划任务里定期从某一台相对可靠的机器同步,但这种方式精度有限,尽量还是让运维把内网时钟源搭起来。

安装了 Docker 之后,我的习惯是把系统时钟同步也纳入交付清单里。你会发现很多看似无关的问题,最后都能回溯到时间或网络这类基础环境上。

最后说一个我自己这些年固定的操作习惯:每做完一次离线安装,我都会把用到的 RPM 包、镜像 tar、daemon.json 模板、安装命令脚本全部归档到一个文件夹,存到内部共享存储里。下次再做类似交付,直接复制这份“离线工具箱”,版本一致、流程一致,踩过的坑不会第二次踩。这比任何“在线速成”方案都更可靠——因为你的工具箱,是用一次次的现场问题喂出来的。

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

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

立即咨询