☰
Kylin ISO转Docker镜像:离线环境容器化构建指南
2026/10/22 4:45:47 网站建设 项目流程

很多搞容器化的朋友应该都遇到过这种需求:手头有一个Kylin系统的ISO安装包,想把它直接变成一个Docker镜像,而不是先去装一台虚拟机、再慢慢往里灌软件做快照。尤其是做国产化适配、离线交付、或者要复刻一套和生产环境完全一致的容器运行环境时,这种“从ISO直接构建Docker镜像”的路子非常实用。

我最早接触这个场景是在一个适配项目里,某公司要求所有中间件和业务应用必须跑在Kylin容器中,但官方仓库里又找不到现成的Kylin基础镜像,网络环境还受限,不能随意从公共仓库拉取。当时翻了不少资料,试过用虚拟机安装再打包,也试过用debootstrap的思路处理rpm系的系统,最后踩出了一条比较顺的路径:把Kylin ISO里的根文件系统完整解出来,再用docker import导入成本地镜像。

这篇文章我把这套方法完整复述一遍,基于Docker 20.10.7环境,结合Kylin ISO的目录结构特点,从原理拆解到实操命令再到排错技巧,尽量每个细节都讲透。

1. 为什么要废这个劲:从ISO构建镜像的核心思路与方案选型

1.1 这条路解决的是什么问题

很多人第一反应是:直接docker pull一个Kylin镜像不就行了?但实际场景里往往没那么简单。

  • 内网环境根本没有公共仓库镜像源,离线环境连不了外网。
  • 某些定制版Kylin系统,官方压根没有发布对应的Docker镜像,只有ISO安装包。
  • 业务方要求“容器环境要和物理机/虚拟机里的系统完全一致”,包括内核版本以外的所有文件、库、工具链、配置风格。

这时候,从ISO构建镜像就成了一个非常可靠的兜底方案。整个过程不需要联网,只要有一份ISO文件,就能生成一个自带完整根文件系统的Docker镜像。

1.2 安装介质里藏着什么秘密

理解Kylin ISO的目录结构,是解决“能不能直接转成镜像”的关键。Kylin系统的ISO,本质上是引导安装程序的启动盘。安装程序运行时,真正的“系统本体”往往以压缩包或只读文件系统的形式隐藏在特定目录中。

常见的情况是:

  • /LiveOS/目录下存在一个巨大的squashfs.img,里面打包了Live系统完整的根文件系统。
  • 或者/root/、/images/等目录下存在installer.img之类的安装镜像文件。

换句话说,ISO不是直接用,而是要去里面把“已经装好的系统的根目录”挖出来。这也是整个方案的核心突破口:用squashfs镜像解压出来的内容,拿到Docker里重新打包。

1.3 对比其他几种方案,为什么选import

我在项目里实际对比过三种方案,各有优劣,但最终都殊途同归。

方案思路优点缺点
虚拟机装系统再快照打包先在虚拟机里装好Kylin,装完以后把整个根目录tar下来,再docker import环境最接近真实机器,可自定义预装软件耗时极长,虚拟磁盘占空间大,操作繁琐,还得处理虚拟机工具残留
用debootstrap类似工具直接构建根目录针对Debian系很成熟,但Kylin是RPM体系,工具链不匹配能生成最小化根文件系统对RPM系的支持弱,依赖解析容易出问题,手动处理很麻烦
从ISO中解包根文件系统再导入直接取官方ISO里的现成rootfs,再docker import速度快、无操作系统安装过程、完全复刻系统文件需要理解ISO结构,解包后要手动做容器化适配

选择第三种方案后,整体效率提升非常明显,一条命令就能搞定根文件系统提取,后续全是修修补补的细活。这篇讲的就是这条路。

2. 准备工作:环境、工具与前置检查一个都不能少

2.1 宿主机环境要求

我的宿主机环境是较常见的Linux服务器,Docker版本正好是20.10.7,通过内网离线安装。这里必须提醒一下,Docker 20.10.7虽然比较“老”,但处理docker import这种基础指令完全没有问题,甚至可以说兼容性很好。

宿主机本身建议也使用同体系的Linux系统,因为后续挂载ISO、处理squashfs需要内核支持相关文件系统。不过如果宿主机是别的Linux发行版,只要装了squashfs-tools和tar,也能正常完成解包操作。

关键检查项:

  • Docker服务状态正常:systemctl status docker确认是running。
  • 宿主机有root权限,因为挂载ISO和解压都会涉及系统级操作。
  • 磁盘空间充足。这一点别忽略,一个几GB的ISO解压后根文件系统可能膨胀到十几GB,再加上后续tar包、docker镜像,至少预留20GB以上空间比较稳妥。

2.2 需要安装的工具

整个流程依赖的工具其实不多,但缺少哪一个都会卡壳。

# 检查是否已安装squashfs-tools rpm -qa | grep squashfs # 未安装时用包管理器安装 yum install -y squashfs-tools

squashfs-tools最主要提供unsquashfs命令,用来解包squashfs.img。这里我建议大家提前确认一下版本,太老的squashfs-tools对高版本压缩算法支持不好,解包时会报Unsupported option之类的错误。

另外还需要tar、mount、losetup这些基础命令,这些绝大多数系统都自带,不需要额外处理。

2.3 把ISO文件拷到目标服务器

生产环境里,ISO文件常常存放在文件服务器或者Windows跳板机上,需要先传到Linux服务器。这个过程建议用scp或内网共享挂载,操作前先确保传输完整性,用md5sum或sha256sum做一下校验。

md5sum Kylin-Desktop-V10-SP1-2024.iso

校验这一步绝对不要偷懒,我见过有人ISO没传完就急着挂载,结果squashfs.img解压到一半直接报CRC错误,既浪费时间又容易怀疑人生。

2.4 明确Docker 20.10.7的适配性

为什么标题里特意强调Docker 20.10.7?因为这个版本处于一个比较微妙的时间点:它支持较新的OCI标准,同时又不强制要求镜像必须包含某些特殊元数据。

构建Kylin镜像时,我们用的是docker import,它本质上不执行RUN、CMD这些指令,只是把tar包直接转换成镜像。这意味着即使根文件系统里有某些不标准的东西,Docker也不会在构建阶段卡住,兼容性上限完全由运行时决定。

提示:如果你用的是更新版本的Docker,比如24.x甚至25.x,这套流程完全通用,docker import的核心行为这么多年基本没变过。

3. 核心实操全流程:从ISO到Docker镜像一步步来

3.1 第一步:挂载ISO并查看目录结构

先把ISO挂载到指定目录,没有目录就自己创建。

mkdir -p /mnt/iso mount -o loop /root/Kylin-Desktop-V10-SP1-2024.iso /mnt/iso ls /mnt/iso/

正常情况下能看到类似这样的目录内容:

boot EFI isolinux LiveOS repodata Packages etc

其中重点检查LiveOS目录,因为这里大概率躺着我们想要的东西。

ls /mnt/iso/LiveOS/

有些版本会看到squashfs.img,有些版本叫rootfs.img或installer.img。如果是squashfs.img,下一步就是解包;如果是一个ext4格式的img,那就要用mount直接挂载或者用guestfish提取,这两种情况我在第四节会补充说明。

3.2 第二步:解出squashfs.img里的根文件系统

先用unsquashfs把它解到一个工作目录。这一步耗时取决于ISO大小和服务器磁盘性能,几GB的文件一般几分钟内能完成。

mkdir -p /opt/kylin-rootfs unsquashfs -d /opt/kylin-rootfs /mnt/iso/LiveOS/squashfs.img

解压完成后检查一下目录内容:

ls /opt/kylin-rootfs

正常的Linux根目录骨架就出来了:bin、etc、usr、var、home等目录都在。这就说明提取成功。

这里提醒一个细节:不要直接在解包出来的目录上改东西,先导入Docker再改。原因很简单,解包目录是普通文件夹,没有容器运行时限制,改了以后不一定能完整保留权限和特殊文件属性。

3.3 第三步:用tar打包根文件系统

在/opt/kylin-rootfs的上级目录,执行打包命令。注意别把目录本身路径打进包,需要在根目录内操作:

cd /opt/kylin-rootfs tar --numeric-owner --xattrs -cf /root/kylin-rootfs.tar .

参数说明一下:

  • --numeric-owner:保留数字形式的UID/GID,避免换环境后因用户映射混乱导致权限错乱。
  • --xattrs:保留扩展属性,Kylin系统里很多文件依赖capabilities和selinux属性,丢了会出问题。

打包过程中如果出现“file changed as we read it”的警告,通常是有进程还在写这个目录,最好确认没有其他任务在占用解压目录。

3.4 第四步:docker import生成镜像

打完tar包,后面的操作就清爽了:

docker import /root/kylin-rootfs.tar kylin:v10

正常情况下输出一个镜像ID。用docker images查看:

docker images | grep kylin

看到有kylin且标签为v10就行。这一步如果报错,常见原因是tar包路径有问题,或者tar包内没有完整的etc/目录。

3.5 第五步:验证镜像能不能启动

导入镜像只是第一步,真正关键的是验证容器能否正常交互:

docker run -it --rm kylin:v10 bash

如果能跳进容器的bash提示符,并且执行cat /etc/os-release能看到Kylin系统信息,基本宣告构建成功。然后再检查几个基础命令是否可用:

cat /etc/os-release which yum which dnf df -h

到这里为止,一个可用的Kylin基础镜像就建好了。不过先别急着用它跑业务,后面还有几个坑等着踩。

4. 镜像生成后的关键配置与验证

4.1 容器内的时区、语言和DNS设置

直接从ISO解包出来的根文件系统,时区和语言通常保持安装默认值。容器里面如果不设置时区,日志时间戳会跟本地区时间对不上,排查问题时分外痛苦。

运行容器后,先做基础配置:

ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime echo "LANG=zh_CN.UTF-8" > /etc/locale.conf

DNS设置直接改/etc/resolv.conf也行,但Docker默认会覆盖这个文件。正确做法是在构建最终镜像时写入配置,或者在运行容器时通过--dns参数指定。

4.2 建设性的建议:第一次import后不要直接交付

docker import生成的镜像,文件系统是原封不动的rootfs,很多东西不适合直接进生产环境。我习惯的做法是,先以这个镜像为基础,启动一个临时容器,在容器里做完系统初始化后再commit成第二个镜像。

docker run -it --name kylin-init kylin:v10 bash

在容器里依次处理:

  1. 清空临时文件和缓存:yum clean all,删除/var/cache/下的残余。
  2. 配置yum源为可用的内网源或保持离线独占。
  3. 安装业务依赖的基础软件包。
  4. 创建需要预先存在的用户和目录。

完成后commit:

docker commit kylin-init kylin:v10-base

这样交付出去的镜像,比直接import出来的干净得多。

4.3 镜像体积与层的关系

导入的Kylin基础镜像通常体积不小,一个完整rootfs打包导入后很可能超过2GB。这不是异常现象,ISO里包含的库和基础工具非常齐全,代价就是镜像体积大。

解决体积问题可以分两步走:

  • 第一步:在容器内清理缓存和临时文件后commit,能瘦掉一些。
  • 第二步:用docker export导出容器快照,再用docker import重新导入,所有中间层都会塌缩成一层,镜像文件会变干净。

4.4 版本信息的反复确认

容器里执行:

cat /etc/kylin-release

确认系统版本和宿主机需求一致。不同版本的Kylin对应的包管理器和glibc版本不同,做国产化适配时需要提前确认这些参数,避免开发完拿去现场跑直接报“缺少GLIBC_XX”。

5. 实操中踩过的坑与排查技巧

再顺的流程,实际操作中也免不了踩坑。我把处理过程中整理的高频问题列成速查表,方便对照处理。

问题现象可能原因处理方法
unsquashfs报错:Unsupported optionsquashfs-tools版本太老,不支持新版压缩算法升级squashfs-tools到4.4以上再试
docker import完成后镜像ID无效tar包路径包含根目录本身,例如打成/root/前缀cd到根文件系统目录内再执行tar .
容器启动后提示Failed to mount cgroup容器缺少systemd特权能力,与rootfs本身无关运行时加--privileged或按需挂载cgroup
yum源无法使用原系统源指向安装盘路径,容器内不可用注释掉无效源,添加内网或离线源配置
找不到systemctl命令有些最小化Kylin镜像未安装systemd用/usr/sbin/init或直接安装systemd
容器启动白屏/闪退根文件系统解包不完整核对ISO校验值和解包空间;重新解压背景

5.1 坑一:systemd作为PID 1的坑

ISO解出的rootfs,服务管理是基于systemd的。但Docker容器里直接用systemd作为1号进程并不可靠,除非做特殊配置。

原因很简单:容器默认不是完整的init系统,systemd启动时需要挂载cgroup等一堆它认为理所当然的资源。最直接的规避方式:容器里不用systemd管服务,应用直接以前台进程方式跑,这是Docker的标准做法。

如果业务非要systemd不可,就得在docker run时加特权模式并手动挂载相关目录:

docker run -d --name test --privileged kylin:v10-base /usr/sbin/init

但对大多数微服务和中间件容器,建议避开这个方向,省得自找麻烦。

5.2 坑二:内核模块与硬件相关工具问题

容器共享宿主机内核,rootfs里的内核模块目录实际上是“自欺欺人”。如果业务程序依赖特定内核模块比如ip_vs、overlay等,必须在宿主机上提前加载,容器内操作没有意义。

# 排查容器内某模块是否存在,通常返回空 find /lib/modules/$(uname -r) -name "*.ko"

这个坑在一些做网络组件的项目里特别常见,很多人在容器里装软件、modprobe半天,结果发现根本没权限,实际上是方向搞反了。

5.3 坑三:磁盘空间预估不足

解压一个squashfs时,临时目录空间消耗是ISO的2~3倍,tar包是rootfs压缩后的量,docker层再做一次快照。整个链路下来,一个不足4GB的ISO,最终占用的磁盘空间轻松超过10GB。

建议操作前先把df -h看清楚,至少在三个位置有足够空间:

  • ISO文件存储目录
  • rootfs解压目录
  • Docker数据目录(通常是/var/lib/docker)

5.4 坑四:selinux上下文的丢失

虽然打包命令带了--xattrs,但导入Docker镜像后,容器内外文件系统上下文属性不一定能完整保留。运行容器时如果遇到权限异常,但普通读写权限检查没问题,可以临时加上:

docker run -it --security-opt label=disable kylin:v10-base bash

ZTE、麒麟这类系统对selinux策略比较敏感,这个参数在排查容器内授权问题时几乎必试。

6. 进阶玩法与实际场景适配

6.1 把custom脚本和配置文件固化成层

手动配置完的容器,通过commit生成镜像,这种方式大家都会。但更推荐把整个初始化过程写成一条自动化脚本,以后每次做完rootfs解包就能一键固化,避免人工操作的遗漏。

大致流程:

  1. 从ISO解包出rootfs。
  2. tar导入成base镜像。
  3. 用Dockerfile基于base镜像,写入所有定制内容。
FROM kylin:v10-base ENV LANG=zh_CN.UTF-8 \ TZ=Asia/Shanghai RUN yum install -y telnet bind-utils && yum clean all ADD ./app /opt/app CMD ["bash"]

这种方式比反复commit要可追溯得多,后面换版本、加依赖时改Dockerfile就行。

6.2 离线仓库的适配

离线场景构建镜像时,基础镜像构建完以后,软件包的安装靠内网yum源解决。如果连内网yum都没有,只能在制作rootfs时提前安装好所有软件,做成胖镜像交付。这两条路我都跑过,前者柔性好,后者一次性,业务连续性要求高的建议走前者。

6.3 镜像导出与再分发

构建好的镜像,打包成tar文件分发到其他服务器:

docker save kylin:v10-base | gzip > kylin-v10-base.tar.gz

目标服务器上导入:

docker load -i kylin-v10-base.tar.gz

这个方法同样适用于跨架构服务器,前提是镜像与宿主机架构匹配,arm的镜像不能在x86的Docker里跑。如果需要同时支持x86和arm,需要分别在对应架构的服务器上从ISO构建镜像,再分别save分发。

6.4 多版本并行维护

实际项目里,经常出现业务系统A基于Kylin V10 SP1验证,业务系统B基于V10 SP2适配的情况。建议镜像tag直接带上ISO版本号,比如kylin:v10-sp1、kylin:v10-sp2,不要统一打latest,否则版本漂移问题会让人很崩溃。

docker tag kylin:v10 kylin:v10-sp1 docker tag kylin:v10 kylin:v10-sp2

镜像本身是廉价的,保留多个tag成本极低,带来的版本可追溯价值却很高。

7. 最后再啰嗦一点:实际操作中的几个心得

这套方法运行了很久,最大的感想是“从ISO直接构建镜像”这事,本质上不是技术在卡人,而是对操作系统文件构成的理解在卡人。搞清楚ISO内部结构,知道squashfs里藏着rootfs,后面一切都顺理成章。

实际操作时建议你先在一个不影响业务的目录里从头到尾跑一遍,把ISO结构、解包时间、镜像体积、容器启动效果都摸清楚,再投入到生产交付里。如果解包过程中遇到特殊版本结构,比如不是squashfs而是ext4根的img,用mount -o loop挂载后再打包,效果是一样。

构建完基础镜像,别忘了验证业务软件在容器里的运行状态。很多国产化适配项目里,软件包和底层系统的兼容性本身就存在不确定性,早发现早处理才是这类工作的最优解。

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

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

立即咨询