Playbooks 是Ansible 管理配置、部署應用和編排的語言,可以使用Playbooks 來描述你想在遠程主機執行的策略或者執行的一組步驟過程等。
如果說Ansible 模塊是工作中的工具的話,那么playbooks 就是方案。
Playbooks 采用YAML 語法結構。
9.1 Playbooks 組成
- Target section:定義將要執行playbook 的遠程主機組
- Variable section:定義playbook 運行時需要使用的變量
- Task section:定義將要在遠程主機上執行的任務列表
- Handler section:定義task 執行完成以后需要調用的任務
9.1.1主機和用戶
在playbook 中的每一個play 都可以選擇在哪些機器和以什么用戶身份完成,hosts 一行可以是一個主機組或者主機也可以是多個,中間以冒號分隔,可以參考前面講的通配模式;
remote_user表示執行的用戶賬號,表示以什么用戶來登錄遠程機器並執行任務。
--- -hosts: webservers remote_user: root
9.1.2每一個任務都可以定義一個用戶
--- - hosts: webservers remote_user: root tasks: - name: test connection ping: remote_user: yourname
9.1.3在play 中支持sudo
--- - hosts: webservers remote_user: yourname sudo: yes
9.1.4在一個任務中支持sudo
--- - hosts: webservers remote_user: yourname tasks: - service: name=nginx state=started sudo: yes
9.1.5 登陸后sudo 到其他用戶執行
--- - hosts: webservers remote_user: yourname sudo: yes sudo_user: postgres
9.2 任務列表
每個任務建議定義一個可讀性較強的名字即name,在執行playbook 時會輸出,tasks 的聲明格式,建議使用”module:options”的格式。
下面以service 模塊為例來定義一個任務,service: key=value 參數,請參看模塊的詳細介紹
tasks: - name: make sure apache is running service: name=httpd state=running
command 和shell 模塊關注命令或者腳本執行后返回值,如果命令成功執行返回值不是0 的情況下,可以使用以下方法
tasks: - name: run this command and ignore the result shell: /usr/bin/somecommand || /bin/true
或者
tasks: - name: run this command and ignore the result shell: /usr/bin/somecommand ignore_errors: True
注:ignore_errors這里的值只要小寫后為true或者yes就可以,所以即使是TRue這種也是正確的。
如果在任務中參數過長可以回車使用空格縮進:
--- - hosts: server tasks: - name: Copy ansible inventory file to client copy: src=/etc/ansible/hosts dest=/tmp/hosts owner=root group=root mode=0644
9.3 變量的使用
1) 如何創建一個有效的變量名
變量名應該由字母、數組和下划線組成,以字母開頭
2) 在inventory 中定義變量
3) 在playbook 中定義變量
4) 在角色和文件中包含變量
5) 如何使用變量:Jinja2
Jinja2 是一個被廣泛使用的全功能的Python 模板引擎,它有完整的unicode 支持
注釋:Ansible 允許在模板中使用循環和條件判斷,但是在playbook 只使用純粹的YAML 語法
6) Jinja2 過濾器
變量可以通過過濾器修改。過濾器與變量用管道符號( | )分割,並且也可以用圓括號傳遞可選參數。多個過濾器可以鏈式調用,前一個過濾器的輸出會被作為后一個過濾器的輸入。
如{{ list | join(', ') }},會把一個列表用逗號連接起來。
下面列舉一些在Ansible 使用較多的Filters:
- 格式化數據:
{{ ansible_devices | join('| ') }}
- 過濾器和條件一起使用:
9.4 register
register 關鍵字的作用是將命令執行的結果保存為變量,結果會因為模塊不同而不同,在運行ansible-playbook 時增加-v 參數可以看到results 可能的值;注冊變量就如同通過setup 模塊獲取facts 一樣。
執行結果:
9.5 過濾器
場景1:將獲取到的變量的值的所有字母都變成大寫。如:
如上例所示,testvar變量的值中包含3個小寫字母,在使用debug模塊輸出這個變量的時候,我們使用了一個管道符,將testvar變量傳給了一個名為“upper”的東西,“upper”就是一個過濾器,執行playbook的時候將變量中的小寫字母變成了大寫。
過濾器是一種能夠幫助我們處理數據的工具。其實,ansible中的過濾器功能來自於jinja2模板引擎,我們可以借助jinja2的過濾器功能在ansible中對數據進行各種處理。
當我們想要通過過濾器處理數據的時候,只需要將數據通過管道符傳遞給對應的過濾器即可。過濾器有很多,有些是jinja2內置的,有些是ansible特有的。除此之外,jinja2還支持自定義過濾器。
跟字符串操作相關的過濾器,示例:
跟數字操作相關的過濾器,示例:
跟列表操作相關的過濾器,示例:
變量未定義相關操作的過濾器,示例:
上述的default過濾器,不僅能在變量未定義的時候返回指定的值,還能夠讓模塊的參數變得“可有可無”。
關於“可有可無”,通過以下示例來說明其含義。
場景2,創建幾個文件,只有個別文件需要指定權限,可以定義如下:
這里只有第一個文件需要指定權限,其余的都是使用系統默認的權限進行創建。在實際工作中,可能需要創建幾十個這樣的文件,有些需要指定權限,有些不需要,因此一般都會使用條件判斷和循環語句來完成,如下:
這樣的playbook確實可以很好的解決問題,但是一共循環了兩遍,因為需要對文件的是否有mode屬性進行判斷,並根據判斷結果調整參數設定。
更好的方法有:
這里並沒有對文件是否有mode權限進行判斷,而是直接調用了file模塊的mode參數,將mode的值設置為了{{item.mode | default(omit)}}。這樣表示的含義就是如果item有mode屬性,就把file模塊的mode參數設置為item的mode屬性值,如果item沒有mode屬性,file模塊就省略mode參數。‘omit’的字面意思就是省略,也就是“可有可無”。
9.6 pre_tasks and post_tasks
- pre_tasks: 設置playbook運行之前的tasks,一般用於准備條件或者變量自定義。
- post_tasks: 設置playbook運行之后的tasks
Playbook中各種task的執行順序:
pre_task > role > tasks > post_task
如果考慮到handler,則執行順序為:
pre_task > pre_handler > role task > task > role handler > task handler > post task > post handler
如果你想立即執行所有的 handler 命令,在1.2及以后的版本,你可以這樣做:
9.7 notify 與 handler
notify指定handler的執行機制:“notify”這個action可用於在每個play的最后被觸發,在notify中列出的操作稱為handler,僅在所有的變化發生完成后一次性地執行指定操作。在notify中列出的操作稱為handle,也即notify中調用handler中定義的操作。
handler:用於當關注的資源發生變化時采取一定的操作。handler是task列表,這些task與前述的task並沒有本質上的不同。
另外,handlers 會按照聲明(notify)的順序執行。
例如:修改ironic配置文件后需要重啟相應的ironic服務。
9.8 tags
tags:對任務進行“打標簽”操作。當任務存在標簽后,我們就可以在執行playbook的時候,借助標簽,指定執行哪些任務,或者不執行哪些任務。
例如:
9.8.1 查看所有tag
ansible-playbook <playbook_yaml> --list-tags
9.8.2 指定tag執行任務:
可以指定某個tag:
ansible-playbook test.yml -t/--tags "tag1"
可以指定多個tag(以逗號分隔,可以加空格):
ansible-playbook test.yml -t "tag1, tag2”
9.8.3 指定tag跳過任務
可以使用--skip-tags來跳過某些tag:
可以指定某個tag:
ansible-playbook test.yml --skip-tags "tag1"
可以指定多個tag(以逗號分隔,可以加空格):
ansible-playbook test.yml --skip-tags "tag1, tag2”
9.9 條件判斷:when
when相當於shell腳本里的if 判斷,when語句就是用來實現這個功能的,它是一個jinja2的語法,但是不需要雙大括號,用法很簡單。
運算比較符有:==、!=、>、<、>=、<=、and、or、not、()、in等
9.9.1 判斷目錄或文件是否存在:exists
#exists關鍵字,注意檢查的是ansible主機。is not exists表示不存在,也可以用not testpath is exists
9.9.2 判斷變量
- defined:判斷變量是否已經定義,已經定義則為真
- undefined:判斷變量是否已經定義,未定義則返回真
- none:判斷變量是否已經定義,如果變量值已經定義,但是變量值為空,則返回真
9.9.3 判斷執行結果
- success或succeeded: 通過任務的返回信息判斷任務的執行狀態,任務執行成功則返回真
- failure或failed: 通過任務的返回信息判斷任務的執行狀態,任務執行失敗則返回真
- change或changed: 通過任務的返回信息判斷任務的執行狀態,任務執行狀態為changed則返回真
- skip或skipped: 通過任務的返回信息判斷任務的執行狀態,當任務沒有滿足條件,而被跳過執行時,則返回真
9.9.4 判斷路徑
- file: 判斷路徑是否是一個文件,如果路徑是一個文件則為真。
- directory: 判斷路徑是否是一個目錄,如果路徑是一個目錄則為真
- link: 判斷路徑是否是一個軟連接,如果路徑是一個軟連接則為真
- mount: 判斷路徑是否是一個掛載點,如果路徑是一個掛載點則為真
- exists: 判斷路徑是否存在,如果路徑存在則為真
注意:某些版本之前可能需要加上“is_”前綴
9.9.5 判斷整除
- even: 判斷數值是否是偶數,偶數則為真
- odd: 判斷數值是否是奇數,奇數則為真
- divisibleby(num): 判斷是否可以整除指定的數值,如果除以指定的值以后余數為0,則返回真
9.5.6 版本號比較
version: 可以用於對比兩個版本號的大小,或者與指定的版本號進行對比,語法version('版本號','比較操作符')。2.5版本此test從version_compare 更名為version。
9.5.7 列表比較
- subset: 判斷一個list是不是另一個list的子集,是則為真
- siperset: 判斷一個list是不是另一個list的父集,是則為真
注:2.5版本之前是issubset和issuperset
9.5.8 字符串與數字判斷
- string: 判斷對象是否是一個字符串,是則為真
- number: 判斷對象是否是一個數字,是則為真
9.5.9 failed_when
先看個例子:
有些時候,我們需要通過返回的字符串來判斷是否failed。例如:
也就是說,我們只有在返回結果中出現字符串‘FAILED’,我們才認為我們的task 失敗了(因為command 命令即使執行成功,返回值才是我們要判斷失敗與否的關鍵)。
9.5.10 changed_when
與failed_when類似。示例:
在使用command /shell 模塊的時候ansible playbook 會按照自己的判斷來決定是否changed了。
有時候我們僅僅是ls 了一下, ansible-playbook 也會認為是changed了,可能這並不是我們想要的,這個時候我們就要用例子中方法來修改task的狀態了:
9.10 循環
9.10.1 標准循環
為了保持簡潔,重復的任務可以用以下簡寫的方式:
如果你在變量文件中或者 ‘vars’ 區域定義了一組YAML列表,你也可以這樣做:
with_items: "{{somelist}}"
以上寫法與下面是完全等同的:
使用 ‘with_items’ 用於迭代的條目類型不僅僅支持簡單的字符串列表。如果你有一個哈希列表,那么你可以用以下方式來引用子項:
注:如果同時使用 when 和 with items (或其它循環聲明), when聲明會為每個條目單獨執行。
9.10.2嵌套循環
循環也可以嵌套:
執行一下:
和以上介紹的with items一樣,你也可以使用預定義變量:
9.10.3 對哈希表使用循環
哈希表:用於存儲Key-Value鍵值對的集合。
使用with_dict 來循環哈希表中的元素:
9.10.4 對文件列表使用循環
with_fileglob 可以以非遞歸的方式來模式匹配單個目錄中的文件
注:當在role中對 with_fileglob 使用相對路徑時, Ansible會把路徑映射到`roles/<rolename>/files`目錄。
9.10.5 對並行數據集使用循環(不常見)
假設你通過某種方式加載了以下變量數據:
--- alpha: [ 'a', 'b', 'c', 'd' ] numbers: [ 1, 2, 3, 4 ]
如果你想得到’(a, 1)’和’(b, 2)’之類的集合.可以使用with_together:
不足的數據則為空:
注:這種使用方式不常見。
9.10.6 對子元素使用循環
假設你想對一組用戶做一些動作,比如創建這些用戶,並且允許它們使用一組SSH key來登錄。
如何實現? 先假設你有按以下方式定義的數據,可以通過”vars_files”或”group_vars/all”文件加載:
那么可以這樣實現:
根據mysql hosts以及預先給定的privs subkey列表,我們也可以在嵌套的subkey中迭代列表:
9.10.7 對整數序列使用循環
with_sequence 可以以升序數字順序生成一組序列。你可以指定起始值、終止值,以及一個可選的步長值。
指定參數時也可以使用key=value這種鍵值對的方式。如果采用這種方式,format是一個可打印的字符串。
字值可以被指定為10進制,16進制(0x3f8)或者八進制(0600)。負數則不受支持。請看以下示例:
9.10.8 隨機選擇
random_choice功能可以用來隨機獲取一些值。它並不是負載均衡器(已經有相關的模塊了)。它有時可以用作一個簡化版的負載均衡器,比如作為條件判斷:
提供的字符串中的其中一個會被隨機選中。
9.10.9 Do-Until循環
有時你想重試一個任務直到達到某個條件。比如:
上面的例子遞歸運行shell模塊,直到模塊結果中的stdout輸出中包含”all systems go”字符串,或者該任務按照10秒的延遲重試超過5次。retries和delay的默認值分別是3和5。
該任務返回最后一個任務返回的結果。單次重試的結果可以使用-vv選項來查看。被注冊的變量會有一個新的屬性attempts,值為該任務重試的次數。
9.10.10 查找第一個匹配的文件(不常見)
這其實不是一個循環,但和循環很相似,如果你想引用一個文件,而該文件是從一組文件中根據給定條件匹配出來的。這組文件中部分文件名由變量拼接而成。
針對該場景你可以這樣做:
該功能還有一個更完整的版本,可以配置搜索路徑.請看以下示例:
9.10.11 迭代程序的執行結果(不常見)
有時你想執行一個程序,而且按行循環該程序的輸出。Ansible提供了一個優雅的方式來實現這一點。但請記住,該功能始終在本地機器上執行,而不是遠程機器。
例如,find一堆文件出來,copy走。
如果你想遠程執行命令,那么以上方法則不行。但你可以這樣寫:
9.10.12 使用索引循環列表(不常見)
如果你想循環一個列表,同時得到一個數字索引來標明你當前處於列表什么位置,那么你可以這樣做:
9.10.13 循環配置文件(不常見)
ini插件可以使用正則表達式來獲取一組鍵值對。因此,我們可以遍歷該集合。以下是我們使用的ini文件:
以下是使用 with_ini 的例子:
以下是返回的值:
9.10.14 扁平化列表(不常見)
在罕見的情況下,你可能有幾組列表,列表中會嵌套列表。而你只是想迭代所有列表中的每個元素,比如有一個非常瘋狂的假定的數據結構:
你可以看到列表中的包到處都是。那么如果想安裝兩個列表中的所有包呢?
9.10.15 循環中使用注冊器
當對處於循環中的某個數據結構使用 register 來注冊變量時,結果包含一個 results 屬性,這是從模塊中得到的所有響應的一個列表。
以下是在 with_items 中使用 register 的示例:
返回的數據結構如下,與非循環結構中使用 register 的返回結果是不同的,非循環結構的返回結果類似下面:
而循環結構的返回結果如:
隨后的任務可以用以下方式來循環注冊變量,用來檢查結果值:
9.11 包含
在編程的時候,我們一般都會將重復性的代碼提取出來,作為一個邏輯單元,這個邏輯單元通常被稱為“函數”或者“方法”。如果需要修改這段邏輯,只需要修改函數本身即可。而且這樣還使得程序的可讀性更強。
Ansible中也有類似的功能,這種功能被稱為包含,通過包含,我們可以在一個playbook中包含另一個文件,以便實現我們想要的效果。
Ansible有兩種包含的操作模式:動態和靜態。Ansible 2.4引入了include和import的概念。
- 如果您使用import*包含Task(import_playbook,import_tasks等),它將是靜態的。
- 如果您使用include*包含Task(include_tasks,include_role等),它將是動態的。
使用include包含Task(用於task文件和Playbook級包括)仍然可用,但現在被認為已被棄用,建議使用 include_tasks和 import_tasks。
9.11.1 include_tasks和import_tasks之間的差異
區別一:
- include_tasks:是動態的,在運行時展開。即在執行play之前才會加載自己變量。when只應用一次, 被include的文件名可以使用變量。
- import_tasks:是靜態的,在加載時展開。即在playbooks解析階段將父task變量和子task變量全部讀取並加載。因為是加載時展開的,文件名的變量不能是動態設定的。 when在被import的文件里的每個task,都會重新檢查一次。
例:
b.yml
y.yml:
運行:
因為 mode被改變之后, include_tasks不會重新evaluate mode, import_tasks會根據變化后的mode值重新evaluate每個task的條件。
區別二:
- include_tasks方法調用的文件名稱可以加變量
- import_tasks方法調用的文件名稱不可以有變量
對於include_tasks,導入文件時可以指定變量:
當使用import_tasks方法時,執行報錯。ansible也給出了錯誤原因,當使用static include時,是不能使用變量的:
9.11.2 include_tasks和import_tasks的優缺點
使用include*語句的主要優點是循環。當循環與include*一起使用時,包含的任務或角色將為循環中的每個項目執行一次。
與import*語句相比,使用include*有一些限制:
- 僅存在於動態包含內的標簽不會顯示在-list-tags輸出中。
- 僅存在於動態包含內的任務不會顯示在-list-tasks輸出中。
- 您不能使用notify來觸發來自動態包含內部的處理程序名稱。
- 您不能使用--start-at-task開始執行動態包含內的任務。
與include*相比,使用import*也可能有一些限制:
- 如上所述,循環不能用於導入。
- 當使用目標文件或角色名稱的變量時,不能使用來自庫存源(主機/組變量等)的變量。
總而言之,沒有使用with的包含,就使用import,使用了with,那就用include。
9.11.3 import_playbook
如果想引入整個playbook,則需要使用include_playbook模塊來代替include。在ansible2.8版本之后,include功能就被刪除掉了。
要求:
- 包含一個帶有要執行的play列表的文件。
- 帶有play列表的文件必須被包含在頂層
- 不能在play中執行該操作。
例如:
main.yml
otherplays.yaml
otherplays.yaml中導入stuff.yaml,由於不是在頂層導入,而是在play中導入,所以執行會失敗。
9.11.4 include_vars
include_vars模塊可以包含JSON或YAML文件中的定義變量,覆蓋已定義的主機變量和playbook變量。如:
9.11.5 include_role 與 import_role
后續再講。
9.12 Roles
上述已經講過tasks和handlers,那么如何組織playbook才是最好的方式呢?
roles!
roles是基於一個已知的文件結構,去自動加載某些vars_file,tasks以及handlers。基於roles對內容進行分組,使得我們可以容易地與其他用戶分享roles。
一個項目的結構如下:
一個 playbook 如下:
這個 playbook 為一個角色x指定了如下的行為:
- 如果 roles/x/tasks/main.yml 存在, 其中列出的 tasks 將被添加到 play 中
- 如果 roles/x/handlers/main.yml 存在, 其中列出的 handlers 將被添加到 play 中
- 如果 roles/x/vars/main.yml 存在, 其中列出的 variables 將被添加到 play 中
- 如果 roles/x/meta/main.yml 存在, 其中列出的 “角色依賴” 將被添加到 roles 列表中 (1.3 and later)
- 所有 copy tasks 可以引用 roles/x/files/ 中的文件,不需要指明文件的路徑。
- 所有 script tasks 可以引用 roles/x/files/ 中的腳本,不需要指明文件的路徑。
- 所有 template tasks 可以引用 roles/x/templates/ 中的文件,不需要指明文件的路徑。
- 所有 include tasks 可以引用 roles/x/tasks/ 中的文件,不需要指明文件的路徑。
如果 roles 目錄下有文件不存在,這些文件將被忽略。比如 roles 目錄下面缺少了 vars/ 目錄,這也沒關系。
如果你在 playbook 中同時使用 roles 和 tasks,vars_files 或者 handlers,roles 將優先執行。如果想在roles前執行一些task,可以這樣:
而且,如果你願意,也可以使用參數化的 roles,這種方式通過添加變量來實現,比如:
當一些事情不需要頻繁去做時,你也可以為 roles 設置觸發條件,像這樣:
它的工作方式是:將條件子句應用到 role 中的每一個 task 上。
最后,你可能希望給 roles 分配指定的 tags。比如:
9.12.1 roles各目錄含義
- tasks目錄:角色需要執行的主任務文件放置在此目錄中,默認的主任務文件為main.yml,當調用角色時,默認會執行main.yml文件中的任務。也可以將其他需要執行的任務通過include的方式包含在tasks/main.yml文件中。
- handlers目錄:當角色需要調用handlers時,默認會在此目錄中的main.yml文件中查找對應的handler
- defaults目錄:角色會使用到的變量可以寫入到此目錄中的main.yml文件中,通常defaults/main.yml文件中的變量都用於設置默認值,以便在你沒有設置對應變量值時,變量有默認的值可以使用,定義在defaults/main.yml文件中的變量的優先級是最低的。
- vars目錄:角色會使用到的變量可以寫入到此目錄中的main.yml文件中。與defaults/main.yml的區別在於,defaults/main.yml文件中的變量的優先級是最低的,而vars/main.yml文件中的變量的優先級非常高,如果只是想提供一個默認的配置,可以定義在defaults/main.yml,如果想要確保別人在調用角色時,使用的值就是你指定的值,則可以將變量定義在vars/main.yml中,因為定義在vars/main.yml文件中的變量的優先級非常高,所以其值難以覆蓋。
- meta目錄:如果想要賦予這個角色一些元數據,則可以將元數據寫入到meta/main.yml文件中,這些元數據用於描述角色的相關屬性,比如作者信息、角色的主要作用等。也可以在meta/main.yml文件中定義這個角色依賴於哪些角色,或者改變角色的默認調用設定。
- templates目錄:角色相關的模板可以放置在此目錄中。當使用角色相關的模板時,如果沒有指定路徑,會默認從此目錄中查找對應名稱模板文件。
- files目錄:角色可能會用到的一些其他文件可以放置在此目錄中。
注:上述目錄並不全是必須的,如果你的角色中沒有用到對應這些目錄的模塊,那么對應的目錄就不需要包含。一般情況下,至少要有一個tasks目錄。
9.12.2 角色默認變量
角色默認變量允許你為 included roles 或者 dependent roles 設置默認變量。要創建默認變量,只需在 roles 目錄下添加 defaults/main.yml 文件。這些變量在所有可用變量中擁有最低優先級,可能被其他地方定義的變量(包括 inventory 中的變量)所覆蓋。
9.12.3 role查找
我們可以把單個role的目錄寫在與入口playbook同級的目錄下,也可以放在同級的roles目錄下,還可以通過/etc/ansible/ansible.cfg中的roles_path(默認為家目錄的.ansible/roles目錄)指定。
role查找優先級:同級roles目錄 > /etc/ansible/ansible.cfg中的roles_path(默認為家目錄的.ansible/roles目錄) > 同級目錄下
即使role目錄不處於上述目錄中的任何一個,也可以使用絕對路徑的方式,調用相應的角色:
這種寫法其實不算正規,標准語法應該這樣:
在roles關鍵字中使用role關鍵字指定角色對應的絕對路徑,可以直接調用角色。即使不使用絕對路徑,也可以使用同樣的語法指定角色名。如:
9.12.4 role變量傳遞
我們可以在調用role的時候傳遞對應的變量。如:
默認變量也可以定義在defaults/main.yml中,不過優先級是最低的。role使用的變量的優先級為:vars/main.yml > 調用role時傳遞的vars > defaults/main.yml。
還可以寫成:
另外,角色中的變量是全局可訪問的。例如:
在調用webserver這個角色時傳遞的變量testvar的值,是可以傳遞給web這個角色的。在兩個角色里面對這個變量進行debug,都可以得到這個值:
也可以為role設置觸發條件,如:
最后,還可以給role分配指定的tags。如:
9.12.5 重復調用
默認情況下,我們無法多次調用同一個角色。也就是說,如下的playbook只會調用一次webserver角色:
執行該playbook,可以發現,webserver中的debug模塊只輸出了一次:
如果想要多次調用同一個角色,有兩種方法。如下:
- 方法一:設置角色的allow_duplicates屬性,讓其支持重復調用
- 方法二:調用角色時,傳入的參數值不同
方法一需要為角色設置allow_duplicates屬性,該屬性需要設置在meta/main.yml中,如:
方法二,當調用角色時需要傳入參數,如果傳入參數的值不同,也可以連續調用多次。如:
9.12.6 role handler
如果想在角色中使用一些handlers以便進行觸發,則可以直接將對應的handlers任務寫入到handlers/main.yml文件中,示例:
9.12.7 角色依賴
角色依賴 使你可以自動地將其他 roles 拉取到現在使用的 role 中。角色依賴保存在 roles 目錄下的 meta/main.yml 文件中。這個文件應包含一列 roles 和 為之指定的參數。
示例:
“角色依賴” 可以通過絕對路徑指定,如同頂級角色的設置:
“角色依賴” 也可以通過源碼控制倉庫或者 tar 文件指定,使用逗號分隔:路徑、一個可選的版本(tag, commit, branch 等等)、一個可選友好角色名(嘗試從源碼倉庫名或者歸檔文件名中派生出角色名):
“角色依賴” 總是在 role (包含”角色依賴”的role)之前執行,並且是遞歸地執行。默認情況下,作為 “角色依賴” 被添加的 role 只能被添加一次,如果另一個 role 將一個相同的角色列為 “角色依賴” 的對象,它不會被重復執行。但這種默認的行為可被修改,通過添加 allow_duplicates: yes 到 meta/main.yml 文件中。
比如,一個 role 名為 ‘car’,它可以添加名為 ‘wheel’ 的 role 到它的 “角色依賴” 中:
wheel 角色的 meta/main.yml 文件包含如下內容:
最終的執行順序是這樣的:
tire(n=1)
brake(n=1)
wheel(n=1)
tire(n=2)
brake(n=2)
wheel(n=2)
...
car
9.12.8 在 Roles 中嵌入模塊
如果您編寫一個定制模塊,則可能希望將其作為角色的一部分進行分發。
在角色的tasks和handlers結構旁邊,添加一個名為‘library’的目錄,然后將定制模塊直接包含在其中。
在一個role中定義的模塊,可供其他role使用:
9.12.9 include_role與import_role
在后來版本(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(靜態)的區別,可以參考之前的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並沒有執行:
(End)