變量的命名應該符以下合兩個規範:html
例如:host_port、HOST_PORT、var5是符合命名規範的,foo-port、 foo port、foo.port 、12都不符合命名規範。node
變量的定義一般是YAML形式,在inventory host文件中也可使用INI形式。python
ansible變量不只能夠支持簡單的key=value格式,並且也支持更復雜數據結構,例如字典類型等。c++
變量的做用域能夠分爲四種:redis
接下來咱們根據變量的做用域,詳細分析下ansible變量的定義、使用和調用順序。shell
ansible配置文件會定義一些變量信息,主要是對執行環境、鏈接信息變量的定義。json
例如inventory目錄、library目錄、與目的主機鏈接方式、越權信息、鏈接超時時間等等。緩存
在ansible鏈接到目的主機時,會以non-login shell登錄到目的主機,此時目的主機的/etc/bashrc和~/.basrc的環境變量會被加載,因此這兩個文件中設置的環境變量會做用於playbook全局。bash
咱們能夠在執行playbook的命令行指定變量,須要注意的是,命令行指定的變量在全部其餘變量中優先級是最高的。也就是說若是命令行指定的變量和其餘地方指定的變量有衝突時,那麼ansible最終會採用命令行定義的變量。數據結構
命令行指定變量示例以下:
ansible-playbook release.yml --extra-vars "version=1.23.45 other_variable=foo"
vars語句定義全局變量
咱們能夠在playbook中使用「vars」語句定義變量,該變量做用於整個play。
例如:
---
# inventory/playbooks/test.yaml - hosts: node1 vars: http_port: 80
上面示例中中「http_port」是一個做用於整個play的變量,對這個play裏的tasks、roles、import、include等等之下定義的task均生效。
引用變量文件
除了將變量寫在playbook中,咱們也能夠將變量放在一個單獨的YAML文件中,經過「vars_files」語句來導入。
「vars_files」變量只能做用於play全局,不能在某個task中單獨被引用。「vars_files」參數可使用系統絕對路徑或playbook文件的相對路徑。
舉個🌰:
咱們在playbooks目錄下建立一個vars-files.yaml文件:
--- # playbooks/vars-files.yaml age: 100
在playbook中使用vars_files語句引用該變量文件:
--- # playbooks/test.yaml - hosts: node1 vars_files: ./vars-files.yaml tasks: - debug: msg: "My age is {{ age }}"
default變量位於roles/defaults/main.yml文件中,該變量做用於role裏的全部play,一般做爲模版或模塊裏的默認參數。
default變量與ansible filter變量 「{{ some_variable | default("some_value") }}」具備一樣的做用,在全部ansible變量中優先級最低。
dependencies變量位於roles/meta/main.yaml文件中,該變量與「role」語句同級縮進,做用於自己的role和dependencies role。
舉個🌰:
role_A 和 role_B定義了相同的task,debug出「age」變量:
--- # tasks file for role_B - debug: var: age
--- # tasks file for role_B - debug: var: age
role_A/meta/main.yaml定義role_A依賴role_B,並指定「age」變量等於26:
--- dependencies: - role: role_B vars: age: 27
寫playbook,引用role_A:
--- # playbooks/test.yaml - hosts: node1 roles: - role: role_A
執行結果以下:
➜ lab-ansible ansible-playbook playbooks/test.yaml PLAY [node1] ******************************************************************************************** TASK [Gathering Facts] ********************************************************************************** ok: [node1] TASK [role_B : debug] *********************************************************************************** ok: [node1] => { "age": 27 } TASK [role_A : debug] *********************************************************************************** ok: [node1] => { "age": 27 } PLAY RECAP ********************************************************************************************** node1 : ok=3 changed=0 unreachable=0 failed=0
輸出結果顯示,dependencise變量「age」在role_A和role_B均生效。
vars變量位於roles/vars/main.yml,該變量做用於role裏的全部模塊。一般將除了默認變量的其餘的變量放在這個文件內。
register方法可以將一個task的執行結果註冊爲一個變量。書寫格式要與模塊名稱對齊,該變量做用於整個play。
一般register變量和when語句聯合使用,以達到知足某些條件才運行task的目的。
with modules
咱們能夠爲某個模塊定義變量,該變量做用於這個task。
舉個🌰,示例中爲「debug」模塊定義了「name」和「age」變量並在「msg」參數後使用了這兩個變量:
--- # playbooks/test.yaml - hosts: node1 tasks: - debug: msg: "My name is {{ name }} and I'm {{ age }} years old" vars: name: Maurice age: 27
with import*/include*
在使用import_playbook、import_tasks、include_tasks、import_role、include_role時能夠在import*/include*的同級位置指定變量,該變量做用於導入的全部play。
使用import_role舉個🌰:
playbook導入role_A,並定義變量「age」,這樣role_A內的play就可使用「age」變量了:
--- # playbooks/test.yaml - hosts: node1 tasks: - import_role: name: role_A vars: age: 1000
其餘import*/include*的語句使用方法相似,只要記住縮進與import*/include*語句保持一致便可。
with roles
在playbook中使用roles語句來導入role時也能夠定義變量,該變量做用於role包含的全部play。
舉個🌰:
playbook使用roles語句導入role_A,並定義變量「age」:
--- # playbooks/test.yaml - hosts: node1 roles: - role: role_A vars: age: 1000
經過上面兩個示例咱們發現,roles和import_role語句定義變量寫法上很類似,其實import_role和include_role是新版本的語法,功能上徹底能夠代替roles語句。若是你使用的ansible版本>=2.4,建議使用include_role和import_role語句。
指的是在tasks/main.yaml或handlers/main.yaml內書寫task時指定的變量,該變量做用於某個task,這個變量類型和上述章節中「5.1playbook中的變量—with modules」相似,這裏就再也不舉例說明。
ansible中有個特殊的變量,這些變量不是開發者定義的,而是ansible根據目的主機環境信息自動收集的,稱之爲fact變量。
fact變量很實用,和「when」語句配合使用會讓你的代碼更加健壯。
舉個🌰,若是當前的操做系統爲「RedHat」類型,則經過yum安裝須要的軟件包:
--- # playbooks/test.yaml - hosts: node1 tasks: - yum: name: firewalld state: present when: ansible_os_family == 'RedHat'
在執行playbook時,咱們發如今「Gathering Facts」步驟時總會卡住一會,若是定義的play多了,會很是耗時。其實這步就是ansible在收集目的主機的facts信息。
若是咱們定義的playbook中並無使用到fact變量,那麼咱們能夠選擇將其關閉,只需添加「gather_facts: false」便可。
若是必需要使用facts信息,咱們能夠將fact信息緩存到redis服務或本地json文件中,這樣當咱們第二次執行playbook時,ansible就會讀取緩存信息,從而加快運行速度。
假設本地redis服務正常運行,咱們只需更改ansible配置文件便可達到緩存fact的目的。
redis緩存:
[defaults] gathering = smart fact_caching = redis fact_caching_timeout = 86400
json文件緩存:
[defaults] gathering = smart fact_caching = jsonfile fact_caching_connection = /path/to/cachedir fact_caching_timeout = 86400
關於主機和主機組變量,咱們在「ansible基礎-安裝與配置:3.1 主機與主機組」中有介紹,當時介紹了組和主機變量的定義方法、變量的分離、優先級等知識點。其實主機變量的知識點不復雜,這裏作下總結。主機變量是指做用在某一臺主機上的變量。位置能夠與主機定義寫在一塊兒也能夠寫在inventory/host_vars/a_host_name.yaml文件裏。一般前者使用使用INI格式,後者使用YAML格式。這裏要注意一下YAML的語法,在「:」後面要留有一個空格。若是組變量和主機變量都對同一個主機定義了相同的變量,那麼ansible最終會採用主機變量而放棄組變量。主機變量示例:INI格式:
# inventory/hosts [nodes] node1 node2 node3 [nodes:vars] http_port=80 database_port=3306
轉換爲YAML格式:
--- # inventory/hosts nodes: hosts: node1: node2: node3: vars: http_port: \'80\'
database_port: \'3306\'
不含節點定義的主機變量定義:
--- # inventory/host_vars/node1.yaml http_port: \'80\'
database_port: \'3306\'
和主機變量相似,組變量做用於主機組,即多個主機。位置能夠與主機組定義寫在一塊兒也能夠寫在inventory/group_vars/a_group_name.yaml文件裏。一般前者使用使用INI格式,後者使用YAML格式。
INI格式:
# inventory/hosts [nodes] node1 node2 node3 [nodes:vars] http_port=80 database_port=3306
轉換爲YAML格式:
--- # inventory/hosts nodes: hosts: node1: node2: node3: vars: http_port: \'80\'
database_port: \'3306\'
定義一個字典變量,位於inventory/group_vars/nodes.yaml:
--- # 一位職工記錄 name: Maurice job: Developer skill: Develop program employed: True foods: - Apple - Orange languages: shell: Elite python: Elite c++: Lame
將上面示例轉換爲一行:
--- # 一位職工記錄 {name: Maurice,job: Developer,skill: Develop program,employed: True,foods: [\'Apple\',\'Orange\'],languages: {shell: Elite,python: Elite,c++: Lame}}
很顯然,YANL格式分行來寫會更加直觀和美觀。
經過上面描述,咱們發現ansible可以定義變量的地方真的是太多太多了,我我的以爲ansible變量這塊的設計有點複雜和冗餘。
在生產中,咱們要讀懂別人的代碼或者讓本身的代碼更加健壯,就必須清楚的知道ansible最終會使用哪一個變量。這裏我總結下ansible的調用變量的順序,當小夥伴迷茫時能夠回來看下這個列表(越靠後變量優先級越高,越會被ansible採用)
一個變量被定義後,在它的做用域內的play能夠直接調用,例如:
咱們定義了整個play做用域的變量「name」和「age」,那麼在以後的兩個debug模塊內能夠直接調用。
--- # playbooks/test.yaml - hosts: node1 vars: name: Maurice age: 27 tasks: - debug: msg: "My name is {{ name }} and I'm {{ age }} years old"
- debug: msg: "Hello Maurice" when: name == 'Maurice'
輸出結果展現:
➜ lab-ansible ansible-playbook playbooks/test.yaml PLAY [node1] ******************************************************************************************** TASK [Gathering Facts] ********************************************************************************** ok: [node1] TASK [debug] ******************************************************************************************** ok: [node1] => { "msg": "My name is Maurice and I'm 27 years old" } TASK [debug] ******************************************************************************************** ok: [node1] => { "msg": "Hello Maurice" } PLAY RECAP ********************************************************************************************** node1 : ok=3 changed=0 unreachable=0 failed=0
變量被頻繁使用的還有roles裏的模版,位於roles/template/xxx.j2,該模版使用python的Jinja2模版語法。
roles模版多被用於生成服務的配置文件,因此會調用不少的變量。
示例以下:
"customerMonthInfo": "{{ cmp_server_customerMonthInfo }}", "type_black_list": [{% for type_black in cmp_server_type_black_list %}"{{ type_black }}"{{ '' if loop.last else ',' }}{% endfor %}],
上述示例中「customerMonthInfo」的參數比較簡單,就是變量「cmp_server_customerMonthInfo」的值
「type_black_list」參數從列表變量「cmp_server_type_black_list」中獲取,執行結果是個字符串,字符串由該列表的元素以逗號爲間隔組成,最後一個參數後沒有逗號。
歡迎你們關注個人公衆號: