Cloudinit通过云平台的metadata服务或ConfigDrive等数据源拿到该userdata后,首先会对其进行切分,
并分别供各模块处理。
Cloud中所有模块都放在/usr/lib/python2.6/site-packages/cloudinit/config。
有配置文件可知主要分为如下三大类:cloud_init_modules、cloud_config_modules、cloud_final_modules、
system_info。
这里需要特别提到的一个模块是scripts-user,该模块负责执行userdata中的user scripts内容以及其他模块
(如runcmd)生成的脚本,因此cloudinit的配置文件将其放在了cloud_final_modules阶段的近乎最后。
Cloud配置文件主要分为两部分:
1、参数、变量定义部分。
2、模块列表部分。
常见的配置包括:设定虚拟机的hostname、hosts文件、设定用户名密码、更新apt-get的本地缓存、
调整文件系统的大小(注意不是调整分区的大小)等。
配置文件:/etc/cloud/cloud.cfg 。
cloudinit会在虚拟机启动的过程中分四个阶段运行,按照时间顺序分为:cloud-init-local, cloud-init,
cloud-config, cloud-final。
cloud-init-local阶段主要是运行本地的一些初始化脚本。cloud-init, cloud-config, cloud-final
阶段分别执行配置文件中名为cloud_init_modules、cloud_config_modules、cloud_final_modules下的所有模块,
如果模块列表为空,则什么都不运行。
各模块在运行时,会根据之前定义的变量/参数的值,配置虚拟机的状态。
update_etc_host模块,/usr/lib/python2.6/site-packages/cloudinit/config/cc_update_etc_hosts.py。
该模块用来设置主机的hosts文件,其中就用到了hostname、fqdn、manage_etc_hosts等变量的值。
模块首先尝试从cloudinit的配置文件中读取这些变量的值,如果没有定义,
则尝试从其他的数据源中获取变量的值,例如对于openstac来讲,
可以从metadata service(http://169.254.169.254/latest/meta-data/hostname)获取虚拟机的主机名。
如果初始模板没有配置此参数,则可以通过创建虚机时的--user-data参数获取相应的参数值)。
4.2. 实例讲解
以主机名写入hosts文件为例进行介绍:
一、模板初始配置
未经设置的hosts文件
/etc/cloud/cloud.cfg配置文件里设置
manage_etc_hosts: True
preserve_hostname: False
manage_etc_hosts设置为true,虚机启动的时候cloud_init_modules阶段运行update_etc_hos模块,
获取变量值和相应的参数值。模板文件/etc/cloud/templates/hosts.redhat.tmpl被利用,
重写hosts文件如下:
二、以自定义脚本添加
如果出事模板里没有设置,可以通过nova boot创建虚机的时候指定--user-data参数获取配置值。
nova boot testhostname --flavor 6 --image d892728d-3652-49ca-a943-e8006b0cbbb2 \
--nic net-id=f4889f14-33ab-4345-b480-92db1d411a67 --user-data /root/img/pass.txt
或通过horizon页面创建虚机时指定脚本如下:
#cloud-config
chpasswd:
list: |
root:123456
expire: False
ssh_pwauth: True
manage_etc_hosts: True
preserve_hostname: False
将全域名、主机名成功写入hosts文件:
5. 部分脚本、配置示例
可以有配置文件cloud-config或者直接以脚本形式给出.
5.1. 修改root用户密码
#cloud-config
chpasswd:
list: |
root:123456
expire: False
ssh_pwauth: True
5.2. 创建新用户、ssh登陆
#!/bin/bash echo "one test about user data" >>userdata chmod 777 userdata useradd -m me echo -e 'me\tALL=(ALL)\tNOPASSWD: ALL' >> /etc/sudoers
passwd me <<EOF
abcabc
abcabc
EOF
sed -i 's/PasswordAuthentication no/PasswordAuthentication yes/g' /etc/ssh/sshd_config
service ssh restart
5.3. 全域名、主机名写入hosts文件
#cloud-config
chpasswd:
list: |
root:123456
expire: False
ssh_pwauth: True
manage_etc_hosts: True
preserve_hostname: False
Cloud-init 能够通过访问这些 URL 来获取其所需要的信息, 然后再进行配置.
但是需要说明的一点是 169.254.169.254 这个 IP 实际是不存在的,
本质上提供 metadata 的是 nova-api service,
所以通常都需要设定防火墙 DNAT 将 169.254.169.254 映射到 nova-api-service-ip:port 这个 IP.
Cloud-Init 还会按照上述模块列表的顺序来进行配置,
这是因为有些模块的执行对虚拟机操作系统当前的状态是有要求的, 后面模块的配置可能需要前面模块的配置做支撑.
而且, 模块列表中的模块具有多种运行模式:
per-once: 仅执行一次, 在执行完毕之后会在 sem 目录中创建一个信号文件, 防止在下次启动虚拟机时重复执行.
per-always: 每次启动都会执行
per-instance: 每一个虚拟机都会执行
EG.
cloud_final_modules:
- scripts-per-once
- scripts-per-boot
- scripts-per-instance
metadata 和 userdata 的区别
其实 userdata 与 metadata 本质上都是提供配置信息的数据源, 使用了相同的信息注入机制,
只是两者代表了不同的信息类型而已:
metadata 主要提供了虚拟机的常用属性, EG. hostname/network/SSH/…, 其以 key/value 的形式进行注入,
所以非常适合应用到 REST 的场景中.
userdata 主要提供了 Shell 相关的 CLI 和 Script 等, 其通过文件的方式进行注入,
支持多种文件格式(EG. gzip/Bash/cloud-init/…).
所以, 两者的区别仅在于虚拟机在获取到信息后, 对两者的处理方式不尽相同而已.
metadata 的服务机制
ConfigDrive
手动指定使用 ConfigDrive:
nova boot --config-drive=true ...
启动虚拟机时, 使用 --config-drive=true 就是使用 ConfigDrive 机制来注入 metadata 信息.
修改配置文件默认使用 ConfigDrive:
vim /etc/nova/nova.conf
[DEFAULT]
...
force_config_drive = True
ConfigDrive 机制: OpenStack 会将 metadata 信息写入虚拟机的特殊设备中, 然后在虚拟机启动时,
会将该设备挂载到虚拟机上并由 Cloud-init 读取内含的 metadata 信息, 从而实现信息注入.