cloud-init is a software package that automates the initialization of cloud instances during system boot.

cloud-init 这个软件是安装在 Guest OS 里面的。同时也是负责 Guest OS 里面组件的初始化工作。但是要运行的配置是我们从宿主机上传进去的。

cloud-init 脚本在每次 guest 重启的时候都会运行。 cloud-init 的服务端是 ad hoc 的方式实现的,各个云厂商都有自己的服务实现方式,并没有一个统一的工具来实现。

公共镜像和自定义镜像里都有 cloud-init 组件吗?

CloudInit 组件是在 guest(云主机)里面 ,主要用于 云主机启动时的初始化操作 ,负责安装和启动 Kubernetes 依赖组件。CloudInit 是注入到云主机(guest)的启动脚本,运行在用户集群的节点(即云主机)内部。

查看 cloud-init 有没有运行成功:

# Guest OS 里运行
cloud-init status --wait

- The standard for customising cloud instances

canonical/cloud-init: Official upstream for the cloud-init: cloud instance initialization

Documentation: cloud-init 25.1.2 documentation

cloud-init 的 4 个主要阶段(按执行顺序)

  • init-local
    • 在系统启动的早期执行(非常早,在网络启动前)。
    • 主要任务:识别 cloud datasource(比如 ConfigDrive、IMDS、VolcStack 等),配置本地磁盘等。
  • init
    • 配置网络、主机名、SSH key、用户等基础内容。
    • 会执行 /etc/cloud/cloud.cfg 里的 cloud_init_modules。
  • config
    • 执行 /etc/cloud/cloud.cfg 中定义的 cloud_config_modules。
    • 这里常见的任务有:写文件、设置包管理、更新系统、设置用户、时区、apt 源等。
  • final(也叫 modules-final) ✅
    • 执行 /etc/cloud/cloud.cfg 中的 cloud_final_modules 列表。
    • 通常是最后阶段,执行用户自定义脚本和指令,比如:
      • /var/lib/cloud/scripts/per-boot/
      • /var/lib/cloud/scripts/per-instance/
      • /var/lib/cloud/scripts/per-once/
      • runcmd(用户在 cloud-config 里写的命令)
      • scripts-user(用户数据中的脚本)
    • 这是 用户定义步骤最常出现的地方。
# 检查当前状态,如果是 Running 就是还在跑着
sudo cloud-init status --long

# 查看运行到哪一步了。
tail -f /var/log/cloud-init.log

# 重新跑一遍
sudo cloud-init clean
sudo cloud-init init
sudo cloud-init modules --mode=config
sudo cloud-init modules --mode=final
阶段 描述 执行脚本目录
init 初始化网络、主机名、SSH key 等 /var/lib/cloud/instance/scripts/init/
config 安装包、写文件、配置服务 /var/lib/cloud/instance/scripts/config/
final 用户脚本 (runcmd 等) 最终执行 /var/lib/cloud/instance/scripts/per-boot/

Bootcmd 第一次装系统时没有生效,但是在后续启动时生效了

检查一下 /etc/cloud/cloud.cfg 这个文件。看一下启动顺序,如果 bootcmd 在 write-files 前面,那么可能是因为先执行了 bootcmd,此时还没有任何从 metadata server 上拉下来的 scripts,再执行了 write-files,此时才把 bootcmd 的脚本放到了对应的位置,这也是为什么第二次 boot 的时候生效了,因为这个时候就有了。

解决方式是吧 bootcmd 的内容也加入到 runcmd 中去,因为 runcmd 在 write-files 后面。

Cloud-init module frequency

有三档:

  • always:每次 boot 都会运行;
  • instance:每个实例第一次创建的时候,都会运行一次;
  • once:如果基于这个镜像创建来一个实例,并且运行了一次,那么后面基于这个镜像克隆出来的其他实例也不会再运行了,频率更低。

如何查看每一个 module 的 frequency:

Cloud-init stages and modules

从下面能看出来,一共有四个 stage,每一个 stage 都有不同的 modules。

# cat /etc/cloud/cloud.cfg
users:
 - default

disable_root: 0
ssh_pwauth:   1
growpart:
    mode: auto
    devices: ['/']
    ignore_growroot_disabled: false

mount_default_fields: [~, ~, 'auto', 'defaults,nofail,x-systemd.requires=cloud-init.service', '0', '2']
resize_rootfs_tmp: /dev
ssh_deletekeys:   1
syslog_fix_perms: ~
disable_vmware_customization: false

manage_etc_hosts: localhost

cloud_init_modules:
 - disk_setup
 - migrator
 - bootcmd
 - write-files
 - growpart
 - resizefs
 - set_hostname
 - update_hostname
 - update_etc_hosts
 - rsyslog
 - users-groups
 - ssh

cloud_config_modules:
 - mounts
 - locale
 - set-passwords
 - rh_subscription
 - yum-add-repo
 - package-update-upgrade-install
 - timezone
 - puppet
 - chef
 - salt-minion
 - mcollective
 - disable-ec2-metadata
 - runcmd

cloud_final_modules:
 - rightscale_userdata
 - scripts-per-once
 - scripts-per-boot
 - scripts-per-instance
 - scripts-user
 - ssh-authkey-fingerprints
 - keys-to-console
 - phone-home
 - final-message
 - power-state-change

system_info:
  distro: debian
  paths:
    cloud_dir: /var/lib/cloud
    templates_dir: /etc/cloud/templates
  ssh_svcname: sshd

scripts-per-boot And bootcmd

bootcmd 不要被这个命令迷惑了。

/var/lib/cloud/

云实例初始化相关的关键数据和状态信息。

/var/lib/cloud/instance

该目录的内容与当前实例强绑定,不同实例(即使基于同一镜像创建)的 instance 目录内容会因元数据、用户数据的不同而存在差异。这也是 cloud-init 能够为每个实例提供独立初始化配置的关键。

/var/lib/cloud/instance/vendor-data.txt

存储云厂商的自定义配置。

主流云平台(如 OpenStack、AWS、GCP 等)通过元数据服务(Metadata Service) 动态向实例传递 vendor-data:

  • 云平台在实例创建时,会将预定义的 vendor-data 存储在其内部元数据服务中;
  • 实例启动后,cloud-init 会通过本地网络(通常是 169.254.169.254 这类保留 IP)访问云平台的元数据服务,拉取包括 vendor-data 在内的各类数据(同时拉取的还有 user-data、meta-data 等);
  • 拉取后,cloud-init 会将 vendor-data 保存到实例本地的 /var/lib/cloud/instance/vendor-data.txt 中,作为执行依据。

可以看到 vendor-data.txt 中已经包含了实例规格信息,比如 path: /home/ecs.ebmhpcpni3lm.48xlarge_runcmd.sh 这种字段。本地不会更改这个字段,这个是在服务端决定的。