尧图精选

Ubuntu自定义镜像制作:从rootfs构建到SD卡烧录全流程

🕒 发布时间:2026/10/1 14:23:27 📁 来源:尧图网络
1. 先把制作镜像这件事想清楚你要做的到底是什么很多刚接触 Ubuntu 的开发者一说制作镜像就以为是把 ISO 文件拷进 U 盘或者用软碟通把官方镜像写入存储卡。这其实只是烧录官方镜像不是真正意义上的制作镜像。我在实际项目里被问到最多的场景是这几类手里有一块 ARM 开发板比如 RK3588、树莓派、全志系列官方提供的 Ubuntu 镜像要么版本太老要么预装了一堆用不上的东西公司内部要批量部署几十台同一型号的 x86 工控机希望每台的系统分区、预装软件、SSH 配置完全一致还有一种是离线环境内网机器无法访问 Ubuntu 官方源需要提前把带有所需软件包的系统做成一个可直接写入的镜像文件。如果你也属于上面任何一种情况这篇文章就是写给你的。我会完整走一遍从零构建 Ubuntu 根文件系统、打包成磁盘镜像、再烧录到 SD 卡或硬盘的流程所有命令都是我在树莓派、RK3399 和 x86 工控机上实际验证过的。先区分两个概念这对后面理解每一步做什么很重要官方 ISO 镜像这是一个安装媒介它的作用是启动电脑、引导安装程序然后把系统解压安装到目标磁盘上。ISO 不能被直接当成系统盘运行Live 模式例外但那是另一套机制。可烧录的系统镜像磁盘镜像这是一个目标磁盘的完整快照包含分区表、文件系统、引导程序、根文件系统。用 dd 或 Etcher 把它写入 SD 卡后卡插进设备就能直接启动。本文做的是第二种。制作它的核心链路是构建根文件系统rootfs→ 设计分区布局 → 把内容写入镜像文件 → 烧录到物理介质。这个流程初看复杂但拆解开就是几个独立步骤。我建议你按顺序执行不要跳步尤其是 chroot 配置阶段少一步后面启动时就要花几倍时间排查。2. 动手之前的硬件确认与环境准备2.1 明确目标架构arm64 和 amd64 不可以混用制作镜像最容易犯的第一个错误就是忽略了目标设备的 CPU 架构。x86 的 Ubuntu 镜像拷到 ARM 开发板上是起不来的反过来也一样。确认架构的方法很简单如果设备能进系统执行uname -m。常见的输出有三种x86_64Intel/AMD 桌面机、服务器、工控机aarch64ARMv8 及以上的 64 位芯片RK3399、RK3588、树莓派 4B/5 都是这一代armv7l32 位 ARM 芯片树莓派 2 时代或更早的板子选定架构之后所有软件包的下载、工具链的选择都要跟着走。例如在 x86 的 PC 上为树莓派构建系统就必须借助 QEMU 模拟 ARM 环境具体方法下面会说。2.2 推荐使用 Ubuntu 22.04/24.04 LTS 作为构建宿主构建镜像的宿主机就是你现在用的电脑不必和目标架构一致但系统版本我建议使用 20.04 以上的 Ubuntu LTS或者 Debian 11/12。原因有两个第一构建 rootfs 的核心工具debootstrap在较新的系统里版本更新对 Ubuntu 24.04noble等新版本的支持更完整老版本 debootstrap 可能不认新 Ubuntu 的源结构。第二qemu-user-static 在较新内核上配合 binfmt_misc 更稳定交叉 chroot 时不容易出现莫名其妙的段错误。如果你的宿主系统是 Windows 或 macOS可以先装一台 VMware/VirtualBox 虚拟机跑 Ubuntu再在虚拟机里做。我早期就是在 VMware 里完成的整套制作流程没有什么障碍。2.3 安装构建工具debootstrap 与 QEMU以 Ubuntu 宿主为例先把依赖装上sudo apt update sudo apt install -y debootstrap qemu-user-static binfmt-support \ rsync wget parted dosfstools xxd这里解释一下几个工具的角色debootstrap制作最小 rootfs 的主工具它会从 Ubuntu 源下载指定版本的软件包解压到目标目录完成系统骨架的搭建。qemu-user-static让 x86 机器可以运行 ARM 程序。chroot 进 ARM rootfs 执行apt、dpkg时其实就是靠它在背后翻译系统调用。binfmt-support 注册脚本让内核自动识别 ELF 程序的架构并将其交给对应的 QEMU 解释器。安装/usr/bin/qemu-aarch64-static后通常还要执行一次update-binfmts --enable qemu-aarch64Debian 系默认已启用但最好确认一下。注意一个细节qemu-user-static 的特殊之处在于它提供的是静态编译版本即使 chroot 环境的动态库不全也能运行。这也意味着如果你要把 ARM rootfs 打包成镜像给真实硬件用应该把qemu-aarch64-static从 rootfs 里删掉因为它在真实 ARM 硬件上没有任何作用反而会误导排查。还有一个容易被忽略的点如果用debootstrap的第二阶段在 chroot 里修系统宿主的binfmt_misc内核模块必须是加载状态。一般 Ubuntu 桌面系统默认识别 ARM 可执行文件但如果你的宿主比较精简可能需要手动加载sudo modprobe binfmt_misc ls /proc/sys/fs/binfmt_misc/看到目录不为空就可以继续了。3. 用 debootstrap 构建最小 Ubuntu 根文件系统3.1 选择好挂载目录并下载核心软件包整个流程的第一个大动作是创建 rootfs 的存放目录并运行 debootstrap。我习惯把构建目录集中放在~/image-build下rootfs 直接用rootfs命名方便后续引用。mkdir -p ~/image-build/rootfs sudo debootstrap --archarm64 --foreign --variantminbase \ noble ~/image-build/rootfs \ http://ports.ubuntu.com/ubuntu-ports如果你构建的是 x86_64 系统把--arch换成amd64源换成http://archive.ubuntu.com/ubuntu即可。这条命令里的参数按顺序拆开看--archarm64目标架构--foreign关键参数表示只下载并解压软件包不进行 chroot 配置。因为在 x86 机器上直接对 ARM rootfs 执行 chroot 里的 post-install 脚本会失败你还未注册 QEMU所以第一步只能做解压第二步再借助 QEMU 完成配置。--variantminbase最小化安装不装文档、不装标准工具包只保留 dpkg/apt 核心。后面需要的软件包我们用apt install按需补充。nobleUbuntu 24.04 的代号。Ubuntu 22.04 是jammy20.04 是focal选 LTS 就好。ports.ubuntu.com是 ARM、RISC-V 等非 x86 架构使用 Ubuntu 软件源的官方入口。下载时间取决于网络通常 3~10 分钟。命令结束时rootfs 里应该已经有一套/bin、/usr、/etc等目录骨架。3.2 注册 QEMU 并执行第二阶段配置接下来把静态 QEMU 复制进 rootfs再 chroot 进去执行配置sudo cp /usr/bin/qemu-aarch64-static ~/image-build/rootfs/usr/bin/ sudo chroot ~/image-build/rootfs /debootstrap/debootstrap --second-stage第二阶段会执行所有软件包的配置脚本需要几分钟。如果这一步报错九成原因出在 binfmt_misc 没生效。可以用一个简单的命令验证sudo chroot ~/image-build/rootfs /bin/true如果返回正常说明 QEMU 调用成功如果报cannot execute binary file就是 binfmt 没注册成功。3.3 在 chroot 环境里定制系统第二阶段完成后rootfs 已经是一个可用的最小系统了。接下来的所有定制都可以通过 chroot 进行。我建议先把宿主机的 DNS 和网络信息带进去否则 chroot 里apt update可能解析不了域名sudo mount --bind /dev ~/image-build/rootfs/dev sudo mount --bind /dev/pts ~/image-build/rootfs/dev/pts sudo mount --bind /proc ~/image-build/rootfs/proc sudo mount --bind /sys ~/image-build/rootfs/sys sudo cp /etc/resolv.conf ~/image-build/rootfs/etc/resolv.conf然后一次性进入 chroot执行下面的配置。有一个使用技巧我把下面所有配置写成一个bootstrap.sh脚本放在 rootfs 根目录再在 chroot 里执行能避免多次进出 chroot 造成的遗漏。sudo chroot ~/image-build/rootfs进入之后切换软件源。/etc/apt/sources.list里的默认源是构建时写入的不同地区的下载速度差异很大。可以换成国内源比如清华 TUNA、阿里云这一步对于后续安装大量软件包节省的时间非常可观。以 24.04 的 ports 源为例cat /etc/apt/sources.list EOF deb http://mirrors.tuna.tsinghua.edu.cn/ubuntu-ports/ noble main restricted universe multiverse deb http://mirrors.tuna.tsinghua.edu.cn/ubuntu-ports/ noble-updates main restricted universe multiverse deb http://mirrors.tuna.tsinghua.edu.cn/ubuntu-ports/ noble-security main restricted universe multiverse EOFx86 机器记得把ubuntu-ports改成ubuntu路径完全对应。接着apt update apt install -y systemd systemd-sysv udev kmod net-tools iproute2 \ openssh-server network-manager locales sudo vim curl wget \ wireless-tools wpasupplicant这组软件包决定了系统能不能正常启动和登录不要精简掉。systemd-sysv尤其关键它提供/sbin/init程序没有它系统启动时会报Failed to execute /sbin/init。然后创建用户、设置密码、启用 SSHuseradd -m -s /bin/bash ubuntu echo ubuntu:ubuntu | chpasswd echo root:root | chpasswd usermod -aG sudo ubuntu # 允许 root 使用 SSH按需开启日常建议保持禁用 echo PermitRootLogin yes /etc/ssh/sshd_config systemctl enable ssh设置时区和语言环境ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime echo Asia/Shanghai /etc/timezone sed -i s/# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/ /etc/locale.gen locale-gen update-locale LANGen_US.UTF-8配置 fstab。这一步非常关键而且容易踩坑。fstab 决定了内核挂载根文件系统时哪些分区要自动挂载cat /etc/fstab EOF # file system mount point type options dump pass PARTUUIDXXXX-01 /boot vfat defaults 0 2 PARTUUIDXXXX-02 / ext4 defaults 0 1 EOF那个PARTUUIDXXXX-01现在先占位等你确定了分区布局和磁盘的 PARTUUID 之后再替换成真实值。这一步千万别偷懒直接写/dev/mmcblk0p1这种设备名因为设备名在不同的启动阶段、不同的 USB 插拔顺序下会变化/dev/sda 变成 /dev/sdb 是常有的事但 PARTUUID 在同一个磁盘内是固定不变的。配置网络。如果目标是树莓派这种需要 WiFi 的场景NetworkManager 更适合。如果是工控机接网线networkd 也够用。我个人习惯全用 NetworkManager因为它提供了nmcli后续排查网络非常直观systemctl enable NetworkManager清理 APT 缓存和临时文件apt clean rm -rf /var/lib/apt/lists/* rm -rf /tmp/*然后退出 chrootexit到这里rootfs 的构建已经完成。你可以用du -sh ~/image-build/rootfs看一眼体积minbase 加上述软件包通常会在 700MB~1GB 之间。如果你的目标存储空间有限可以用apt-get autoremove --purge再清一轮但不要手动删库文件否则后面安装任何包都会报依赖错误。4. 设计分区布局并制作镜像文件4.1 计算镜像容量留足余量是基本原则在创建空白镜像文件之前先算一算需要多大空间。一个基础 Ubuntu rootfs 约 1GB但我们还需要 boot 分区、交换分区可省、以及系统运行时的日志和临时文件空间。我推荐这么算总大小 rootfs 当前体积 * 1.5 boot 分区大小(建议 256MB~512MB) 200MB 冗余比如 rootfs 是 1GB那镜像文件建议做到 2GB 左右。如果你要预装 Docker、开发工具链rootfs 体积会膨胀到 3~4GB镜像就按同样的比例扩大。注意镜像文件不是越大越好。写入时间、SD 卡兼容性、后续压缩传输的耗时都跟大小正相关。够用就行不要拍脑袋建一个 16GB 的镜像除非你的需求里确实有那么多数据要放。用truncate创建稀疏文件是比较推荐的做法它不会立即占用真实的磁盘空间只在写入数据时按需分配truncate -s 2G ~/image-build/ubuntu.img4.2 用 fdisk 划分 boot 分区与 root 分区接下来给这个空白镜像写入分区表。我采用经典的两分区布局第一个是 FAT32 格式的 boot 分区存放内核、设备树、引导文件第二个是 ext4 格式的 root 分区存放整个 rootfs。为什么不把 /boot 直接放在 ext4 根分区里因为某些 ARM 平台的引导程序比如树莓派的 VideoCore GPU 固件、Rockchip 的 miniloader并不会解析 ext4 文件系统它们只认 FAT32。这个约束不是 Ubuntu 设计的而是底层 SoC 的 BootROM 决定的。理解了这个逻辑你就知道为什么大多数 ARM 板卡的镜像顶部分区都是 vfat。# 挂载镜像为 loop 设备得到 /dev/loop0 sudo losetup -fP --show ~/image-build/ubuntu.img sudo fdisk /dev/loop0在 fdisk 交互界面中依次输入以下命令o新建一个空的 DOS 分区表MBRn→p→1创建主分区 1起始扇区默认2048即 1MB 对齐大小输入512Mt→ 输入c把分区 1 的类型改为 W95 FAT32 (LBA)n→p→2创建主分区 2起始扇区默认大小直接回车用完剩余空间w写入分区表并退出执行完w后运行lsblk /dev/loop0能看到loop0p1和loop0p2两个分区节点。如果你像我一样用了新版 util-linuxfdisk 可能会默认创建一个 GPT 分区表那也没问题ARM 引导程序大多兼容 GPT只是个别老旧的 SoC BootROM 不认建议还是用 MBR 最稳。给两个分区创建文件系统sudo mkfs.vfat -F 32 -n bootfs /dev/loop0p1 sudo mkfs.ext4 -L rootfs /dev/loop0p2-L是给文件系统写卷标。卷标对后续定位分区有一定帮助也方便你忘了哪个分区是干嘛的时候用blkid一眼认出来。4.3 用 rsync 把 rootfs 灌入镜像文件系统建好后把镜像的分区挂载到临时目录把构建好的 rootfs 同步过去。这一步我强烈推荐用rsync而不是cp -a因为 rsync 对大目录的同步效率更高而且如果中途失败重跑时能够断点续传。mkdir -p /mnt/rootfs_mnt sudo mount /dev/loop0p2 /mnt/rootfs_mnt sudo rsync -aHAX ~/image-build/rootfs/ /mnt/rootfs_mnt/ sudo mkdir -p /mnt/rootfs_mnt/boot sudo mount /dev/loop0p1 /mnt/rootfs_mnt/boot注意-a保留权限和符号链接-H保留硬链接Ubuntu 某些库文件之间是硬链接关系丢了会导致系统异常-X保留扩展属性SELinux 标签、ACL 等Ubuntu 默认不强制 SELinux但保留没有坏处。同步完成之后把 qemu 静态文件从 rootfs 中删除已经是真实目标平台了不需要模拟器sudo rm -f /mnt/rootfs_mnt/usr/bin/qemu-aarch64-static然后把 fstab 里的 PARTUUID 占位符换成真实值sudo blkid /dev/loop0p1 sudo blkid /dev/loop0p2拿到两个分区的 PARTUUID 后编辑/mnt/rootfs_mnt/etc/fstab替换占位字符串。如果你的 target 平台需要特殊的内核与设备树文件比如树莓派的kernel8.img、bcm2711-rpi-4b.dtb或者 RK3588 的boot.img、dtb/rockchip/*.dtb把它们拷贝到/mnt/rootfs_mnt/boot/对应位置。这部分内容因硬件而异我在第六章里会单独细说。确认无误后卸载所有挂载点sudo umount /mnt/rootfs_mnt/boot sudo umount /mnt/rootfs_mnt sudo losetup -d /dev/loop0到这一步ubuntu.img已经是一块具备完整 Ubuntu 系统的虚拟硬盘了。可以随时用 dd 写入 SD 卡或硬盘。4.4 验证镜像完整性后再烧录烧录前先做一次全力检查。重新把镜像挂到 loop 设备上跑一遍文件系统检查sudo losetup -fP --show ~/image-build/ubuntu.img sudo fsck -f /dev/loop0p1 sudo fsck -f /dev/loop0p2如果没有输出错误说明文件系统是健康的。接着挂载检查关键文件是否存在sudo mount /dev/loop0p2 /mnt/rootfs_mnt ls /mnt/rootfs_mnt/bin/init 2/dev/null || ls /mnt/rootfs_mnt/sbin/init只要init存在通常是指向 systemd 的符号链接系统启动的第一关就过了。全部验证完后记得卸载写保护sudo umount /mnt/rootfs_mnt sudo losetup -d /dev/loop05. 烧录到 SD 卡工具、命令与防呆操作5.1 最稳妥的方式还是 dd但它要求你足够小心Linux 下最直接、也最容易被骂的方式就是 dd。它在烧录时不做任何校验成败全靠镜像本身质量和设备的正确性。正因如此烧录前必须确认目标设备名这一步做错后果是灾难性的。我的防呆流程是这样的# 1. 先看当前有哪些块设备 lsblk -o NAME,SIZE,MODEL,TRAN # 2. 插入 SD 卡后再次执行 lsblk找到新增的那一项 lsblk -o NAME,SIZE,MODEL,TRANTRAN列能看到设备传输类型usb、sata、mmc一目了然。新增的那个设备名就是我们需要的比如/dev/sdb。注意是 /dev/sdb 而不是 /dev/sdb1dd 必须整盘写入写分区会丢失分区表。另外可以用一个更直观的方式确认插卡前后各执行一次lsblk用 diff 对比输出新增的设备就是目标。这一步多花十秒钟能避免手滑覆盖整块硬盘。确认目标无误后执行sudo dd if~/image-build/ubuntu.img of/dev/sdb bs4M statusprogress oflagsync convfsync参数说明bs4M每次读写 4MB是性能和稳定性的主流平衡点statusprogress显示实时进度oflagsync convfsync确保数据真正写入物理介质后才返回避免 write-back 缓存导致的假完成dd 结束后执行sync再等待几秒钟然后查看分区是否被识别sudo partprobe /dev/sdb lsblk /dev/sdb如果看到两个分区并按预期大小出现烧录成功。5.2 Windows/macOS 下的替代烧录工具如果你的开发环境是 Windows最省心的工具是 balenaEtcher。它提供可视化界面选中镜像、选中目标设备、烧录不容易出错。它默认也会在写入后做一遍校验。Rufus 也可以但对整盘镜像写入的支持不如 Etcher 直观Rufus 更适合做安装 U 盘。至于 Win32DiskImager在读写速度上明显偏慢如果不是老项目沿用不建议再用了。macOS 下同样推荐 Etcher或者用命令行dd命令格式和 Linux 类似只是目标设备名是/dev/rdisk2这样带r前缀的原始磁盘节点。对 macOS 的 dd 一定要多加小心macOS 的设备命名方式和 Linux 完全不同/dev/disk0 是系统盘烧错几乎等于重装电脑。建议无论用什么工具烧录完成后都执行一次fsck或重新挂载检查文件这是很多教程不会强调的步骤。5.3 烧录后的第一次启动验证清单插卡上电之前先把验证清单理清避免启动失败后手忙脚乱串口或 HDMI 输出是否能看到 U-Boot 日志ARM 平台通常是串口树莓派可以直接 HDMI内核是否解压并挂载 rootfs看到VFS: Mounted root (ext4 filesystem)就说明分区没问题systemd 是否启动到 multi-user.target能看到登录提示符即可网络是否正常能否 ping 通网关如果卡在某个位置优先查看 U-Boot 传递的内核参数。ARM 平台的/boot里通常会有一个cmdline.txt或者是 extlinux.conf 文件里面的root参数必须指向我们配置的 root 分区。比如consolettyS0,115200 rootPARTUUIDXXXX-02 rw rootwaitrootwait参数很关键。它告诉内核等待存储设备就绪后再挂载根文件系统没有它SD 卡这类慢速设备经常在启动早期还不可见导致内核 panic。6. 我在实际烧录中踩过的坑与解决记录6.1 PARTUUID 与设备名的混用问题我最早做树莓派镜像时直接在 fstab 里写了/dev/mmcblk0p1。在树莓派上相安无事因为它的 SD 卡接口固定是 mmcblk0。但同一套镜像拿到 USB SD 读卡器启动的 x86 工控机上内核把 SD 卡识别成了/dev/sdafstab 里写的/dev/mmcblk0p1根本不存在启动直接进入 initramfs 紧急 shell。后来我统一改成 PARTUUID无论设备名怎么变只要分区属于同一块磁盘PARTUUID 就不变。改完后再也没出现过这类问题。具体操作是先在宿主机上拿到两个分区的 PARTUUID烧录后在目标机上用blkid核对一致再启动。这样跟设备名彻底解耦。6.2 烧录目标选错覆盖了数据盘这个教训比较惨痛。当时我同时插着 USB 移动硬盘和 SD 卡读卡器lsblk看了一眼看到/dev/sdb大小接近就下了 dd 命令结果把移动硬盘的数据全写了。从那以后我形成了一套自己的强制规范烧录前先弹出所有不相关的 USB 存储设备用lsblk -o NAME,SIZE,MODEL,TRAN确认型号而不仅仅是大小执行 dd 前再跑一次fdisk -l /dev/sdX看分区表跟记忆中的目标做交叉验证这套流程看起来啰嗦但在批量烧录几十张卡的场景下多花的一点时间完全可以接受。毕竟任何一张卡烧错返工成本都远高于这十几秒。6.3 镜像文件越来越大稀疏文件与压缩的取舍用truncate创建的稀疏文件虽然在文件系统层面不占空间但一旦被 dd 写到 SD 卡整张卡都会被填满未写入的区域是零。如果只给它分配 2GB 的空间但 rootfs 只用了 1.2GB那剩余 800MB 全是零既浪费存储也不优雅。更好的做法是在镜像制作阶段就只建够用的大小多出的空间等烧录后用growpart扩展到 SD 卡的真实容量。ARM 平台一般需要 initramfs 里带 growpart 工具或者在首次启动时通过 systemd 服务自动扩展。如果你需要这个能力在 chroot 阶段就安装cloud-guest-utils和growpart然后在/etc/systemd/system/下写一个 one-shot 的扩展服务。分发镜像时用压缩能够显著减小传输体积。对全零区域xz的压缩比非常高xz -9 -k ubuntu.img压缩后通常能减少一半以上体积。接收方解压后直接 dd 即可。发布镜像的同时附上sha256sum让使用者校验完整性能避免很多镜像损坏类的假故障。6.4 ARM 平台引导程序的差异不是有 rootfs 就能启动这是专门提醒想给 ARM 开发板做镜像的读者。不同厂商的引导方式差别很大树莓派引导流程是 BootROM 读取 SD 卡第一个 FAT 分区里的start4.elf和fixup4.dat再由这些固件加载内核。所以树莓派的 /boot 里必须有这两个文件缺一个都起不来。RockchipRK3399/RK3588通常需要 idbloader.img、u-boot.itb 等引导文件放在分区起始的特定偏移位置用 dd 单独写入而不是简单地拷贝。官方 SDK 里一般有update.img的制作脚本会一并处理。Allwinner全志需要boot.scr和uEnv.txt之类的 U-Boot 脚本指定内核加载地址和设备树文件。如果你只是想把 Ubuntu 装到树莓派上直接用树莓派官方 Ubuntu 镜像套壳修改是最省力的路径。如果一定要从零做需要先去厂商的 SDK 文档里确认引导文件布局这部分内容没法在本文里统一覆盖因为每一家的 BootROM 行为都不同。7. 把镜像做成可升级的分发物做好的镜像通常是给多台设备用的。直接发一个 2GB 的 ubuntu.img 当然可以但在实际工程里我更推荐把镜像和权限还原分开管理。具体做法是保留一份最小化的基础镜像包含最基本的系统、网络、SSH需要部署新机器时把基础镜像烧录进去然后通过 Ansible 或 Shell 脚本注入每台机器的独立配置hostname、IP、SSH key、业务软件。这样团队里的其他人拿到镜像后不需要再关心系统内部结构只需要跑一遍配置脚本即可。这个模式在公司内批量部署工控机时尤其好用。另外镜像制作流程本身值得用脚本固化下来。我自己把前文的步骤整理成了一个build.sh每次要出新版本 Ubuntu 的系统时只需改一下版本代号和目标架构跑一遍就能得到新镜像。这样既能追 Ubuntu 的版本更新也能保证流程的可重复性。脚本化还有另一个好处如果有人问你这个镜像里做了哪些定制把脚本给他看比对着系统一个个翻命令要清晰得多。如果你打算长期维护多个镜像比如同时维护 arm64 和 amd64建议给每个镜像都配一个version文件记录创建时间、基础版本、已装软件包列表。这个文件在排查问题时能省下大量时间。
上一篇/下一篇内容由系统自动关联 返回资讯列表 →