cloud-init 26.1 快速入门与 NoCloud 数据源实战

以 NoCloud 数据源为主线从零跑通 cloud-init 26.1 首次初始化,覆盖四阶段模型、meta-data/user-data 编写与 schema 校验、systemd 自动执行与手工四阶段、首启产物逐项验证、脚本与 MIME/ISO 种子形态,全部命令实测通过。

cloud-initcloud-initUbuntuUbuntu 22.04Linux2026/10/17

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,写入演示文件与日志

二、前置条件

  1. 已按《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
  1. 具备 root 权限,以下命令均以 root 执行。
  2. 根目录存在 /var/lib/cloud/(安装后自动创建的运行数据目录):
ls /var/lib/cloud/

实测回显:

data
handlers
instance
instances
scripts
seed
sem
  1. 无遗留运行状态:本文在全新初始化的状态下演练。若机器已跑过一次首启,可先执行 cloud-init clean --logs 清理(详见《cloud-init 26.1 进阶实战与运维》)。

三、cloud-init 工作原理速览

本章先建立三个核心概念——四阶段执行模型、数据源、user-data 形态,后续章节全部围绕它们展开。

3.1 四阶段执行模型

cloud-init 不是常驻服务,它是「首次引导(first boot)时跑一遍」的初始化框架,由 systemd 按 4 个阶段依次拉起,每个阶段对应一个单元、执行一批模块:

阶段systemd 单元执行命令职责
init-localcloud-init-local.servicecloud-init init --local挂载本地数据源(NoCloud/ConfigDrive),配置网络之前运行
init(network)cloud-init.servicecloud-init init网络可用后运行,应用 user-data 中的系统级配置(用户、SSH 主机密钥等)
modules-configcloud-config.servicecloud-init modules --mode=config执行 config 模块清单(时区、apt 源、runcmd 注册等)
modules-finalcloud-final.servicecloud-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、自建虚拟化
Ec2169.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,逐个拉取并按上述规则处理
多部分 MIMEContent-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/hoststrue 时按模板渲染 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、三大模块清单等全部生效键值,排障「我配置的项到底有没有生效」时以它为准。

九、参考链接