news 2026/9/2 4:54:45

麒麟V10离线部署Docker:从RPM依赖到镜像分发的一键实践

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
麒麟V10离线部署Docker:从RPM依赖到镜像分发的一键实践

简介:面向麒麟V10 X86架构的离线一键安装包,专为无外网或网络受限的机房环境打造,解决从Docker引擎到数据库镜像无法在线拉取的难题,适合内网运维、国产化适配及信创项目交付人员快速落地。压缩包共4个文件,核心为2个shell安装脚本,分别负责Docker服务的自动安装与数据库镜像的自动导入;另含tgz/gz格式的Docker镜像压缩包和数据库镜像包,覆盖引擎、运行依赖及常用业务镜像,整体约280.67MB。已有325人学习下载。拿到后可直接执行安装脚本,无需手动处理依赖关系,也无需在离线环境中逐一导入镜像;同时脚本与打包结构清晰,便于根据自身业务替换镜像包或做二次封装。对于需要批量交付麒麟服务器、降低部署时间成本的技术团队而言,是一份即取即用的基础工具包。 接手第一台银河麒麟V10(X86架构)服务器时,我以为装个Docker是十分钟的事,毕竟网上教程一抓一大把。等真正开工才发现,这台机器摆在隔离机房,不通外网,连基础yum源都配不起来,更别说拉Docker官方仓库了。折腾了大半天,最后我把整套方案固化成了一个离线一键安装包,在十多个节点上重复部署,再没出过乱子。这篇文章就把做包的过程、脚本设计思路和现场踩过的坑全部写出来,给同样在麒麟V10上做内网部署的朋友省点时间。

1. 先摸清麒麟V10的家底,再谈离线安装

先说结论:别把麒麟V10当成“CentOS换皮”来对待。我见过太多同事直接从CentOS的教程里复制命令往麒麟上跑,最后多半卡在奇奇怪怪的依赖报错上。麒麟V10虽然对CentOS 8的生态做过兼容,但它的软件仓库、内核参数、系统服务默认配置都和原生CentOS有差异,尤其在安全策略和文件系统默认属性上,经常是离线装Docker时翻车的源头。

1.1 你的麒麟V10是哪个“流派”

登录系统后先执行这两条命令:

cat /etc/os-release uname -a

重点看两点:系统ID是什么,内核版本是多少。麒麟V10常见的上游底座有CentOS系和openEuler系,不同底座对应的可用RPM包并不完全一致。Docker运行要求内核版本在3.10以上,麒麟V10默认内核一般是4.19或5.4,这块基本不用操心,但内核模块是否齐全会影响后续存储驱动的选择。生产环境里我还遇到过内核开了强制安全模块导致容器启动异常的情况,这些都要在装之前心里有数。

1.2 离线安装为什么不能照搬CentOS的包

我最初图省事,直接把CentOS 8下面准备好的docker-ce RPM包拷贝到麒麟V10上,用rpm强制安装——结果containerd.io起来就崩,docker info里看不到存储驱动,日志显示libseccomp版本过低。这类问题在离线环境下特别烦,因为没法临时通过yum补依赖。所以我的经验是:离线包必须在目标机同体系、同架构、同底座版本的机器上生成,这个原则谁违反谁吃亏。如果手头只有CentOS机器,至少要在测试机上完整验证一遍再上生产。

2. 在联网打包机上备齐RPM依赖集合

如果你手头也有一台能联网的麒麟V10 X86机器,那直接把它当“打包机”。如果没有,用一台同版本、同架构的机器也行,但装完后必须在测试机完整验证一遍。打包机的价值在于将在线yum源的所有依赖关系“冻结”下来,变成一组可在离线环境重复使用的rpm文件。

2.1 Docker版本怎么选

选版本是很多人忽略但很关键的一步。别一上来就装最新版,要看目标机器依赖库到底跟不跟得上。

Docker版本依赖复杂度典型场景
20.10.x较低存量系统、追求最稳
24.x中等大部分新项目
27.x及更高较高需要新特性的场景

我最后选的是24.x + containerd.io 1.6.x的组合,功能上满足后续跑MySQL8、Redis、中间件栈,又不至于拉太多新依赖。新版本Docker对iptables、nftables、libseccomp的版本要求更苛刻,在麒麟V10上有时会引入额外风险,没必要为了尝鲜去背这个包袱。

2.2 用yumdownloader一次拉全依赖

在打包机上执行下面这组命令:

mkdir -p /opt/kylin-docker-offline/{rpms,images,scripts} yum install -y yum-utils createrepo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo yum-config-manager --enable docker-ce-stable yumdownloader --resolve --destdir=/opt/kylin-docker-offline/rpms \ docker-ce docker-ce-cli containerd.io iptables libcgroup libseccomp slirp4netns

这里有个麒麟V10特有的坑:它的/etc/os-releaseVERSION_ID往往不是数字,而是“V10”这种字符串,导致docker-ce.repo里的$releasever变量解析成乱值,yum源URL直接404。解决办法是编辑/etc/yum.repos.d/docker-ce.repo,把baseurl里的$releasever手动改成8

yumdownloader --resolve只会下载并写入指定目录,不会安装,所以不会污染打包机环境,这是我喜欢用它的原因。但有个细节:如果打包机上已经装过这些包,yumdownloader可能认为依赖已满足而漏下载,更保险的二选一方案是:

yum install --downloadonly --downloaddir=/opt/kylin-docker-offline/rpms \ docker-ce docker-ce-cli containerd.io

两种方式差别不大,关键是把依赖下得足够全。

2.3 本地yum仓库:离线安装最省心的形态

下下来的rpm如果直接rpm -Uvh *.rpm,依赖顺序稍有不对就会中断。所以我习惯把这些rpm做成一个本地yum仓库:

createrepo /opt/kylin-docker-offline/rpms

然后把下面这段写入目标机的/etc/yum.repos.d/docker-local.repo

[local-docker] name=Local Docker RPMS baseurl=file:///opt/install/rpms enabled=1 gpgcheck=0

在目标机上一条yum install -y docker-ce docker-ce-cli containerd.io就能搞定,yum会自动解析依赖顺序,这是整个一键脚本里最靠谱的一步。需要说明的是,createrepo命令在麒麟V10的默认源里一般就有,但它本身也是一个包,离线目标机上不一定可用,我会把它也放一份在安装包里备用。

3. 一键安装脚本怎么设计才不算“伪一键”

“一键”不是把一堆命令塞进脚本就叫一键。我的标准是:分发到任何一台干净麒麟V10上,一条命令执行完,服务状态、docker info、容器网络全部正常,不需要人工干预。

3.1 脚本主流程与控制逻辑

完整脚本放在安装包的scripts/install.sh里,核心流程分四步:环境检测、清理可能冲突的存量容器运行时、安装并配置Docker、启动自检。关键代码块展示如下:

#!/bin/bash set -e BASE_DIR="$(cd "$(dirname "$0")/.." && pwd)" RPMS_DIR="$BASE_DIR/rpms" if [ "$(id -u)" -ne 0 ]; then echo "请用root执行" exit 1 fi # 环境检测 if ! grep -qi 'kylin' /etc/os-release; then echo "警告:非麒麟V10系统,继续执行但请自行确认兼容性" fi # 清理冲突 rpm -qa | grep -E "^(docker|podman)" | grep -vE "docker-offline" | xargs -r rpm -e --nodeps # 方式一:优先用本地yum仓库 if command -v createrepo >/dev/null 2>&1; then createrepo "$RPMS_DIR" >/dev/null 2>&1 cat > /etc/yum.repos.d/docker-local.repo <<EOF [local-docker] name=Local Docker RPMS baseurl=file://$RPMS_DIR enabled=1 gpgcheck=0 EOF yum clean all >/dev/null yum install -y docker-ce docker-ce-cli containerd.io else rpm -Uvh "$RPMS_DIR"/*.rpm --replacepkgs fi

这里有个小技巧:清理冲突时用xargs -r rpm -e --nodeps,避免在没有匹配包时直接报错中断。麒麟V10有些发行版本默认预装podman-docker,它会提供docker命令软链,这个包如果不清理,后面会和真正的Docker装到一起,非常混乱。

3.2 daemon.json配置里有两个“坑中坑”

安装完成后我会固定写一份/etc/docker/daemon.json

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

第一个坑是cgroupdriver。麒麟V10用systemd管理服务,Docker也建议统一用systemd驱动,否则容器内的进程和宿主机systemd对cgroup的管理会打架,尤其之后如果再引入Kubernetes等上层编排,这个问题会直接导致节点状态异常。

第二个坑是overlay2。麒麟V10默认文件系统通常是XFS,XFS要支持overlay2,必须在文件系统创建时开启ftype=1属性。如果因为历史原因磁盘是旧格式,d_type检测不过,Docker会自动回退到vfs驱动,容器能跑但性能极差。检查命令:

xfs_info /var/lib/docker | grep ftype

如果看到ftype=0,最省事的做法是把data-root指向一个ext4或开启了ftype的xfs分区。

3.3 安装完成的自动校验

脚本最后我会加一段自检,而不是甩个“安装完成”就结束:

systemctl daemon-reload systemctl enable docker >/dev/null 2>&1 systemctl start docker sleep 3 if ! systemctl is-active docker >/dev/null 2>&1; then echo "Docker启动失败,请执行 journalctl -u docker -n 50 查看日志" exit 1 fi echo "Docker版本:$(docker version --format '{{.Server.Version}}')" echo "存储驱动:$(docker info --format '{{.Driver}}')"

这一步能提前暴露大部分问题。离线环境下没有hello-world镜像可拉,所以一般用docker image ls配合之后导入的镜像做验证,不追求一上来就跑容器。

4. 现场安装中我踩过的四个坑

这部分我按“现象—排查链路—解决”的顺序写,方便你遇到问题照着定位。

4.1 缺container-selinux导致Docker冷启动失败

现象:rpm安装结束后,执行systemctl start docker,服务起来没几秒又退出,日志里出现类似error while loading shared libraries: libseccomp.so.2: cannot open shared object fileFailed to start Docker Application Container Engine

排查链路:先执行ldd $(which dockerd) | grep not,看缺哪些动态库;再执行rpm -qa | grep container-selinux,确认selinux策略包是否安装。这个包在离线环境中经常被忽略,因为在线yum安装时它会作为依赖自动补上,但手工下载rpm时只要漏一条命令就会缺失。解决办法是把container-selinuxpolicycoreutils-python-utils都提前放进rpms目录,重新执行安装脚本即可。

4.2 麒麟V10预装的podman“抢”了docker命令

现象:在一台新机器上执行docker --version,居然输出了podman的版本号。后来发现麒麟V10服务器版预装了podman-docker包,它会给系统装上/usr/bin/docker软链和podman运行环境。这种情况如果不做清理就装docker-ce,会出现“docker daemon起不来,但docker命令能执行”的诡异现象。

排查链路:执行rpm -qa | grep -E "docker|podman",看到podman相关包后先卸载:rpm -e --nodeps podman-docker podman,再执行安装脚本。卸载时要确认没有依赖它的业务正在运行,否则会连累服务。这也是为什么我建议在脚本开头做存量清理,而不是只在报错时才处理。

4.3 overlay2不可用,容器性能直线下跌

现象:docker info显示Storage Driver: vfs,或者启动容器时偶发failed to mount overlay: Operation not permitted

排查链路:先执行dmesg | grep -i overlay看内核有没有相关报错,再看xfs_info的ftype参数。麒麟V10默认安装时,如果分区是用旧版mkfs.xfs创建的,确实可能出现ftype=0。离线环境不适合重新格式化整套系统,我的做法是找一个ext4或开启ftype的xfs分区,把data-root指过去。vfs驱动虽然能跑,但每次写操作都会复制整个镜像层,跑MySQL这种重量级容器时IO损耗非常明显,不能忍。

4.4 容器能起来但没有网络

现象:docker run成功,容器里ping任何地址都不通,宿主机却能正常上网。检查ip a发现docker0网桥起来了,但容器侧没有流量。

排查链路分三步走:

  1. 执行sysctl net.ipv4.ip_forward,如果输出0,执行echo "net.ipv4.ip_forward=1" >> /etc/sysctl.conf然后sysctl -p
  2. 执行systemctl status firewalld,如果防火墙开着,Docker在iptables里插入的策略会被firewalld重置,需要systemctl restart firewalld或者临时关掉做验证。
  3. 执行iptables -t nat -L POSTROUTING,确认有没有MASQUERADE链,Docker的SNAT规则被清过也会导致出网失败。

这个坑出现概率不低,因为麒麟V10默认开启firewalld,和Docker的iptables管理策略经常有摩擦。我一般不主动关防火墙,而是确认放行了需要的端口,然后restart一次firewalld让规则重新加载。

5. 让安装包真正“开箱即用”:把镜像一起带过去

Docker本身装完,内网机器还是没有可用的镜像。所以安装包要连镜像一起分发,这一步不做好,“一键安装包”只完成了一半。

5.1 镜像导出导入的细节

在打包机上:

docker pull mysql:8.0 docker pull redis:7.0 docker save -o /opt/kylin-docker-offline/images/mysql-8.0.tar mysql:8.0 docker save -o /opt/kylin-docker-offline/images/redis-7.0.tar redis:7.0

如果想一个文件带多个镜像,可以执行docker save -o all.tar mysql:8.0 redis:7.0。镜像多的时候,建议打tar后再gzip压缩,打包体机能省不少。导入脚本scripts/load_images.sh

#!/bin/bash BASE_DIR="$(cd "$(dirname "$0")/.." && pwd)" for tar in "$BASE_DIR"/images/*.tar; do echo "导入: $tar" docker load -i "$tar" done

这里有个小提醒:docker save出来的tar包是保留镜像历史层的,体积通常比镜像本身大不少。导出前可以先用docker system df看下占用,如果磁盘吃紧,考虑裁剪无用标签或使用docker export+docker import的方式,但后者会丢失历史层和部分元数据,业务镜像不建议这么做。

5.2 安装包最终目录结构与使用

我最终交付的离线包结构大致是:

kylin-v10-x86-docker-offline/ ├── rpms/ # docker及全部依赖rpm ├── images/ # 提前save好的业务镜像 ├── scripts/ │ ├── install.sh │ └── load_images.sh └── README.md # 版本号、构建时间、使用说明

分发后在目标机上执行:

tar -xf kylin-v10-x86-docker-offline.tar.gz cd kylin-v10-x86-docker-offline bash scripts/install.sh bash scripts/load_images.sh

两条命令之后,Docker服务和镜像就位,可以直接docker run。这也是“一键”体验的核心:对现场实施人员来说,只需要解压、执行两个脚本,不需要理解内部依赖关系。

5.3 后续升级维护的个人建议

离线包不是做完一次就完事。我在每个包里都坚持写上版本号、构建日期、依赖清单,避免半年后连自己都忘了包里的Docker是什么版本。升级时只在打包机上重新拉取新版rpm集合,覆盖rpms目录再打包,生产环境执行install.sh即可,脚本里的yum installrpm -Uvh会处理覆盖升级。但容器镜像版本升级要单独管理,不要和rpm升级混在一起。

装完Docker后,建议在目标机上执行一次docker info,重点确认Server Version、Storage Driver、Cgroup Driver三个字段,这三个值不对,后面排查成本会很高。尤其是Storage Driver显示vfs时一定要当场解决,拖到业务上线再处理就非常被动了。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/2 4:53:28

Windows下VideoDownloadHelper 120分钟限制解除实战指南

简介&#xff1a;这款视频下载工具高级版专为谷歌浏览器打造&#xff0c;面向需要在Windows系统上保存长视频的用户。其核心价值在于通过监测网页媒体流自动识别音视频&#xff0c;并解除了原版120分钟的时间限制&#xff0c;非常适合下载电影、纪录片和在线课程等超长内容。资…

作者头像 李华
网站建设 2026/9/2 4:53:22

Android性能调优实战:使用Scene自定义CPU调度实现省电与游戏提帧

在实际 Android 性能调优领域&#xff0c;手动调整 CPU 调度策略是资深玩家和开发者用来平衡设备性能与功耗的常见手段。Scene 作为一款功能强大的系统工具箱&#xff0c;其核心能力之一就是允许用户绕过系统默认的调度器&#xff0c;自定义 CPU 核心的在线状态、频率、调度器类…

作者头像 李华
网站建设 2026/9/2 4:53:18

LangGraph工具调用实战:从零构建大模型智能体核心逻辑

各位读者朋友好&#xff0c;今天我们围绕 LangGraph 的工具调用&#xff08;Tool Calling&#xff09;做一期完整实战拆解。这个话题来自智能体开发中非常核心的一环&#xff1a;当大模型只负责“思考”时&#xff0c;谁来负责“行动”&#xff1f;答案就是工具调用。无论你是在…

作者头像 李华
网站建设 2026/9/2 4:52:39

游戏账号安全代练指南:通行证思维与权限管理实践

1. 先搞清楚“通行证”到底在防什么看到“害怕无良代肝乱动手脚&#xff1f;通行证了解一下”这个标题&#xff0c;很多玩家第一反应可能是游戏里的“通行证”系统。但这里讨论的“通行证”&#xff0c;核心不是游戏内的赛季奖励&#xff0c;而是一种账号安全与权限管理的解决方…

作者头像 李华
网站建设 2026/9/2 4:52:35

Krea AI Slack集成Beta版:团队协作中的实时AI图像生成利器

这次我们来看一个能直接在 Slack 里调用 AI 图像生成能力的工具&#xff1a;Krea AI 推出的 Slack 集成 Beta 版。对于团队协作和创意工作流来说&#xff0c;这绝对是个效率利器。想象一下&#xff0c;在讨论产品设计、营销素材或头脑风暴时&#xff0c;不用离开 Slack 聊天窗口…

作者头像 李华
网站建设 2026/9/2 4:52:23

奶蛙、牛来、肥嘟嘟:“黄色三幻神”谁才是真正的王?

最近互联网上黄色生物严重超标。奶蛙统治了表情包世界一整年&#xff0c;牛来靠一部“烂到出圈”的动画电影杀出重围&#xff0c;同名Meme币$牛来也一度爆火。但你知道吗&#xff0c;就在牛来横扫热搜的同时&#xff0c;另一只黄色生物&#xff0c;正在悄悄完成一场更离谱的逆袭…

作者头像 李华