一 簡介
注:本文demo使用ansible2.7穩定版
在我看來,role是task文件、變量文件、handlers文件的集合體,這個集合體的顯著特點是:可移植性和可重復執行性。
實踐中,通常我們以部署某個服務為單元作為一個role ,然后將這些服務單元(role)放在一個roles目錄下。主playbook文件通過調用roles目錄下的role,來實現各種靈活多變的部署需求。
本節主要為大家介紹下roles的目錄結構、引用方法及其他特性。
二 創建與目錄結構
2.1 創建roles
通常創建一個role的方法有兩種:
-
命令mkdir和touch行手動創建
-
使用ansible-galaxy自動初始化一個role
命令行手動創建方式就無需多說了,即需要哪個目錄和文件就用「mkdir」和「touch」命令創建出來。
我個人比較喜歡使用「ansible-galaxy」命令創建,創建完后再刪除我不需要的目錄,這樣可以避免因手誤創建出錯的問題。
例如,我想使用「ansible-galaxy init」命令創建一個名字為role_A 的role,可以這樣寫:
➜ lab-ansible ansible-galaxy init role_A - role_A was created successfully
創建后的目錄結構如下:
➜ lab-ansible tree role_A role_A ├── defaults │ └── main.yml ├── files ├── handlers │ └── main.yml ├── meta │ └── main.yml ├── README.md ├── tasks │ └── main.yml ├── templates ├── tests │ ├── inventory │ └── test.yml └── vars └── main.yml 8 directories, 8 files
使用「ansible-galaxy」命令自動創建的role是最全的目錄結構,根據需求,可以刪除不用的目錄文件。
2.2 目錄結構
我們以上面創建的「role_A」為例,介紹下各目錄文件的作用:
- tasks : 用於存放role_A的主要任務,也可以添加其他task文件,供main.yaml調用,從而實現更加復雜的部署功能。
- handlers : 用於存放觸發執行( hanlders )的任務。
- defaults : 用於存放默認變量,優先級最低,變量優先級可參考《ansible基礎-變量》。
- vars : 用於存放變量文件,role_A中任務和模版里用到的變量可以在這里定義。
- files :用於存放需要拷貝到目的主機的文件,例如,作為「copy」模塊src參數的默認根目錄。
- template : 用於存放模版文件,格式為.j2,文件內容要符合Jinja2語法規則,通常使用「template」模塊部署服務的配置文件。
- meta : 用於存放role依賴列表,這個知識點后面會詳細闡述。
- tests : 用於存放測試role本身功能的playbook和主機定義文件,在開發測試階段比較常用。
role中各個目錄下的main.yaml文件很重要,這是ansible默認加載的YAML文件。
三 role的引用與執行
3.1 roles語句引用
比較常用的方法,我們可以使用「roles:」語句引用role :
---
- hosts: node1 roles: - role_A
或者
---
- hosts: node1 roles: - name: role_A - name: role_A
或者
---
- hosts: node1 roles: - role: role_A - role: role_A
或者使用絕對路徑:
--- # playbooks/test.yaml - hosts: node1 roles: - role: /root/lab-ansible/roles/role_A
引入的同時添加變量參數:
--- # playbooks/test.yaml - hosts: node1 roles: - role: role_A vars: name: Maurice age: 100
引入的同時添加tag參數:
--- # playbooks/test.yaml - hosts: node1 roles: - role: role_B tags: - tag_one - tag_two # 等價於上面 - { role: role_B, tags:['tag_one','tag_two'] }
根據需求,我們在playbook中引用不同的role,引用后的效果也很好理解:ansible會把role所包含的任務、變量、handlers、依賴等加載到playbook中,順次執行。
檢索路徑
上面介紹了使用「roles」語句的引用方法,那么ansible去哪找這些role呢?
在不使用絕對路徑的情況下,ansible檢索role的默認路徑有:
- 執行ansible-playbook命令時所在的當前目錄
- playbook文件所在的目錄及playbook文件所在目錄的roles目錄
- 當前系統用戶下的~/.ansible/roles目錄
- /usr/share/ansible/roles目錄
- ansible.cfg 中「roles_path」指定的目錄,默認值為/etc/ansible/roles目錄
注:上面的檢索路徑是在centos操作系統下測試出來的結果。
3.2 include和import引用
在后來版本(ansible>=2.4)中,ansible引入了「import_role」(靜態)和「include_role」(動態)方法:
--- # playbooks/test.yaml - hosts: node1 tasks: - include_role: name: role_A vars: name: maurice age: 100
- import_role: name: role_B
比較於「roles」語句,「import_role」和「include_role」的優點如下:
- 可以在task之間穿插導入某些role,這點是「roles」沒有的特性。
- 更加靈活,可以使用「when」語句等判斷是否導入。
關於include_role(動態)和import_role(靜態)的區別,可以參考筆者之前的文章《ansible中include_tasks和import_tasks》。
也正是因為「include_task」是動態導入,當我們給「include_role」導入的role打tag時,實際並不會執行該role的task。
舉個🌰,當我們使用include導入role_A,使用import導入role_B時:
--- # playbooks/test.yaml - hosts: node1 tasks: - include_role: name: role_A tags: maurice - import_role: name: role_B tags: maurice
role_A內容如下:
--- # tasks file for role_A - debug: msg: "age"
- debug: msg: "maurice"
執行結果顯示,role_A雖然被引用,但里面的task並沒有執行:
PLAY [node1] ************************************************************* TASK [Gathering Facts] ************************************************************* ok: [node1] TASK [include_role : role_A] ************************************************************* TASK [role_B : debug] ************************************************************* ok: [node1] => { "msg": "I'm just role_B" } PLAY RECAP ************************************************************* node1 : ok=2 changed=0 unreachable=0 failed=0
3.3 重復引用
不添加其他變量、tag等的情況下,一個playbook中對同一個role引入多次時,實際ansible只會執行一次。
例如:
--- # playbooks/test.yaml - hosts: node1 roles: - role_A - role_A
當然,我們也可以讓其運行多次,方法如下:
- 引用role的同時定義不同的變量
- 在meta/main.yaml中添加「allow_duplicates: true」(這個特性筆者實測未生效……)
兩種情況示例分別如下:
---
- hosts: webservers roles: - role: foo vars: message: "first"
- { role: foo, vars: { message: "second" } }
# playbook.yml ---
- hosts: webservers roles: - foo - foo # roles/foo/meta/main.yml --- allow_duplicates: true
3.4 執行順序
筆者之前的文章《ansible基礎-playbooks》「5.執行順序」中提到,如果playbook中只有「tasks」和「roles」,ansible總是會先執行「roles」語句部分。此時可以使用「per_tasks」和「post_tasks」來規范執行順序。
在使用「per_tasks」+「roles」+「tasks」+「post_tasks」結構下,task的執行順序為:
- per_task包含的play
- per_task中handlers任務
- roles語句中role列表依次執行,每個role優先執行依賴的play及任務
- tasks語句中的所有play
- 前兩步所觸發的handlers
- post_tasks包含的play
- post_tasks觸發的handlers
四 role的依賴
role的依賴指role_A可以引入其他的role,例如role_B。
roles的依賴知識點總結如下:
- 配置的路徑在role_A的meta/main.yaml
- 引入role列表的方式只能使用類似「roles」語句的方法,只需將「roles」換為「dependencies」語句,不能用新版本的include和import語句
- 在meta/main.yaml文件內可以引入多個role,且必須以列表的形式引入
- 在引入role的同時,可以添加變量,方法同「roles」語句
多層依賴
被引入的role總是優先執行,即便是同一個 role 被引入了多次(遵循3.3重復引用規則)。
舉個🌰:
role「car」引入了role「wheel」:
--- # roles/car/meta/main.yml dependencies: - role: wheel vars: n: 1
- role: wheel vars: n: 2
- role: wheel vars: n: 3
- role: wheel vars: n: 4
同時,role「wheel」引入了role「tire」和「brake」:
--- # roles/wheel/meta/main.yml dependencies: - role: tire - role: brake
最終的執行結果為:
tire(n=1) brake(n=1) wheel(n=1) tire(n=2) brake(n=2) wheel(n=2) ... car
五 插件和模塊
我們可以為一個role自定義模塊和插件,這部分屬於高級特性,在以后的「ansible進階」系列文章中會詳細闡述,這里只簡單介紹下。
模塊
給某個role自定義模塊,需要在這個role的目錄下創建「library」目錄,然后將自定義模塊放在該目錄下。
創建自定義模塊目錄結構示例:
roles/ my_custom_modules/ library/ module1 module2
引用的時候在「my_custom_modules」后被引用的role也可以使用該自定義模塊:
- hosts: webservers roles: - my_custom_modules - some_other_role_using_my_custom_modules - yet_another_role_using_my_custom_modules
插件
自定義插件的方法與模塊類似,需要創建的目錄為「filter_plugins」。
創建自定義插件目錄結構示例:
roles/ my_custom_filter/ filter_plugins filter1 filter2
與模塊一樣,自定義插件可以在本身role的task和模版內使用,也可以在 role「my_custom_filter」之后被引用的role內使用。
六 Ansible Galaxy
Ansible Galaxy是一個免費的roles倉庫,里面有很多社區里現成穩定的role,在生產中的部署項目中,可以直接下載下來使用。
Ansible Galaxy客戶端是「ansible-galaxy」,「ansible-galaxy」命令行可以用來初始化一個role(本文2.1 創建roles有提),也可以用來從Ansible Galaxy下載role。
關於Ansible Galaxy的詳細介紹,因篇幅原因,這里不再擴展,有興趣的同學可以去官網<https://galaxy.ansible.com/docs/>加深學習下。
七 本節應該掌握的技能
- 掌握role的目錄結構及其含義
- 掌握引用role的方法
- 掌握role的依賴及執行順序
- 了解自定義模版和插件
- 了解Ansible Galaxy
八 參考鏈接
- https://docs.ansible.com/ansible/latest/user_guide/playbooks_reuse_roles.html
歡迎大家關注我的公眾號: