ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

x86服务器离线安装Docker全攻略:RPM仓库与静态二进制方案

x86服务器离线安装Docker全攻略:RPM仓库与静态二进制方案 很多时候我们以为装 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 RFCRPM仓库法和静态二进制法的本质区别离线安装 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 -rDocker 在 CentOS 7 上要求内核不低于 3.10太老的内核会出现 cgroup 和网络功能跟不上的问题。第四确认/var/lib/docker所在挂载点的文件系统类型df -hT /var/lib/docker如果是 xfs最好确认是否有 ftype1 属性这个细节很多坑都是从这里冒出来的。除此之外还要看一下防火墙状态。很多内网机器默认启动了 firewallddocker 启动之后会自动往 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 文件避免污染系统的其他 repovi /etc/yum.repos.d/docker-offline.repo内容如下[docker-offline] nameOffline Docker Repository baseurlfile:///opt/docker-offline/packages enabled1 gpgcheck0gpgcheck0是关键配置因为内网机器往往没有 Docker 官方 GPG 公钥如果保留gpgcheck1会直接安装失败。有些同学担心关闭 GPG 检查不安全我的看法是离线包在源机器上已经校验过来源只要确保包文件在传输过程中没有被篡改这里关闭检查和 RPM 完整性校验并不冲突。配置完后执行yum repolist查看一下新源是否被识别。3.2 禁用外部源执行本地安装这一步是整个 RPM 方案里最容易翻车的地方。如果目标机器原本配置了多个公网源直接用yum install docker-ce时yum 会拿这些源与本地源做依赖解析而在无外网条件下访问那些源会超时导致安装卡死或者报错。正确的做法是临时禁用所有外部源只保留 docker-offlineyum --disablerepo* --enablerepodocker-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 安装有问题而是镜像来源问题。所以推荐改用早就准备好的本地镜像验证比如预先导入一个 busyboxdocker 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] DescriptionDocker Application Container Engine Documentationhttps://docs.docker.com Afternetwork-online.target firewalld.service Wantsnetwork-online.target [Service] Typenotify ExecStart/usr/bin/dockerd ExecReload/bin/kill -s HUP $MAINPID TimeoutStartSec0 LimitNOFILEinfinity LimitNPROCinfinity LimitCOREinfinity Delegateyes KillModeprocess Restarton-failure StartLimitBurst3 StartLimitInterval60s [Install] WantedBymulti-user.target这里最关键的配置是Typenotify它依赖 dockerd 的 sd_notify 机制dockerd 完成初始化后通知 systemdsystemd 认为服务启动成功。如果这个值写错了就会看到明明 docker 已经能跑了但systemctl status docker却是启动失败状态。创建之后systemctl daemon-reload systemctl enable --now docker如果没有写 systemd 文件也可以直接nohup /usr/bin/dockerd /var/log/docker.log 21 拉起来但不建议这么做因为无法开机自启进程守护和日志管理都很不正规。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 *.rpmrpm 不会像 yum 那样自动解决依赖顺序遇到安装失败几乎是必然的。有的人会加--nodeps跳过依赖检查我强烈不建议这么干。跳过之后也许能装上但 dockerd 一启动就因找不到libcgroup.so而失败到时候定位问题的成本比装之前高得多。正确的做法是用本文前面说过的yum --disablerepo* --enablerepodocker-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 文件系统如果格式化时没有开启ftype1内核无法识别目录项的 file typeoverlay2 驱动会直接拒绝工作。可以执行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} ] }修改后重启 dockersystemctl 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 pulldocker save打成 tar再到内网docker load。如果镜像数量大也可以部署一套私有 registry。这一点虽然不属于安装环节但凡是做离线 docker 环境的人大概率会马上碰到提前做好计划会省很多事。最后再分享一个小技巧制作离线包的时候可以顺带把curl、vim、tcpdump这类内网平时装不上的排障工具也一起打进离线目录。离线环境出问题时最大的痛苦不是问题本身而是缺工具导致连排查手段都没有。我在离线包里固定放几个常用工具之后后续排障的效率高了很多这个习惯一直留到现在。
返回列表