麒麟V10 X86离线安装Docker一键安装包制作实战

麒麟V10 X86离线安装Docker一键安装包制作实战 简介面向麒麟V10 X86架构的容器离线安装包专为无法访问公网软件源的内网环境设计供运维工程师、容器平台建设人员以及需要交付国产化环境的实施团队使用。整体共4个文件包含两个Shell自动化脚本和两类离线镜像压缩包脚本分别处理Docker引擎安装与数据库镜像导入压缩包则针对Hygon处理器和麒麟系统进行了适配能有效规避依赖缺失、版本冲突等问题。包体大小约280.67MB属于中等体量方便在内网传输和存储。当前已有325人学习下载说明该方案在国产化部署、离线迁移等场景中具有实际参考价值。用户拿到后可直接执行打包脚本快速完成镜像加载、容器启动等流程大幅缩短环境准备时间压缩包中还预置了基础数据库镜像便于在容器内直接初始化数据库服务适合在多台机器上批量部署或作为容器环境练习使用。 搞过信创项目的同事应该都有这个体验一台崭新的麒麟V10 X86服务器放到你面前系统装好了网络是断开的任务是把Docker弄上去还得是能一键搞定、拿去就能用的那种。这就是“麒麟V10 X86 docker 离线一键安装包”这个需求出现的原因。简单说这件事的本质不是发明新东西而是把别人在联网环境下几行命令就能完成的事在断网的内网环境里也能照样完成。麒麟V10虽然是国产系统但X86版本底子是CentOS/RHEL那一套生态Docker官方其实提供了完整的rpm包只是我们在内网拿不到。所以核心工作就落在两件事上一是在联网机器上把Docker本体和依赖全部收集齐二是把这些包打包成脚本让目标机器上跑一下就能装完、配置好、还能直接导入离线镜像。这篇文章我把我实际做这套离线安装包的完整过程写出来包括怎么收依赖、怎么解决缺失的rpm、怎么写一键脚本、踩了哪些坑。适合正在做麒麟V10环境适配、内网交付、批量部署的运维和研发同学。1. 为什么需要离线一键安装包麒麟V10环境下的真实痛点1.1 麒麟V10的生态与Docker安装的特殊性银河麒麟V10分成桌面版和服务器版X86架构下本质上跟CentOS 7/8的血缘关系很近。很多人一开始想得很简单既然跟CentOS兼容那直接把CentOS的docker-ce.repo配上去yum install不就行了问题就在这。很多生产环境、涉密内网、专网环境根本不允许访问外网yum源是失效的。哪怕你手工下载了docker-ce的rpm包docker-ce-cli、containerd.io、docker-compose-plugin以及一堆底层依赖库比如libcgroup、policycoreutils-python这些缺一个就装不上。我之前在公司内网装的时候第一次就栽在依赖上报错信息乱七八糟最后老老实实回联网机器把依赖全部拉下来才解决。另外麒麟V10本身的光盘镜像里是不带Docker的系统自带的软件源里也没有docker-ce这个包。这就意味着你没法从系统自带的repo里找到一个干净的安装路径。1.2 离线部署的核心应用场景我总结了一下做离线一键安装包基本跑不掉这几个场景内网/专网交付客户机房物理隔离别说外网有时候连运维跳板机都管得严随身带个安装包是最省事的。批量重复部署一次交付不是一台机器可能是十台二十台。每台都手工去敲命令、配环境时间成本太高也容易出偏差。脚本化以后一台机器五分钟搞定。版本一致性管理在线yum install有个问题今天装的和下周装的Docker版本可能不一样。离线包把版本固定在rpm包里谁来了装的都是同一个版本排查问题的时候少了很多变量。我做这个离线包的时候核心思路就是在一台能联网、且系统版本跟目标机器一致的麒麟V10 X86机器上把Docker的rpm包和全部依赖拉下来做成一个本地YUM仓库然后写一个install.sh脚本把本地仓库配置、依赖安装、服务启动、镜像导入这些步骤串起来。整个过程做完以后目标机器上只需要把安装包目录拷过去执行一条命令。2. 离线安装包的技术选型与整体方案设计2.1 两种主流方案对比rpm包集合与静态二进制做Docker离线安装网上能搜到的主流做法有两类rpm包集合和官方静态二进制包。这两种我都试过各有优劣。rpm包集合是把我说的docker-ce、containerd.io这些包以及它们的所有依赖全部收集到一起在目标机器上通过本地YUM源或者rpm命令安装。优点是很贴近系统原生的安装方式用systemd管理服务跟系统的兼容性最好缺点是你得花时间把依赖关系理清楚漏一个都不行。静态二进制包是直接从Docker官方GitHub Release里下载docker-x.x.x.tgz解压以后把docker、dockerd这些二进制文件拷贝到/usr/bin下面然后自己写systemd服务文件。优点是收集成本低一个tar包就搞定缺点是服务管理、启动参数、环境变量都得自己写而且没有经过系统的包管理卸载和升级都比较别扭。我最终选了rpm包集合的方案理由很简单麒麟V10 X86本身是RHEL生态rpm方式装完以后docker就用系统的systemd托管日志、开机自启、资源限制这些都能用系统标准方式去管后续排查问题也方便。静态二进制更适合那种对系统侵入性要求极低的场景。2.2 离线安装包的整体目录结构与制作流程这个离线包我建议按下面的目录结构来组织清晰也好维护docker-offline-install/ ├── packages/ # 存放所有rpm包 ├── docker-images/ # 存放离线镜像tar包 ├── install.sh # 一键安装脚本 ├── uninstall.sh # 卸载脚本可选 └── README.md # 使用说明制作流程大致分四步准备一台联网且系统版本一致的麒麟V10 X86机器用yumdownloader把Docker的rpm包和依赖全部拉下来用createrepo生成本地YUM仓库索引编写安装脚本部署时一条命令完成安装、配置、启动、导入镜像。这套流程的好处是制作一次可以无限复制使用。我后来每次遇到同版本的新机器直接把整个目录scp过去三分钟装一台基本不用动脑子。3. 构建离线仓库从零收集Docker及相关依赖3.1 在联网机器上用yumdownloader收集RPM依赖这是整个离线包能不能成的关键一步。收集rpm依赖我用的工具是yumdownloader它是yum-utils这个包里带的。第一次用的时候先装一下yum install -y yum-utils createrepo然后配置Docker官方仓库。麒麟V10 X86可以直接用CentOS 7或8的docker-ce.repo我用的是CentOS 7的源实测兼容性没问题yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo接下来就是用yumdownloader把Docker的核心包和所有依赖全部拉下来。这里有一个很重要的参数叫--resolve它会自动解析依赖关系把目标包依赖的所有rpm一起下载下来。mkdir -p /data/docker-offline-install/packages cd /data/docker-offline-install/packages yumdownloader --resolve docker-ce docker-ce-cli containerd.io docker-compose-plugin docker-buildx-plugin这条命令执行完packages目录里面会多出二十几个rpm包。除了docker本身的几个包还有像libcgroup、libseccomp、policycoreutils-python这些底层依赖都是Docker运行时需要的。这里要留意一点yumdownloader --resolve有时候会把一些不必要的推荐包也拉下来但这不影响多几个包总比少几个好。3.2 校验依赖完整性并搭建本地YUM源rpm包收集完以后不能直接拿到目标机器上rpm -Uvh *.rpm。为什么因为rpm命令不解析依赖它只会傻乎乎地按你给的顺序装一旦某个依赖在前面没装上后面就报错。更麻烦的是rpm -Uvh --force --nodeps虽然能跳过依赖检查装上去但装完以后Docker可能因为某个库文件缺失启动的时候才告诉你起不来。正确的姿势是在目标机器上建一个本地YUM源让yum命令自己去解析依赖关系。做法是把packages目录拷到目标机器上然后写一个本地repo文件。createrepo /data/docker-offline-install/packagescreaterepo会在packages目录下生成repodata目录这就是YUM仓库的元数据索引。在目标机器上创建/etc/yum.repos.d/local.repo[local] nameLocal Docker Repo baseurlfile:///data/docker-offline-install/packages enabled1 gpgcheck0然后指定只使用这个本地源来安装yum --disablerepo* --enablerepolocal install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin这样yum会自动把本地仓库里所有的依赖包按顺序装好不会出现依赖缺失的问题。我实际操作中还碰到过一种情况目标机器上已经装过老版本的docker或者container-selinux会导致依赖冲突。解决办法是先把老版本卸掉或者在联网机器上把container-selinux也拉下来放进仓库里。3.3 离线镜像的收集与打包内网环境装完Docker以后还不能直接run镜像因为镜像仓库也访问不了。所以你还得顺便把要用到的镜像一起打进去。这一步通常在联网机器上完成docker pull mysql:8.0 docker pull redis:7.2 docker save -o /data/docker-offline-install/docker-images/mysql-8.0.tar mysql:8.0 docker save -o /data/docker-offline-install/docker-images/redis-7.2.tar redis:7.2这里有个细节值得说docker save和docker export是两回事。save是保存整个镜像包括层信息和历史记录export是导出容器的文件系统丢掉了镜像的层结构。离线分发一定要用save因为load回来以后镜像原封不动tag、entrypoint、环境变量都在。export导出的包在另一台机器上load不了只能import成一个新的镜像很多配置会丢失。镜像tar包体积通常比较大建议打成tar.gz再放进包里拷盘和网络传输都能快不少gzip /data/docker-offline-install/docker-images/*.tar4. 编写一键安装脚本安装、配置、启动全流程4.1 安装脚本的核心逻辑离线仓库准备好以后剩下就是写install.sh脚本。脚本的逻辑其实不复杂但要考虑得细不能光是把安装命令串起来。我的脚本核心步骤是检查环境、配置本地YUM源、安装Docker、写daemon.json、启动服务、导入镜像。一个精简但可用的install.sh长这样#!/bin/bash set -e BASE_DIR$(cd $(dirname $0) pwd) REPO_FILE/etc/yum.repos.d/local-docker.repo PACKAGES_DIR$BASE_DIR/packages # 1. 检查是否root if [ $EUID -ne 0 ]; then echo 请使用root用户执行此脚本 exit 1 fi # 2. 配置本地yum源 cat $REPO_FILE EOF [local-docker] nameLocal Docker Repo baseurlfile://$PACKAGES_DIR enabled1 gpgcheck0 EOF # 3. 清理缓存并安装 yum clean all yum --disablerepo* --enablerepolocal-docker install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin # 4. 配置daemon.json mkdir -p /etc/docker cat /etc/docker/daemon.json EOF { registry-mirrors: [https://docker.m.daocloud.io], exec-opts: [native.cgroupdriversystemd], log-driver: json-file, log-opts: { max-size: 100m, max-file: 3 }, storage-driver: overlay2 } EOF # 5. 启动服务并设置开机自启 systemctl daemon-reload systemctl enable --now docker # 6. 导入离线镜像 if ls $BASE_DIR/docker-images/*.tar.gz /dev/null 21; then for img in $BASE_DIR/docker-images/*.tar.gz; do gunzip -c $img | docker load done fi docker version echo Docker安装完成这里有几个地方要特别说明一下。yum clean all这句千万别省因为目标机器上可能缓存了旧的repo数据不清理的话yum可能会去用缓存里的旧索引导致找不到本地仓库里的包。另外set -e这个参数很重要它让脚本在任意一条命令失败时立即退出不会继续往下跑。离线安装最怕的就是装到一半失败了但脚本还在傻乎乎地往下执行最后你也不知道到底装没装上。4.2 daemon.json关键配置项与镜像加速daemon.json是Docker守护进程的核心配置文件这里面每一项都有讲究。我先说最常用的几个registry-mirrors配置的是镜像加速地址。内网环境虽然拉不了docker hub的镜像但如果有能访问的外部仓库或者公司自建的harbor这里可以配成harbor地址。如果没有特殊要求填一个公共加速地址也能用但千万别指望在内网环境里通过它拉公共镜像那是拉不下来的离线包的镜像还是得靠load。exec-opts配置cgroup驱动为systemd。这个在麒麟V10上尤其重要如果这里不配Docker默认用cgroupfs驱动而系统的systemd用的是cgroup混合模式两边不一致的话在容器里操作systemd相关命令可能会报错。麒麟系统虽然跟CentOS同源但systemd的版本和配置有些小差异我在测试时就碰到过类似问题后来统一改成systemd驱动才稳定。log-driver和log-opts限制日志大小。Docker默认的日志是json-file如果不在daemon.json里限制最大尺寸和文件数量跑时间长了/var/lib/docker/containers目录会被日志撑爆。我在生产上见过很多次服务器磁盘满的故障十有八九都是容器日志没限制。这里配了max-size100m、max-file3每个容器最多不超过300MB日志。storage-driver配overlay2这是当前主流且性能最好的存储驱动。但如果目标机器的内核版本太旧或者文件系统是xfs且不支持ftype1overlay2会起不来。遇到这种情况Docker会自动回退到vfs但vfs性能很差对磁盘空间要求也高所以还是建议确保文件系统满足条件。4.3 服务管理与验证启动服务这步直接用systemdsystemctl daemon-reload systemctl enable --now docker systemctl status docker验证是否安装成功核心看三个指标docker version能正常输出、docker info里Storage Driver是overlay2、docker run一个本地镜像能正常起来。我在脚本最后加了docker version这句这样部署人员一眼就能看到服务端和客户端版本号确认安装成功。关于开机自启enable --now这个参数是同时完成启用和启动两件事。麒麟V10默认是systemd管理开机自启直接靠enable就行。这个跟Windows上装Docker Desktop是两码事很多从Windows转过来的同事会习惯性去找桌面图标在Linux服务器上根本没这回事Docker就是作为一个系统服务跑在后台的。5. 常见问题与避坑实录5.1 依赖缺失与冲突症状安装时提示Requires: xxx is needed by docker-ce-xxx或者包冲突。原因收集rpm的时候没有带上全部依赖或者目标机器上已经装了不同版本的container-selinux、docker相关包。解决回到联网机器上用yumdownloader把报错里提到的依赖包名追加下载重新createrepo。如果是老版本冲突先yum remove掉老的docker和containerd再执行install.sh。这里我有一条个人经验收集依赖的时候与其用yumdownloader不如用yum install --downloadonly --downloaddir指定目录的方式装一遍。这个命令会在装着装着的时候把依赖一起下载下来比yumdownloader更彻底因为它会从尝试安装的完整依赖树里去收集。我后来做离线包都用这个命令。yum install docker-ce docker-ce-cli containerd.io docker-compose-plugin --downloadonly --downloaddir/data/docker-offline-install/packages5.2 服务启动失败症状systemctl start docker报Job for docker.service failed或者docker info执行的时候报Cannot connect to the Docker daemon。排查先看日志命令是journalctl -xeu docker也可以直接看/var/log/messages里跟docker相关的记录。常见的坑有三个第一个是overlay2存储驱动不支持。判断方法是dmesg | grep overlay如果提示文件系统不支持d_type就说明xfs格式的时候没有开启ftype1。要么格式化磁盘要么换ext4要么在daemon.json里临时改成vfs应急但vfs真的只是应急。第二个是iptables问题。麒麟V10默认用的iptables版本或者nftables配置可能跟Docker的预期不一致导致Docker创建iptables链失败。排查方法是用journalctl看日志里有没有iptables相关报错。如果确认是这个问题可以先把firewalld停掉再启动docker试试但生产环境能不能停防火墙要按客户要求来不能拍脑袋。第三个是内核参数问题。Docker需要转发IPv4流量/etc/sysctl.conf里必须有net.ipv4.ip_forward1。检查方法sysctl net.ipv4.ip_forward返回0就不行。临时改sysctl -w net.ipv4.ip_forward1永久改就把参数写进/etc/sysctl.conf再sysctl -p。5.3 镜像导入后的Tag为None症状docker load成功但docker images看不到镜像或者镜像名是 。原因docker save的时候没有指定tag或者save时用的镜像名和load时解析出来的不一致。解决docker load -i xxx.tar以后如果镜像显示为 可以用docker tag手动打标签。更聪明的做法是在联网机器上save之前把镜像重新tag成项目规范的名字比如registry.internal/ns/mysql:8.0这样save出来的tar包自带完整tagload进去直接能用。这里还要注意save和export的区别前面已经讲过再补充一个实操细节load的镜像是保留仓库名和tag的如果save时是ubuntu:20.04这种load进来镜像名就是ubuntu:20.04不会自动改成别的。所以离线镜像包的命名一定要在打包阶段就倒腾好不然到内网里再改tag很痛苦。5.4 版本与架构匹配最后一个坑也是最能避免却最常犯的X86的包只能装X86的机器。听起来是废话但信创项目里ARM和X86混着用的场景很常见。麒麟V10有AMD64版也有飞腾、鲲鹏的ARM64版这两者的rpm包完全不通用。做离线包之前先用uname -m确认目标机器的架构再在对应架构的联网机器上制作。另外麒麟V10的SP1、SP2、SP3版本之间底层库的版本有差异。我在SP2上做的包拿到SP3的机器上装虽然大部分能用但偶尔会碰到libseccomp版本过旧导致容器权限受限的问题。有条件的话最好在跟目标机器完全一致的版本来制作没有条件也要注意版本差异可能带来的兼容性风险。我个人在这套离线包上踩过最多的一个坑其实是“做的时候很认真用的时候很随意”。离线安装包这种东西做好了不是终点关键是版本记录和维护。我强烈建议在安装包里附带一个version.txt文件记录Docker版本、rpm包收集日期、镜像清单和对应的目标系统版本。这样过了半年哪怕最初做这个包的人已经不在项目上了后来的人看到version.txt也能快速判断这个包能不能用在新的机器上。最后再分享一个小技巧如果你的内网环境是多台机器批量部署可以先在一台机器上完整跑一遍install.sh然后把那台机器的/var/lib/docker目录整个打包带走在目标机器上安装完Docker以后直接解压覆盖。这样做的好处是连镜像load这步都省了几十个镜像的导入时间直接归零。这种做法的前提是Docker版本一致我已经在很多批量交付场景里验证过效率提升非常明显。本文还有配套的精品资源点击获取