Rocky 10云镜像首启慢:用systemd-analyze精准定位120秒延迟

Rocky 10云镜像首启慢:用systemd-analyze精准定位120秒延迟
上午在一处内部讨论里看到有人提问从仓库拉了一份 Rocky 10 云镜像实例创建成功后进入系统非常慢控制台已经打印完常规启动日志但 SSH 要等两分钟左右才能连上。群里很快就滑向“网络问题”这个方向有人建议查路由有人建议重新配置静态 IP还有人准备抓包。这类“首启慢两分钟”的现象在云镜像场景里其实经常不是网络链路劣化而是系统启动流程里某个服务把一切卡在了“等待”状态。本文就按这个思路展开排障先不碰网络参数用 systemd 自带工具把启动时间拆开找到那 120 秒到底消耗在哪个单元上再判断要不要修改网络配置。文末会给出一套可复用的云镜像优化操作适用于 Rocky 8/9/10 以及其它使用 systemd 的 RHEL 系发行版。排障思路很简单系统不是“传输慢”而是“等超时”。云镜像首启慢的常见来源基本都集中在等待网络在线、等待元数据服务、等待 SSH 主机密钥、等待 SELinux 重标记这几类。1. 核心排查点速览先给出这张速查表后面的操作都对应到这里的行项目。遇到 120 秒级别的首启延迟优先从下面这些对象入手。排查点为什么会导致首启慢常用验证手段NetworkManager-wait-online等待所有网络连接进入“已连接”状态超时普遍按 90 秒或 120 秒设置systemctl is-enabled、systemd-analyze critical-chaincloud-init 元数据访问启动时请求云平台元数据服务连接不上会连续重试journalctl -u cloud-init.serviceSSH 主机密钥生成镜像未预生成主机密钥首次启动临时生成日志量少但明显ls /etc/ssh/ssh_host_*SELinux 重标记镜像内文件安全上下文缺失整机文件需要重新标定journalctl 中检索 relabel 相关日志云盘挂载与 udev 扫描多路径、磁盘热插拔、设备重命名导致内核等待systemd-analyze plot注意第一行NetworkManager-wait-online 这类服务虽然名字带网络但它慢的原因不是带宽不够而是“等待状态始终没满足”。它背后有非常典型的超时机制这正是“两分钟”这个数字的常见出处。所以在动手改 DNS、路由、静态 IP 之前先把系统启动时间轴打出来看。2. 排障前先把“慢”的边界定清楚“首启慢两分钟”这句话其实不够精确因为不同人看到“慢”的起点和终点不一样。有人从实例创建开始计时到 SSH 能连上也有人从内核开始启动算起到控制台出现登录提示。这两种口径会差出不少时间因为前者还包含云平台调度、磁盘初始化、cloud-init 拉取用户数据等环节。推荐统一成 systemd 的视角关注内核接管之后到 multi-user.target 就绪之间的耗时。这个区间是云镜像排障时最值得分析的一段因为绝大多数“等待型”服务都集中在里。先跑三条基础命令把这段启动耗时拉出来。# 列出本次启动的整体耗时 systemd-analyze # 查看启动过程的时间分布 systemd-analyze time # 查看耗时最长的启动单元 systemd-analyze blame | head -30如果 systemd-analyze 不可用说明当前环境是轻量容器或缺少 systemd 工具链先切换到完整安装的 Rocky 实例再排。后续验证也应该在同一个规格的测试实例上进行避免云平台调度差异影响判断。另外建议在排障时记录三个时间点内核启动时间、用户空间初始化完成时间、SSH 端口可连接时间。云平台控制台的 VNC 截图也可以作为旁证但最终以 journald 的时间戳为准。3. 用 systemd-analyze 把两分钟拆开systemd 系列发行版有一个比直觉好用的地方启动过程不是一团黑盒而是由带依赖关系的 service 组成。任何一个 service 卡住都能在启动时间轴上体现出来。先看systemd-analyze critical-chain它可以直接指出卡在“链路”上的单元。输出大体是一个倒推结构从 multi-user.target 往回列。下面是一段典型格式具体内容以你的环境为准multi-user.target 36.7s └─cloud-init.service 35.1s 100ms └─network-online.target 34.2s └─NetworkManager-wait-online.service 2.1s 30.5s如果你看到的输出里某一行的耗时明显在 30 秒、60 秒甚至 90 秒以上说明根因已经浮出来了。重点看两类单元后缀带-wait-online的服务以及cloud-*开头的 cloud-init 相关服务。继续用systemd-analyze blame看单点耗时 Top 列表。注意blame只显示单个服务的“已用时间”不一定能直接区分“服务主动运行很久”和“服务在等待别的资源”。可以把critical-chain的结果当作依赖链参考两者配合使用。# 查看指定目标的启动关键链路 systemd-analyze critical-chain systemd-analyze critical-chain sshd.service # 生成启动过程 SVG 图表方便快速定位长时间间隔 systemd-analyze plot /tmp/boot.svgSVG 文件可以在浏览器打开也可以直接用scp拉回本地看。图中每个服务是一条横向时间条超过 30 秒的“长条”非常显眼。实际排障里这一步基本能把 90% 的问题定性。4. 用 journalctl 精确到秒定位延迟systemd-analyze 给出的是服务级结果但还需要进一步确认具体卡在哪一次操作上。journald 默认记录了本次启动的完整日志可以根据时间戳逐行核对。# 查看本次启动日志使用单调时间 journalctl -b --no-pager -o short-monotonic | grep -E systemd\[1\]|cloud-init|NetworkManager|sshd-keygen | head -100 # 只看本次启动中的错误和告警 journalctl -b --no-pager -p 3观察相邻两条日志的时间差。如果两行日志之间隔了 60 秒到 90 秒而且附近出现NetworkManager-wait-online或cloud-init的日志说明系统在等待某个外部条件满足超时后才继续往下走。也可用更细分的字段筛选配合 awk 计算连续日志的时间间隔。不同的 systemd 版本输出格式略有差异但思路一致把时间轴拉出来找“空窗”。# 按时间先后打印启动日志便于人工找大间隔 journalctl -b --no-pager -o short-precise --since 2025-01-01 00:00:00如果不想看日志也可以在测试机上用systemctl list-jobs临时观察当前挂起任务。首次启动慢的场景里list-jobs可以显示出仍在等待的 job比如wait-online或cloud-init目标。这个命令适合在另一个 SSH 会话或 VNC 控制台里执行。5. 卡住的位置往往不在“网络传输”上定位到具体服务后下一步是判断它到底在为什么等待。这一节把最常见的几类原因展开说明方便对照日志快速归类。5.1 网络等待型服务名字带网络不等于网络不好NetworkManager-wait-online 的作用是等待所有受管连接进入 connected 状态。云服务器通常只有一张网卡如果这张网卡在 DHCP 分配 IP 之前被标记为“未连接”wait-online 就会进入超时等待。更麻烦的是有些多网卡实例默认有多个连接配置其中某个连接在云环境里根本不存在。NetworkManager 会一直尝试激活这个连接直到超时。这类场景里哪怕你手动配置静态 IP也无法避免等待因为问题不在 IP 获取而在连接状态管理。先验证 wait-online 是否被启用systemctl is-enabled NetworkManager-wait-online.service systemctl status NetworkManager-wait-online.service --no-pageris-enabled返回enabled时再结合 critical-chain 里的耗时基本就能确定是它在拖慢启动。5.2 cloud-init 元数据等待日志像网络本质是云平台对接cloud-init 在首启时会尝试访问云平台的元数据服务比如阿里云、AWS、OpenStack 各自的接口。如果镜像里的 datasource 列表配置过宽或者当前环境没有元数据服务cloud-init 会逐项尝试每次超时后继续试下一个最终表现就是启动过程被拉长。日志上看起来非常像“在访问网络”因为确实有网络请求发生。但它和带宽、丢包、DNS 关系不大属于云平台适配问题。用这条命令可以快速查看 cloud-init 在启动阶段做了什么journalctl -u cloud-init.service --no-pager -b journalctl -u cloud-init-network.service --no-pager -b如果日志里出现大量Retry、Timed out、Trying datasource等关键字说明 cloud-init 正卡在元数据探测上。5.3 SSH 主机密钥生成SSH 连不上但服务已经在跑云镜像是为了分发而打包的通常不保留源机器的 SSH 主机密钥。这样做的目的是防止私钥泄露但也意味着每个新实例第一次启动时要临时生成密钥。生成密钥本身只要几百毫秒到几秒但如果系统熵源不足或者/etc/ssh所在分区 IO 很慢这一过程会被拉长。更关键的是sshd.service 会等待密钥生成完成后再开始监听因此用户看到的现象是“端口没起来”“SSH 超时”。检查方式很直接ls -l /etc/ssh/ssh_host_*如果看到多个ssh_host_ed25519_key、ssh_host_rsa_key文件说明密钥已生成。如果文件为空或只有部分类型说明首启生成还没完成或者生成过程中断。注意不要把同一份 SSH 主机密钥散落到所有实例。安全敏感环境下让每个实例保留独立密钥是正确做法排障时要同时考虑安全和启动速度不要一删了之。5.4 SELinux 重标记镜像文件上下文不完整RHEL 系发行版默认启用 SELinux云镜像打包时如果文件没有正确的安全上下文首次启动就需要重标记整个文件系统。文件数量越多磁盘 IO 越慢耗时越长。日志中会出现relabel、restorecon、selinux相关字样。处理办法是等首启完成重标记后再制作镜像或者在镜像构建阶段执行一次自动重标记。5.5 其它“等待型”服务除了上面几类还有 systemd-random-seed、systemd-tmpfiles、fstrim 和 udev settle 也可能产生明显延迟。它们的共同特点是不是持续吞吐数据而是在等待某个条件变成“就绪”一旦超时就继续往下走。排障时记住一个经验如果某个服务的耗时接近 90 秒或 120 秒基本都是超时等待而不是运算密集任务。这个规律对定位非常有用。6. 几种典型的“冤枉网络”故障模型很多“首启慢”排到最后都会发现网络配置没改任何东西。下面这几类模型值得在排查时优先对照。第一类wait-online超时但主机网络完全正常。你可以在实例启动后用nmcli device status查看网卡状态发现已经 connected。这说明 wait-online 等待的不是当前主网卡而是某个失效连接或额外网卡。此时静态 IP、路由、DNS 都没有问题却依然整体卡 120 秒。第二类cloud-init 反复重试元数据从现象看像“访问外网慢”但用网络测速工具看带宽又正常。这种场景常见于本地虚拟机测试或镜像在云平台之间迁移后 datasource 列表残留。日志特征是 cloud-init 模块逐个尝试多个 datasource每个都超时。第三类能 Ping 通实例但 SSH 端口迟迟不监听。第一反应通常是防火墙或安全组拦截但实际可能只是 ssd 在等待主机密钥生成。安全组规则没问题系统防火墙也没拦就是 SSH 服务本身没就绪。此时在 VNC 控制台或另一条会话里执行systemctl status sshd能看到等待关系。这三类模型覆盖了绝大多数“首启慢两分钟”的云镜像排障场景。核心判断依据不是网络工具而是systemd-analyze和journalctl的时间戳。7. 修复与验证流程找到根因后修复方式要区分“临时救急”和“镜像持久优化”。下面按模块给出可复制的操作。7.1 处理 wait-online 超时如果是 NetworkManager-wait-online 引发的等待最常见的处理有两种一是直接禁用二是给它设置一个更短的启动超时。对于云服务器强烈建议保留基本等待能力但把超时压缩到 15 秒左右避免无限等待。# 临时禁用验证是否为问题根因 sudo systemctl disable --now NetworkManager-wait-online.service sudo reboot# 保留服务但缩短超时 sudo mkdir -p /etc/systemd/system/NetworkManager-wait-online.service.d sudo tee /etc/systemd/system/NetworkManager-wait-online.service.d/timeout.conf /dev/null EOF [Service] TimeoutStartSec15 EOF sudo systemctl daemon-reload如果是网卡存在多余连接先查看连接列表nmcli connection show只保留真正使用的连接删除无用连接sudo nmcli connection delete 冗余连接名7.2 调整静态 IP 与 DHCP 超时云服务器上手动配置静态 IP 时不要把 DHCP 等待时间拉得太长。用 NetworkManager 可单独配置连接的超时时间# 查看现有连接的名称 nmcli connection show sudo nmcli connection modify 连接名 ipv4.dhcp-timeout 10 sudo nmcli connection up 连接名如果公司或云 VPC 要求固定内网 IP更推荐在连接文件中直接配置而不是使用 DHCP reservation 之外的方式。配置完毕后用nmcli device show eth0验证 IP 是否在预期网段内。注意这里的连接名要替换成实际连接名称不要照抄。7.3 SSH 密钥预生成与保留策略对于测试环境或内部镜像可以在构建阶段预生成 SSH 主机密钥sudo ssh-keygen -A sudo systemctl restart sshd这条命令会补齐所有平台所需的密钥类型。之后重启一次确认 SSH 能在几秒内就绪。多租户分发场景下如果要保证私钥不泄露建议在快照前清掉主机密钥并接受首启生成的一次性开销。真正的优化目标是把生成耗时控制到秒级而不是完全避免生成。7.4 cloud-init 限制 datasource如果确定实例只运行在特定云平台应该在/etc/cloud/cloud.cfg.d/下限制 datasource 列表避免 cloud-init 逐个尝试所有平台。具体配置格式以所用系统版本和云平台文档为准。下面是一个通用示意不要直接照抄# /etc/cloud/cloud.cfg.d/99-datasource.cfg datasource_list: [AliYun, None]改完配置后立即验证语法是否正确sudo cloud-init schema --system sudo cloud-init clean --logs sudo reboot注意cloud-init clean --logs会清理 cloud-init 状态首启流程会在下次启动时重新执行。用于排障验证没问题但不要在正式运行中的业务实例上随意操作。7.5 处理 SELinux 重标记如果确定首启慢来自 SELinux 重标记可以主动触发一次完整重标记并观察后续启动是否恢复正常。sudo fixfiles -f relabel sudo reboot重标记会持续一段时间期间不要中断电源。重启后检查启动耗时并确认系统进入 enforcing 模式后一切正常。7.6 验证修复结果修改完任何一项都要重新验证启动耗时systemd-analyze systemd-analyze blame | head -20 systemd-analyze critical-chain journalctl -b --no-pager | grep -E startup finished|reach target|Timed out只有重启后确认总耗时明显下降才说明定位正确。如果耗时依旧回到第 4 节重新看日志时间轴。8. 发布云镜像前的优化清单如果手头在维护 Rocky 9/10 的云镜像与其等用户报“首启慢”不如在构建阶段就把这些坑填掉。下面是一份可纳入镜像发布流程的检查清单。第一快照前处理一次性初始化。运行一次cloud-init clean --logs清掉临时状态文件避免快照包含上一实例的机器 ID、SSH 密钥指纹或日志残留。很多首启慢其实是“残留状态与当前实例冲突”造成的。第二重置或预留 machine-id。云镜像通常会把/etc/machine-id清空让每个实例启动时生成唯一 ID。若镜像保留了旧 machine-id会导致部分工具等待异常。可以先清空再重新生成。sudo cloud-init clean --logs sudo rm -f /etc/machine-id sudo systemd-machine-id-setup第三SSH 主机密钥按安全策略处理。内部测试镜像可以直接预生成多租户镜像需要在速度和私钥泄露风险之间做取舍。至少要在快照前确认没有把包含未知主机密钥的 SSH 指纹写进镜像说明文档。第四NetworkManager 连接配置提前固化。在构建阶段就把主网卡的连接文件写好明确使用 DHCP 或静态 IP并设置连接超时参数。避免实例首启时重新执行交互式网络配置。第五配置内核参数时不要盲目禁用网卡命名。Rocky 10 默认使用可预测的网络接口命名云平台驱动和 systemd 依赖接口名变化来识别设备。强行关闭可能反而导致启动等待设备匹配超时。第六做一次“冷启动回归测试”。每次发版前用最终镜像新建一个实例记录systemd-analyze的耗时和 SSH 就绪时间。把这项测试加入发布流水线能拦截绝大多数回归问题。9. 常见问题与排查清单下面这张表适用于 Rocky 8/9/10 云镜像首启慢的现场快速排查可以直接复制到自己的排障手册里。问题现象可能原因先行检查解决方案首启刚好卡 120 秒wait-online 等待超时systemctl is-enabled NetworkManager-wait-online.service禁用服务或设置 TimeoutStartSec15cloud-init 日志大量 Retry元数据服务无法访问journalctl -u cloud-init.service限制 datasource 列表能 Ping 通但 SSH 连不上sshd 等待主机密钥生成ls /etc/ssh/ssh_host_*预生成密钥或检查熵不足日志出现大量 relabel 字眼SELinux 重标记文件系统journalctl -bfixfiles -f relabel内核到 systemd 阶段耗时很长云盘挂载或驱动加载慢systemd-analyze plot调整存储类型或驱动参数修改后重启又回到 120 秒修改没有持久化或连接配置冲突对比两次 journalctl检查 drop-in 文件和 nmcli 连接只有首次启动慢后续正常一次性初始化任务再次 reboot 验证在镜像构建阶段执行 clean首启阶段 DHCP 反复尝试DHCP 服务超时journalctl -u NetworkManager设置 ipv4.dhcp-timeout如果按下表定位后仍然找不到根因就把完整的journalctl -b日志导出重点找两条日志之间的时间空洞。只要时间空洞找到了问题基本就水落石出。10. 总结与下一步云镜像首启慢两分钟最值得先跑的命令就是systemd-analyze critical-chain和journalctl -b。这两个命令可以把模糊的“两分钟”还原为具体的服务等待时间。最容易踩的坑则是一上来就调网络参数静态 IP、DNS、路由都改一遍最后发现 wait-online 超时和这些配置毫无关系。建议把这套时间轴分析方法固化成自己的排障模板先看总时长、再看单服务耗时、再看日志空窗、最后判断类型。只要遵循这个顺序Rocky 10 云镜像首启慢这类问题就不会再反复折腾网卡和防火墙了。下一步可以进一步测试不同云平台下 cloud-init 的表现差异也可以把发布前冷启动测试接入 CI 流程让“首启慢”这类问题在镜像发布前就被自动拦截。

最新新闻

日新闻

周新闻

月新闻