cloud-init 26.1 进阶实战与运维
面向运维场景的 cloud-init 26.1 进阶实战,覆盖多数据源对比与收窄、四阶段与 systemd 单元、实例缓存与 clean 重跑、single 单模块执行、analyze/collect-logs/query 诊断三件套与 26.1 对 21.1 版本差异速查,全部命令实测通过。
cloud-init 26.1 进阶实战与运维
目标:面向日常运维与排障,讲清 cloud-init 26.1 的进阶操作——数据源清单管理与查询、systemd 单元与四阶段手工运维、实例缓存与 clean 重跑、单模块执行、status/analyze/collect-logs/query 诊断命令集,并给出 26.1 与 21.1 的版本差异速查。全部命令已在 Ubuntu 22.04、cloud-init 26.1-0ubuntu1~22.04.1 环境逐条实测。
一、环境信息
- 操作系统:Ubuntu 22.04(jammy),x86_64
- 内核:6.8.0-138-generic
- cloud-init:26.1-0ubuntu1~22.04.1
- 数据源:NoCloud(seed 目录
/var/lib/cloud/seed/nocloud/,instance-id 为iid-cloudinit-demo-001) - 关键路径:
/run/cloud-init/(运行态状态)、/var/lib/cloud/(实例缓存与脚本目录)、/var/log/cloud-init.log(主日志) - 基础概念(四阶段/数据源/user-data 形态)见《cloud-init 26.1 快速入门与 NoCloud 数据源实战》,安装过程见《cloud-init 26.1 Ubuntu 22.04 安装指南》
二、前置条件
- cloud-init 已安装且完成过一次初始化:
cloud-init status
实测回显:
status: done
- 以下命令均以 root 执行。
- 本文多处演示「清理 → 重跑」,会重放 user-data 中的动作(建用户、写文件、装包等),在承载业务的机器上操作前先确认 user-data 内容幂等。
三、多数据源清单管理与查询
3.1 本机数据源清单
cloud-init 启动时按 datasource_list 顺序探测数据源,第一个命中的生效。Ubuntu 打包把清单放在 /etc/cloud/cloud.cfg.d/90_dpkg.cfg,实测 31 项:
cat /etc/cloud/cloud.cfg.d/90_dpkg.cfg
实测回显:
# to update this file, run dpkg-reconfigure cloud-init
datasource_list: [ NoCloud, ConfigDrive, OpenNebula, DigitalOcean, Azure, AltCloud, VMware, OVF, MAAS, GCE, OpenStack, CloudSigma, SmartOS, Bigstep, Scaleway, AliYun, Ec2, CloudStack, Hetzner, IBMCloud, Oracle, Exoscale, RbxCloud, UpCloud, Vultr, LXD, NWCS, Akamai, WSL, CloudCIX, None ]
💡 技术拓展:常见数据源横向对比——
数据源 元数据来源 探测耗时特征 典型场景 NoCloud 本地 seed 目录/ISO 或 URL 秒级(本地文件) 私有环境、镜像构建 ConfigDrive cidata 卷标配置盘 秒级(本地挂载) OpenStack、自建虚拟化 Ec2 169.254.169.254 HTTP 服务 未命中时最长等 120 秒 AWS 及兼容云 OpenStack 元数据服务 + ConfigDrive 网络就绪后较快 公有/私有 OpenStack AliYun / Azure / GCE / Vultr 等 各平台元数据服务 平台内秒级,平台外超时 对应公有云 None 无 立即生效 固定镜像、禁用初始化 关键差异在「探测代价」:本地类(NoCloud/ConfigDrive)零网络开销,网络类在非目标平台上会白等探测超时。生产机务必按实际平台收窄清单(见 3.3 小节),本演示环境因使用 NoCloud 种子,清单顺序无需调整即可命中第一项。
3.2 查询当前命中的数据源
三个层次的查询命令:
cloud-id
实测回显:
nocloud
cloud-init status --long
实测回显:
status: done
extended_status: done
boot_status_code: enabled-by-sysvinit
last_update: Thu, 01 Jan 1970 00:45:18 +0000
detail: DataSourceNoCloud [seed=/var/lib/cloud/seed/nocloud]
errors: []
recoverable_errors: {}
cloud-init query ds
实测回显:
{
"_doc": "EXPERIMENTAL: The structure and format of content scoped under the 'ds' key may change in subsequent releases of cloud-init.",
"meta_data": {
"dsmode": "net",
"instance-id": "iid-cloudinit-demo-001",
"local-hostname": "cloudinit-demo"
}
}
💡 说明:
detail字段给出数据源实现类与 seed 位置;query ds树里是原始 meta-data 内容。/run/cloud-init/cloud-id-nocloud这类标记文件也会按命中的数据源生成。
3.3 收窄数据源清单
写一个编号更靠后的 .cfg 覆盖清单(文件名 91-ds-limit.cfg),清理后重跑生效:
printf 'datasource_list: [ NoCloud, ConfigDrive ]' > /etc/cloud/cloud.cfg.d/91-ds-limit.cfg
cloud-init clean --logs
cloud-init init --local
cloud-init init
cloud-init modules --mode=config
cloud-init modules --mode=final
重跑后确认合并视图中的清单已收窄:
python3 -c "import json; print(json.load(open('/run/cloud-init/combined-cloud-config.json')).get('datasource_list'))"
实测回显:
['NoCloud', 'ConfigDrive']
验证完成后删除该文件并再跑一轮,恢复 31 项清单:
rm -f /etc/cloud/cloud.cfg.d/91-ds-limit.cfg
python3 -c "import json; print(len(json.load(open('/run/cloud-init/combined-cloud-config.json')).get('datasource_list')))"
实测回显:
31
四、systemd 单元与四阶段运维
4.1 单元文件与关键依赖
四阶段各对应一个 systemd 单元。查看单元注册与关键指令:
systemctl list-unit-files "cloud-init*"
实测回显:
UNIT FILE STATE VENDOR PRESET
cloud-init-hotplugd.service static -
cloud-init-local.service enabled enabled
cloud-init.service enabled enabled
cloud-init-hotplugd.socket enabled enabled
cloud-init.target static -
5 unit files listed.
grep -E '^(ExecStart|Before|After|RequiresMountsFor|Condition)' /lib/systemd/system/cloud-init-local.service
实测回显:
ExecStart=/usr/bin/cloud-init init --local
Before=network-pre.target
RequiresMountsFor=/var/lib/cloud
ConditionPathExists=!/etc/cloud/cloud-init.disabled
ConditionKernelCommandLine=!cloud-init=disabled
grep -E '^(ExecStart|After|TasksMax)' /lib/systemd/system/cloud-final.service
实测回显:
ExecStart=/usr/bin/cloud-init modules --mode=final
After=multi-user.target
After=network-online.target
After=systemd-user-sessions.service
TasksMax=infinity
💡 说明:init-local 排在 network-pre.target 之前(本地数据源可决定网络怎么配);两个 Condition 行是整机禁用的官方开关(见 4.3 小节)。cloud-init.target 是聚合 target,由四个服务单元的 WantedBy 关系串成依赖链。
4.2 手工执行四阶段
无 systemd 运行的环境(救援模式、chroot、最小化环境)或调试时,手工按序执行,效果与开机自动执行一致(完整四阶段回显见《cloud-init 26.1 快速入门与 NoCloud 数据源实战》5.2 小节):
cloud-init init --local
Cloud-init v. 26.1-0ubuntu1~22.04.1 running 'init-local' at Sat, 17 Oct 2026 00:08:59 +0000. Up 2194.31 seconds.
cloud-init init
Cloud-init v. 26.1-0ubuntu1~22.04.1 running 'init' at Sat, 17 Oct 2026 00:09:00 +0000. Up 2194.85 seconds.
cloud-init modules --mode=config
Cloud-init v. 26.1-0ubuntu1~22.04.1 running 'modules:config' at Sat, 17 Oct 2026 00:09:01 +0000. Up 2195.56 seconds.
cloud-init modules --mode=final
Cloud-init v. 26.1-0ubuntu1~22.04.1 running 'modules:final' at Sat, 17 Oct 2026 00:09:01 +0000. Up 2195.83 seconds.
Cloud-init v. 26.1-0ubuntu1~22.04.1 finished at Sat, 17 Oct 2026 00:09:01 +0000. Datasource DataSourceNoCloud [seed=/var/lib/cloud/seed/nocloud]. Up 2195.90 seconds
4.3 禁用与恢复
两种官方禁用开关,任选其一:
方式一,禁用标记文件(利用 4.1 小节的 ConditionPathExists=!/etc/cloud/cloud-init.disabled 条件):
touch /etc/cloud/cloud-init.disabled
方式二,内核启动参数(利用 ConditionKernelCommandLine=!cloud-init=disabled),编辑引导配置给内核追加 cloud-init=disabled。
恢复时删除标记文件或移除内核参数:
rm -f /etc/cloud/cloud-init.disabled
⚠️ 注意:禁用只影响「后续引导」,已完成初始化的机器上已创建的用户/文件不会回滚。确认单元状态用
systemctl list-unit-files "cloud-init*"(回显见 4.1 小节),每个单元单独一行核对,不要用一条命令批量传多个单元名。
五、实例缓存与重跑机制
5.1 instance-id 缓存原理
cloud-init 以 instance-id 为键缓存实例数据:id 不变时,重跑只执行 per-boot 类动作,cloud-config 主体(建用户/写文件/装包)因「该实例已处理过」被跳过。缓存证据:
cat /run/cloud-init/.instance-id
实测回显:
iid-cloudinit-demo-001
ls /var/lib/cloud/instances/
实测回显:
iid-cloudinit-demo-001
因此「改了 user-data 不生效」是缓存机制的预期行为,两种重跑方式见 5.2 与 5.3 小节。
5.2 方式一:换 instance-id 触发重新初始化
模拟新实例(真实云平台上换 instance-id 由平台自动完成)。修改 meta-data 的 instance-id:
sed -i 's/iid-cloudinit-demo-001/iid-cloudinit-demo-002/' /var/lib/cloud/seed/nocloud/meta-data
cloud-init clean --logs
重跑四阶段(命令见 4.2 小节)后,新实例目录生成且 user-data 重新执行:
ls /var/lib/cloud/instances/
实测回显:
iid-cloudinit-demo-002
cat /var/log/script-userdata.log
实测回显:
script user-data executed on cloudinit-demo at Fri Oct 16 17:59:41 UTC 2026
uid=1000(deploy) gid=1000(deploy) groups=1000(deploy),4(adm),27(sudo)
💡 说明:旧实例目录
iid-cloudinit-demo-001被清走,/var/lib/cloud/instances/只保留当前实例。runcmd/脚本类动作随新实例重放。
5.3 方式二:cloud-init clean 清理重跑
clean 子命令删除运行数据让 cloud-init 回到「未开始」状态。先看参数(实测节选):
cloud-init clean --help
实测回显(节选):
usage: /usr/bin/cloud-init clean [-h] [-l] [--machine-id] [-r] [-s]
[-c {all,ssh_config,network,datasource,fstab} [{all,ssh_config,network,datasource,fstab} ...]]
options:
-h, --help show this help message and exit
-l, --logs Remove cloud-init logs.
--machine-id Set /etc/machine-id to 'uninitialized\n' for golden
image creation. On next boot, systemd generates a new
machine-id. Remove /etc/machine-id on non-systemd
environments.
-r, --reboot Reboot system after logs are cleaned so cloud-init re-
runs.
-s, --seed Remove cloud-init seed directory /var/lib/cloud/seed.
参数解读:-l 连日志一起删;-r 清完立即重启(真实服务器重跑首选);-s 连种子目录一起删(golden image 制作时用,种子是投放来源时千万不要加);-c 定向清理某类生成配置(ssh_config/network/datasource/fstab);--machine-id 把 machine-id 置为未初始化(制作模板镜像时避免多机重复 machine-id)。
实测 clean 过程(保留 seed):
cloud-init clean --logs
echo $?
实测回显:
0
ls /var/lib/cloud/
实测回显:
seed
cloud-init status
实测回显:
status: not started
💡 说明:
clean --logs后/var/lib/cloud/只剩 seed 种子目录,状态回到 not started;重跑四阶段即完成一次全新的初始化(四阶段回显见 4.2 小节)。若加了-s,连 seed 也删除,ls /var/lib/cloud/输出为空。
5.4 status --wait:自动化同步点
自动化脚本里用 --wait 阻塞等待初始化完成(未完成时阻塞,完成后立即返回)。实测:clean 后后台启动四阶段,wait 阻塞直至完成:
cloud-init status --wait
实测回显(等待重跑完成后输出):
status: done
echo $?
实测回显:
0
已完成的机器上执行则立即返回,无副作用。失败场景下返回非 0,可据此中断自动化流程。
六、单模块执行与脚本频率
6.1 single:单独运行某个模块
调试某个模块时不必重跑整个四阶段,single 可按指定频率执行单模块。参数(实测节选):
cloud-init single --help | head -8
实测回显:
usage: /usr/bin/cloud-init single [-h] --name NAME
[--frequency {instance,always,once}]
[--report] [--file FILES]
[argument ...]
positional arguments:
argument Any additional arguments to pass to this module.
参数解读:--name 模块名(如 write_files、runcmd);--frequency 三档——instance(默认,每实例一次)、always(每次都跑)、once(仅下一次);--file 提供独立的 user-data 配置文件。
实测:用独立配置单独跑 write_files 模块写一个文件:
cat > /tmp/single-cfg.yaml <<'CFG'
#cloud-config
write_files:
- path: /tmp/single-test.txt
content: hello-single
CFG
cloud-init single --name write_files --frequency always --file /tmp/single-cfg.yaml
实测回显:
Cloud-init v. 26.1-0ubuntu1~22.04.1 running 'single' at Sat, 17 Oct 2026 00:19:12 +0000. Up 2806.58 seconds.
cat /tmp/single-test.txt
实测回显:
hello-single
6.2 scripts 四类频率目录
/var/lib/cloud/scripts/ 下按执行频率分四个目录,由 final 阶段的 scripts_* 系列模块执行:
ls /var/lib/cloud/scripts/
实测回显:
per-boot
per-instance
per-once
vendor
| 目录 | 执行频率 | 执行模块 |
|---|---|---|
| per-once | 全生命周期一次 | scripts_per_once |
| per-instance | 每个实例一次(instance-id 变更即重跑) | scripts_per_instance |
| per-boot | 每次引导都跑 | scripts_per_boot |
| vendor | 发行版/镜像厂商预置脚本 | scripts_vendor |
实测:放一个 per-boot 脚本并触发 final 阶段:
cat > /var/lib/cloud/scripts/per-boot/10-hello <<'EOF'
#!/bin/sh
echo "per-boot ran at $(date)" >> /var/log/per-boot.log
EOF
chmod +x /var/lib/cloud/scripts/per-boot/10-hello
cloud-init modules --mode=final
cat /var/log/per-boot.log
实测回显:
per-boot ran at Fri Oct 16 17:59:14 UTC 2026
⚠️ 注意:脚本必须有可执行位且shebang 正确;per-instance/per-once 的执行记录在
/var/lib/cloud/sem/信号目录,手工删除对应 sem 文件可强制重跑。
七、诊断三件套:analyze / collect-logs / query
7.1 analyze:启动耗时分析
analyze 有 4 个子命令(blame/show/dump/boot)。show 按时间线展示每个阶段的每个事件,blame 按耗时倒排:
cloud-init analyze show
实测回显(节选,保留首尾阶段):
-- Boot Record 01 --
The total time elapsed since completing an event is printed after the "@" character.
The time the event takes is printed after the "+" character.
Starting stage: init-local
|`->no cache found (duration: 0.000s) @00.00400s +00.00000s
|`->found local data from DataSourceNoCloud (duration: 0.287s) @00.06900s +00.28700s
Finished stage: (init-local) 00.38100 seconds
Starting stage: init-network
|`->restored from cache with run check: DataSourceNoCloud [seed=/var/lib/cloud/seed/nocloud] (duration: 0.002s) @00.58600s +00.00200s
|`->config-ssh ran successfully and took 0.928 seconds (duration: 0.928s) @00.65900s +00.92800s
Finished stage: (init-network) 01.03900 seconds
Starting stage: modules-final
|`->config-package_update_upgrade_install ran successfully and took 4.102 seconds (duration: 4.102s) @02.15900s +04.10100s
Finished stage: (modules-final) 04.15600 seconds
cloud-init analyze blame | head -8
实测回显(节选):
-- Boot Record 01 --
04.10100s (modules-final/config-package_update_upgrade_install)
00.92800s (init-network/config-ssh)
00.28700s (init-local/search-NoCloud)
00.04600s (modules-config/config-grub_dpkg)
00.03600s (modules-config/config-apt_configure)
00.02800s (modules-final/config-keys_to_console)
💡 说明:blame 排第一的通常是
package_update_upgrade_install(装包耗时)与config-ssh(主机密钥生成),首启慢先查这两项;search-NoCloud耗时异常则检查 seed 路径。
7.2 collect-logs:一键打包诊断材料
cloud-init collect-logs --tarfile /tmp/cloud-init-logs.tar.gz
实测回显:
Wrote /tmp/cloud-init-logs.tar.gz
WARNING:
Sensitive data may have been included in the collected logs.
Please review the contents of the tarball before sharing or
rerun with --redact-sensitive to redact sensitive data.
ls -l /tmp/cloud-init-logs.tar.gz
实测回显:
-rw-r--r-- 1 root root 55989 Oct 17 00:19 /tmp/cloud-init-logs.tar.gz
tar -tzf /tmp/cloud-init-logs.tar.gz | head -12
实测回显:
cloud-init-logs-2026-10-17/
cloud-init-logs-2026-10-17/dmesg.txt
cloud-init-logs-2026-10-17/etc/
cloud-init-logs-2026-10-17/etc/cloud/
cloud-init-logs-2026-10-17/etc/cloud/cloud.cfg.d/
cloud-init-logs-2026-10-17/etc/cloud/cloud.cfg.d/README
cloud-init-logs-2026-10-17/etc/cloud/cloud.cfg.d/90_dpkg.cfg
cloud-init-logs-2026-10-17/etc/cloud/cloud.cfg.d/05_logging.cfg
cloud-init-logs-2026-10-17/etc/cloud/cloud.cfg.d/99-disable-network-config.cfg
cloud-init-logs-2026-10-17/etc/cloud/cloud.cfg
cloud-init-logs-2026-10-17/etc/cloud/build.info
cloud-init-logs-2026-10-17/version
⚠️ 注意:默认打包可能包含 user-data 中的密码等敏感信息(本文 chpasswd 的 root 口令即在其中),对外提供日志前务必加
--redact-sensitive重打:cloud-init collect-logs --tarfile /tmp/redacted.tar.gz --redact-sensitive实测回显(脱敏模式无 WARNING):
Wrote /tmp/redacted.tar.gz
7.3 query:查询实例数据树
query 读取 /run/cloud-init/instance-data.json 的标准化数据树。列出全部可用键:
cloud-init query --list-keys
实测回显:
_beta_keys
availability-zone
availability_zone
base64_encoded_keys
cloud-name
cloud_id
cloud_name
combined_cloud_config
distro
distro_release
distro_version
ds
features
instance-id
instance_id
kernel_release
local-hostname
local_hostname
machine
merged_cfg
merged_system_cfg
platform
public_ssh_keys
python_version
region
sensitive_keys
subplatform
sys_info
system_info
system_platform
userdata
v1
variant
vendordata
点号路径取值(v1 是标准化视图,推荐):
cloud-init query v1.instance_id
实测回显:
iid-cloudinit-demo-001
cloud-init query v1.local_hostname
实测回显:
cloudinit-demo
--format 自定义输出(变量用双花括号引用):
cloud-init query --format '{{v1.cloud_name}} / {{v1.instance_id}}'
实测回显:
unknown / iid-cloudinit-demo-001
💡 说明:
cloud_name: unknown是 NoCloud 本地种子不携带云标识的正常取值。--all输出完整 JSON 树(含 combined_cloud_config、sys_info、features 等),配合python3 -m json.tool或 jq 阅读。
八、26.1 与 21.1 版本差异速查
运维多版本混合环境(如 Ubuntu 26.1 与 CentOS 8 自带的 21.1)时,以下差异实测确认,命令脚本要注意兼容:
| 维度 | 26.1(Ubuntu 22.04 实测) | 21.1(CentOS 8 实测) |
|---|---|---|
| schema 子命令 | 有(cloud-init schema -c <file>) | 无,报 invalid choice: 'schema' |
| query 键风格 | 连字符与下划线并存(instance-id/instance_id 均可) | 仅下划线(instance-id 报 Undefined key) |
| status --long 字段 | extended_status/boot_status_code/errors/recoverable_errors | status/time/detail 三字段 |
| 子命令清单 | init,modules,single,query,features,analyze,devel,collect-logs,clean,status,schema | 少 schema,多 dhclient-hook |
| 模块清单命名 | 下划线(write_files/users_groups/set_passwords) | 连字符旧名(write-files/users-groups/set-passwords)+ migrator/rh_subscription |
| 日志前缀 | log_util.py[WARNING]: | util.py[WARNING]: |
| devel make-mime | 有(-a 文件:类型 多部分合成) | 无 make-mime(21.1 devel 子命令集更小) |
跨版本投放 user-data 时以公共键集为准(users/packages/runcmd/write_files 等核心指令两版兼容);校验动作只在 26.1 上做,21.1 靠首启日志观察。
九、常见问题(FAQ)
Q1:cloud-init status --wait 一直阻塞不返回?
说明初始化未完成,通常是网络类数据源在探测超时(Ec2 未命中最长等 120 秒)或某阶段卡住。另开终端看 /var/log/cloud-init.log 尾部定位卡住的模块;确认数据源场景后按 3.3 小节收窄 datasource_list 可消除探测等待。
Q2:cloud-init clean 之后系统会回到什么状态?
回到「未初始化」:/var/lib/cloud/ 实例缓存与 sem 信号清空(保留 seed 时种子仍在),/run/cloud-init/ 运行态清空,加 --logs 连两个日志文件一起删。已落盘的系统变更(用户、文件、包)不会回滚。重跑后即按当前 seed/user-data 重新执行一遍完整首启。
Q3:analyze 输出里有多个 Boot Record 怎么回事?
每次引导产生一个 Boot Record,show/blame 默认全部列出。只看最新一次时按 Record 顺序取最后一段;对照两次首启的 blame 可定位「这次为什么变慢」。
Q4:collect-logs 的 tar 包里都有什么?
实测包含四类:dmesg.txt 与 version(内核与版本信息)、etc/cloud/(全部配置)、run/cloud-init/(运行态 JSON 与实例数据)、var/log/(cloud-init 两个日志)。共 51 个条目(实测 tar -tzf | wc -l),即官方支持渠道要求的标准诊断包。
Q5:怎么判断一台机器的 cloud-init 到底跑没跑过?
三个判据任选:cloud-init status(not started/running/done 三态);ls /var/lib/cloud/instances/ 有实例目录即跑过;cat /run/cloud-init/result.json 有 v1.datasource 即有数据源命中记录。
十、参考链接
- cloud-init 官网:https://cloud-init.io/
- 官方文档(Read the Docs):https://cloud-init.readthedocs.io/
- 命令行参考:https://cloud-init.readthedocs.io/en/latest/reference/cli.html
- analyze 工具说明:https://cloud-init.readthedocs.io/en/latest/howto/analyze_logs.html
- GitHub 仓库:https://github.com/canonical/cloud-init