Rocky 10云镜像首启慢两分钟?systemd-analyze揪出UUID残留真凶

发布时间:2026/9/8 5:59:15
Rocky 10云镜像首启慢两分钟?systemd-analyze揪出UUID残留真凶 1. 现象描述云镜像首次启动慢最先背锅的总是网络在实际运维工作中云镜像首次启动慢是一个出现频率并不低的问题。现象往往很统一从创建虚拟机到 SSH 能够连通中间隔着一段让人心里发慌的等待时间有时候是几十秒有时候直接超过两分钟。更麻烦的是这个时间差并不稳定同一份镜像在同一个云平台上反复重置每次的启动耗时可能还不一样。由于“云镜像”本身带有较强的网络属性很多人第一反应就是网络配置是不是有 problem比如说 DHCP 获取地址超时、DNS 解析等待、NetworkManager 服务启动异常、cloud-init 等待网络就绪等等。于是排查方向一上来就扑到网络配置上查看网卡配置文件、检查 NetworkManager 日志、反复测试 DHCP 服务但最后往往会发现网络本身一点问题都没有。本文要展开的就是这样一个排障案例Rocky 10 云镜像首次启动慢两分钟初步判断像是卡在网络但真正定位后却发现元凶并不是网络。文章会完整给出排障思路、关键分析工具、定位过程和最终优化方案。对经常接触云镜像制作、系统初始化、自动化交付的运维和开发同学来说这套排查方法是可以直接复用和扩展的。适合阅读本文的读者使用 Rocky Linux 或其他 RHEL 系发行版作为云镜像的运维工程师。在 OpenStack、KVM、公有云、私有云环境下做过镜像定制的人。遇到过“首启慢但不知道慢在哪”的开发者。想学习 systemd 启动性能分析方法的系统爱好者。读完本文你能够掌握如何用systemd-analyze快速判断启动瓶颈。如何区分“网络等待”和“非网络原因”。如何从 systemd 单元、日志、初始化脚本中定位真正耗时项。如何针对首启场景做合理优化同时不破坏系统稳定性。先说结论这类问题在首次启动时尤其常见因为首次启动会触发很多“一次性”初始化工作例如密钥生成、磁盘扩容、日志持久化目录创建、随机数生成等。这些工作如果设计不合理就会表现为启动耗时异常。而这其中很大一部分工作和网络半毛钱关系都没有。2. 环境准备与复现方法在动手排查前需要一个稳定的复现环境和一套明确的测量方法。否则“慢两分钟”只是一个模糊的主观感受无法量化也不方便前后对比。2.1 环境信息本文的排障过程基于以下环境实际项目中版本可能不同但排查思路完全适用项目说明操作系统Rocky Linux 10RHEL 10 系虚拟化平台常见云平台 / KVM / OpenStack镜像类型官方云镜像或基于官方镜像二次定制启动方式默认 GRUB 引导UEFI 或 BIOS 均可网络模式DHCP 获取地址常规云环境需要注意的是Rocky Linux 10 尚处于快速迭代期不同小版本、不同内核版本之间systemd 服务名和默认行为可能有差异。所以本文更加侧重通用排障逻辑具体服务名以你手中系统实际显示为准。2.2 精确测量启动时间不要靠“感觉”判断慢不慢。进入系统后第一件事是获取启动时间基线。systemd-analyze预期输出类似Startup finished in 3.452s (kernel) 2min 1.368s (initrd) 8.583s (userspace) 2min 13.403s graphical.target reached after 2min 13.401s in userspace从这行输出马上就能看到两件事慢在哪一阶段kernel、initrd、userspace 哪个阶段耗时最长。总耗时是多少方便和优化后的结果做对比。上面这个输出里initrd阶段占了 2 分 1 秒这就意味着在切换到根文件系统之前初始化内存盘阶段已经卡了很久。这是非常关键的线索因为很多人在这种时候只顾着盯着用户态的服务日志看而忽略了 initrd 阶段。再看每个 systemd 单元的具体启动耗时systemd-analyze blameblame会列出所有单元的耗时从高到低排序。这是后续定位“罪魁祸首”最直接的命令之一。再看关键链路的依赖关系systemd-analyze critical-chaincritical-chain会显示从系统启动到最终graphical.target的关键路径每一条依赖链条上各单元的耗时都会列出来比blame更适合理解“为什么这个服务要等这么久”。最后查看本次启动的完整日志按时间顺序排查异常journalctl -b如果觉得日志太长可以只看本次启动中标记为 error、warning 或 timeout 的记录journalctl -b -p warning这一组操作完成之后已经能够确定慢在哪个阶段下一步就是判断这个阶段里到底发生了什么。3. 排查“网络嫌疑”如何确认不是网络的锅因为这次问题的表象很容易让人联想到网络所以先快速把网络相关疑点排除掉。排障过程要讲究证据不能凭直觉下结论。3.1 检查网络管理服务状态Rocky Linux 10 默认使用 NetworkManager 管理网络。首先确认网络服务本身是否已经启动并且是否处于 active 状态systemctl status NetworkManager如果 NetworkManager 本身启动很快也没有卡住说明问题大概率不在网络管理层。3.2 检查是否存在网络等待单元RHEL 系系统中存在一个常见的“隐性网络等待点”NetworkManager-wait-online.service。这个服务会等待网络连接“完全就绪”后才允许后续服务启动。在很多环境里这个等待服务会白白消耗几十秒甚至更长时间特别是 DHCP 没有立即返回地址、或者存在多个网卡但只有一个在使用时。systemctl status NetworkManager-wait-online.service查看该服务本次启动耗时systemd-analyze blame | grep wait-online如果该服务耗时非常高确实存在网络等待嫌疑。但这里要提醒一句即便这个服务耗时长也不代表“网络配置有问题”。它更像是一个“关卡”真正耗时的是它背后的等待逻辑。如果确认这个服务没有参与关键链路或者网络环境本身不需要等待可以在确认不会影响网络连通性的前提下考虑禁用systemctl disable NetworkManager-wait-online.service这只是一种手段是否禁用的前提是确认你的系统不依赖该等待逻辑。在云环境里很多场景下 SSH 连通性并不依赖这个服务因为网卡在很早的阶段就已经获得地址了。3.3 检查 DHCP 和 DNS 是否异常用普通命令确认实际网络状态快速判断 DHCP 和 DNS 有没有问题ip addr show ip route show cat /etc/resolv.conf如果地址、路由、DNS 都已经正常获得说明网络功能本身没有问题。这里体现出来的排障思路是网络通信正常 ≠ 启动过程中没有网络等待。3.4 检查 cloud-init 是否在等待网络云镜像场景下cloud-init 堪称“首启慢第一嫌疑人”。cloud-init 的网络模块会在启动早期执行包括等待网络就绪、从 metadata 服务拉取网络配置等内容。查看 cloud-init 各阶段的耗时systemd-analyze blame | grep cloud-init也可以查看 cloud-init 的日志确认是否有超时journalctl -u cloud-init-network -b如果 cloud-init 网络阶段没有报错只是等待了一些时间那就要看等待的是什么。很多时候它等的是 metadata 服务而 metadata 服务在某些网络环境下响应不够及时这就容易造成“首启慢”的假象。不过如果在我们的案例中经过以上检查网络层面一切都正常那么下一步就应该把目光从网络转向系统其他部分也就是下一节的内容。4. 根因定位真正耗时点在哪里在排除了网络配置本身的问题之后我们需要重新回到systemd-analyze的输出从数据中寻找真正耗时点。下面的分析过程是本次排障的核心。4.1 阶段定位慢在 initrd回顾前面systemd-analyze的输出Startup finished in 3.452s (kernel) 2min 1.368s (initrd) 8.583s (userspace) 2min 13.403sinitrd阶段耗时 2 分 1 秒这个数字非常可疑。正常情况下initrd 阶段应该只有几秒到十几秒。如果 initrd 阶段异常耗时常见原因包括initrd 内的某个 systemd 单元在等待设备或服务超时。磁盘设备扫描、LVM 扫描、多路径设备等待时间过长。内存盘内缺少某些驱动导致反复尝试加载。根文件系统设备在等待某个延迟设备如网络块设备、慢速 SCSI 设备。这时要进入 initrd 内部做分析不能只看用户态日志。4.2 查看 initrd 内的启动耗时journalctl -b默认显示当前系统的日志但 initrd 阶段的日志比较特殊。我们可以通过重启一次并在启动参数中加systemd.log_leveldebug来获取更详细的信息。不过更简单的方法是先从现有信息看起。Rocky Linux 10 使用 dracut 生成 initramfs。要查看 initrd 内执行了哪些单元可以尝试lsinitrd | grep systemd如果需要查看 initrd 内部某个服务的执行情况可以把 initrd 解包分析。不过对于排障来说最快的路径还是观察启动画面的卡点。在虚拟机的 VNC 或串口控制台上观察启动过程你会发现启动卡在一个非常具体的位置比如卡在等待某个 device。这一步往往能直接暴露出问题所在。如果暂时没有控制台画面也可以从内核环缓冲区获取线索dmesg | grep -E timeout|fail|error | head -20不过dmesg只能显示内核日志对于 systemd 单元级别的超时诊断作用有限。4.3 定位到具体单元等待一个不存在的设备如果能够在控制台看到卡住的画面通常会发现系统停在类似下面这样的界面[ OK ] Started Show Plymouth Boot Screen. [ TIME ] Timed out waiting for device /dev/disk/by-uuid/xxxx.或者是A start job is running for dev-disk-by\\x2duuid-xxxx.device (2min 1s / 2min 1s)这个信息非常关键系统在等待一个 UUID 对应用户设备节点出现但是这个设备一直没出现直到 systemd 达到默认超时时间默认 90 秒或 120 秒才跳过继续启动。在这个案例中2 分钟左右的等待时间刚好对应到 systemd 设备单元的启动超时时间所以表面上的“两分钟卡顿”其实是一个等待超时过程。那么这个 UUID 是谁写入的呢常见来源有两个/etc/fstab里配置了不存在的磁盘分区initrd 内的某个 systemd 单元依赖了某个不存在的设备。检查/etc/fstabcat /etc/fstab再看系统实际识别的磁盘lsblk -f如果 fstab 里存在一个 UUID但在lsblk -f中找不到对应设备那问题基本就水落石出了。造成这种问题的原因往往是制作镜像时绑定了源 VM 的磁盘 UUID或者手动修改 fstab 时写错了 UUID导致每次首次启动都会去等待一个不存在的设备。4.4 确认根因镜像封装时的 UUID 残留这是云镜像场景下非常典型的坑。制作镜像时如果定制者用 chroot 方式进入了文件系统或者直接把原系统的/etc/fstab复制到了新镜像中就很容易把源机器的磁盘 UUID 带过来。目标机器上的磁盘 UUID 与 fstab 中记录的不一致于是启动过程就一直等待旧设备节点。另外还要注意 swap 分区。云镜像中如果 fstab 写了一个 swap 的 UUID但镜像里实际没有这个 swap 分区也会触发同样的等待问题。grep -v ^# /etc/fstab查看每一行是否都能在系统里找到对应设备。如果存在“孤儿”配置立即修正或删除对应行。4.5 为什么首次启动尤其容易踩这个坑这里还需要解释一下为什么“首次启动”更容易踩雷云镜像在模板制作阶段通常是在一台已经运行过的 VM 上进行精简和打包。这台 VM 的磁盘 UUID 会被写进/etc/fstab、/boot/grub2/grub.cfg、initramfs 等位置。从云镜像创建新 VM 时新磁盘会被重新分配一个新的 UUID。如果镜像发布流程没有执行“去 UUID 化”的清理动作新 VM 启动时就会拿着旧的 UUID 去等待设备直到超时。所以这个问题的本质不是网络而是镜像模板中残留的源设备信息。这也是为什么它特别容易骗过没有经验的排障者你查网络半天查不出问题因为网络本来就健康。5. 解决方案清理残留 UUID 与镜像优化确认根因后修复方案就很清晰了。根据场景不同有两种修复路径已经创建的故障 VM可以现场修复。尚未发布的镜像模板应当从源头修正。5.1 现场修复已创建的故障 VM登录系统后先备份 fstabcp /etc/fstab /etc/fstab.bak.$(date %F)然后编辑/etc/fstab删除或修正无效行vi /etc/fstab如果只是普通的/根分区可以改成不依赖 UUID 的方式例如直接使用设备名/dev/vda1但实际生产环境更推荐使用 UUID因为设备名可能随驱动加载顺序变化。正确的做法是填入当前系统真实的 UUIDblkid /dev/vda1用输出的真实 UUID 替换 fstab 中的旧值。如果 fstab 中某一行对应的设备在系统中根本不存在建议直接注释或删除该行。修改完成后执行mount -a该命令会按 fstab 重新挂载所有未挂载的文件系统如果输出没有报错说明配置基本无误。之后重新生成 initramfs避免 initrd 中也残留旧的设备等待逻辑dracut -f最后重启验证systemctl reboot重启后再看启动时间systemd-analyze一般情况下initrd 阶段会从两分钟下降到数秒。5.2 源头修补镜像模板如果你负责维护镜像模板需要在模板发布前就把这类问题扼杀掉。在模板关机前执行以下清理流程。第一用系统当前的真实标识重建 fstab。如果模板系统只有根分区最简单的做法是保留以下内容即可# /etc/fstab # 实际内容请根据你的分区情况调整第二清理 cloud-init 相关的缓存和实例标识。不同发行版的路径不完全一样常见清理命令cloud-init clean rm -rf /var/lib/cloud/instances第三清理机器 ID。如果不清理同一模板生成的所有 VM 会拥有相同的 machine-id可能引发各种诡异问题。rm -f /etc/machine-id或者systemd-machine-id-setup第四清理 SSH 主机密钥。这一步很重要。如果模板中带着原来的 SSH 主机密钥新 VM 首次启动后所有实例的指纹相同安全风险很高。建议在模板关机前删除rm -f /etc/ssh/ssh_host_*新版 systemd 会在首次启动时自动生成新的 SSH 主机密钥。第五清理日志和临时文件避免把源机信息带入新实例rm -rf /var/log/journal/* rm -rf /tmp/*这些清理动作做完之后再关闭模板虚拟机制作新镜像。5.3 不仅限于 UUID其他常见的首启慢原因虽然本文的核心结论指向 UUID 残留但“首启慢”的根因不止这一种。其他容易被误判为非网络问题的原因包括慢的原因表现如何定位解决思路fstab 中存在无效 UUID 或设备启动卡在等待设备超时systemd-analyze blame、journalctl -b修正 fstab重建 initramfscloud-init 等待 metadata 服务启动卡在 cloud-init 阶段cloud-init 日志优化 metadata 服务响应或配置超时SSH 主机密钥生成耗时用户态启动慢systemd-analyze blame模板中预先生成密钥但需注意安全策略熵源不足导致随机数生成卡顿服务启动慢journalctl -b看随机数相关报错安装熵源服务或模拟熵源NetworkManager-wait-onlineinitrd/userspace 进入较慢systemd-analyze blame评估是否需要等待在线合理禁用日志持久化目录首次创建大量文件用户态启动慢journalctl --disk-usage预创建目录结构提前初始化这里只列了常见的几类实际生产环境中还可能有 UDEV 规则等待、LVM 扫描慢、RAID 设备组装超时等情况排查方法论都是一样的先用systemd-analyze定位阶段再逐层下钻。6. 遗留风险与优化建议处理完 UUID 问题后也不要急着收工。云镜像的启动速度和稳定性是一整个体系的事单点修复只是第一步。下面几项优化建议对 Rocky 10 及 RHEL 系云镜像都有实际价值。6.1 谨慎关闭网络等待服务关于NetworkManager-wait-online.service前面提到过可以禁用但这里必须负责任的提醒一句不要在没搞清楚依赖关系的情况下盲目禁用。有些云环境确实不需要这个服务但如果你使用 NFS 根、iSCSI 启动、或者依赖网络挂载的业务禁用该服务会导致后续服务在网卡尚未就绪时就开始执行进而引发挂载失败。更安全的做法不是彻底禁用而是调整其等待策略。可以通过 NetworkManager 的连接配置控制哪些连接需要在线等待nmcli connection modify eth0 connection.wait-device-timeout 1000或者为关键连接设置更高的优先级。这样既保证了网络等待又不会无限期地卡住。6.2 合理使用 systemd 超时设置如果某些服务确实可能因为外部条件延迟但不希望整个启动流程被拖垮可以设置合理的超时时间。例如在指定服务的 unit 文件中加入[Unit] JobTimeoutSec30或者在/etc/systemd/system.conf和/etc/systemd/user.conf中调整全局默认值DefaultTimeoutStartSec30s DefaultTimeoutStopSec30s需要注意的是修改全局超时时间会影响到所有服务必须结合业务整体评估不能为了追求启动速度而把超时设得过短否则会误杀需要较长时间初始化的合法服务。6.3 镜像发布前的自动化体检如果镜像需要频繁发布建议把启动检查自动化。例如发布前用一个临时 VM 从该镜像启动然后自动执行启动时间采集和关键项检查systemd-analyze systemd-analyze blame | head -10 systemctl is-system-running dmesg | grep -i timed out只有这些检查全部通过镜像才允许进入发布流程。这套思路虽然简单但在实际工程中能拦截大量“首启慢”问题成本远低于出了问题再修。6.4 做好启动日志的长期保存启动日志是排障的第一手资料。无论是物理机还是云主机建议开启持久化日志mkdir -p /var/log/journal systemd-tmpfiles --create --prefix /var/log/journal systemctl restart systemd-journald开启后即使重启也能通过journalctl --list-boots查看历史启动记录journalctl --list-boots journalctl -b -1第一次启动慢的问题通常只有首次启动能够复现如果日志不持久化等你开机想去查时日志可能已经丢了。所以在修复完问题之后立刻开启持久化日志是一个非常重要的操作。7. 常见问题与排查清单结合这个案例整理了一份常见问题排查清单方便你在遇到类似现象时快速对照。7.1 快速排查清单操作命令排查目的查看启动总耗时systemd-analyze确定慢在哪个阶段查看各单元耗时systemd-analyze blame找到耗时最高的单元查看关键启动链路systemd-analyze critical-chain理解服务依赖等待关系查看当前启动日志journalctl -b查找错误和超时记录查看历史启动日志journalctl --list-boots对比多次启动差异检查 fstabcat /etc/fstab确认是否有无效设备配置检查磁盘 UUIDlsblk -f/blkid对比 fstab 中的 UUID 是否存在检查网络服务systemctl status NetworkManager排除网络服务异常检查网络等待systemd-analyze blame | grep wait-online判断是否存在网络等待检查 cloud-initjournalctl -u cloud-init-*排除 cloud-init 等待问题7.2 典型误区与更正误区实际情况首启慢一定是网络配置问题网络只是众多可能原因之一需要量化定位禁用 wait-online 一定提速安全禁用前需要评估对依赖网络挂载业务的影响修改 fstab 后不需要重建 initramfs旧 initramfs 中可能残留旧设备等待逻辑需要dracut -f模板镜像可以直接复用原 fstab云镜像场景下极易携带源设备 UUID需要清理和校验第一次启动慢就只查一次日志持久化没开启时重启后现场丢失难以复现排查8. 最佳实践与工程建议从这次排障中可以提炼出几条适用于云镜像项目的最佳实践。8.1 镜像模板要建立“可重复启动”标准一个好的云镜像模板应该是可以从同一份模板无限次创建 VM且行为完全可预期的。要实现这一点模板中就不应该包含任何“单机身份信息”包括机器 ID、SSH 主机密钥、网络配置痕迹、fstab 中的旧 UUID 等。模板发布前至少完成以下动作cloud-init clean rm -f /etc/machine-id rm -rf /var/lib/cloud/instances rm -f /etc/ssh/ssh_host_* rm -rf /var/log/journal/*然后再次检查 fstabgrep -v ^# /etc/fstab确认每一行都指向当前系统真实存在的设备或合理路径。8.2 启动时间要纳入发布验收指标如果你负责大规模云镜像交付建议把“首次启动时间”作为一个明确的验收指标。可以在 CI/CD 流水线里创建临时 VM 启动镜像自动采集systemd-analyze输出如果initrd或userspace阶段超过阈值则镜像发布失败。这种“体检式”的发布流程在长期维护多个镜像版本时非常有效。因为一次性能优化可能在下一轮定制中被无意破坏只有每次都测才能保持镜像质量的稳定性。8.3 排障时永远先量化再定位这次排障最大的经验教训就是不要凭直觉猜测原因也不要凭直觉排除原因。先用systemd-analyze看清慢在哪一阶段再看具体单元最后看日志。每一步都用数据说话排查效率会高出很多。8.4 区分首次启动与后续启动在生产环境的故障处置中还要注意区分“首次启动慢”和“每次启动都慢”。两者的根因往往不同首次启动慢多与初始化任务相关UUID 残留、密钥生成、cloud-init 初始化、日志目录创建。每次启动都慢多与硬件等待、网络依赖、服务启动顺序、资源争用相关。排障时先确认当前观察到的慢是首次还是每次都有能大幅缩小排查范围。8.5 修完立即做回归验证修复完成后建议不要只启动一次就宣布结束。至少进行两到三次冷启动测试并记录每次启动的耗时for i in 1 2 3; do systemd-analyze sleep 2 done通过多次取样确认修复效果的稳定性同时也能发现是否引入了新的随机性问题。9. 总结从“两分钟”到“几秒”的排障复盘这次 Rocky 10 云镜像首启慢的排障核心收获可以概括为三句话网络不一定是首启慢的元凶但先排除网络疑点依然是高效的排障路径。因为网络检查的成本低、结论明确能够快速帮助缩小范围。systemd-analyze是最可靠的定位工具没有之一。它能够把“模糊的慢”变成“具体的阶段、单元、时间”后续的排查只要顺着数据走就够了。云镜像首启慢的很多根因藏在“一次性初始化”逻辑里UUID 残留是最典型但最容易被忽略的情况。修正 fstab、重建 initramfs、清理模板身份信息就能根除问题。最后提醒各位读者遇到“首启慢”不要急着把问题按到网络头上也不要急着在镜像里加各种复杂优化。先量化、再定位、最后最小化改动往往才是最省时间的解法。如果你在 Rocky 或其他 RHEL 系云镜像上也踩过类似的坑欢迎在评论区分享你的排障经历。