☰
x86服务器离线安装Docker全攻略:RPM仓库与静态二进制方案
2026/10/7 10:31:21 网站建设 项目流程

很多时候我们以为装 docker 是一件特别无脑的事:一条 curl 脚本,几分钟搞定,然后 Run 一个hello-world收工。但如果你真正经历过那种机房防火墙只开放白名单、数据不能出内网、或者甲方就给了你一台没有外网权限的 x86 服务器,你会发现所谓“瞬间安装”根本不存在,唯一能走的路就是离线安装。这篇就围绕“x86版本环境下如何离线安装docker环境”这条主线,把我实际踩过的坑、试过能稳定复现的方案、以及各种常见报错的排查思路全部写出来,给准备做内网容器化落地的同学一个可以直接抄的作业。

我默认的目标环境是 x86_64 架构的 Linux 服务器,发行版以 CentOS/RHEL 系为主,这类机器在政企机房、运营商网络、工业内网里非常常见。离线安装的核心困难从来不是“docker 本身怎么装”,而是“它的所有依赖怎么齐”、“装完之后怎么启动起来”、“启动之后怎么验证”。这三个问题如果只靠随手下载一个 rpm 硬怼,通常会在第二天被各种libcgroup.so、container-selinux、overlay2报错折磨到崩溃。所以我会把两种主流方案都讲清楚:一种是 RPM 本地仓库法,适合批量交付、依赖最稳;另一种是静态二进制分发法,适合快速部署、不污染系统包管理器。每种方案我都会给出完整命令、参数解释和现场排错实录。

1. 离线安装docker前先想清楚:方案选型的3个关键问题

1.1 为什么会有离线安装这种需求

大部分在线安装教程都默认一个前提:服务器可以访问公网。但真实生产环境里,这个前提很多时候是不成立的。比如机房实行双向网络隔离,业务服务器只允许通过跳板机访问;比如等保合规要求禁止服务器直连外网;再比如某些工业现场的控制网段本身就跟互联网物理断连。在这些场景下,你不能依赖yum install docker-ce在线拉取,也不能指望curl https://get.docker.com | sh,只能把安装所需的所有文件在带外网络里准备好,再人工拷进去。

离线安装的另一个隐藏动机是“可控性”。在线安装时,rpm 包版本、依赖解析结果、下载源状态都由远端决定,可能今天装出来的版本和明天装出来的版本就不一样。而离线安装包可以固定版本、固定依赖、固定校验和,在批量部署几十上百台机器时,这种一致性带来的幸福感是很明显的。尤其是 x86 环境下,不同厂商的服务器、不同的 BIOS、不同的内核小版本,在线装可能遇到各种“只有这台机器才有的怪问题”,离线包反而更容易统一排查。

1.2 RFC:RPM仓库法和静态二进制法的本质区别

离线安装 docker 的方案看似五花八门,但剥开来看只有两条路线。

第一条路线是“把包管理器搬到本地”。你在一台能联网的 x86 机器上,用 yumdownloader 把 docker-ce 以及它所有依赖的 rpm 全部拉下来,再用 createrepo 生成本地仓库元数据,拷到目标机器后配置一个 file:// 的 yum 源,然后用常规的 yum install 命令安装。这条路线的好处是:依赖关系由 yum 自动解析,安装完的状态和在线安装完全一致,后续使用yum update(如果把本地仓库指向同一个目录)也很方便。坏处是:制作离线包的过程稍繁琐,而且必须严格匹配操作系统大版本,比如 CentOS 7 的 rmp 包通常不能直接用到 CentOS 8 上。

第二条路线是“静态编译二进制直拷”。Docker 官方发布过一套静态编译的二进制压缩包,里面包含 dockerd、docker、containerd、runc 等所有运行组件,解压后复制到/usr/bin,再自己写一个 systemd 服务文件就可以跑起来。这条路线的好处是:不依赖任何系统自带库和包管理器,只要内核满足要求就行,非常适合批量分发;坏处是:升级和卸载都靠手动,如果机器上已经存在其他版本的 docker 或者 containerd,容易造成路径冲突。

我在实际项目里的选择逻辑很简单:如果是 CentOS/RHEL 且要维护半年以上,用 RPM 仓库法;如果是临时测试、或者是同一套包要分发到不太一样的多个发行版,用静态二进制法。下文我会把两种方案的完整流程都走一遍。

1.3 动手之前先做一份环境清单

不管选择哪种方案,到了目标机器上第一件事不是装,而是确认环境。我建议你至少检查这几项。第一,确认真机架构是 x86_64,打命令uname -m,输出必须是x86_64,如果是aarch64那下面的所有包都不能用。第二,确认操作系统版本,cat /etc/os-release看VERSION_ID,比如"7"还是"8",离线包的兼容范围以它为准。第三,确认内核版本,uname -r,Docker 在 CentOS 7 上要求内核不低于 3.10,太老的内核会出现 cgroup 和网络功能跟不上的问题。第四,确认/var/lib/docker所在挂载点的文件系统类型,df -hT /var/lib/docker,如果是 xfs,最好确认是否有 ftype=1 属性,这个细节很多坑都是从这里冒出来的。

除此之外还要看一下防火墙状态。很多内网机器默认启动了 firewalld,docker 启动之后会自动往 iptables 里追加规则,如果机器上有很严格的防火墙策略,Docker 的网桥转发会被打断,容器网络就会各种不通。我处理这类问题的一般做法是:先确认当前防火墙策略是否允许容器网段流量,拿不准的时候暂时不纠结,等装完再统一调。

2. 在联网机器上制作RPM离线安装包:一条龙实操记录

2.1 准备下载工具和Docker官方repo源

制作 RPM 离线包的第一站,是找一台和目标机器相同操作系统版本、且能访问公网的 x86 机器。这里有一个小但不允许出错的原则:制作端和目标端的大版本必须一致,最好是同一个小版本。比如目标机是 CentOS 7.9,那制作端也尽量找 7.9。跨大版本打包出来的依赖很容易出问题,因为 glibc、libseccomp、systemd 的版本差异会导致 rpm 安装时冲突。

首先在这台联网机器上安装 yum-utils,它提供了我们后面要用的 yumdownloader 工具。同时把 Docker 官方的 yum 源配置好。命令如下:

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

这里我补一个坑:如果你平时用的是国内镜像源,不要先急着把 Docker 的官方源替换成镜像站。做离线包的时候,最好亲自从官方源拉取一遍,这样能保证软件包来源可靠。下载过程如果很慢,可以临时把 Docker 官方源地址替换为可用的镜像地址,但装完之后我会调整回官方源再检查一遍。

2.2 使用yumdownloader拉取全量依赖rpm包

接下来创建目录,把 docker-ce 相关的软件包全部下载到这个目录。常见需要离线分发的组件是docker-ce、docker-ce-cli、containerd.io、docker-compose-plugin,这四件套是现在 docker 运行的最小组合。如果没有 docker compose 需求,可以去掉最后一个,但建议还是一并打包,因为内网环境后续补装组件非常麻烦。

mkdir -p /opt/docker-offline/packages cd /opt/docker-offline/packages yumdownloader --resolve docker-ce docker-ce-cli containerd.io docker-compose-plugin

--resolve参数的意思是自动解析并下载所有依赖包。这一步会在当前目录生成一堆 rpm 文件,里面除了 docker 自身,还会包含 container-selinux、iptables、libcgroup 等系统依赖。

不过要注意,yumdownloader --resolve依赖 yum 库的元数据,如果某些依赖在已安装过的系统上已经被装入,它就不会重复下载。这本身没有问题,因为目标机器上安装时也只需要缺失的依赖。但为了保险起见,我会再用 repoquery 把所有依赖列出来核查一遍,防止因为本地缓存问题漏掉某个包:

repoquery --requires --resolve docker-ce docker-ce-cli containerd.io docker-compose-plugin

这条命令会把所有递归依赖列出来。你不需要逐条看懂每个包是干嘛的,只需要肉眼扫一遍,确认里面包含container-selinux、libcgroup、libseccomp这类常见硬性依赖。如果发现缺了,直接yumdownloader单独补下。

2.3 生成本地repo元数据并打包成tar

光有一堆 rpm 文件还不够,yum 安装时需要一个“索引”,告诉它这个目录里有哪些包、每个包提供了什么依赖。这个动作由createrepo完成。如果联网机器上还没装这个工具,先yum install -y createrepo,然后执行:

createrepo /opt/docker-offline/packages

执行成功后,目录里会生成一个repodata子目录,里面是各种 xml 和 sqlite 文件。到这一步,离线仓库就算生成完毕了。为了方便拷贝,我会把整个目录打成 tar 包:

cd /opt/docker-offline tar -czf docker-offline-packages.tar.gz packages

打包的时候我建议不要在压缩包里混入其他无关文件,也不要用太高级的压缩参数,保持 tar.gz 格式,缓冲区大、传输快、兼容性也好。

这里有个重要细节:拷贝到目标机器之后,务必先校验一下文件完整性。可以用md5sum或者在解压前查验一下文件数量。内网传输工具五花八门,U盘复制丢文件、FTP 传一半断掉、Windows 和 Linux 之间换行符问题,这些我都踩过。最好是在目标机器上解压后执行ls packages | wc -l,核对数量是否和源机器一致。

3. 目标机器离线安装实战:本地yum源的配置与验证

3.1 规划目录并创建离线repo文件

把打包好的离线包传到目标机器/opt/docker-offline/后,解压:

cd /opt/docker-offline tar -xzf docker-offline-packages.tar.gz

接下来给这台机器配置一个本地 yum 源。我的做法是新建一个独立的 repo 文件,避免污染系统的其他 repo:

vi /etc/yum.repos.d/docker-offline.repo

内容如下:

[docker-offline] name=Offline Docker Repository baseurl=file:///opt/docker-offline/packages enabled=1 gpgcheck=0

gpgcheck=0是关键配置,因为内网机器往往没有 Docker 官方 GPG 公钥,如果保留gpgcheck=1会直接安装失败。有些同学担心关闭 GPG 检查不安全,我的看法是:离线包在源机器上已经校验过来源,只要确保包文件在传输过程中没有被篡改,这里关闭检查和 RPM 完整性校验并不冲突。

配置完后,执行yum repolist查看一下新源是否被识别。

3.2 禁用外部源执行本地安装

这一步是整个 RPM 方案里最容易翻车的地方。如果目标机器原本配置了多个公网源,直接用yum install docker-ce时,yum 会拿这些源与本地源做依赖解析,而在无外网条件下访问那些源会超时,导致安装卡死或者报错。正确的做法是临时禁用所有外部源,只保留 docker-offline:

yum --disablerepo='*' --enablerepo='docker-offline' install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin

--disablerepo='*'并不是一个危险操作,它只在当前命令生效,不会修改系统 repo 文件里的enabled配置。执行完这条命令后,yum 只会在本地目录里查找依赖,如果之前依赖包拉得全,整个过程会非常短。

安装完成后先不要急着启动,执行一次:

yum list installed | grep docker

确认安装的版本号。如果目标机器上本来就有旧版 docker,建议先卸载干净再装新的,否则会出现二进制冲突。卸载命令是:

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

注意,老版本系统里这些包名和 docker-ce 不同,务必在安装前清理。

3.3 启动服务并做一次最基础的运行验证

启动 Docker 服务:

systemctl daemon-reload systemctl enable --now docker systemctl status docker --no-pager

看到active (running)之后,紧接着执行:

docker version

这条命令会分别输出 client 和 server 的版本,只要 server 部分能正常显示,就说明守护进程已经起来了。接下来做运行验证:

docker run --rm hello-world

这里我要说明一下:很多离线环境根本没有外网,docker run hello-world会因为拉不到镜像而报错。这不是 docker 安装有问题,而是镜像来源问题。所以推荐改用早就准备好的本地镜像验证,比如预先导入一个 busybox:

docker load -i busybox.tar docker run --rm busybox echo "docker offline ok"

如果连本地镜像都没有,那就用docker ps和docker info两个命令做状态验证,能正常返回就说明基础环境没有问题了。

4. 静态二进制方式:适合批量分发的快速替代方案

4.1 获取官方静态二进制包并解压

RPM 仓库法虽然稳,但制作流程相对重,依赖版本和系统版本绑得很死。如果碰到“目标机器是 CentOS 7,但内网还有一个 Ubuntu 20.04 也要装 docker”这种混部场景,再按 RPM 法做两套离线包就有点累。这时候我更喜欢用 Docker 官方提供的静态二进制包。

Docker 官方把各架构的静态包放在download.docker.com/linux/static/stable/下,x86_64 架构对应的文件名类似docker-24.0.7.tgz。在联网机器上下载:

wget https://download.docker.com/linux/static/stable/x86_64/docker-24.0.7.tgz

解压后你会看到一个docker目录,里面包含这些可执行文件:dockerd、docker、containerd、containerd-shim-runc-v2、ctr、runc、docker-proxy。这里一个关键认知是:这个包跟发行版无关,任何 x86_64 Linux 发行版基本都可以直接使用,因为它把运行需要的库都静态编译进二进制了。

tar -xvf docker-24.0.7.tgz cp -p docker/* /usr/bin/

复制到/usr/bin后,先确认下权限和能否执行:

ls -l /usr/bin/dockerd /usr/bin/dockerd --version

如果能输出版本号,说明二进制可以在当前内核下正常运行。

4.2 手动编写systemd服务文件

静态包只给二进制,不给 init 服务脚本,所以我们要自己补一个 systemd 服务文件。这里我直接给出一份可用的版本,存到/etc/systemd/system/docker.service:

[Unit] Description=Docker Application Container Engine Documentation=https://docs.docker.com After=network-online.target firewalld.service Wants=network-online.target [Service] Type=notify ExecStart=/usr/bin/dockerd ExecReload=/bin/kill -s HUP $MAINPID TimeoutStartSec=0 LimitNOFILE=infinity LimitNPROC=infinity LimitCORE=infinity Delegate=yes KillMode=process Restart=on-failure StartLimitBurst=3 StartLimitInterval=60s [Install] WantedBy=multi-user.target

这里最关键的配置是Type=notify,它依赖 dockerd 的 sd_notify 机制,dockerd 完成初始化后通知 systemd,systemd 认为服务启动成功。如果这个值写错了,就会看到明明 docker 已经能跑了,但systemctl status docker却是启动失败状态。

创建之后:

systemctl daemon-reload systemctl enable --now docker

如果没有写 systemd 文件,也可以直接nohup /usr/bin/dockerd > /var/log/docker.log 2>&1 &拉起来,但不建议这么做,因为无法开机自启,进程守护和日志管理都很不正规。

4.3 RPM法和二进制法的当机选择

两种方案都走完一遍后,做个简单对比。RPM 法的优势是和系统包管理器无缝集成,yum 会记录所有安装过的依赖,后续卸载、清理、依赖查询都能走 yum 体系;缺点是离线包制作流程较重,且只能用于和制作端相同大版本的系统。静态二进制法的优势是免依赖、跨发行版兼容性强、目录结构可控,特别适合“拿到机器马上要跑起来”的临时场景;缺点是升级、卸载全靠手动,万一机器上已有一个 libcontainerd 之类的老组件,冲突排查起来要自己来。

我在真实项目里的选择标准是:批量稳定交付选 RPM,快速临时验证选静态二进制。如果目标机器数量超过 5 台,且后续还会持续运维,多花半小时做 RPM 仓库是值得的。

5. 离线安装实战中的高频坑与排查手册

5.1 依赖缺失与安全策略类报错

离线安装最常见的翻车现场,是执行安装时提示缺少container-selinux。这是因为 docker-ce 的 RPM 包强依赖 selinux 策略,而默认最小化安装的 CentOS 通常没有把 container-selinux 打进 base 源。如果在下载依赖时忘了拉它,到目标机器上就会报 “Requires: container-selinux”。解决办法不是去网上随便找个 rpm 硬装,而是回到联网机器上yumdownloader container-selinux,补进离线包重新 createrepo。

还有一种是包顺序问题。如果手动执行rpm -ivh *.rpm,rpm 不会像 yum 那样自动解决依赖顺序,遇到安装失败几乎是必然的。有的人会加--nodeps跳过依赖检查,我强烈不建议这么干。跳过之后也许能装上,但 dockerd 一启动就因找不到libcgroup.so而失败,到时候定位问题的成本比装之前高得多。正确的做法是用本文前面说过的yum --disablerepo='*' --enablerepo='docker-offline' install安装,让 yum 自己处理顺序。

5.2 启动失败与内核、存储驱动类问题

安装顺利完成但服务起不来,也是离线环境里的高发现象。我遇到次数最多的是Unit docker.service not found。这个八成是因为使用了静态二进制方案但没有创建 systemd 服务文件,或者服务文件里 ExecStart 写错了路径。先执行systemctl cat docker.service看看服务文件有没有被识别,再检查/usr/bin/dockerd是否存在。

另一种典型报错是启动后docker info里看到的 Storage Driver 是vfs,而正常环境应该是overlay2。这种情况往往是文件系统不支持 overlay 所需特性。xfs 文件系统如果格式化时没有开启ftype=1,内核无法识别目录项的 file type,overlay2 驱动会直接拒绝工作。可以执行xfs_info /var/lib/docker查看 ftype 标记。生产环境如果不能重新格式化,可以暂时在/etc/docker/daemon.json里切换存储驱动:

{ "storage-driver": "vfs" }

但要注意 vfs 性能明显差于 overlay2,每层镜像都是完整复制,镜像多了磁盘空间消耗非常快。这只适合应急,不适合长期运行。

5.3 容器网络不通与网段冲突

离线环境通常有自己固定的内网网段,docker 默认的172.17.0.0/16网段有很大概率和内网已有网段冲突。冲突的表现是:宿主机能 ping 通容器,但容器访问不了宿主机上其他业务系统,或者路由表互相串扰。解决办法是在/etc/docker/daemon.json里显式指定一个不冲突的网段:

{ "bip": "192.168.100.1/24", "default-address-pools": [ {"base": "192.168.101.0/24", "size": 24} ] }

修改后重启 docker:

systemctl restart docker

容器内部网络不通还有个常见原因是 firewalld 把转发拦了。离线环境里很多机器要满足安全要求,会开启 firewalld 且默认拒绝 FORWARD 链。但 docker 的网桥需要在内核层开启 IP 转发,并且让 FORWARD 链放行。临时检查可先执行:

sysctl net.ipv4.ip_forward

输出必须是 1。如果不是,在/etc/sysctl.conf里写入net.ipv4.ip_forward = 1并sysctl -p。至于 firewalld 的策略,我建议在离线内网里把 docker0 添加到 trust 区域,而不是直接 disable firewalld,这样既不影响业务系统安全边界,也不影响容器互访。

5.4 我在离线安装中沉淀的几条经验

多套环境折腾下来,我最大的体会是,离线安装 docker 本质上是“供应链前置”。真正困难的不是敲那几条命令,而是把依赖梳理清楚、版本固定好、传输校验做到位。所以我每次进入新项目,都会在联网环境里一次性把离线包做全、做准,然后写一个版本记录文件,里面写明包名、版本号、下载时间、来源地址,随离线包一起放在目录里。

第二是不要追求最新版本。内网环境一旦装完就很难频繁升级,所以选 docker 版本的时候我会优先选择当前时间点稳定已经超过半年的版本,而不是刚发布的版本。新版本往往需要更新的内核特性,而离线机房的内核版本通常非常保守。比如基于 CentOS 7.9 的内核 3.10,我一般选 docker-ce 20.10 系列或者 23.0 前期的版本,实测翻车概率最小。

第三是把镜像仓库的问题提前想好。docker 装完只是第一步,离线环境里镜像从哪来才是接下来的大头。常见的做法是准备一台带外网络的镜像中转机,用docker pull+docker save打成 tar,再到内网docker load。如果镜像数量大,也可以部署一套私有 registry。这一点虽然不属于安装环节,但凡是做离线 docker 环境的人大概率会马上碰到,提前做好计划会省很多事。

最后再分享一个小技巧:制作离线包的时候,可以顺带把curl、vim、tcpdump这类内网平时装不上的排障工具也一起打进离线目录。离线环境出问题时最大的痛苦不是问题本身,而是缺工具导致连排查手段都没有。我在离线包里固定放几个常用工具之后,后续排障的效率高了很多,这个习惯一直留到现在。

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

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

立即咨询