VPS首次开机 cloud-init 卡住怎么办?从状态、日志到网络与重试安全恢复

从状态、日志到网络与重试的安全恢复路径
发布于
2

VPS首次开机后,cloud-init长时间停在running、软件包安装失败或SSH密钥没有写入,先不要连续执行cloud-init clean或重跑整套初始化。正确做法是先确定卡在哪个阶段,保留日志和当前配置,再按网络、元数据、用户数据和systemd依赖逐层修复。cloud-init的状态恢复,不等于把所有初始化动作再执行一遍。

先判断是等待、失败还是已经完成

不同发行版和镜像的单元名称可能略有差异,先读取本机实际状态:

cloud-init status --long
cloud-init query --all 2>/dev/null | head -c 4000
systemctl status cloud-init-local cloud-init cloud-config cloud-final --no-pager
systemctl list-jobs

status --long显示的是总体状态;cloud-init-localcloud-configcloud-final分别对应不同阶段。若某个阶段仍在等待,不要只看控制台“初始化中”的字样。list-jobs可以提示systemd是否在等挂载、网络或其他单元。

先把现场保存下来:

sudo journalctl -b -u cloud-init-local -u cloud-init -u cloud-config -u cloud-final --no-pager > /root/cloud-init-journal.txt
sudo cp -a /var/log/cloud-init.log /root/cloud-init.log.$(date +%s)
sudo cp -a /var/log/cloud-init-output.log /root/cloud-init-output.log.$(date +%s)
sudo cloud-init query userdata 2>/dev/null > /root/cloud-init-userdata.txt

日志中可能包含用户名、令牌或密码片段,提交给服务商前应先脱敏。不要把完整日志直接贴到公开论坛。

按四个阶段定位停点

阶段 主要任务 常见停点
local 读取本地数据源、网络前的早期准备 磁盘、挂载或数据源探测异常
config 用户、SSH、写文件和基础配置 YAML格式、权限或模块参数错误
final 安装软件包、执行脚本和启动服务 DNS、软件源、外部下载或脚本阻塞
cleanup 记录完成标记并收尾 前置任务未退出,服务重复触发

/var/log/cloud-init.log适合看模块级调用,cloud-init-output.log更接近用户脚本的标准输出。找到第一条有因果意义的错误比追最后一行“failed”更重要:后者经常只是前面超时或退出码的结果。

网络和DNS:能连IP不代表初始化能下载

cloud-init的final阶段经常要访问软件源、镜像仓库或元数据服务。先在不改配置的情况下验证:

ip addr
ip route
getent hosts archive.ubuntu.com 2>/dev/null
resolvectl status 2>/dev/null || cat /etc/resolv.conf
curl -I --connect-timeout 5 https://archive.ubuntu.com/

如果IP可达而域名解析失败,应沿解析器、resolv.conf、DNS服务和出站53端口排查,可参考VPS能访问IP却解析不了域名的分层排查。不要为了让初始化“先跑完”而永久写死一个未经验证的DNS地址;云厂商的内网软件源和元数据地址也可能依赖特定路由。

用户数据和YAML:先验证格式,再谈模块

用户数据常见问题包括缩进错误、Tab字符、未加引号的特殊值、脚本没有shebang,以及脚本返回非零退出码。可以先检查文件中是否存在明显的Tab或不可见字符,再把复杂脚本拆到独立文件测试。不要在生产实例上直接重复执行包含分区、删除或迁移动作的脚本。

sudo sed -n '1,240p' /var/lib/cloud/instance/user-data.txt
sudo sed -n 'l' /var/lib/cloud/instance/user-data.txt
sudo cloud-init devel schema --config-file /var/lib/cloud/instance/user-data.txt

部分旧版本不提供cloud-init devel schema,命令失败不等于配置错误,此时应以日志和发行版文档为准。脚本最好具备幂等性:重复运行不会重复创建用户、覆盖证书或追加相同的配置行。

软件包安装卡住时,先查锁、代理和交互提示

如果日志停在apt、dnf或脚本下载,先确认是否有另一个包管理进程、仓库证书错误、代理环境变量或等待交互输入:

ps -ef | grep -E '[a]pt|[d]pkg|[d]nf|[y]um'
sudo journalctl -b -u apt-daily.service -u apt-daily-upgrade.service --no-pager
env | grep -iE '^(http|https|all|no)_proxy='
sudo grep -RIn 'DPkg::|Acquire::.*Proxy' /etc/apt 2>/dev/null

不要直接删除包管理器锁文件,也不要用-y掩盖需要人工确认的变更。若初始化依赖代理,明确区分cloud-init服务环境和交互终端环境;两者不会自动共享所有变量。

systemd依赖未就绪:检查顺序而不是盲目重启

用户数据常会在数据库、数据盘或网络服务未就绪时启动应用。此时先检查实际单元、依赖和本次启动日志,再调整排序、拉起关系或应用重试,可结合systemd服务依赖启动失败的三层排查。cloud-init负责初始化,systemd负责服务编排,不能用一个层面的重试替代另一个层面的健康检查。

什么时候可以重跑,怎样避免重复破坏

  1. 先做快照或至少保存配置、日志和数据目录清单。
  2. 确认用户脚本中没有不可逆操作,必要时先注释外部副作用。
  3. 只针对失败模块做受控验证,不要直接清空整个/var/lib/cloud
  4. 需要重新模拟首次启动时,再评估cloud-init clean的影响,并准备控制台或带外登录。
  5. 重跑后记录新的实例状态和日志,确认完成标记、SSH、网络、软件包与服务都通过。

cloud-init clean --logs --seed会影响实例下次启动时的识别和日志,不能当作普通“刷新按钮”。不同镜像对数据源、实例ID和清理行为的支持也不同,执行前要查对应版本文档。

恢复后验收清单

  • cloud-init status --long为完成状态,且没有新的失败单元;
  • SSH密钥、主机名、时区、网络路由和DNS符合预期;
  • 软件包版本、配置文件权限和服务启停状态已记录;
  • 应用能完成一次无破坏性的健康检查;
  • 初始化日志已归档并去除敏感字段;
  • 将修复后的用户数据和镜像版本纳入下一次恢复演练,可参考VPS备份恢复后的完整性验收

结论

VPS的cloud-init故障排查顺序应是“确认阶段—保存证据—验证网络和数据源—检查用户数据—核对systemd依赖—受控重跑—完整验收”。先定位实际阻塞点,再决定是否重跑,才能避免重复创建、重复安装或覆盖已有数据。初始化完成的标志不是页面显示成功,而是配置、服务和日志都能被复核。

常见问题(FAQ)

cloud-init一直显示running,应该先重启VPS吗?
不建议先重启。先用cloud-init status、systemctl和journalctl判断是等待、失败还是用户脚本阻塞,并保存现场日志;确认阶段后再决定是否重启或针对模块处理。
cloud-init重跑会不会重复创建用户或覆盖配置?
有可能。用户数据里的脚本若不幂等,重跑可能重复写配置、安装软件或触发外部副作用。重跑前先做快照或备份,检查脚本并优先只验证失败模块。
能访问公网IP但cloud-init仍下载失败,问题在哪里?
通常还要检查DNS解析、软件源证书、默认路由、出站端口、代理环境和元数据地址。IP可达只证明一段网络路径,不代表初始化依赖都可用。
什么时候可以执行cloud-init clean?
只有在明确需要模拟首次启动、已保存配置和日志、并准备好控制台或带外登录时再评估。clean会影响实例ID和下次启动行为,不是普通刷新按钮。

本文由作者原创/授权发布于极跃圈(jiyueip.com)未经许可,禁止转载。题图来自Unsplash,基于CC0协议。

声明:极跃圈(JIYUEIP.com)内网友所发表的所有内容及言论仅代表其本人,并不反映任何极跃圈(JIYUEIP.com)之意见及观点。

0 讨论
热门最新
总结
暂无总结
0 / 600