ansible基礎-變量

一 變量的命名規範

變量的命名應該符以下合兩個規範:html

  • 變量應該由字母、數字、下劃線組成
  • 變量應該以字母開頭

例如:host_port、HOST_PORT、var5是符合命名規範的,foo-port、 foo port、foo.port 、12都不符合命名規範。node

變量的定義一般是YAML形式,在inventory host文件中也可使用INI形式。python

ansible變量不只能夠支持簡單的key=value格式,並且也支持更復雜數據結構,例如字典類型等。c++

二 變量的做用域

 變量的做用域能夠分爲四種:redis

  • 做用於全局的變量
  • 做用於play的變量
  • 做用於task的變量
  • 做用於host的變量

接下來咱們根據變量的做用域,詳細分析下ansible變量的定義、使用和調用順序。shell

三 做用於全局的變量

3.1 配置文件變量

ansible配置文件會定義一些變量信息,主要是對執行環境、鏈接信息變量的定義。json

例如inventory目錄、library目錄、與目的主機鏈接方式、越權信息、鏈接超時時間等等。緩存

3.2 系統環境變量

在ansible鏈接到目的主機時,會以non-login shell登錄到目的主機,此時目的主機的/etc/bashrc和~/.basrc的環境變量會被加載,因此這兩個文件中設置的環境變量會做用於playbook全局。bash

3.3 命令行變量

咱們能夠在執行playbook的命令行指定變量,須要注意的是,命令行指定的變量在全部其餘變量中優先級是最高的。也就是說若是命令行指定的變量和其餘地方指定的變量有衝突時,那麼ansible最終會採用命令行定義的變量。數據結構

命令行指定變量示例以下:

ansible-playbook release.yml --extra-vars "version=1.23.45 other_variable=foo"

四 做用於play的變量

4.1 playbook中的變量

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 }}"

4.2 roles中的變量

4.2.1 default變量 

default變量位於roles/defaults/main.yml文件中,該變量做用於role裏的全部play,一般做爲模版或模塊裏的默認參數。

default變量與ansible filter變量 「{{ some_variable | default("some_value") }}」具備一樣的做用,在全部ansible變量中優先級最低。

4.2.2 dependencies變量

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均生效。

4.2.3 vars變量

vars變量位於roles/vars/main.yml,該變量做用於role裏的全部模塊。一般將除了默認變量的其餘的變量放在這個文件內。

4.3 register變量

register方法可以將一個task的執行結果註冊爲一個變量。書寫格式要與模塊名稱對齊,該變量做用於整個play。

一般register變量和when語句聯合使用,以達到知足某些條件才運行task的目的。

五 做用於task的變量 

5.1 playbook中的變量

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語句。

5.2 roles中的變量

指的是在tasks/main.yaml或handlers/main.yaml內書寫task時指定的變量,該變量做用於某個task,這個變量類型和上述章節中「5.1playbook中的變量—with modules」相似,這裏就再也不舉例說明。

六 做用於host的變量

6.1 系統變量Facts

6.1.1 facts變量

ansible中有個特殊的變量,這些變量不是開發者定義的,而是ansible根據目的主機環境信息自動收集的,稱之爲fact變量。

fact變量很實用,和「when」語句配合使用會讓你的代碼更加健壯。

舉個🌰,若是當前的操做系統爲「RedHat」類型,則經過yum安裝須要的軟件包:

--- # playbooks/test.yaml - hosts: node1 tasks: - yum: name: firewalld state: present when: ansible_os_family == 'RedHat'

6.1.2 facts緩存

在執行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

6.2 inventory中的變量

6.2.1 主機變量

關於主機和主機組變量,咱們在「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\'

6.2.2 組變量 

和主機變量相似,組變量做用於主機組,即多個主機。位置能夠與主機組定義寫在一塊兒也能夠寫在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採用)

  • 命令行參數(非-e指定的參數,eg: "-u user -b yes")
  • roles defaults目錄下的變量
  • 組變量:inventory 文件
  • 組變量:inventory/group_vars/all
  • 組變量:playbook/group_vars/all
  • 組變量:inventory/group_vars/*
  • 組變量:playbook/group_vars/*
  • 主機變量:inventory 文件
  • 主機變量:inventory/group_vars/*
  • 主機變量:playbook/group_vars/*
  • facts變量
  • play變量:vars定義的
  • play變量:vars_prompt定義的
  • play變量:vars_files導入的
  • roles vars目錄下的變量
  • block中task定義的變量
  • playbook中task定義的變量
  • include_vars導入的變量
  • set_facts/register註冊的變量
  • 使用roles/include_role/import_role語句時定義的變量
  • 使用include語句(ansible舊版本)時定義的變量
  • 命令行-e參數指定的額外變量(優先級最高)

八 變量的使用

8.1 模塊使用變量

一個變量被定義後,在它的做用域內的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

8.2 模版使用變量

變量被頻繁使用的還有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」中獲取,執行結果是個字符串,字符串由該列表的元素以逗號爲間隔組成,最後一個參數後沒有逗號。

九 本節應該掌握的技能

  • 掌握變量的命名規範
  • 掌握變量定義的方法
  • 掌握變量的做用域及調用順序
  • 會在模塊和模版裏使用變量
  • 熟悉Jinja2模版的語法規則

十 參考連接

  • https://docs.ansible.com/ansible/latest/user_guide/playbooks_variables.html#passing-variables-on-the-command-line
  • https://docs.ansible.com/ansible/latest/user_guide/playbooks_reuse_roles.html
  • https://docs.ansible.com/ansible/latest/user_guide/intro_inventory.html
  • 紅帽DO407 Automation with Ansible 教材

 

歡迎你們關注個人公衆號:

相關文章
相關標籤/搜索