cloud-init 26.1 快速入门与 NoCloud 数据源实战
以 NoCloud 数据源为主线从零跑通 cloud-init 26.1 首次初始化,覆盖四阶段模型、meta-data/user-data 编写与 schema 校验、systemd 自动执行与手工四阶段、首启产物逐项验证、脚本与 MIME/ISO 种子形态,全部命令实测通过。
cloud-init 26.1 快速入门与 NoCloud 数据源实战
目标:在一台 Ubuntu 22.04 服务器上以 NoCloud 数据源从零跑通 cloud-init 26.1 的首次初始化:准备种子数据 → 编写并校验 user-data → 执行四阶段 → 逐项验证首启结果,并实操脚本、多部分 MIME、ISO 种子盘三种进阶形态。全部命令已在 Ubuntu 22.04(x86_64)、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(安装过程见《cloud-init 26.1 Ubuntu 22.04 安装指南》)
- 数据源:NoCloud(本地种子目录
/var/lib/cloud/seed/nocloud/) - 关键路径:
/etc/cloud/(配置)、/var/lib/cloud/(运行数据与种子)、/run/cloud-init/(运行态状态)、/var/log/cloud-init.log(主日志) - 演示目标:主机名
cloudinit-demo,创建用户deploy,设置 root 密码,安装 htop 与 nginx,写入演示文件与日志
二、前置条件
- 已按《cloud-init 26.1 Ubuntu 22.04 安装指南》完成 cloud-init 26.1 安装,
cloud-init --version可正常输出:
cloud-init --version
实测回显:
/usr/bin/cloud-init 26.1-0ubuntu1~22.04.1
- 具备 root 权限,以下命令均以 root 执行。
- 根目录存在
/var/lib/cloud/(安装后自动创建的运行数据目录):
ls /var/lib/cloud/
实测回显:
data
handlers
instance
instances
scripts
seed
sem
- 无遗留运行状态:本文在全新初始化的状态下演练。若机器已跑过一次首启,可先执行
cloud-init clean --logs清理(详见《cloud-init 26.1 进阶实战与运维》)。
三、cloud-init 工作原理速览
本章先建立三个核心概念——四阶段执行模型、数据源、user-data 形态,后续章节全部围绕它们展开。
3.1 四阶段执行模型
cloud-init 不是常驻服务,它是「首次引导(first boot)时跑一遍」的初始化框架,由 systemd 按 4 个阶段依次拉起,每个阶段对应一个单元、执行一批模块:
| 阶段 | systemd 单元 | 执行命令 | 职责 |
|---|---|---|---|
| init-local | cloud-init-local.service | cloud-init init --local | 挂载本地数据源(NoCloud/ConfigDrive),配置网络之前运行 |
| init(network) | cloud-init.service | cloud-init init | 网络可用后运行,应用 user-data 中的系统级配置(用户、SSH 主机密钥等) |
| modules-config | cloud-config.service | cloud-init modules --mode=config | 执行 config 模块清单(时区、apt 源、runcmd 注册等) |
| modules-final | cloud-final.service | cloud-init modules --mode=final | 执行 final 模块清单(软件包安装、各类脚本、final_message) |
核验本机单元注册情况:
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.
💡 说明:
cloud-init-local.service与cloud-init.service为 enabled,随开机自动执行;static的 target/hotplugd 由依赖关系拉起。执行结果记录在/run/cloud-init/result.json与status.json,状态查询见 5.3 小节。
3.2 数据源与 NoCloud
数据源(DataSource)决定 cloud-init 从哪里读取实例元数据(meta-data)与用户数据(user-data)。
💡 技术拓展:数据源类型不止本文使用的 NoCloud,常见类型对比——
数据源 元数据来源 典型场景 NoCloud 本地 seed 文件/ISO 或自定义 URL 私有环境、本地实验、镜像构建 ConfigDrive 挂载 cidata卷标的配置盘(ISO/vfat)OpenStack、自建虚拟化 Ec2 169.254.169.254 元数据服务 AWS 及兼容云 OpenStack 元数据服务 + ConfigDrive 公有云/私有 OpenStack AliYun / Azure / GCE / Vultr 等 各云平台元数据服务 对应公有云 None 不使用数据源 无需初始化的固定镜像 本机允许探测的数据源清单由
/etc/cloud/cloud.cfg.d/90_dpkg.cfg的datasource_list定义(共 31 项,清单顺序即探测优先级)。本文演示环境使用 NoCloud 本地种子,因为它不依赖任何云平台 API,是私有环境与本地验证最常用的形态。
NoCloud 的种子可以放在两个约定目录:/var/lib/cloud/seed/nocloud/ 或 /var/lib/cloud/seed/nocloud-net/(后者在网络配置之后读取,可用 URL 形式),目录内固定放两个文件:meta-data 与 user-data。
3.3 user-data 的四种形态
user-data 是用户交给 cloud-init 执行的「指令书」,支持四种形态:
💡 技术拓展:user-data 形态对比——
形态 文件开头 用途 cloud-config #cloud-config声明式 YAML 指令(建用户、写文件、装包、跑命令等),最常用 脚本 #!任意 shell 脚本,首启时原样执行 include #include列出多个 URL,逐个拉取并按上述规则处理 多部分 MIME Content-Type: multipart/mixed把多种形态打包成一份(见 7.2 小节) 本文主线使用 cloud-config 形态(4.2 小节),脚本形态在 7.1 小节、多部分 MIME 在 7.2 小节实操。
四、准备 NoCloud 种子数据
本章创建 NoCloud 种子目录,写 入 meta-data 与 user-data,并用 schema 子命令校验 user-data 合法性。
4.1 创建目录与 meta-data
meta-data 是实例级元数据,最简只需 instance-id(实例唯一标识,变更会触发重新初始化)与 local-hostname(主机名):
mkdir -p /var/lib/cloud/seed/nocloud
cat > /var/lib/cloud/seed/nocloud/meta-data <<'EOF'
instance-id: iid-cloudinit-demo-001
local-hostname: cloudinit-demo
EOF
无输出即写入成功,核对内容:
cat /var/lib/cloud/seed/nocloud/meta-data
实测回显:
instance-id: iid-cloudinit-demo-001
local-hostname: cloudinit-demo
4.2 编写 user-data(cloud-config 完整示例)
下面是一份覆盖常用能力的 cloud-config:设置主机名与 hosts 管理、创建带密钥的 deploy 用户、设置 root 密码、更新软件源并安装 htop/nginx、写入演示文件、执行 runcmd、自定义完成消息:
cat > /var/lib/cloud/seed/nocloud/user-data <<'EOF'
#cloud-config
hostname: cloudinit-demo
manage_etc_hosts: true
users:
- name: deploy
gecos: Deploy User
groups: [adm, sudo]
sudo: "ALL=(ALL) NOPASSWD:ALL"
shell: /bin/bash
lock_passwd: true
ssh_authorized_keys:
- ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIExvp0N1RzwyIh2iuiY3G5lN5surL0GdBmGtL92oOMUa deploy@cloudinit-demo
chpasswd:
expire: false
users:
- name: root
password: q1w2e3r4
type: text
package_update: true
packages: [htop, nginx]
write_files:
- path: /etc/motd.d/cloudinit-demo
content: |
This host was provisioned by cloud-init 26.1.
runcmd:
- echo "hello from cloud-init $(date)" > /var/log/hello-cloud-init.txt
- uname -r >> /var/log/hello-cloud-init.txt
final_message: "cloud-init has finished after $UPTIME seconds"
EOF
逐项说明:
| 指令 | 作用 | 说明 |
|---|---|---|
| hostname | 设置主机名 | 与 meta-data 的 local-hostname 重复时以此为准,两者一致即可 |
| manage_etc_hosts | 托管 /etc/hosts | true 时按模板渲染 hosts,模板为 /etc/cloud/templates/hosts.debian.tmpl |
| users | 创建用户 | deploy 加入 adm/sudo 组,lock_passwd: true 表示密码锁定(仅密钥登录) |
| chpasswd | 设置密码 | root 设为 q1w2e3r4,type: text 为明文输入(cloud-init 落盘前做哈希),expire: false 不强制改密 |
| package_update | 更新源索引 | 等价于安装前执行 apt-get update |
| packages | 安装软件包 | htop 与 nginx,由 final 阶段的 package_update_upgrade_install 模块执行 |
| write_files | 写文件 | 落一个登录提示文件 /etc/motd.d/cloudinit-demo |
| runcmd | 执行命令 | final 阶段执行,此处写一行演示日志 |
| final_message | 完成消息 | $UPTIME 是 cloud-init 替换的内置变量(不是 shell 变量),输出启动至今秒数 |
💡 说明:以上演示公钥
ssh-ed25519 AAAA…MUa deploy@cloudinit-demo为本文实测环境真实生成的密钥对公钥,读者应替换为自己的公钥(ssh-keygen -t ed25519生成)。
4.3 schema 校验
26.1 提供 schema 子命令,投放前先校验 user-data 是否符合 cloud-config 规范:
cloud-init schema --config-file /var/lib/cloud/seed/nocloud/user-data
实测回显:
Valid schema /var/lib/cloud/seed/nocloud/user-data
echo $?
实测回显:
0
⚠️ 注意:拼写错误的指令键不会在运行时报错,只会被静默忽略(例如
usres),schema 校验是提前发现这类问题的唯一手段。一个实测的失败样例(键拼错 + 类型写错):
cat > /tmp/bad-user-data <<'EOF'
#cloud-config
usres:
- name: deploy
packagea:
- htop
runcmd: not-a-list
EOF
cloud-init schema --config-file /tmp/bad-user-data
实测回显:
Error: Cloud config schema errors: : Additional properties are not allowed ('usres', 'packagea' were unexpected), runcmd: 'not-a-list' is not of type 'array'
Error: Invalid schema: user-data
Invalid user-data /tmp/bad-user-data
echo $?
实测回显:
1
五、执行首次初始化
5.1 真实服务器上的自动执行
真实服务器装好 cloud-init 后无需任何手工操作:systemd 在开机时按 cloud-init-local → cloud-init → cloud-config → cloud-final 的顺序自动执行四阶段,日志写入 /var/log/cloud-init.log。想判断「开机初始化是否已完成」,在任意时刻执行:
cloud-init status --wait
已完成时立即返回:
status: done
返回码 0(echo $? 验证)。首次引导完成前该命令会阻塞等待,适合写进自动化脚本做同步点。
5.2 手工执行四阶段(实测)
调试或在没有 systemd 运行的最小化环境(救援模式、chroot 等)中,可按官方支持的方式手工执行四阶段,效果与开机自动执行完全一致。以下为完整实测过程。
第一步,init-local 阶段(查找本地数据源):
cloud-init init --local
实测回显:
Cloud-init v. 26.1-0ubuntu1~22.04.1 running 'init-local' at Sat, 17 Oct 2026 00:09:44 +0000. Up 2238.66 seconds.
第二步,init 网络阶段(应用系统级配置、生成 SSH 主机密钥),输出节选(实测首尾):
cloud-init init
实测回显(节选):
Cloud-init v. 26.1-0ubuntu1~22.04.1 running 'init' at Sat, 17 Oct 2026 00:09:44 +0000. Up 2239.15 seconds.
ci-info: +++++++++++++++++++++++++++++Net device info++++++++++++++++++++++++++++++
ci-info: +--------+------+-------------+-------------+--------+-------------------+
ci-info: | Device | Up | Address | Mask | Scope | Hw-Address |
ci-info: +--------+------+-------------+-------------+--------+-------------------+
ci-info: | eth0 | True | 172.17.0.13 | 255.255.0.0 | global | 92:ca:f8:60:cc:e3 |
ci-info: | lo | True | 127.0.0.1 | 255.0.0.0 | host | . |
ci-info: | lo | True | ::1/128 | . | host | . |
ci-info: +--------+------+-------------+-------------+--------+-------------------+
ci-info: +++++++++++++++++++++++++++Route IPv4 info++++++++++++++++++++++++++++
ci-info: +-------+-------------+------------+-------------+-----------+-------+
ci-info: | Route | Destination | Gateway | Genmask | Interface | Flags |
ci-info: +-------+-------------+------------+-------------+-----------+-------+
ci-info: | 0 | 0.0.0.0 | 172.17.0.1 | 0.0.0.0 | eth0 | UG |
ci-info: | 1 | 172.17.0.0 | 0.0.0.0 | 255.255.0.0 | eth0 | U |
ci-info: +-------+-------------+------------+-------------+-----------+-------+
Generating public/private rsa key pair.
Your identification has been saved in /etc/ssh/ssh_host_rsa_key
Your public key has been saved in /etc/ssh/ssh_host_rsa_key.pub
第三步,config 阶段(执行 config 模块清单):
cloud-init modules --mode=config
实测回显:
Cloud-init v. 26.1-0ubuntu1~22.04.1 running 'modules:config' at Sat, 17 Oct 2026 00:09:45 +0000. Up 2239.67 seconds.
第四步,final 阶段(装包、跑脚本、输出 final_message),输出节选(实测首尾):
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.
htop is already the newest version (3.0.5-7build2).
nginx is already the newest version (1.18.0-6ubuntu14.21).
0 upgraded, 0 newly installed, 0 to remove and 2 not upgraded.
cloud-init has finished after 2246.70 seconds
ci-info: ++++++++++++++++++++++++++++++++++++++Authorized keys from /home/deploy/.ssh/authorized_keys for user deploy+++++++++++++++++++++++++++++++++++++++
ci-info: +-------------+-------------------------------------------------------------------------------------------------+---------+-----------------------+
ci-info: | Keytype | Fingerprint (sha256) | Options | Comment |
ci-info: +-------------+-------------------------------------------------------------------------------------------------+---------+-----------------------+
ci-info: | ssh-ed25519 | 52:ae:79:77:80:4d:23:fc:e0:30:ee:ee:33:fe:76:7a:07:81:c4:8d:97:99:f1:e4:a4:ba:29:be:8c:23:4f:83 | - | deploy@cloudinit-demo |
ci-info: +-------------+-------------------------------------------------------------------------------------------------+---------+-----------------------+
-----BEGIN SSH HOST KEY KEYS-----
ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBOI7U9qNcJGRuey1ieMh0LguCwopvGFw8TQVSb9yuWbHSDWiUccbQnKeQ3RtX9VjTjz8+CZ1Z2f7Z8MrzuMw784= root@cloudinit-demo
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBvDW90FWxBenGniN150kLLqe/hqCoATR5UFr2KNH6dg root@cloudinit-demo
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCTmR9QUq0oI32yqMgc+1mXn3GEUtDt9eCVyJw6G0lUt6zvNMrlLTspoMetfuEUVnMGgMaJujWS0wV04ff4xk2sBT7ZAW5gNj089SO+z1CV/jiksuYsWVbz8nH5LRn0CvIvQ9j5nTgUi8cS6/mHyykK+I8oC3aQKX8HF7Qv8AV/UsclvaHi0Y+swTWXvvzrA4lg6LpbOPlsLqqLIq7ThZC+VgtW138c5qwQiYQcUlkdwrc1fXfqTGnF2XGcw8ZohswQsJuefSYTOrd3598c196RBVDBX5qFY8nKoj9jP6eNriInUaRocLpLIUi6DkZ8NbVspn8ASW+c2RKz6NU8VbWmazCOzVuB7RXTUPkL7qBXnNvRhXZYTD88HF6W2wWfX4v0JLI8ooRw1QnqAk7v2tEAmbx0DYEnzxEHlJcQ71uv+X6Rh6MS4CDA+73VtJPlC5ceDQVCI9ZO60BZVsoLzdfKkrRjnO0eCEp7nr1rbl6i0jtYAEwMlnJcLlclobFOxrk= root@cloudinit-demo
-----END SSH HOST KEY KEYS-----
💡 说明:
htop is already the newest version是因为演示环境先前已装过这两个包——packages指令由 apt 幂等执行,已安装时不会重复动作。首尾两段控制台输出(含主机密钥指纹表)同时落盘于/var/log/cloud-init-output.log。
5.3 状态确认
四阶段跑完后查询状态:
cloud-init status
实测回显:
status: done
长格式给出各阶段详情:
cloud-init status --long
实测回显:
status: done
extended_status: done
boot_status_code: enabled-by-sysvinit
last_update: Thu, 01 Jan 1970 00:37:26 +0000
detail: DataSourceNoCloud [seed=/var/lib/cloud/seed/nocloud]
errors: []
recoverable_errors: {}
逐项解读:extended_status: done 表示全部阶段成功;boot_status_code 是单元自启方式;detail 显示本次命中的数据源;errors/recoverable_errors 非空时表示有失败或可恢复告警,排障时先看这里。机器重启后 last_update 会更新为真实时间戳,演示环境的时钟为相对计时故显示为 epoch 附近值。
六、首启结果逐项验证
本章对 4.2 小节 user-data 的每一项能力逐一取证,确认全部生效。
6.1 主机名与 hosts
hostname
实测回显:
cloudinit-demo
grep '127.0.1.1' /etc/hosts
实测回显:
127.0.1.1 cloudinit-demo cloudinit-demo
6.2 deploy 用户、密钥与 sudo
id deploy
实测回显:
uid=1000(deploy) gid=1000(deploy) groups=1000(deploy),4(adm),27(sudo)
ls -l /home/deploy/.ssh/authorized_keys
实测回显:
-rw------- 1 deploy deploy 103 Oct 17 00:09 /home/deploy/.ssh/authorized_keys
cat /etc/sudoers.d/90-cloud-init-users
实测回显:
# Created by cloud-init v. 26.1-0ubuntu1~22.04.1 on Fri, 16 Oct 2026 17:51:34 +0000
# User rules for deploy
deploy ALL=(ALL) NOPASSWD:ALL
# User rules for ubuntu
ubuntu ALL=(ALL) NOPASSWD:ALL
💡 说明:
90-cloud-init-users由 users_groups 模块自动生成并设为只读(root 只读权限),除 deploy 外的ubuntu条目来自发行版默认用户(cloud.cfg 的 system_info.default_user)。
6.3 root 密码
chpasswd 落盘的是 yescrypt 哈希,用 python 的 crypt 模块验证口令可匹配:
python3 -c "
import crypt, spwd
h = spwd.getspnam('root').sp_pwdp
print('hash prefix:', h[:10])
print('q1w2e3r4 matches:', crypt.crypt('q1w2e3r4', h) == h)
print('wrongpw matches:', crypt.crypt('wrongpw', h) == h)
"
实测回显:
hash prefix: $y$j9T$X7h
q1w2e3r4 matches: True
wrongpw matches: False
6.4 软件包、write_files 与 runcmd 产物
dpkg -l htop nginx | tail -2
实测回显:
ii htop 3.0.5-7build2 amd64 interactive processes viewer
ii nginx 1.18.0-6ubuntu14.21 amd64 small, powerful, scalable web/proxy server
cat /etc/motd.d/cloudinit-demo
实测回显:
This host was provisioned by cloud-init 26.1.
cat /var/log/hello-cloud-init.txt
实测回显:
hello from cloud-init Sat Oct 17 00:09:52 UTC 2026
6.8.0-138-generic
6.5 运行数据目录与实例标识
ls /var/lib/cloud/instances/
实测回显:
iid-cloudinit-demo-001
cat /run/cloud-init/.instance-id
实测回显:
iid-cloudinit-demo-001
cloud-id
实测回显:
nocloud
cloud-init query instance-id
实测回显:
iid-cloudinit-demo-001
cloud-init query local-hostname
实测回显:
cloudinit-demo
💡 说明:
cloud-id输出小写数据源类型;cloud-init query直接读/run/cloud-init/instance-data.json的标准化实例数据树,query --list-keys可列出全部可用键。
七、进阶:其他 user-data 形态实战
7.1 #! 脚本形态
user-data 以 #! 开头时被当作 shell 脚本原样执行。替换种子内容(同时把 instance-id 换新以触发重跑):
cat > /var/lib/cloud/seed/nocloud/user-data <<'EOF'
#!/bin/sh
echo "script user-data executed on $(hostname) at $(date)" > /var/log/script-userdata.log
id deploy >> /var/log/script-userdata.log
EOF
sed -i 's/iid-cloudinit-demo-001/iid-cloudinit-demo-002/' /var/lib/cloud/seed/nocloud/meta-data
重跑四阶段(命令同 5.2 小节)后,脚本确实执行并产出日志:
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)
新实例目录随之生成:
ls /var/lib/cloud/instances/
实测回显:
iid-cloudinit-demo-002
⚠️ 注意:instance-id 不变时,即使修改 user-data,重跑也只执行 per-boot 类模块(如 per-boot 脚本),cloud-config 主体动作会因「该实例已处理过」被跳过——这是排障「改了 seed 不生效」的关键(实例缓存机制详见《cloud-init 26.1 进阶实战与运维》)。
7.2 多部分 MIME:cloud-config 与脚本合并投放
cloud-init devel make-mime 把多个文件打包成一份 multipart user-data。先准备两个成分文件:
cat > /tmp/u1 <<'EOF'
#!/bin/sh
echo "mime script part ran at $(date)" >> /var/log/mime-parts.log
EOF
cat > /tmp/u2 <<'EOF'
#cloud-config
write_files:
- path: /tmp/mime-test.txt
content: hello-mime
EOF
用 文件:类型 的参数形式合成(多个 -a 按顺序追加成分):
cloud-init devel make-mime -a /tmp/u2:cloud-config -a /tmp/u1:x-shellscript > /tmp/mime-userdata
head -6 /tmp/mime-userdata
实测回显:
Content-Type: multipart/mixed; boundary="===============4276096959122858351=="
MIME-Version: 1.0
--===============4276096959122858351==
Content-Type: text/cloud-config; charset="us-ascii"
MIME-Version: 1.0
把 /tmp/mime-userdata 覆盖到种子 user-data 并换新 instance-id 后重跑,两种成分都会执行:/tmp/mime-test.txt 出现且内容为 hello-mime,/var/log/mime-parts.log 追加了脚本输出。
7.3 ISO 种子盘:一份种子同时服务 NoCloud 与 ConfigDrive
除了种子目录,NoCloud 也支持从卷标为 cidata 的 ISO 读取种子。用 genisoimage 打包(ConfigDrive 数据源同样认 cidata 卷标,一份 ISO 两种数据源都能消费):
cd /var/lib/cloud/seed/nocloud
genisoimage -output /tmp/seed.iso -volid cidata -joliet -rock user-data meta-data
实测回显:
I: -input-charset not specified, using utf-8 (detected in locale settings)
Total translation table size: 0
Total rockridge attributes bytes: 273
Total directory bytes: 0
Path table size(bytes): 10
Max brk space used 0
183 extents written (0 MB)
核对产物:
ls -l /tmp/seed.iso
实测回显:
-rw-r--r-- 1 root root 374784 Oct 16 18:01 /tmp/seed.iso
💡 说明:
-volid cidata是硬性要求(小写),数据源识别逻辑按卷标匹配;物理服务器与虚拟化平台可直接把该 ISO 作为配置盘挂载。
7.4 per-boot 脚本目录
/var/lib/cloud/scripts/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
重跑 final 阶段(cloud-init modules --mode=final)后查看:
cat /var/log/per-boot.log
实测回显:
per-boot ran at Fri Oct 16 17:59:14 UTC 2026
脚本目录全家福(四类频率各一个目录):
ls /var/lib/cloud/scripts/
实测回显:
per-boot
per-instance
per-once
vendor
八、常见问题(FAQ)
Q1:首启日志报 RuntimeError: 'udevadm test-builtin net_setup_link' unable to run successfully for all devices. 怎么办?
这是网络渲染阶段在无 udev 设备管理环境(最小化安装、救援环境)中的已知失败形态。若机器网络由外部管理、无需 cloud-init 接管,写入禁用文件后重跑:
printf 'network: {config: disabled}' > /etc/cloud/cloud.cfg.d/99-disable-network-config.cfg
cat /etc/cloud/cloud.cfg.d/99-disable-network-config.cfg
实测回显:
network: {config: disabled}
重跑后网络渲染跳过,其余阶段正常执行。若仍需 cloud-init 配置网络,则要修复 udev 环境后再跑。
Q2:修改了 user-data 但重跑没有生效?
实例缓存机制在起作用:cloud-init 以 instance-id 为键缓存实例数据,id 不变时只跑 per-boot 类动作。两种处理:其一,按 7.1 小节换新 instance-id;其二,执行 cloud-init clean --logs 清掉运行数据后完整重跑(clean 用法见《cloud-init 26.1 进阶实战与运维》)。
Q3:cloud-init schema 报 Additional properties are not allowed 是什么意思?
表示 user-data 里出现了规范之外的指令键,十有八九是拼写错误(如 usres 应为 users)。cloud-config 的指令键区分大小写且全小写下划线风格,建议对照 cloud-init schema --help 与官方 examples 目录逐项检查,改完再校验到 Valid schema 为止。
Q4:无 systemd 运行的环境里 set_passwords/ssh 模块会失败吗?
部分动作会降级:26.1 的 set_passwords 模块会尝试查询 ssh 服务状态(systemctl show --property ActiveState --value ssh),无 systemd 时该查询失败并留下告警,但密码写入 /etc/shadow 的动作本身已完成;SSH 服务重启则在 systemd 可用后随开机完成。这是手工执行四阶段时日志里出现 sshd 相关告警的常见原因,属预期行为。
Q5:怎么查看 cloud-init 把最终配置合并成了什么样?
查看聚合配置文件 /run/cloud-init/combined-cloud-config.json,它是 cloud.cfg、cloud.cfg.d、meta-data、user-data 合并后的最终视图:
head -20 /run/cloud-init/combined-cloud-config.json
实测回显(节选):
{
"_doc": "Aggregated cloud-config created by merging merged_system_cfg (/etc/cloud/cloud.cfg and /etc/cloud/cloud.cfg.d), metadata, vendordata and userdata. The combined_cloud_config represents the aggregated desired configuration acted upon by cloud-init.",
"_log": [
"[loggers]\nkeys=root,cloudinit\n\n[handlers]\nkeys=consoleHandler,cloudLogHandler\n\n[formatters]\nkeys=simpleFormatter,arg0Formatter\n\n[logger_root]\nlevel=DEBUG\nhandlers=consoleHandler,cloudLogHandler\n\n[logger_cloudinit]\nlevel=DEBUG\nqualname=cloudinit\nhandlers=\npropagate=1\n\n[handler_consoleHandler]\nclass=StreamHandler\nlevel=WARNING\nformatter=arg0Formatter\nargs=(sys.stderr,)\n\n[formatter_simpleFormatter]\nformat=[CLOUDINIT] %(filename)s[%(levelname)s]: %(message)s\n",
"[handler_cloudLogHandler]\nclass=FileHandler\nlevel=DEBUG\nformatter=arg0Formatter\nargs=('/var/log/cloud-init.log', 'a', 'UTF-8')\n",
"[handler_cloudLogHandler]\nclass=handlers.SysLogHandler\nlevel=DEBUG\nformatter=simpleFormatter\nargs=(\"/dev/log\", handlers.SysLogHandler.LOG_USER)\n"
],
"cloud_config_modules": [
末行截断为展示节选;完整文件还包含合并后的 datasource_list、system_info、三大模块清单等全部生效键值,排障「我配置的项到底有没有生效」时以它为准。
九、参考链接
- cloud-init 官网:https://cloud-init.io/
- 官方文档(Read the Docs):https://cloud-init.readthedocs.io/
- NoCloud 数据源文档:https://cloud-init.readthedocs.io/en/latest/reference/datasources/nocloud.html
- cloud-config 模块示例库:https://cloud-init.readthedocs.io/en/latest/reference/examples.html
- GitHub 仓库:https://github.com/canonical/cloud-init