動態 Inventory

使用配置管理系統經常有一種需求,可能要在其他的軟體系統中儲存自己的 inventory 配置資訊.

Ansible 本身通過基於文字的方式來記錄 inventory 配置資訊,這在前面已介紹過(詳見 Inventory檔案 ).

除此之外,Ansible 也支援用其他方式儲存配置資訊.

在其他軟體系統儲存配置資訊的例子有:

1, 從雲端拉取 inventory
2, LDAP(Lightweight Directory Access Protocol,輕量級目錄訪問協議)
3, `Cobbler <http://cobbler.github.com>`_
4, 或者是一份昂貴的企業版的 CMDB(配置管理資料庫) 軟體.

對於這些需求,Ansible 可通過一個外部 inventory 系統來支援.在 ansible 的 “/plugins” 外掛目錄下已經含有一些選項 – 包括 EC2/Eucalyptus, Rackspace Cloud,and OpenStack,我們稍後會詳細介紹它們.

Ansible Ansible Tower 提供了一個數據庫來儲存 inventory 配置資訊, 這個資料庫可以通過 web 訪問,或通過 REST 訪問. Tower 與所有你使用的 Ansible 動態 inventory 源保持同步,並提供了一個圖形化的 inventory 編輯器. 有了這個資料庫,便可以很容易的關聯過去的事件歷史,可以看到在上一次 playbook 執行時,哪裡出現了執行失敗的情況.

關於如何編寫你自己的動態 inventory 源,請參見 開發動態的Inventory資料來源.

Cobbler 外部 Inventory 指令碼

當管理的物理機器到達了一定數量的時,很多使用 Ansible 的使用者可能同時也會使用到 Cobbler . (注: Cobbler 最初由 Michael DeHaan 編寫,現在項目主導人是 James Cammarata, 他目前在 Ansible 公司工作).

Cobbler 主要用於作業系統的 kickoff 安裝,以及管理 DHCP 和 DNS,除此之外,它有一個通用層,可為多種配置管理系統(甚至是同時的)提供資料. 所以 Cobbler 也被一些管理員稱為是輕量級的 CMDB.

如何將 Ansible 的 inventory 與 Cobbler 聯絡起來呢?方法是: 將指令碼 script 拷貝到 /etc/ansible,通過 chmod +x 賦予可執行許可權.

在使用 Ansible 之前,先啟動 cobblerd 程序.

現在使用 Ansible 要加上 -i 選項 ( 例如:-i /etc/ansible/cobbler.py).cobbler.py這個指令碼使用 Cobbler 的 XMLRPC API 與 Cobbler 通訊.

執行指令碼 /etc/ansible/cobbler.py ,應該能看到一些 JSON 格式的資料輸出(也許還沒有具體的內容).

在 cobbler 中,假設有一個如下的場景:

cobbler profile add --name=webserver --distro=CentOS6-x86_64
cobbler profile edit --name=webserver --mgmt-classes="webserver" --ksmeta="a=2 b=3"
cobbler system edit --name=foo --dns-name="foo.example.com" --mgmt-classes="atlanta" --ksmeta="c=4"
cobbler system edit --name=bar --dns-name="bar.example.com" --mgmt-classes="atlanta" --ksmeta="c=5"

‘foo.example.com’ 是一個域名,Ansible 可以通過這個域名定址找到對應的主機foo,對其進行操作.也可以通過組名 ‘webserver’ 或者 ‘atlanta’ 定址找到這個主機,只要這個主機是屬於這兩個組的.直接使用 foo 是不行的.例如執行命令 “ansible foo” ,無法找到該主機,但使用 “ansible ‘foo*’” 卻可以,因為域名 ‘foo.example.com’ 以foo開頭.

這個指令碼不僅提供主機和組的資訊.如果運行了 ‘setup’ 模組(只要使用 playbooks,’setup’ 模組會自動執行),變數 a, b, c 可按照以下模板自動填充:

# file: /srv/motd.j2
Welcome, I am templated with a value of a={{ a }}, b={{ b }}, and c={{ c }}

模板的使用如下:

ansible webserver -m setup
ansible webserver -m template -a "src=/tmp/motd.j2 dest=/etc/motd"

Note

組名 ‘webserver’ 是 cobbler 中定義的.你仍然可以在 Ansible 的配置檔案中定義變數. 但要注意,變數名相同時,外部 inventory 指令碼中定義的變數會覆蓋 Ansible 中的變數.

執行上面命令後,主機 foo 的/etc/motd檔案被寫入如下的內容:

Welcome, I am templated with a value of a=2, b=3, and c=4

主機 ‘bar’ (bar.example.com)的 /etc/motd 中寫入如下內容:

Welcome, I am templated with a value of a=2, b=3, and c=5

你也可以通過下面這個命令測試變數的替換:

ansible webserver -m shell -a "echo {{ a }}"

也就是說,你可以在參數或命令操作中使用變數的替換.

AWS EC2 外部 inventory 指令碼

使用 AWC EC2時,維護一份 inventory 檔案有時不是最好的方法.因為主機的數量有可能發生變動,或者主機是由外部的應用管理的,或者使用了 AWS autoscaling.這時,使用 EC2 external inventory 指令碼是更好的選擇.

指令碼的使用方式有兩種,最簡單的是直接使用 Ansible 的命令列選項 -i ,指定指令碼的路徑(指令碼要有可執行許可權):

ansible -i ec2.py -u ubuntu us-east-1d -m ping

第二種方式,把指令碼拷貝為 /etc/ansible/hosts ,並賦予可執行許可權.還需把 ec2.ini 檔案拷貝到 /etc/ansible/ec2.ini,然後執行 ansible.

要成功的呼叫 API 訪問 AWS,需要配置 Boto (Boto 是 AWS 的 Python 介面).可用的方法有多種,請參見: methods .

最簡單的方法是定義兩個環境變數:

export AWS_ACCESS_KEY_ID='AK123'
export AWS_SECRET_ACCESS_KEY='abc123'

如何知道配置是否正確,執行指令碼來測試:

cd plugins/inventory
./ec2.py --list

你可以看到以 JSON 格式表示的覆蓋所有 regions 的 inventory 資訊.

因為每一個 region 需要自己的 API 呼叫,如果你僅使用了所有 regions 中的一個子集,可以編輯 ec2.ini ,使之僅顯示你所感興趣的那些 regions. 在配置檔案 ec2.ini 中,包含了其他配置選項,包括快取控制和目的地址變數.

inventory 檔案的核心部分,是一些名字到目的地址的對映.預設的 ec2.ini 設定適用於在 EC2 之外執行 Ansible(比如一臺膝上型電腦),但這不是最有效的方式.

在 EC2 內部執行 Ansible 時,內部的 DNS 名和 IP 地址比公共 DNS 名更容易理解.你可以在 ec2.ini 檔案中修改 destination_variable 變數, 改為一個例項的私有 DNS 名.對於在私有子網的 VPC 上執行 Ansible ,這種設定很重要,使得我們可以使用內部IP地址之外的方式訪問到一個VPC.在 ec2.ini 檔案中, vpc_destination_variable 可以命名為任意一個 boto.ec2.instance 變數.

EC2 外部 inventory 提供了一種從多個組到例項的對映:

全局 例項都屬於 ec2 這個組.

例項ID
例如: i-00112233 i-a1b1c1d1
Region
屬於一個 AWS region 的所有例項構成的一個組. 例如: us-east-1 us-west-2
可用性區域
所有屬於 availability zone 的例項構成一個組. 例如: us-east-1a us-east-1b
安全組

例項可屬於一個或多個安全組.每一個組的字首都是 security_group_ ,符號(-) 已被轉換為(_). with all characters except alphanumerics (這句沒明白)

例如: security_group_default security_group_webservers security_group_Pete_s_Fancy_Group

標籤
每一個例項可有多個不同的 key/value 鍵值對,這些鍵值對被稱為標籤.標籤名可以隨意定義,最常見的標籤是 ‘Name’.每一個鍵值對是這個例項自己的組. 特殊字元已轉換為下劃線,格式為 tag_KEY_VALUE 例如: tag_Name_Web tag_Name_redis-master-001 tag_aws_cloudformation_logical-id_WebServerGroup

使用 Ansible 與指定的伺服器進行互動時,EC2 inventory 指令碼被再次呼叫(呼叫時加上了命令列選項 --host HOST ),這個呼叫會在索引快取中進行查詢,獲取例項 ID,然後呼叫 API 訪問 AWS,獲取指定例項的所有資訊.這些資訊被轉換為 playbooks 中的變數,可以進行訪問.每一個變數的字首為 ec2_,下面是一些變數的示例:

  • ec2_architecture
  • ec2_description
  • ec2_dns_name
  • ec2_id
  • ec2_image_id
  • ec2_instance_type
  • ec2_ip_address
  • ec2_kernel
  • ec2_key_name
  • ec2_launch_time
  • ec2_monitored
  • ec2_ownerId
  • ec2_placement
  • ec2_platform
  • ec2_previous_state
  • ec2_private_dns_name
  • ec2_private_ip_address
  • ec2_public_dns_name
  • ec2_ramdisk
  • ec2_region
  • ec2_root_device_name
  • ec2_root_device_type
  • ec2_security_group_ids
  • ec2_security_group_names
  • ec2_spot_instance_request_id
  • ec2_state
  • ec2_state_code
  • ec2_state_reason
  • ec2_status
  • ec2_subnet_id
  • ec2_tag_Name
  • ec2_tenancy
  • ec2_virtualization_type
  • ec2_vpc_id

其中 ec2_security_group_idsec2_security_group_names 變數的值為所有安全組的列表,使用逗號分隔.每一個 EC2 標籤是一個格式為 ec2_tag_KEY 的變數.

要檢視一個例項的完整的可用變數的列表,執行指令碼:

cd plugins/inventory
./ec2.py --host ec2-12-12-12-12.compute-1.amazonaws.com

注意,AWS inventory 指令碼會將結果進行快取,以避免重複的 API 呼叫,這個快取的設定可在 ec2.ini 檔案中配置.要顯式地清空快取,你可以加上 --refresh-cache 選項,執行指令碼如下:

# ./ec2.py --refresh-cache

其它 inventory 指令碼

除了 Cobbler 和 EC2 之外,還有以下的系統可以使用 inventory 指令碼:

BSD Jails
DigitalOcean
Google Compute Engine
Linode
OpenShift
OpenStack Nova
Red Hat's SpaceWalk
Vagrant (not to be confused with the provisioner in vagrant, which is preferred)
Zabbix

關於這些系統還沒有專門的章節講述如何操作,但步驟與上面所講述的 AWS 一樣,具體可看看Ansible checkout 的 “plugins/” 目錄.

如果你開發了一個通用的 inventory 指令碼,請提交一個 pull request,我們可能會把它放入項目中.

使用多個 inventory 源

如果 -i 選項後給出的地址是一個目錄 (or as so configured in ansible.cfg),Ansible 可以同一時間使用多個 inventory 源.這樣在同一個 ansible 執行操作中,可混合的使用動態和靜態的 inventory 源.

動態組作為靜態組的子組

在靜態 inventory 檔案中,如果定義一個由一些組作為子成員的組,這些子組也需要定義(譯者注:即包含具體的 host),否則執行時 ansible 會返回一個錯誤. 如果定義一些動態組作為一個靜態組的子組,也需在靜態 inventory 檔案中定義動態組,但是動態組定義為一個空的組即可:

[tag_Name_staging_foo]

[tag_Name_staging_bar]

[staging:children]
tag_Name_staging_foo
tag_Name_staging_bar

See also

Inventory檔案
All about static inventory files
Mailing List
Questions? Help? Ideas? Stop by the list on Google Groups
irc.freenode.net
#ansible IRC chat channel