雖然自動化存在使得更容易使事情重復,但所有的系統可能不完全一樣。
在某些系統上,您可能需要設置一些與其他操作略有不同的行為或配置。
此外,一些觀察到的遠程系統的行為或狀態可能需要影響如何配置這些系統。 (例如您可能需要找到系統的IP地址,甚至將其用作另一個系統上的配置值)。
您可能有一些配置文件的模板大部分是相同的,但基於這些變量略有不同。
Ansible中的變量是我們如何處理系統之間的差異。
要了解變量,您還需要挖掘條件和循環 。 有用的東西,如group_by模塊和when
條件也可以與變量一起使用,並幫助管理系統之間的差異。
強烈建議您查閱ansible-examples github倉庫,以查看大量有關使用變量的示例。
有關最佳做法建議,請參閱“ 最佳實踐”一章中的變量和保險庫 。
What Makes A Valid Variable Name
變量名稱應為字母,數字和下划線。 變量應始終以字母開頭。
foo_port
是一個正確的變量。 foo5
也是。
foo-port
, foo port
, foo.port
和12
都不是有效的變量名。
YAML還支持將鍵映射到值的字典。 例如:
foo: field1: one field2: two
然后,您可以使用括號符號或點表示法引用字典中的特定字段:
foo['field1'] foo.field1
這兩者都將引用相同的值(“one”)。 但是,如果您選擇使用點符號,請注意某些鍵可能會導致問題,因為它們與python字典的屬性和方法相沖突。
您應該使用括號符號而不是點符號,如果您使用以兩個下划線開頭和結尾的鍵(在python中為特殊含義保留)或者是任何已知的公共屬性:add
,append
,as_integer_ratio
,bit_length
,capitalize
,center
,clear
,conjugate
,copy
,count
,decode
,denominator
,difference
,difference_update
,discard
,encode
,endswith
,expandtabs
,extend
,find
,format
,fromhex
,fromkeys
,get
,has_key
,hex
,imag
,index
,insert
,intersection
,intersection_update
,isalnum
,,
isalphaisdecimal
,isdigit
,isdisjoint
,is_integer
,islower
,isnumeric
,isspace
,issubset
,issuperset
,istitle
,isupper
,items
,iteritems
,iterkeys
,itervalues
,join
,keys
,ljust
,lower
,lstrip
,numerator
,partition
,pop
,popitem
,real
,remove
,replace
,reverse
,rfind
,rindex
,rjust
,rpartition
,rsplit
,rstrip
,setdefault
,sort
,split
,splitlines
,startswith
,strip
,swapcase
,symmetric_difference
,symmetric_difference_update
,title
,translate
,union
,update
,upper
,values
,viewitems
,viewkeys
,viewvalues
,zfill
.
Variables Defined in Inventory
我們實際上已經在另一部分中介紹了很多變量,到目前為止,這不應該是非常新鮮的,而是一點點復習。
通常,您將需要根據機器所在的組來設置變量。例如,波士頓的機器可能要使用“boston.ntp.example.com”作為NTP服務器。
有關如何在庫存中定義變量的多種方法,請參閱庫存憑證。
如:
192.168.1.116 key=116
192.168.1.117 key=117
192.168.1.118 key=118
[nginx]
192.168.1.11[6:8]
[nginx:vars]
ansible_python_interpreter=/usr/bin/python2.6
Variables Defined in a Playbook
在一個playbook中,可以直接內嵌定義變量:
- hosts: webservers vars: http_port: 80
Variables defined from included files and roles
原來我們已經在另一個地方談過變量了。
如“ 手冊角色和包含聲明”中所述 ,變量也可以通過包含文件包含在playbook中,這些文件可能是或可能不是“可選角色”的一部分。 使用角色是首選,因為它提供了一個很好的組織系統。
Using Variables: About Jinja2
知道如何定義變量是很好的,但是如何使用它們?
可以使用Jinja2模板系統,您可以在Playbook中引用變量。 雖然你可以在Jinja做許多復雜的事情,但只有基礎才是你真正需要學習的東西。
例如,在簡單的模板中,您可以執行以下操作:
My amp goes to {{ max_amp_value }}
這將提供最基本的變量替代形式。
這也是直接在playbook中有效的,你偶爾會想做一些事情:
template: src=foo.cfg.j2 dest={{ remote_install_path }}/foo.cfg
在上面的例子中,我們使用一個變量來幫助決定放置文件的位置。
在模板中,您可以自動訪問主機范圍內的所有變量。 實際上它不止於此 - 您還可以讀取有關其他主機的變量。 我們將展示如何做到這一點。
也可以看看
- 模板(Jinja2)
- 有關Jinja2模板的更多信息
-
Hey Wait, A YAML Gotcha
YAML語法要求,如果您使用
{{ foo }}
啟動值,則引用整行,因為它要確保您沒有嘗試啟動YAML字典。 這在YAML Syntax頁面中有所描述。這不行:
- hosts: app_servers vars: app_path: {{ base_path }}/22
這樣做,你會沒事的- hosts: app_servers vars: app_path: "{{ base_path }}/22"
Information discovered from systems: Facts
還有其他變量可以來自的地方,但是這些變量是被發現的,不是由用戶設置的變量。
事實是從與您的遠程系統通話中獲得的信息。
這方面的一個例子可能是遠程主機的IP地址或操作系統的IP地址。
要查看可用的信息,請嘗試以下操作:
ansible hostname -m setup
這將返回一個巨大的可變數據,可能看起來像這樣,從Ubuntu 12.04系統上的Ansible 1.4在上文中,第一個硬盤驅動器的型號可以在模板或playbook中被引用為:
{{ ansible_devices.sda.model }}
同樣,系統報告的主機名是:{{ ansible_nodename }}
並且不合格的主機名顯示第一個句點(.)之前的字符串:{{ ansible_hostname }}
事實經常用於條件(見條件 )以及模板中。事實也可用於創建符合特定條件的主機的動態組,有關詳細信息,請參閱關於 groups_by的關於Modules文檔,以及條件一章中討論的廣義條件語句。
Turning Off Facts
如果您知道您不需要有關您的主機的任何事實數據,並且集中了解您的系統的所有內容,您可以關閉事件收集。 這在具有非常大量系統的推送模式中可擴展的可能性主要有以下優點,或者如果您在實驗平台上使用可解密的話。 在任何play中,只要這樣做:
- hosts: whatever gather_facts: no
Local Facts (Facts.d)
1.3版新功能
正如在playbook一章中討論的那樣,可解的facts是一種獲取有關遠程系統的數據以用於playbook變量的方式。
通常這些由Ansible中的安裝模塊自動發現。 用戶還可以編寫自定義facts模塊,如API指南中所述。 但是,如果您想要一個簡單的方法來提供系統或用戶提供的數據,以便在可寫變量中使用,而不必寫入facts模塊?
例如,如果您希望用戶能夠控制系統管理的一些方面呢? “facts”是一種這樣的機制。
如果遠程管理的系統具有
/etc/ansible/facts.d
目錄,則該目錄中以.fact
結尾的任何文件都可以是JSON,INI或返回JSON的可執行文件,並且這些文件可以在Ansible中提供本地facts。 可以使用fact_path
play指令指定備用目錄。例如假設一個
/etc/ansible/facts.d/preferences.fact
:[general] asdf=1 bar=2
這將產生一個名為general
的哈希變量facts,asdf
和bar
作為成員。 要驗證此操作,請運行以下命令:ansible <hostname> -m setup -a“filter = ansible_local”
你會看到以下facts:"ansible_local": { "preferences": { "general": { "asdf" : "1", "bar" : "2" } } }
並且可以在template/playbook
訪問此數據:{{ ansible_local.preferences.general.asdf }}
本地命名空間可防止任何用戶提供的facts覆蓋系統facts或在該playbook中其他地方定義的變量。
如果您有一個正在復制自定義facts然后運行它的play,則顯式調用重新運行安裝模塊可以允許在該特定play期間使用該facts。 否則,它將在下一次收集facts信息的play中可用。 這是一個可能是這樣的例子:
- hosts: webservers tasks:
- name: create directory for ansible custom facts
file: state=directory recurse=yes path=/etc/ansible/facts.d
- name: install custom impi fact
copy: src=ipmi.fact dest=/etc/ansible/facts.d
- name: re-read facts after adding custom fact
setup: filter=ansible_local
然而,在這種模式下,您也可以編寫一個facts模塊,並且不妨將其視為一個選項。Ansible version
1.8版新功能
要將playbook行為適應特定版本的ansible,可以使用一個變量ansible_version,具有以下結構:
"ansible_version": { "full": "2.0.0.2", "major": 2, "minor": 0, "revision": 0, "string": "2.0.0.2" }
Fact Caching
1.8版新功能
如文檔中的其他位置所示,一個服務器可以引用另一個服務器的變量,如下所示:
{{ hostvars [ 'asdf.example.com' ] [ 'ansible_os_family' ] }}
對於“事實緩存”禁用,為了做到這一點,Ansible必須已經在當前的播放中與“asdf.example.com”進行了對話,或者在劇本中再次播放。 這是ansible的默認配置。
為了避免這種情況,Ansible 1.8允許在Playbook運行之間保存事實,但是此功能必須手動啟用。 為什么這樣會有用?
想象一下,例如,擁有數千台主機的非常大的基礎架構。 事實緩存可以配置為每晚運行,但是一小組服務器的配置可以在一天內進行臨時或定期運行。 啟用事實緩存后,無需“打”所有服務器來引用變量和有關它們的信息。
啟用事實緩存后,盡管在/ usr / bin / ansible-playbook的當前執行中沒有與其通信,但一組中的機器可能會引用另一組中的機器的變量。
為了從緩存的事實中受益,您將希望將
gathering
設置更改為smart
或explicit
或者在大多數播放中將gather_facts
設置為False
。目前,Ansible具有兩個持久緩存插件:redis和jsonfile。
要使用redis配置事實緩存,請在
ansible.cfg
啟用它,如下所示:[defaults] gathering = smart fact_caching = redis fact_caching_timeout = 86400 # seconds
要重新啟動並運行,請執行等效的操作系統命令:yum install redis service redis start pip install redis
請注意,Python redis庫應該從pip安裝,打包在EPEL中的版本太舊,不能被Ansible使用。
在當前實施例中,該特征處於beta級狀態,並且Redis插件不支持端口或密碼配置,預計在不久的將來會發生變化。
要使用jsonfile配置事實緩存,請在
ansible.cfg
啟用它,如下所示:[defaults] gathering = smart fact_caching = jsonfile fact_caching_connection = /path/to/cachedir fact_caching_timeout = 86400 # seconds
fact_caching_connection
是到可寫目錄的本地文件系統路徑(如果不存在,可能會嘗試創建目錄)。fact_caching_timeout
是緩存記錄事實的秒數。Registered Variables
變量的另一個主要用途是運行命令並使用該命令的結果將結果保存到變量中。 結果將因模塊而異。 執行playbook時使用
-v
將顯示結果的可能值。在ansible中執行的任務的值可以保存在變量中,以后使用。 請參閱條件一章中的一些例子。
雖然在該文檔的其他地方也提到,這里有一個快速的語法示例:
- hosts: web_servers tasks: - shell: /usr/bin/foo register: foo_result ignore_errors: True - shell: /usr/bin/bar when: foo_result.rc == 5
注冊變量在主機上運行的剩余部分是有效的,與Ansible中“facts”的生命周期相同。 有效注冊的變量就像facts一樣。當循環使用
register
,在循環中放置在變量中的數據結構將包含一個results
屬性,即該模塊的所有響應的列表。 有關如何工作的更深入的示例,請參閱“ 循環”部分,使用帶有循環的寄存器。Accessing Complex Variable Data
我們已經在文檔中談到了一些facts。
一些提供的facts,如網絡信息,作為嵌套數據結構可用。 要訪問他們一個簡單的
{{ foo }}
是不夠的,但它仍然很容易做到。 以下是我們如何獲取IP地址:{{ ansible_eth0 [ “ipv4” ] [ “address” ] }}
或者:
{{ ansible_eth0.ipv4.address }}
類似地,這是我們如何訪問數組的第一個元素:
{{ foo [ 0 ] }}
Magic Variables, and How To Access Information About Other Hosts
即使您沒有自己定義它們,Ansible會為您自動提供一些變量。 其中最重要的是
hostvars
,group_names
和groups
。 用戶不應該自己使用這些名稱,因為它們是保留的。environment
也保留。hostvars
可讓您詢問另一個主機的變量,包括已經收集到關於該主機的事實。 如果在這一點上,你還沒有在劇本或劇集中玩過這個主機,那么你仍然可以得到這些變量,但是你將無法看到事實。如果您的數據庫服務器想要使用另一個節點的“事實”值,或者分配給另一個節點的清單變量,那么在一個模板甚至一個動作行中可以輕松實現:
{{ hostvars [ ' test.example.com' ] [ 'ansible_distribution' ] }}
另外,
group_names
是當前主機所有組的列表(數組)。這可以在使用Jinja2語法的模板中使用,以使得根據主機的組成員資格(或角色)而變化的模板源文件{% if 'webserver' in group_names %} # some part of a configuration file that only applies to webservers {% endif %}
groups
是清單中所有組(和主機)的列表。 這可以用於枚舉組內的所有主機。 例如:{% for host in groups['app_servers'] %} # something that applies to all app servers. {% endfor %}
一個經常使用的成語是走一個組來查找該組中的所有IP地址{% for host in groups['app_servers'] %} {{ hostvars[host]['ansible_eth0']['ipv4']['address'] }} {% endfor %}
一個例子可能包括將前端代理服務器指向所有應用服務器,在服務器之間設置正確的防火牆規則等。您需要確保這些主機的事實已經填充,例如,通過運行如果事實最近還沒有被緩存,那么他們就會玩這個游戲(在Ansible 1.8中添加了事實緩存)。此外,
inventory_hostname
是在Ansible的清單主機文件中配置的主機名的名稱。 當您不想依賴於發現的主機名ansible_hostname
或其他神秘原因時,這可能很有用。 如果你有一個很長的FQDN,inventory_hostname_short
也包含第一個時間段,沒有其余的域。play_hosts
在2.2中已被棄用,它與新的ansible_play_batch
變量相同。新版本2.2。
ansible_play_hosts
是當前播放中仍然有效的所有主機的完整列表。新版本2.2。
ansible_play_batch
可用作播放當前“批”的范圍內的主機名列表。 批量大小由serial
定義,當不設置它相當於整個播放(使其與ansible_play_hosts
相同)。版本2.3中的新功能。
ansible_playbook_python
是用於調用可執行命令行工具的python可執行文件的路徑。這些變量可能對於填寫具有多個主機名的模板或將列表注入到負載均衡器的規則中是有用的。
除非你認為你需要,否則不要擔心這些。 你會知道你什么時候做的
inventory_dir
也是可用的目錄,該目錄包含Ansible的庫存主機文件,inventory_file
是路徑名,文件名指向Ansible的庫存主機文件。playbook_dir
包含playbook基本目錄。然后我們有
role_path
,它將返回當前角色的路徑名(自1.8)。 這只能在一個角色中發揮作用。最后,
ansible_check_mode
(在版本2.1中添加),一個布爾魔術變量,如果您使用--check
運行可執行文件,則將其設置為True
。Variable File Separation
這是一個很好的主意,讓您的Playbook受到源代碼的控制,但您可能希望將Playbook的來源公開,同時保留某些重要的變量。 同樣,有時您可能只想將某些信息保存在不同的文件中,遠離main playbook。
您可以通過使用外部變量文件或文件來執行此操作,如下所示:
--- - hosts: all remote_user: root vars: favcolor: blue vars_files: - /vars/external_vars.yml tasks: - name: this is just a placeholder command: /bin/echo foo
這可以消除與他人共享您的手冊源的敏感數據的風險。每個變量文件的內容是一個簡單的YAML字典,如下所示:
--- # in the above example, this would be vars/external_vars.yml somevar: somevalue password: magic
Passing Variables On The Command Line
除了
vars_prompt
和vars_files
,還可以通過可執行命令行發送變量。 在編寫通用發行版手冊時,您可能希望通過要部署的應用程序版本,這一點尤其有用:ansible-playbook release.yml --extra-vars“version = 1.23.45 other_variable = foo”
這對於設置play的主機組或用戶而言非常有用。--- - hosts: '{{ hosts }}' remote_user: '{{ user }}' tasks: - ... ansible-playbook release.yml --extra-vars "hosts=vipers user=starbuck"
從Ansible 1.2開始,您還可以傳入額外的var,如引用的JSON,如下所示:--extra-vars'{“pacman”:“mrs”,“ghosts”:[“inky”,“pinky”,“clyde”,“sue”]}
key=value
形式顯然更簡單,但是如果需要它就在那里!
從Ansible 1.3起,可以使用@
語法從JSON文件中加載額外的var:--extra-vars“@ some_file.json”
也可以從Ansible 1.3,額外的vars可以格式化為YAML,無論是在命令行還是在上面的文件中。
Variable Precedence: Where Should I Put A Variable?
很多人可能會問,變量如何覆蓋另一個。 最終,Ansible的理念是更好地知道在哪里放一個變量,然后你必須考慮一下。
避免在47個位置定義變量“x”,然后詢問“哪個x被使用”的問題。 為什么? 因為那不是禪宗的做事哲學。
只有一個帝國大廈。 一個蒙娜麗莎等,找出定義變量的位置,不要復雜。
但是,讓我們繼續前進吧! 它存在 這是一件真實的事情,你可能會用它。
如果在不同的地方定義了相同名稱的多個變量,則它們將按照一定的順序被覆蓋。
在1.x中,優先級如下(最后列出的變量獲得優先級排序):
- “role defaults”,其優先於所有事物,並且是最容易被覆蓋的
- inventory中定義的變量
- 在有關系統中發現的facts
- “most everything else”(命令行開關,play中的變量,include變量,角色變量等)
- 連接變量(
ansible_user
等) - 額外的vars(
-e
在命令行中)最優先
注意
在1.5.4之前的版本中,有關系統的事實發現在上述的“其他一切”類別中。
在2.x中,我們使優先順序更具體(最后列出的變量獲得優先級排序):
- role defaults[1]
- inventory文件或腳本組vars [2]
- inventory group_vars / all
- playbook group_vars / all
- inventory group_vars / *
- playbook group_vars / *
- inventory 文件或腳本主機vars [2]
- inventory host_vars / *
- playbook host_vars / *
- host facts
- play facts
- play vars_prompt
- play vars_files
- role vars(在role / vars / main.yml中定義)
- block 變量(僅適用於塊中的任務)
- 任務變量(僅用於任務)
- 角色(和include_role)參數
- include參數
- include_vars
- set_facts / registered vars
- 額外的vars(總是贏得優先)
基本上,進入“角色默認值”(角色中的默認文件夾)的任何東西都是最有價值的,容易被覆蓋的。 該角色的vars目錄中的任何內容都會覆蓋該命名空間中該變量的先前版本。 這里要遵循的一個想法是,在范圍上越明確,命令行
-e
額外的vars總是勝出越多的優先級。 主機和/或庫存變量可以勝過角色默認值,但不顯式包括vars目錄或include_vars
任務。