ARTICLE DETAIL

资讯详情

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

离线安装Docker:一套搞定rpm包与tar包的内网部署方案

离线安装Docker:一套搞定rpm包与tar包的内网部署方案 简介这是一套专为CentOS系统离线安装Docker 1.12.6而打包的rpm软件包集合适合内网环境或不便联网的服务器运维人员使用帮助用户免去自行寻找依赖包的麻烦。整个压缩包共16个文件以docker、docker-client、docker-common等核心rpm安装包为主体同时附带repodata仓库元数据含xml.gz、sqlite.bz2等格式可用于yum本地源的配置与依赖校验整体体积约19.27MB小巧易传输。资源当前已有381人学习下载说明其在同类离线部署场景中具有一定参考价值。通过这份软件包用户能一次性获得安装Docker所需的必要组件和依赖信息按常规rpm安装或搭建本地yum源即可完成部署适合初学者快速上手也方便运维人员批量分发安装。1. 离线安装 Docker 的 rpm/tar 包一套流程把内网机器的容器环境从零拉起来内网服务器要装 Docker在线环境一条yum install docker的事放到隔离网络里往往能折腾一整个下午。这份 docker.rpm.tar 软件包就是干这个用的它把 Docker 的服务端、客户端以及依赖组件打成 rpm 集合把可用的镜像打成 tar 包让没有外网的 CentOS/RHEL 机器也能把整套容器环境搭起来。适合的读者很明确——做交付部署的运维、搞内网实验的工程师、在比赛机房临时搭环境的队伍。我拿它在客户现场装过好几次最大的感受是真正难的从来不是执行命令而是搞清楚 rpm 和 tar 各负责哪一块顺序错一步后面全是坑。2. rpm 包与 tar 包的分工先分清程序文件和镜像文件再动手2.1 为什么离线交付首选 rpm 集合而不是一个安装脚本在线环境下yum 会直接从软件源拉取 Docker 的 rpm 包并且自动解析依赖链。依赖缺失时它会提示你缺什么、问你要不要一起装依赖冲突时它会拒绝执行。这一切的前提是机器能访问软件源。内网机器没有这个条件所以交付方通常会把 Docker 本体拆成一组 rpm 包——docker-ce、docker-ce-cli、containerd.io、docker-compose-plugin这些组件全都在里面一起拷到目标机器上再通过本地安装方式把它们装好。那镜像为什么用 tar 而不是 rpm因为镜像本身不是“软件包”它是一套分层文件系统由多个只读层堆叠而成。rpm 只管安装程序文件、注册 systemd 服务它没办法把镜像装进 Docker 的存储目录。镜像是通过docker save导出成 tar 归档再在目标机器上用docker load导回本地镜像库。所以这套软件包里的 rpm 负责让 Docker 变成可执行程序tar 负责让 Docker 里有可跑的镜像两者各管一段缺一个都不行。2.2 动手前先摸清现场三个命令判断这台机器适不适合装我拿到这种离线包第一件事不是急着解压而是先看目标机器是什么系统、有没有装过 Docker、SELinux 是什么状态。这三个问题没确认之前就安装后面几乎一定会翻车。# 确认系统发行版本和内核判断这份 rpm 包是否匹配 cat /etc/redhat-release # 检查机器上有没有装过其他版本的 docker rpm -qa | grep docker # 查看 SELinux 当前状态enforcing 状态常导致容器启动失败 getenforce第一条命令看系统版本。这份 rpm 包面向 CentOS/RHEL 7 或 8 是常见做法你至少要知道目标系统是哪个大版本因为yum localinstall的行为在 7 和 8 上不一样rpm 依赖关系也会有差异。第二条命令看已有安装如果机器上已经装了旧版docker-ce直接再装一份新的大概率出现版本冲突或者旧服务抢占端口。第三条命令看 SELinuxenforcing状态下 Docker 的 overlay 存储驱动可能会被安全策略拦下来导致容器创建失败。常见做法是临时用setenforce 0切到 permissive确认能跑起来之后再决定要不要固化这个配置。2.3 安装 Docker 本体yum localinstall 批量处理 rpm 依赖确认现场没问题之后进入存放 rpm 包的目录执行安装命令。我见过不少同事在这一步直接用rpm -ivh *.rpm然后被一堆依赖报错砸懵。正确的姿势是用yum localinstall让 yum 帮你做依赖分析。# 进入 rpm 包所在目录 cd /root/docker-packages # 用 yum 本地安装自动解析 rpm 之间的依赖关系 yum localinstall -y docker-ce-*.rpm docker-ce-cli-*.rpm containerd.io-*.rpmlocalinstall是 yum 针对本地 rpm 文件设计的安装模式它会把目录里的 rpm 作为数据源来解析依赖找到docker-ce依赖containerd.io就一起装或者按顺序装。-y参数跳过交互确认脚本化部署时必须有它。文件名里的*是为了匹配带版本号的完整文件名比如docker-ce-24.0.x.el7.x86_64.rpm。这里要强调一个边界如果这份包里还带了docker-compose-plugin或docker-buildx-plugin我一般会一起写上避免后面用docker compose时才发现命令不存在。有人问为什么不直接rpm -ivh *.rpm因为 rpm 工具本身不做依赖解析它只负责按你给的顺序一个个装。顺序不对时它会直接报libcgroup is needed by docker-ce这类错误然后中止不会像 yum 那样帮你自动调整安装顺序。离线环境下手动排 rpm 依赖顺序是纯玄学不如直接交给 yum。2.4 如果系统里压根没有 rpm 命令搜索“没找到 rpm 命令”能找到一堆人问这个问题。-bash: rpm: command not found通常有两种情况一是机器不是 RHEL 系发行版rpm命令从未安装二是 PATH 环境变量被改过了/usr/bin不在里面。确认方法很简单# 查看 rpm 命令的位置 which rpm # 如果没有输出检查 PATH echo $PATH如果which rpm没有结果先看/etc/os-release里写的是什么发行版。如果是 Ubuntu/Debian 系这份 rpm 包根本不适用Debian 系用的是dpkg和.deb包你需要找对应格式的离线包。如果系统确实是 CentOS 但 rpm 缺失常见做法是用yum install -y rpm先把包管理器补上。另外也要提醒一点有人喜欢在 Windows 上先解压这份 tar 包看看里面有什么Windows 10 以上自带的tar.exe确实能解压但解压出来的 rpm 文件在 Windows 上毫无意义它必须回到 Linux 环境里用 yum/rpm 安装。3. tar 包加载与镜像恢复从 docker save 产物到容器能跑起来3.1 先看 tar 包里到底装了什么三步快速识图rpm 装完Docker 本体是有了但镜像还在 tar 包里躺着。拿到一个 tar 包我从不直接tar -xvf全解出来而是先看它的目录结构因为这决定了接下来怎么处理。# 查看 tar 包内文件列表只看前 20 行 tar -tf images.tar.gz | head -20 # 查看文件类型确认是不是 docker save 生成的归档 file images.tar.gz如果列表里出现manifest.json、repositories这类文件以及一堆十六进制命名的目录这基本可以断定是docker save的标准产物里面装的是镜像层数据。这种情况你完全不需要手动解压直接让 Docker 自己读。如果列表里是docker/、dockerd、containerd/这类可执行文件路径那就是把 Docker 程序文件打了包这种 tar 走的是另一套用法后面 3.3 节单独说。file命令的输出可以告诉你这个文件是 gzip 压缩还是裸 tar压缩过的在加载前可能要多一步解压。3.2 docker load 的正确姿势不要先解压再导入很多人会习惯性地先tar -xvf把镜像解压出来再想办法导入这是绕了远路。docker load本身就支持直接读压缩或未压缩的 tar 归档你把目录解出来反而会破坏 Docker 期望的目录结构。我一般是直接交给 load# 直接加载镜像归档Docker 会自动识别层结构 docker load -i images.tar.gz # 加载完成后立刻查看镜像列表确认有没有导入成功 docker images # 如果镜像名是 none手动打上自己习惯的 tag docker tag IMAGE_ID myapp:latest-i参数指定输入文件支持 gzip 压缩的 tarDocker 内部会处理解压逻辑。docker images的作用是验证成功的输出会有一行Loaded image: xxx:latest同时docker images里能看到对应的 REPOSITORY 和 TAG。注意这里有个细节——如果对方导出镜像时用的是镜像 ID 而不是仓库名标签docker load完成后你的镜像列表里会出现一堆none:none的悬空镜像。这种镜像不是坏的它只是缺少名字可以用docker tag重新打上一个 tag。如果你不做这一步后面docker run就没有一个可以直接引用的名字只能用IMAGE_ID操作起来非常别扭。3.3 如果 tar 包不是 save 产物而是 docker 程序包docker save导出的 tar 是镜像但还有一种情况对方把整个 Docker 程序目录包括docker、dockerd、containerd这些二进制文件直接打包成 tar 给你。这种情况在应急交付里也常见。处理方式是解压到系统目录然后手动配置服务。# 解压到临时目录看清楚里面的结构 mkdir -p /tmp/docker-bin tar -xvf docker-binary.tar -C /tmp/docker-bin # 把二进制放到标准目录并建立 PATH 软链 mv /tmp/docker-bin/docker /usr/bin/docker mv /tmp/docker-bin/dockerd /usr/bin/dockerd # 配置 systemd 服务让 docker 开机自启 cat /etc/systemd/system/docker.service EOF [Unit] DescriptionDocker daemon Afternetwork-online.target [Service] Typenotify ExecStart/usr/bin/dockerd ExecReload/bin/kill -s HUP $MAINPID Restarton-failure [Install] WantedBymulti-user.target EOF systemctl daemon-reload systemctl enable --now docker这个 systemd 服务文件是离线场景下最简可用版本ExecStart指向 dockerd 的实际路径Typenotify是 docker 官方常用的服务类型要求 dockerd 启动完成后通过 sd_notify 通知 systemdRestarton-failure保证进程异常退出后会自动拉起。文件写完后必须daemon-reload否则 systemd 不会识别新服务。这种二进制 tar 包的劣势也提一下它缺少containerd、runc这类底层组件的话dockerd 可能起不来而且没有 rpm 包的版本记录后面想卸载只能手动删文件很难清干净。3.4 加载前检查磁盘空间镜像体积和你想的往往不一样内网服务器上磁盘空间不足导致 load 失败是我遇到过最多的问题之一。docker load不是简单拷贝 tar 文件它要把镜像的每一层解包写入/var/lib/docker的存储目录消耗的空间通常是 tar 包体积的 1.2 到 1.5 倍。加载前先看一眼磁盘成本极低。# 查看 Docker 数据目录所在分区的空间 df -h /var/lib/docker # 对比 tar 包体积 du -sh images.tar.gz # 清理不再使用的镜像层释放空间 docker system prune -fdf -h看可用空间du -sh看 tar 包实际大小两者一对比就知道够不够装。如果空间紧张docker system prune -f是常用手段它会清理所有悬空镜像和停止的容器、无用网络。注意它不会删除你正在使用的镜像也不会删带 tag 的镜像安全边界比较明确。另一个容易被忽略的点是内核版本overlay2 存储驱动要求内核支持老机器内核版本过低时即使镜像 load 成功容器运行也可能报failed to mount overlay。我一般会顺带执行uname -r确认内核版本在 3.10 以上CentOS 7 默认内核在这个边界上docker 官方对 overlay2 的支持从内核 4.0 开始才算完整。4. 离线部署避坑指南五个必踩的坑含 rpm 依赖和 tar 权限问题4.1 现象rpm -ivh *.rpm 装到一半报 libcgroup is needed有同事第一次装这份离线包直接rpm -ivh docker-ce-*.rpm装到一半报错error: Failed dependencies: libcgroup is needed by docker-ce。我另一个同事更头铁把 rpm 传参顺序换了一下结果缺的依赖从 libcgroup 变成了别的。原因rpm 工具本身不做依赖解析它按你命令行里给的顺序逐个安装后一个包依赖前一个包时一旦顺序不对就会立即中止而且 Docker 的 rpm 包依赖一堆底层库靠人肉排序根本不现实。解决统一改用yum localinstall -y *.rpmyum 会把目录里所有 rpm 作为候选源自动解析依赖关系并排好安装顺序一次性装完。从那以后我再也不在 CentOS 上手工排列 rpm 顺序了。4.2 现象docker load 成功但 docker run 提示 no such imagedocker load -i images.tar输出Loaded image ID: sha256:xxxx看起来一切正常但执行docker run nginx:latest提示Unable to find image nginx:latest locally。原因对方在导出镜像时本地只有镜像 ID没有仓库名和 tagdocker save导出的 tar 里就没有nginx:latest这个引用load 进来后只能看到一个none镜像。解决先用docker images查看镜像 ID再手动打 tagdocker images docker tag IMAGE_ID nginx:latest docker run -d --name web -p 8080:80 nginx:latestdocker tag的第一个参数是镜像 ID第二个参数是你要赋予的仓库名和标签。这一步是 load 之后最容易遗漏的操作漏了它后面所有引用镜像名的命令全都会找不到。我现在每次 load 完的习惯是先跑docker images看 REPOSITORY 列是否全是none是就立刻补 tag。4.3 现象docker 命令提示 permission denied连接不上 docker api在服务器上输入docker ps报错内容里有permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock。原因docker 客户端连接的是/var/run/docker.sock这个 unix socket当前用户不在docker用户组里没有读写权限。很多内网机器的管理员习惯用 root 装完 docker 后直接把 root 给交付人员交付人员又用普通用户登录操作就撞上这个权限墙。解决把当前用户加进 docker 组重新登录会话。usermod -aG docker $USER newgrp docker docker ps-aG表示追加用户到 docker 组newgrp docker用于当前会话立即刷新组权限不用退出重新登录。我处理客户现场问题时还会顺手检查另一种情况如果连 root 执行docker ps都报一样的错多半是 docker 服务本身没起来先用systemctl status docker看服务状态再对 socket 做排查。4.4 现象tar 包解压出来的 docker 二进制启动时报 Cannot connect to the Docker daemon拿到的是 docker 程序 tar 包解压完执行docker version输出 Client 版本正常但 Server 部分显示Cannot connect to the Docker daemon。原因你解压的只是客户端二进制dockerd 守护进程压根没启动或者你用的docker是客户端它连接后台服务时才去检查守护进程二进制 tar 包不像 rpm 包会自带 systemd 服务文件不会自动注册开机自启。解决确认/usr/bin/dockerd是否存在并手动拉起服务。# 确认 dockerd 二进制存在 ls -l /usr/bin/dockerd # 手工启动 dockerd前台运行观察日志 dockerd --hostunix:///var/run/docker.sock # 确认可以连接后CtrlC 结束用 systemd 管理 systemctl start docker这里有个常见误解要说明docker命令和dockerd是两个程序前者是客户端后者是守护进程客户端永远只负责把请求发给守护进程它自己不会去启动容器。如果你解压出来的 tar 包里只有docker而没有dockerd那它只算半个交付包。我在 3.3 节写过最简 systemd 服务文件的写法遇到这种包先把服务文件补上再谈后面的使用。4.5 现象镜像加载进去了但容器一启动就立即退出docker run -d nginx执行成功容器状态却显示Exited (0)或者Exited (1)。原因分两类一类是镜像本身没问题但启动命令需要前台进程你手动指定的命令把进程跑后台了另一类是内网机器 SELinux 处于 enforcing 状态容器挂载或网络初始化被策略拦截退出码是 1。解决先看日志再查 SELinux不要上来就重建容器。# 查看容器退出日志 docker logs CONTAINER_ID # 检查 SELinux 状态 getenforce # 临时切换到 permissive 模式确认是不是 SELinux 拦截 setenforce 0 docker start CONTAINER_IDdocker logs是第一步它能告诉你进程退出前最后写了什么setenforce 0是排查手段切到 permissive 后如果容器能正常启动那问题就锁定在 SELinux 策略上。内网生产环境不建议长期 permissive更合适的做法是把需要用到的端口通过semanage port -a -t docker_port_t -p tcp 端口加入策略或者按 docker 官方文档给存储目录设置正确的 SELinux 标签。5. 把离线安装流程固化成脚本从手工 step 到一条命令交付踩过上面这些坑之后我给客户交付离线包时不再手工一步步敲命令而是把整个流程写进一个安装脚本和 rpm/tar 包放同一目录。这个脚本现在是我离线部署的标准起点。#!/bin/bash set -e cd $(dirname $0) echo [1/4] 安装 Docker rpm 包 yum localinstall -y docker-*.rpm echo [2/4] 启动并设置开机自启 systemctl enable docker systemctl start docker echo [3/4] 加载目录下所有镜像 tar 包 find . -maxdepth 1 -name *.tar | xargs -n1 docker load -i echo [4/4] 验证版本与镜像列表 docker version --format Server: {{.Server.Version}} docker images脚本里的细节值得说一下。set -e让脚本在任意一步失败时立即退出避免装到一半没发现错误继续往后跑。cd $(dirname $0)保证无论在哪个目录执行脚本都能切换到脚本所在目录也就是 rpm 包和 tar 包所在的目录。第三步用find xargs而不是for循环是因为xargs -n1每次只传一个文件给docker load -i文件名里有空格也不会出错我用for i in *.tar时踩过文件名带空格的坑$i会被拆成两个参数load 直接失败。第四步的docker version --format只输出 Server 版本字段方便自动化脚本后面做版本判断。这个脚本不是万能药如果目标机器的 yum 源本身有问题yum localinstall可能尝试去外网拉依赖如果这份离线包里的 rpm 不完整第二步systemctl start docker会失败。我通常在步骤二后面再加一段检查逻辑用systemctl is-active docker判断服务状态不活跃就输出错误并退出。从那以后我每次交付离线 Docker 环境都强制走一遍这条流程环境检查、yum 本地安装、服务拉起、镜像加载、版本验证五步串成一行命令。这套脚本帮我少处理了至少十次现场突发的依赖问题也把交接成本压到了最低希望帮到你。本文还有配套的精品资源点击获取
返回列表