一、cloud-init 工作原理
cloud-init 是 linux 的一個工具,當系統(tǒng)啟動時,cloud-init 可從 nova metadata 服務或者 config drive 中獲取 metadata,完成包括但不限于下面的定制化工作:
設置默認語言環(huán)境
設置實例主機名
添加 ssh keys到 .ssh/authorized_keys
設置用戶密碼
配置網(wǎng)絡
安裝軟件包
為了實現(xiàn) instance 定制工作,cloud-init 會按 4 個階段執(zhí)行任務:
local
init
config
final
cloud-init 安裝時會將這 4 個階段執(zhí)行的任務以服務的形式注冊到系統(tǒng)中,比如在 systemd 的環(huán)境下,我們能夠看到這4個階段分別對應的服務:
local - cloud-init-local.service
init - cloud-init.service
config - cloud-config.service
final - cloud-final.service

local 階段
作為 cloud-init 執(zhí)行的第一個階段,此時 instance 還不知道該如何配置網(wǎng)卡,cloud-init 的任務就是從 config drive 中獲取配置信息,然后寫入 /etc/network/interfaces 文件(如果是 centos 則寫入 /etc/sysconfig/network-scripts/ifcfg-xxx)。
如果沒有 config drive,則將所有網(wǎng)卡配置成 dhcp 模式。這是非常關鍵的一步,只有當網(wǎng)卡正確配置后,才能獲取到 metadata。
關于 local 階段下一節(jié)會通過實驗詳細分析。
init, config 和 final 階段
正常情況下,在這三個階段執(zhí)行之前 instance 網(wǎng)絡已經(jīng)配置好了,并且已經(jīng)成功獲取到 metadata。cloud-init 的配置文件 /etc/cloud/cloud.cfg 定義了三個階段分別要執(zhí)行的任務,任務以 module 形式指定。

instance 真正的定制工作就是由這些 module 完成的。module 決定做哪些定制化工作,而 metadata 則決定最終定制化的結(jié)果。
舉個例子,如果 cloud.cfg 中指定了set_hostname這個 module,則意味著 cloud-int 會設置 instance 的主機名,而具體設置成哪個主機名則由 metadata 中hostname參數(shù)決定。
有些 module 是有默認行為的,比如growpart,如果 metadata 中沒有特別指定,它會自動擴展/分區(qū)。
二、 cloud-init 的典型應用(設置 hostanme,設置用戶初始密碼,安裝軟件)
設置 hostname
cloud-init 默認會將 instance 的名字設置為 hostname。但這樣不太方便,有時希望能夠?qū)⒍叻珠_,可利用 cloud-init 的set_hostname模塊實現(xiàn)。set_hostname它會查詢 metadata 中 hostname 信息,默認值就是 instance 的名字。我們可以指定自己的 hostname,方法是將下面的內(nèi)容傳給 cloud-init:
#cloud-config
hostname: my1.cloudman.cc
manage_etc_hosts: true
說明如下:
cloud-init 只會讀取以#cloud-config開頭的數(shù)據(jù),所以這一行一定要寫對。
hostname: my1.cloudman.cc告訴 cloud-init 將 hostname 設置為 my1.cloudman.cc。
manage_etc_hosts: true告訴 cloud-init 更新 /etc/hosts 文件。
接下來的問題是:如何將這些信息傳給 cloud-init?
有三幾種方法:
① instance 部署時,直接將其粘貼到Customization Script輸入框中。

② 將其保存為文件,instance 部署時上傳(上圖 ② 所示)。
③ 將其保存為文件,命令行nova boot或者openstack server create部署 instance 時,使用參數(shù)--user-data傳入。
部署成功后,hostname 正確設置,/etc/hosts 也相應更新。
定制用戶初始密碼
官方的 cloud image 默認只能通過 ssh key 登錄。我們可以利用set-passwords模塊為用戶設置密碼并啟用密碼登錄。需要傳入的腳本如下:
#cloud-config
chpasswd:
list: |
root:123456
ubuntu:123456
expire: false
ssh_pwauth: true
說明如下:
root 和 ubuntu 用戶密碼設置為 123456。
ssh_pwauth啟用密碼登錄。
instance 啟動后 ssh 驗證:

ubuntu 用戶 ssh 密碼登錄成功,并且可通過密碼切換到 root。
安裝軟件
標準鏡像中不可能包含我們需要的所有軟件,定制安裝是不可避免的。一個辦法是部署完后手動安裝,另一個辦法是通過package-update-upgrade-install模塊讓 cloud-init 自動為我們安裝。
需要傳入的腳本如下:
#cloud-config
apt:
primary:
- arches: [default]
search:
- https://mirrors.tuna.tsinghua.edu.cn/ubuntu
search_dns: true
packages:
- pwgen
- pastebinit
- [libpython2.7, 2.7.3-0ubuntu3.1]
說明如下:
apt指定安裝源的位置,這里為http://1.2.3.4。如果是 yum 源則用yum_repos模塊指定,具體用法可參看官網(wǎng)文檔。
packages指定需要安裝的軟件包,還可以指定具體版本。
instance 啟動后可看到 /etc/apt/sources.list 中安裝源已經(jīng)更新為http://1.2.3.4。

由于http://1.2.3.4不是一個有效的 apt 源,安裝肯定會失敗,我們可以在 /var/log/cloud-init.log 看到失敗的信息。

雖然失敗了,但我們至少可以確定如下事情:
傳入的腳本是有效的,cloud-init 確實在嘗試安裝指定的軟件。
/var/log/cloud-init.log 會完整地記錄 cloud-init 運行的所有細節(jié),是 debug 最重要的工具。