怎樣去構建目錄
ansible會在同一時間管理你的很多主機,使用一個列表或者組作為一個目錄。一旦你的Inventory定義好了,你就可以使用一些pattern去操作你列表里的主機。
默認的設備目錄文件是在/etc/ansible/hosts。你也可以使用選項-i <path>指定一個目錄文件。你也可以同時使用多個目錄文件,更或者也可以從一個動態的或者雲資源更或者不同格式的目錄(YAML,ini,etc)。
Inventory基礎元素: formats, hosts和groups
inventory文件可以是一種或者多種格式,取決於你的目錄插件。最普遍的格式為INI和YAML。一個基礎的INI文件etc/ansible/hosts應該向下面的例子這樣:
mail.example.com
[webservers]
foo.example.com
bar.example.com
[dbservers]
one.example.com
two.example.com
three.example.com
中括號里的標題是組名稱,用於分類主機和確定你在何時和控制主機的目的。
這是YAML格式的inventory文件:
all:
hosts:
mail.example.com:
children:
webservers:
hosts:
foo.example.com:
bar.example.com:
dbservers:
hosts:
one.example.com:
two.example.com:
three.example.com:
默認組
有兩個默認組:all和ungroup。all里面包含所有的主機。ungroup里面包含了所有沒有在組里的主機。所有的主機會至少屬於2個組(all和group或者其他的組)。因為all和ungroup是一直存在的,所以他們也不必要以組名的形式存在於Inventory中。
主機在多個組的情況
你可以把一個主機歸為多個組。例如生產上的一台web服務器在DC A里,它既屬於[prod] [DC A]和[webservers]里。你可以按如下步驟創建組:
- What :一個應用、棧或者微服務(比如 database servers, web servers等).
- Where : 一個DC或者一個地點. (比如 east, west).
- When :開發測試階段還是生產使用階段。 (比如prod, test).
擴展之前的YAML目錄,使其包含what, when和where:
hosts:
mail.example.com:
children:
webservers:
hosts:
foo.example.com:
bar.example.com:
dbservers:
hosts:
one.example.com:
two.example.com:
three.example.com:
east:
hosts:
foo.example.com:
one.example.com:
two.example.com:
west:
hosts:
bar.example.com:
three.example.com:
prod:
hosts:
foo.example.com:
one.example.com:
two.example.com:
test:
hosts:
bar.example.com:
three.example.com:
可以看到one.example.com同時存在於dbservers, east, 和prod組里.
你也可以使用嵌套的組來簡化生產主機和測試主機:
all:
hosts:
mail.example.com:
children:
webservers:
hosts:
foo.example.com:
bar.example.com:
dbservers:
hosts:
one.example.com:
two.example.com:
three.example.com:
east:
hosts:
foo.example.com:
one.example.com:
two.example.com:
west:
hosts:
bar.example.com:
three.example.com:
prod:
children:
east:
test:
children:
添加某固定范圍的主機
如果你有大量命名類似的主機,你可以使用一個范圍參數來批量添加,而不用一個一個地單獨添加。
INI格式:
[webservers]
www[01:50].example.com
YAML格式:
webservers:
hosts:
www[01:50].example.com:
對於數字模式,前面的0可以包含也可以不包含.你也可以定義一個字母范圍:
[databases]
db-[a:f].example.com
添加變量到inventory
你可以為一個主機或者主機組存儲變量值。剛開始,你可以直接在主Inventory文件里添加主機或者組變量。當你添加越來越多的主機在你的Inventory里時候,你可能就想用單獨的文件來存儲主機和主機組的變量。
添加變量到單個主機:主機變量
你可以輕松地給單一的主機配置變量,然后再playbook中使用它。在INI格式下:
[atlanta]
host1 http_port=80 maxRequestsPerChild=808
host2 http_port=303 maxRequestsPerChild=909
YAML格式:
atlanta:
host1:
http_port: 80
maxRequestsPerChild: 808
host2:
http_port: 303
maxRequestsPerChild: 909
比如非標准SSH端口可以很好用於主機變量中。你可以把端口添加在主機名冒號的后面:
badwolf.example.com:5309
連接協議也可以在配置在主機變量里:
[targets]
localhost ansible_connection=local
other1.example.com ansible_connection=ssh ansible_user=myuser
other2.example.com ansible_connection=ssh ansible_user=myotheruser
注:如果使用非標准SSH端口的話,openssh連接會找到並使用它,但是paramiko連接方式不會。
Inventory aliases
在inventory里定義aliases:
INI:
jumper ansible_port=5555 ansible_host=192.0.2.50
YAML:
hosts:
jumper:
ansible_port: 5555
ansible_host: 192.0.2.50
在上面的例子中,ansible會連接主機別名“jumper” 的5555端口。
注:INI使用key=value格式,他的值取決於在哪里聲明他。
- 在主機聲明中,INI的值會被解釋為PYTHON的內容結構(字符,數字,元組,列表,字典,布爾,空)。每個主機行接受多個
key=value的值。所以需要一個方法去分辨空格是一個分隔符還是屬於定義的值的一部分。 - 當聲明在
:vars中時候,INI的值會被解釋成字符。比如var=FALSE會被創建為一個字符‘FALSE’。與主機行不同,:vars部分值接受一個單獨的條目,所以所有在=號后面的都是該條目的值。 - 在INI inventory中的變量值必須都是一個確定的類型(比如,字符串類型或者布爾類型),在task中記得定義過濾器來指定類型。不要依賴INI inventory來處理。
- 考慮使用YMAL格式作為inventory源來避免變量類型的混亂。YAML inventory插件會持續正確處理變量值。
- 一般情況下,建議把主機變量存於‘host_vars’文件夾里。
給多台設備分配變量:組變量
如果一個組的主機共享變量,你可以把變量一次性應用到組內。
INI格式:
[atlanta]
host1
host2
[atlanta:vars]
ntp_server=ntp.atlanta.example.com
proxy=proxy.atlanta.example.com
In YAML:
atlanta:
hosts:
host1:
host2:
vars:
ntp_server: ntp.atlanta.example.com
proxy: proxy.atlanta.example.com
組變量是比較方便的方法能批量應用變量。但是在執行命令之前,ansible會應用變量到主機級別。如果主機屬於多個組,那么ansible會從所有的組中讀取值。如果在不同的組里給相同的變量分配了不同的值,ansible會根據內部規則選擇哪些值進行合並。
變量繼承:組變量
使用:children后綴在INI或者children:在YMAL中應用:vars或vars:的組變量
INI格式:
[atlanta]
host1
host2
[raleigh]
host2
host3
[southeast:children]
atlanta
raleigh
[southeast:vars]
some_server=foo.southeast.example.com
halon_system_timeout=30
self_destruct_countdown=60
escape_pods=2
[usa:children]
southeast
northeast
southwest
northwest
在YAML中:
all:
children:
usa:
children:
southeast:
children:
atlanta:
hosts:
host1:
host2:
raleigh:
hosts:
host2:
host3:
vars:
some_server: foo.southeast.example.com
halon_system_timeout: 30
self_destruct_countdown: 60
escape_pods: 2
northeast:
northwest:
southwest:
如果需要存儲列表或者哈希數據,再或者需要單獨存放主機和組變量,需要查詢組織主機和組變量環節。
子組有一些特性需要知悉:Child groups have a couple of properties to note:
- 子組主機自動也屬於父組
- 子組的變量優先級高於父組的變量
- 組可以有多個子組和父組,但是不能有循環的關系
- 主機可以屬於多個組,變量也會從多個組進行融合,但是只會有一個進程。
結構化主機和組變量Organizing host and group variables
雖然你可以存儲變量到主inventory文件里,但是把主機和組變量分別存儲到分開的文件中可以更方便我們的管理。主機和組變量文件必須是YAML格式。有效的文件擴展名包括‘.yml’, ‘.yaml’, ‘.json’或者無擴展名。
ansible會通過尋找相關的Inventory文件或者Playbook路徑來加載主機和組變量。如果你的inventory文件在/etc/ansible/hosts目錄下,並且包含屬於兩個組‘raleigh’ 和‘webservers’的主機‘foosball’,那么這個主機會使用如下路徑的YAML變量文件。
/etc/ansible/group_vars/raleigh # 擴展名可以是'.yml', '.yaml', 或者'.json'
/etc/ansible/group_vars/webservers
/etc/ansible/host_vars/foosball
例如,如果你以DC來分類你的主機,而且每個DC有自己的NTP服務或者DB服務器,那么你可以創建一個文件名為/etc/ansible/group_vars/raleigh來存儲你raleigh組的變量
---
ntp_server: acme.example.org
database_server: storage.example.org
你可以以主機名字或者組名字來創建目錄。ansible會按照字典順序來讀取全部的目錄。
一個名為‘raleigh’組的例子:
/etc/ansible/group_vars/raleigh/db_settings
/etc/ansible/group_vars/raleigh/cluster_settings
所有在‘raleigh’組的主機將可使用定義在這些文件中的變量。如果你變量文件很大的話,這個方式會幫助你整理變量文件以及在ansible加密某些組變量。
你也可以在playbook目錄里添加group_vars/和host_vars/目錄。ansible-playbook命令會默認在目前工作目錄里尋找這些目錄。但是其他的ansible命令(比如ansible,ansible-console等)只會在inventory目錄下尋找group_vars/和host_vars/目錄。如果你想用其他的ansible命令從其他目錄里加載組和主機變量,需要添加--playbook-dir選項指定目錄。如果你從playbook目錄和inventory一起加載inventory文件,那Playbook目錄中的變量會覆蓋掉Inventory目錄的變量。
把你的inventory文件和變量放在git上可以跟蹤你的inventory和主機變量的改變過程。
變量合並
默認情況下,在playbook執行前會將某主機的變量進行合並。這使ansible只關注於主機和任務,所以組的概念只是被限制於目錄的主機匹配中。默認情況下,Ansible會按照優先級去覆蓋那些為組或者主機定義的變量。從低到高的優先級順序是:
- all group 因為是所有組的父組
- parent group 父組
- child group 子組
- host 主機
默認情況下ansible會按照字母順序合並相同級別的組,后加載的組會覆蓋前面的組。比如 B 開頭命名的組變量會覆蓋 A 開頭中同樣匹配到的組變量。
你可以通過修改組變量中ansible_group_priority選項來改變合並相同級別組變量時的優先級順序。數字越大,優先級越高,如果不修改則優先級默認為1.
a_group:
testvar: a
ansible_group_priority: 10
b_group:
testvar: b
在這個例子中,如果這兩個組有相同的優先級,那么變量會是testvar == b。但是如果給a_group一個更高的優先級,那么結果就會是testvar == a.
注:ansible_group_priority 只能在inventory文件中設置,不能在group_vars/設置,因為這個變量在加載group_vars的時候被用到。
使用多個 inventory 文件
你可以通過使用命令行或者配置ANSIBLE_INVENTORY來同時使用多inventory源(目錄、動態目錄腳本或者inventroy插件支持的其他文件)。當你想同時分別配置生產或者測試環境的時候,這個功能會很有用處。
使用命令行選中兩個inventory。
ansible-playbook get_logs.yml -i staging -i production
此時要注意變量沖突的問題,如果沖突了的話,會按照變量合並的規則去處理。合並的順序是按照Inventory源的參數順序控制。如果[all:vars]在staging inventory里定義myvar = 1,但是production inventory定義myvar = 2,那么playbook會使用myvar = 2的值。如果上面的例子中使用的參數是-i production -i staging,那么結果將會相反。
聚合多inventory源到一個目錄中
也可以只創建一個inventory目錄,然后把多個inventory源或者其他類型的文件放在里面。這對於管理動態和靜態主機來說很方便。下面這個invetory就包含了inventory插件源,動態inventory腳本和一個靜態主機文件:
inventory/
openstack.yml # 配置inventory插件獲取Openstack Cloud主機
dynamic-inventory.py # 使用動態inventory腳本添加主機
static-inventory # 添加靜態的主機和組
group_vars/
all.yml # 分配變量到所有主機
你可以這樣直接調用這個inventory目錄:
ansible-playbook example.yml -i inventory
因為這些inventory的合並規則是遵循文件名字的字母表順序,所以如果有變量沖突的話,可以給文件添加一個前綴來定義優先級:
inventory/
01-openstack.yml
02-dynamic-inventory.py
03-static-inventory
group_vars/
all.yml
如果01-openstack.yml定義myvar = 1,02-dynamic-inventory.py定義myvar = 2,03-static-inventory定義myvar = 3,那playbook會采用myvar = 3。
關於執行的inventory參數
以下是ansible控制主機涉及到的一些重要參數。
主機連接:
注:在使用默認ssh連接插件的時候,ansible不會釋放一個通道去允許用戶和SSH進程間手動接受密碼或者解密秘鑰。推薦使用ssh代理的方式。
ansible_connection: 連接到主機的方式,可以是ansible連接插件的名字。SSH協議連接類型有:smart,ssh 或者paramiko。默認是smart。
一些通用的參數:
ansible_host : 要連接的主機名稱
ansible_port : 連接端口
ansible_user : 連接的用戶名
ansible_password : 主機的用戶密碼(不要使用明文密碼,應該使用vault功能進行加密)
針對於SSH的參數:
ansible_ssh_private_key_file : SSH使用的私鑰,如果不想使用ssh代理的話,可以指定多個主機的私鑰
ansible_ssh_common_args : 參數會添加到sftp,scp,ssh的默認命令行中。通常用來配置ProxyCommand 。
ansible_sftp_extra_args : 參數會添加到sftp的默認命令行中
ansible_scp_extra_args : 參數會添加到scp的默認命令行中
ansible_ssh_extra_args : 參數會添加到ssh的默認命令行中
ansible_ssh_pipelining : 決定是否使用SSH pipelining,這個可以覆蓋掉ansible.cfg中的pipelining參數
權限升級:
ansible_become : 相當於ansible_sudo 和 ansible_su,允許強制提升用戶權限。
ansible_become_method : 設置權限升級的方式
ansible_become_user :相當於ansible_sudo_user 或者ansible_su_user , 允許某用戶權限升級
ansible_become_password : 允許你設置權限升級的密碼(不要直接使用明文的方式)
ansible_become_exe : 允許設置升級權限的可執行文件
ansible_become_flags : 允許為權限升級方式設置標志位,也可以在ansible.cfg里全局設置
遠程主機環境參數:
ansible_shell_type : 遠程主機的shell類型。一般不用設置。默認為sh。
ansible_python_interpreter :遠程主機的Python路徑
ansible_*_interpreter :支持ruby, perl 。
一個Ansible-INI主機文件示例:
some_host ansible_port=2222 ansible_user=manager
aws_host ansible_ssh_private_key_file=/home/example/.ssh/aws.pem
freebsd_host ansible_python_interpreter=/usr/local/bin/python
ruby_module_host ansible_ruby_interpreter=/usr/bin/ruby.1.9.3
非SSH連接類型
ansible並非僅使用ssh的連接類型。根據ansible_connection=<connector>參數的設置,連接類型可以被更改。比如:
local : 這個參數意味着你你的playbook將部署再本機上。
docker : 這個參數是將playbook直接用docker client部署到docker容器里。
這個連接類型將會使用以下參數。
ansible_host : 連接的Docker容器名
ansible_user : 容器中的操作用戶名,這個用戶必須存在於容器內。
ansible_become: 如果置位true,那就會使用become_user在容器內進行操作
ansible_docker_extra_args : 可以是一個包含Docker其他參數的字符串,單並不是特定於命令的。此參數主要用於配置要使用的遠程Docker守護程序。
下面是個docker部署示例:
- name: create jenkins container
docker_container:
docker_host: myserver.net:4243
name: my_jenkins
image: jenkins
- name: add container to inventory
add_host:
name: my_jenkins
ansible_connection: docker
ansible_docker_extra_args: "--tlsverify --tlscacert=/path/to/ca.pem --tlscert=/path/to/client-cert.pem --tlskey=/path/to/client-key.pem -H=tcp://myserver.net:4243"
ansible_user: jenkins
changed_when: false
- name: create directory for ssh keys
delegate_to: my_jenkins
file:
path: "/var/jenkins_home/.ssh/jupiter"
state: directory
