cloud-init 26.1 配置参数详解
基于 Ubuntu 22.04 实测环境逐项拆解 cloud-init 26.1 配置体系,覆盖配置目录与合并规则、cloud.cfg 顶层参数、三大模块清单 53 个模块、system_info 发行版配置、日志配置与生产配置模板,全部配置内容实测采集。
cloud-init 26.1 配置参数详解
目标:逐项讲清 cloud-init 26.1 的配置体系——配置目录与合并规则、cloud.cfg 全部顶层参数、三大模块清单 53 个模块的职责、system_info 发行版配置与日志配置,并给出可直接落地的生产配置模板。全部配置文件内容已在 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
- 配置目录:
/etc/cloud/(主配置cloud.cfg、扩展目录cloud.cfg.d/、模板目录templates/) - 运行数据目录:
/var/lib/cloud/;运行态状态:/run/cloud-init/ - 主日志:
/var/log/cloud-init.log;命令输出日志:/var/log/cloud-init-output.log
二、前置条件
- 已安装 cloud-init 26.1 并能正常输出版本:
cloud-init --version
实测回显:
/usr/bin/cloud-init 26.1-0ubuntu1~22.04.1
- 以下命令均以 root 执行;改动
/etc/cloud/前建议先备份原文件。 - 修改配置后,对已初始化的机器需要
cloud-init clean后重跑才会生效(详见《cloud-init 26.1 进阶实战与运维》),本章只讲参数含义与改法。
三、配置文件体系与查看方式
3.1 配置目录结构
cloud-init 的全部配置落点在 /etc/cloud/,实测目录结构如下:
ls -R /etc/cloud/ | head -14
实测回显:
/etc/cloud/:
build.info
clean.d
cloud.cfg
cloud.cfg.d
templates
/etc/cloud/clean.d:
/etc/cloud/cloud.cfg.d:
05_logging.cfg
90_dpkg.cfg
99-disable-network-config.cfg
README
wc -l /etc/cloud/cloud.cfg
实测回显:
136 /etc/cloud/cloud.cfg
各项说明:
| 路径 | 作用 |
|---|---|
| cloud.cfg | 发行版基线配置(实测 136 行),定义默认用户、三大模块清单与 system_info |
| cloud.cfg.d/ | 扩展配置目录,按文件名字母序合并覆盖 cloud.cfg |
| 05_logging.cfg | 日志行为配置(见第七章) |
| 90_dpkg.cfg | 包维护脚本生成的数据源清单(见 4.4 小节) |
| 99-disable-network-config.cfg | 演示环境自建的文件(禁用 cloud-init 网络管理,见 6.3 小节) |
| templates/ | 各模块渲染配置用的 jinja 模板(hosts、chrony、apt 源等,实测共 52 个) |
| clean.d/ | cloud-init clean 时调用的清理钩子目录(包自带为空) |
| build.info | 包构建标识,实测内容为 serial: 20260924.1 |
3.2 配置合并规则
cloud-init 启动时按以下顺序合并出最终配置:
- 先读内置默认值;
- 读
/etc/cloud/cloud.cfg; - 再按文件名字母序读
/etc/cloud/cloud.cfg.d/*.cfg,后读的键覆盖先读的键; - 数据源的 meta-data / user-data / vendor-data 中的系统配置键再叠加其上。
因此「改配置」的标准姿势是:不直接改 cloud.cfg,而在 cloud.cfg.d/ 新建一个编号更靠后的 .cfg 文件覆盖(如 99-custom.cfg)。cloud.cfg 的注释原文也提示了 datasource 单行数组的书写要求(跨行数组 ds-identify 读不到)。
3.3 查看合并结果
改完配置后,用聚合视图确认最终生效值(排障利器):
python3 -c "
import json
d = json.load(open('/run/cloud-init/combined-cloud-config.json'))
for k in ['users', 'disable_root', 'preserve_hostname', 'output', 'network']:
print(k, '=>', json.dumps(d.get(k)))
"
实测回显(演示环境已写 network: {config: disabled}):
users => ["default"]
disable_root => true
preserve_hostname => false
output => {"all": "| tee -a /var/log/cloud-init-output.log"}
network => {"config": "disabled"}
💡 说明:
combined-cloud-config.json是 cloud.cfg、cloud.cfg.d、meta-data、user-data、vendor-data 合并后的最终视图,见《cloud-init 26.1 快速入门与 NoCloud 数据源实战》8 章 Q5。检查任意参数是否生效,以它为准,不要凭 cloud.cfg 内容推断。
四、cloud.cfg 顶层参数详解
Ubuntu 22.04 打包的 cloud.cfg 顶层参数实测如下(行号为实测文件位置):
grep -nE '^[a-z_]+:' /etc/cloud/cloud.cfg | head -8
实测回显:
7:users:
12:disable_root:
15:preserve_hostname:
27:cloud_init_modules:
45:cloud_config_modules:
63:cloud_final_modules:
90:system_info:
顶层只有 4 个业务参数(其余 3 个是模块清单与 system_info),逐项详解如下。
4.1 users
users:
- default
决定首启创建哪些用户。default 是占位符,引用 system_info.default_user 定义的发行版默认用户(Ubuntu 为 ubuntu,见 6.1 小节)。也可以写成显式清单创建任意用户,写法与 user-data 的 users 指令一致(示例见《cloud-init 26.1 快速入门与 NoCloud 数据源实战》4.2 小节)。常见取值对比:
| 写法 | 效果 |
|---|---|
- default | 创建发行版默认用户(ubuntu) |
- default + - name: ops | 默认用户之外再创建 ops |
[] | 不创建任何用户 |
4.2 disable_root
disable_root: true
是否禁用 root 直接 SSH 登录。true 时 users_groups/ssh 模块会在 root 的 authorized_keys 中为密钥行添加限制前缀(no-port-forwarding 等选项与提示登录默认用户的 command 指令),使 root 密钥登录被引导到默认用户。实测值为 true;要放开 root 登录则改为 false。
4.3 preserve_hostname
preserve_hostname: false
false 时 set_hostname/update_hostname 模块按数据源元数据(meta-data 的 local-hostname 或 user-data 的 hostname 指令)设置主机名;true 则完全不动主机名。固定主机名的机器改 true,避免每次首启被数据源覆盖。
4.4 datasource_list(90_dpkg.cfg)
Ubuntu 打包把数据源清单放在 cloud.cfg.d/90_dpkg.cfg(由 deb 维护脚本生成):
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 ]
清单顺序即探测优先级,实测 31 项。生产建议收窄到实际平台,缩短首启探测耗时:
printf 'datasource_list: [ NoCloud, ConfigDrive ]' > /etc/cloud/cloud.cfg.d/91-ds-limit.cfg
python3 -c "import json; print(json.load(open('/run/cloud-init/combined-cloud-config.json')).get('datasource_list'))"
收窄后重跑,合并视图实测回显:
['NoCloud', 'ConfigDrive']
💡 技术拓展:数据源类型全量对比(NoCloud/ConfigDrive/Ec2/OpenStack/各公有云/None 的来源与场景)已在《cloud-init 26.1 快速入门与 NoCloud 数据源实战》3.2 小节给出,此处不重复。修改 90_dpkg.cfg 本体不要手工编辑,按文件首行提示用
dpkg-reconfigure cloud-init;自建新编号文件覆盖是等效且更可控的做法(本文即用 91-ds-limit.cfg)。
4.5 output
output: {all: '| tee -a /var/log/cloud-init-output.log'}
定义四阶段 stdout/stderr 的去向。all 一键同时管 stdout 与 stderr,值是管道命令:所有阶段控制台输出经 tee -a 追加到 /var/log/cloud-init-output.log。该键实际写在 05_logging.cfg 中随 cloud.cfg 一起合并,可在自建 .cfg 中覆盖,例如只要 stderr 时写 output: {err: '| tee -a /var/log/cloud-init-err.log'}。支持的键:all/out/err,值可以是字符串(当作命令管道)或文件路径。
4.6 其他常用顶层键
以下键在 Ubuntu 26.1 的 cloud.cfg 中未显式写出,走内置默认值,但都是高频定制项,实测默认行为如下:
| 键 | 默认值 | 说明 |
|---|---|---|
| ssh_pwauth | 0 | 是否允许密码 SSH 登录;显式写入 cloud.cfg 即可覆盖 |
| manage_etc_hosts | false | 是否托管 /etc/hosts,多用 user-data 按实例控制 |
| growpart.mode | auto | 磁盘分区扩容模式(auto/growpart/off) |
| resize_rootfs | true | 根文件系统是否随分区扩容 |
| timezone | 无 | 设定时区,等价 user-data 的 timezone 指令 |
| package_update | false | 首启是否执行 apt-get update |
| final_message | "Cloud-init v. VERSION finished at TIME. Up UPTIME seconds" | 完成消息模板,支持 VERSION/TIME/UPTIME/DATASOURCE 四个内置变量 |
验证默认值最直接的方法是看合并视图:
python3 -c "
import json
d = json.load(open('/run/cloud-init/combined-cloud-config.json'))
print('ssh_pwauth:', d.get('ssh_pwauth', '(unset -> default 0)'))
print('final_message:', d.get('final_message', '(unset -> built-in)'))
print('vendor_data:', d.get('vendor_data'))
"
实测回显:
ssh_pwauth: (unset -> default 0)
final_message: (unset -> built-in)
vendor_data: {'enabled': True, 'prefix': []}
五、三大模块清单
模块(module)是 cloud-init 的最小执行单元,三大清单决定每个阶段跑哪些模块,顺序即执行顺序。26.1 实测共 15+15+23=53 个模块。
5.1 cloud_init_modules(init 阶段,15 个)
sed -n '/^cloud_init_modules:/,/^cloud_config_modules:/p' /etc/cloud/cloud.cfg | grep ' - ' | tr -d ' -' | paste -sd,
实测回显:
seed_random,bootcmd,write_files,growpart,resizefs,disk_setup,mounts,set_hostname,update_hostname,update_etc_hosts,ca_certs,rsyslog,users_groups,ssh,set_passwords
逐个模块职责:
| 模块 | 职责 | 对应 user-data 指令 |
|---|---|---|
| seed_random | 向内核熵池注入随机数据 | seed_random |
| bootcmd | 极早期执行的命令(每此阶段必跑) | bootcmd |
| write_files | 写入文件 | write_files |
| growpart | 根分区扩容到磁盘大小 | growpart |
| resizefs | 根文件系统随分区扩容 | resizefs |
| disk_setup | 磁盘分区表与文件系统创建 | disk_setup / fs_setup |
| mounts | 挂载点与 swap 配置 | mounts / swap |
| set_hostname | 设置主机名 | hostname / fqdn |
| update_hostname | 每次引导更新主机名 | 同上 |
| update_etc_hosts | 更新 /etc/hosts | manage_etc_hosts |
| ca_certs | 管理 CA 证书 | ca_certs |
| rsyslog | 配置 rsyslog 转发 | rsyslog |
| users_groups | 创建用户与用户组 | users / groups |
| ssh | 生成/写入 SSH 主机密钥与 authorized_keys | ssh_* 键、ssh_authorized_keys |
| set_passwords | 设置用户密码与 ssh_pwauth | chpasswd / ssh_pwauth / password |
5.2 cloud_config_modules(config 阶段,15 个)
sed -n '/^cloud_config_modules:/,/^cloud_final_modules:/p' /etc/cloud/cloud.cfg | grep ' - ' | tr -d ' -' | paste -sd,
实测回显:
wireguard,snap,ubuntu_autoinstall,ssh_import_id,keyboard,locale,grub_dpkg,apt_pipelining,apt_configure,ubuntu_pro,ntp,timezone,disable_ec2_metadata,runcmd,byobu
逐个模块职责:
| 模块 | 职责 | 对应 user-data 指令 |
|---|---|---|
| wireguard | 配置 WireGuard 隧道 | wireguard |
| snap | 安装 snap 包 | snap |
| ubuntu_autoinstall | Ubuntu 自动安装相关 | autoinstall |
| ssh_import_id | 从 GitHub/LaunchPad 导入公钥 | ssh_import_id |
| keyboard | 设置键盘布局 | keyboard |
| locale | 设置系统 locale | locale |
| grub_dpkg | 处理 grub 升级交互(grub-pc 安装确认) | grub_dpkg |
| apt_pipelining | apt 下载管线配置 | apt_pipelining |
| apt_configure | 配置 apt 源/代理/首选项 | apt / apt_primary 等 |
| ubuntu_pro | 附加 Ubuntu Pro 订阅 | ubuntu_pro |
| ntp | 配置 NTP 服务与服务器列表 | ntp |
| timezone | 设置时区 | timezone |
| disable_ec2_metadata | 关闭 EC2 元数据路由 | disable_ec2_metadata |
| runcmd | 注册 final 阶段执行的命令 | runcmd |
| byobu | 配置 byobu 终端复用 | byobu |
5.3 cloud_final_modules(final 阶段,23 个)
sed -n '/^cloud_final_modules:/,/^system_info:/p' /etc/cloud/cloud.cfg | grep ' - ' | tr -d ' -' | paste -sd,
实测回显:
package_update_upgrade_install,fan,landscape,lxd,ubuntu_drivers,write_files_deferred,puppet,chef,ansible,mcollective,salt_minion,reset_rmc,scripts_vendor,scripts_per_once,scripts_per_boot,scripts_per_instance,scripts_user,ssh_authkey_fingerprints,keys_to_console,install_hotplug,phone_home,final_message,power_state_change
逐个模块职责:
| 模块 | 职责 | 对应 user-data 指令 |
|---|---|---|
| package_update_upgrade_install | 安装/升级/卸载软件包 | packages / package_update / package_upgrade |
| fan | 配置 fan 网络覆盖(跨主机 overlay 地址段) | fan |
| landscape | 配置 Canonical Landscape 管理端 | landscape |
| lxd | 初始化 LXD | lxd |
| ubuntu_drivers | 自动安装硬件驱动 | drivers |
| write_files_deferred | 延迟写文件(final 才写) | write_files 中 defer: true |
| puppet / chef / ansible / mcollective / salt_minion | 各配置管理工具接入 | puppet / chef / ansible 等 |
| reset_rmc | 重置 RMC(IBM Cloud 场景) | 无 |
| scripts_vendor | 执行 vendor 脚本目录 | /var/lib/cloud/scripts/vendor |
| scripts_per_once / per_boot / per_instance | 按频率执行脚本目录 | scripts_per_once 等 |
| scripts_user | 执行 user-data 脚本形态 | #! 脚本 |
| ssh_authkey_fingerprints | 输出 authorized_keys 指纹 | 无 |
| keys_to_console | 把密钥指纹打到控制台 | ssh |
| install_hotplug | 安装热插拔钩子 | 无 |
| phone_home | 上报完成状态到 URL | phone_home |
| final_message | 输出完成消息 | final_message |
| power_state_change | 按计划关机/重启 | power_state |
5.4 模块启停定制
不需要的模块直接从清单删行(或注释)即可;单个模块的参数写在顶层键(与模块同名)或 user-data 指令中。注意 21.x 的连字符旧名(write-files/users-groups/set-passwords 等)在 26.1 已全部改为下划线风格,跨版本迁移配置时模块清单要改名(CentOS 8 的 21.1 仍用连字符旧名,对照见《cloud-init 21.1 CentOS 8 安装指南》8.1 小节)。
六、system_info 详解
system_info(cloud.cfg 第 90 行起)是发行版相关的底层定义,一般不改动,但读懂它才能解释默认用户、网络渲染器等行为。
6.1 default_user
实测内容:
default_user:
name: ubuntu
lock_passwd: True
gecos: Ubuntu
groups: [adm, audio, cdrom, dialout, dip, floppy, lxd, netdev, plugdev, sudo, video]
sudo: ["ALL=(ALL) NOPASSWD:ALL"]
shell: /bin/bash
逐项说明:name: ubuntu 即 users 清单里 default 引用的对象;lock_passwd: True 密码锁定只能密钥登录;sudo 免密 ALL 权限;groups 决定该用户的附加组。首次引导后验证:
id ubuntu
实测回显:
uid=1001(ubuntu) gid=1003(ubuntu) groups=1003(ubuntu),4(adm),20(dialout),24(cdrom),25(floppy),27(sudo),29(audio),30(dip),44(video),46(plugdev),1001(lxd),1002(netdev)
6.2 distro 与 ssh_svcname
实测 distro: ubuntu 决定加载 Ubuntu 发行版类(软件包命令用 apt、用户管理用 useradd 等);ssh_svcname: ssh 对应 Ubuntu 的 SSH 服务名。CentOS/RHEL 打包为 distro: rhel、ssh_svcname: sshd,这是跨发行版迁移配置时的关键差异。
6.3 network
实测内容:
network:
dhcp_client_priority: [dhclient, dhcpcd, udhcpc]
renderers: ['netplan', 'eni', 'sysconfig']
activators: ['netplan', 'eni', 'network-manager', 'networkd']
💡 技术拓展:网络渲染器(renderer)决定网络配置写到哪个体系——
渲染器 配置落点 适用 netplan /etc/netplan/*.yaml Ubuntu 18.04+ 默认 eni /etc/network/interfaces Debian 传统 ifupdown sysconfig /etc/sysconfig/network-scripts/ RHEL/CentOS 系 Ubuntu 打包按优先级先试 netplan;activators 是渲染后激活网络的实现。禁用 cloud-init 网络管理用
network: {config: disabled}(实测见《cloud-init 26.1 快速入门与 NoCloud 数据源实战》8 章 Q1)。
6.4 paths 与 package_mirrors
实测 paths.cloud_dir: /var/lib/cloud/、paths.templates_dir: /etc/cloud/templates/,另有 paths.docs_dir: /usr/share/doc/cloud-init/(合并视图实测)。package_mirrors 按架构定义 apt 镜像搜索规则:i386/amd64 失败兜底 http://archive.ubuntu.com/ubuntu 与 http://security.ubuntu.com/ubuntu,并在 EC2 等平台按 region 变量搜索区域镜像;arm64/armel/armhf 走 http://ports.ubuntu.com/ubuntu-ports。私有源场景在 user-data 的 apt 指令里覆盖更常见。
七、05_logging.cfg 日志配置详解
该文件实测位于 /etc/cloud/cloud.cfg.d/05_logging.cfg,用 YAML 锚点定义三套日志后端、按 log_cfgs 选用。核心结构实测如下:
grep -nE '^\s*(- )?&|^log_cfgs|^output' /etc/cloud/cloud.cfg.d/05_logging.cfg
实测回显:
11: - &log_base |
42: - &log_file |
48: - &log_syslog |
55:log_cfgs:
71:output: {all: '| tee -a /var/log/cloud-init-output.log'}
逐项说明:
&log_base:loggers/handlers/formatters 骨架,root 与 cloudinit 两个 logger 都是 DEBUG 级,控制台 handler 只输出 WARNING 以上;&log_file:FileHandler 写/var/log/cloud-init.log(追加模式);&log_syslog:SysLogHandler 写/dev/log(集中日志场景);log_cfgs是候选清单,逐项尝试、第一个可用者生效——当前选中[ *log_base, *log_file ](文件日志),注释行里预置了 syslog 组合,把log_cfgs改为- [ *log_base, *log_syslog ]即切换;output见 4.5 小节。
验证日志确实按此配置落盘:
ls -l /var/log/cloud-init.log /var/log/cloud-init-output.log
实测回显:
-rw-r----- 1 root adm 6583 Oct 17 00:09 /var/log/cloud-init-output.log
-rw-r----- 1 root adm 74752 Oct 17 00:09 /var/log/cloud-init.log
八、生产配置模板
一份可直接落地的生产基线(写入 /etc/cloud/cloud.cfg.d/99-production.cfg,按 3.2 小节规则覆盖默认值):
# /etc/cloud/cloud.cfg.d/99-production.cfg
# 场景:私有虚拟化平台(NoCloud/ConfigDrive 数据源)、16GB 内存、NVMe SSD、无状态交付
datasource_list: [ NoCloud, ConfigDrive ]
ssh_pwauth: 0
preserve_hostname: false
package_update: true
package_upgrade: false
manage_etc_hosts: localhost
final_message: "cloud-init completed at __TIME__ after __UPTIME__ seconds on __DATASOURCE__"
逐项说明:收窄数据源清单到实际平台(加快探测、减少误命中);禁密码 SSH(配合 user-data 注入密钥);保留数据源主机名管理;首启更新源索引但不升级全量包(升级交给镜像构建流程);hosts 改 localhost 模式(仅本机回环行,不整文件托管);final_message 模板带上数据源标识便于控制台确认。
落地后核验(需重跑初始化后生效):
cloud-init schema --config-file /etc/cloud/cloud.cfg.d/99-production.cfg
实测回显:
Valid schema /etc/cloud/cloud.cfg.d/99-production.cfg
九、常见问题(FAQ)
Q1:改了 cloud.cfg 不生效?
三种可能:其一,实例已完成初始化,cloud-init 不会自动重跑,需 cloud-init clean 后重跑;其二,被 cloud.cfg.d/ 中编号更靠后的文件覆盖,用合并视图(3.3 小节)确认实际生效值;其三,改的是发行版默认文件而升级包时会被包管理器接管,标准做法是自建 99-*.cfg。
Q2:datasource_list 顺序影响什么? 顺序即探测优先级,第一个命中的数据源生效。把不存在的平台排前面会白等探测超时(Ec2 默认最长等 120 秒),生产机按实际平台收窄能显著缩短首启时间(实测见 4.4 小节)。
Q3:模块清单里删掉 ssh 模块会怎样?
首启不再生成 SSH 主机密钥与 authorized_keys,已有密钥的机器不受影响,新机器会因无主机密钥导致 sshd 启动失败——不要删。想自定义主机密钥类型用顶层键 ssh_genkeytypes(如 ['ed25519'],CentOS 8 打包默认即此值)。
Q4:两个文件都写了同一参数,到底谁生效?
按文件名字母序后读覆盖先读:05_logging.cfg、90_dpkg.cfg、91-ds-limit.cfg、99-production.cfg 依次读取,后者覆盖前者同名键。cloud.cfg 本身先于全部 cloud.cfg.d 文件。有歧义时直接查合并视图,不要猜。
Q5:怎么确认某模块实际跑了没有?
两个手段:看主日志 grep 'config-runcmd' /var/log/cloud-init.log(模块名逐个落日志);或用 analyze 工具看耗时报告(cloud-init analyze blame,实测回显见《cloud-init 26.1 进阶实战与运维》)。
十、参考链接
- cloud-init 官网:https://cloud-init.io/
- 官方文档(Read the Docs):https://cloud-init.readthedocs.io/
- 配置参考(merge/base config):https://cloud-init.readthedocs.io/en/latest/reference/base-config.html
- 模块清单参考:https://cloud-init.readthedocs.io/en/latest/reference/modules.html
- GitHub 仓库:https://github.com/canonical/cloud-init