一、什麼是playbooks
playbooks是ansible的腳本、如同shell腳本一樣,它是控制遠程主機的一系列命令的集合,通過YAML語言編寫。執行一些簡單的任務,我們可以使用ad-hoc命令就可以解決,對於一些較複雜的任務,ad-hoc就不能勝任了,這時候playbooks就派上用場了,在playbooks中可以編排有序的執行過程,甚至可以在多組機器間來回有序的執行特定的步驟,並且可以同步或異步發起任務。
二、YAML語法
1、文件開始符
1 | --- |
2、數組
1 2 3 | - name - hosts - user |
3、字典
1 2 | name: restart apache service: name=httpd state=restarted |
字典與字典的嵌套:
1 2 3 | vars: http_port: 80 max_clients: 200 |
字典與數組的嵌套:
1 2 3 4 5 6 7 8 9 | tasks: - name: ensure apache is at the latest version yum: pkg=httpd state=latest - name: write the apache config file template: src= /srv/httpd .j2 dest= /etc/httpd .conf notify: - restart apache - name: ensure apache is running service: name=httpd state=started |
此外,Ansible 使用 "{{ var }}"來引用變量.,如果一個值以 "{" 開頭, YAML 將認爲它是一個字典, 所以我們必須引用它, 像這樣:foo: "{{ variable }}"
三、playbooks的基本用法
最基本的playbook分爲四部分:
定義主機和用戶
1 2 | hosts users |
定義 playbook 執行需要的變量
1 | variable |
定義任務
1 | tasks |
定義響應事件
1 | handlers |
簡單示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | --- - name: Install apache hosts: webservers user: root gather_facts: false vars: http_port: 80 max_clients: 200 tasks: - name: ensure apache is at the latest version yum: pkg=httpd state=latest - name: write the apache config file template: src= /srv/httpd .j2 dest= /etc/httpd .conf notify: - restart apache - name: ensure apache is running service: name=httpd state=started handlers: - name: restart apache service: name=httpd state=restarted |
說明:
name參數對此playbook實現的功能的概述,執行時會輸出name變量值。
hosts參數指定了在哪些主機上執行playbook
user參數指定在遠程主機上使用什麼用戶執行任務
gather_facts參數指定了下面任務執行前,是否先執行setup模塊獲取遠程主機相關信息,這些信息在task中可以作爲變量使用
vars參數指定了變量
task參數指定了任務,這裏有3個任務。name參數是對具體任務的描述,在執行過程中會輸出
handlers參數指定一個響應事件,當template: src=/srv/httpd.j2 dest=/etc/httpd.conf這個任務執行狀態是changed時纔會觸發。
1、主機和用戶
key | 含 義 |
hosts | 爲主機的IP,或者主機組名,或者關鍵字all |
user | 在遠程以哪個用戶身份執行。 |
become | 切換成其它用戶身份執行,值爲yes或者no |
become_method | 與became一起用,指可以爲‘sudo’/’su’/’pbrun’/’pfexec’/’doas’ |
become_user | 與bacome一起用,可以是root或者其它用戶名 |
一般用法:
1 2 3 | --- - hosts: webserver, [all] user: root |
還可以在每個 task 中,定義遠程執行用戶
1 2 3 4 5 6 7 | --- - hosts: webserver user: root tasks: - name: test connection ping : remote_user: root |
也支持 sudo 方法,在 task中同樣支持,在sudo需要密碼時,可以加上選項 –ask-sudo-pass
1 2 3 4 5 6 7 8 | --- - hosts: all user: test sudo : yes task: - service: name=nginx state=started sudo : yes sudo_user: root |
2、任務列表
tasks 是從上到下順序執行,如果中間發生錯誤,整個 playbook 便會中斷。
每一個 task 是對module的一次調用,通常會帶有特定參數,參數可以使用變量。
每一個 task 有一個 name 屬性,name 值會在命令行中輸出,以提示用戶,如果沒有定義,aciton 的值會作爲輸出信息來標記task。
語法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | tasks: - name: make sure apache is running service: name=httpd state=running // 如果參數過長,可以使用空格或者縮進分隔爲多行 tasks: - name: copy ansible inventory file to client copy: src= /etc/ansible/hosts dest= /etc/ansible/hosts owner=root group=root mode=0644 // 或者使用 yaml 的字典作爲參數 tasks: - name: copy ansible inventory file to client copy: src: /etc/ansible/hosts dest: /etc/ansible/hosts owner: root group: root mode: 0644 // 大部分的模塊都是使用 `key-value` 這種格式的,其中有兩個比較特殊, command 和 shell 模塊。 tasks: - name: disable selinux command : /sbin/setenforce 0 tasks: - name: run this command and ignore the result shell: /usr/bin/command || /bin/true tasks: - name: run some command and ignore the reslut shell: /usr/bin/somecommadn ignore_error: True |
執行狀態:
task中每個action會調用一個module,在module中會去檢查當前系統狀態是否需要重新執行。
如果本次執行了,那麼action會得到返回值changed
如果不需要執行,那麼action得到返回值ok
3、響應事件
每個主流的編程語言都會有event機制,那麼handler就是playbook的event。
Handlers裏面的每一個handler,也是對module的一次調用。而handlers與tasks不同,tasks會默認的按定義順序執行每一個task,handlers則不會,它需要在tasks中被調用,纔有可能被執行。Tasks中的任務都是有狀態的,changed或者ok。 在Ansible中,只在task的執行狀態爲changed的時候,纔會執行該task調用的handler,這也是handler與普通的event機制不同的地方。
什麼情況下使用handlers呢?
如果你在tasks中修改了apache的配置文件。需要重起apache。此外還安裝了apache的插件。那麼還需要重起apache。像這樣的應該場景中,重啓apache就可以設計成一個handler。
特性:
一個handler最多隻執行一次
在所有的任務裏表執行之後執行,如果有多個task notify同一個handler,那麼只執行一次。
在下面的例子裏apache只執行一次
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | --- - hosts: lb remote_user: root vars: random_number1: "{{ 10000 | random }}" random_number2: "{{ 10000000000 | random }}" tasks: - name: Copy the /etc/hosts to /tmp/hosts .{{ random_number1 }} copy: src= /etc/hosts dest= /tmp/hosts .{{ random_number1 }} notify: - call in every action - name: Copy the /etc/hosts to /tmp/hosts .{{ random_number2 }} copy: src= /etc/hosts dest= /tmp/hosts .{{ random_number2 }} notify: - call in every action handlers: - name: call in every action debug: msg= "call in every action, but execute only one time" |
action是Changed ,纔會執行handler
只有當TASKS種的action的執行狀態是changed時,纔會觸發notify handler的執行。
下面的腳本執行兩次,執行結果是不同的:
第一次執行是,tasks的狀態都是changed,會觸發兩個handler
第二次執行是,
第一個task的狀態是OK,那麼不會觸發handlers"call by /tmp/hosts",
第二個task的狀態是changed,觸發了handler"call by /tmp/hosts.random_number"
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | // 示例代碼 --- - hosts: lb remote_user: root vars: random_number: "{{ 10000 | random }}" tasks: - name: Copy the /etc/hosts to /tmp/hosts copy: src= /etc/hosts dest= /tmp/hosts notify: - call by /tmp/hosts - name: Copy the /etc/hosts to /tmp/hosts .{{ random_number }} copy: src= /etc/hosts dest= /tmp/hosts .{{ random_number }} notify: - call by /tmp/hosts .random_number handlers: - name: call by /tmp/hosts debug: msg= "call first time" - name: call by /tmp/hosts .random_number debug: msg= "call by /tmp/hosts.random_number" |
按Handler的定義順序執行
andlers是按照在handlers中定義個順序執行的,而不是安裝notify的順序執行的。
下面的例子定義的順序是1>2>3,notify的順序是3>2>1,實際執行順序:1>2>3
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | --- - hosts: lb remote_user: root gather_facts: no vars: random_number1: "{{ 10000 | random }}" random_number2: "{{ 10000000000 | random }}" tasks: - name: Copy the /etc/hosts to /tmp/hosts .{{ random_number1 }} copy: src= /etc/hosts dest= /tmp/hosts .{{ random_number1 }} notify: - define the 3nd handler - name: Copy the /etc/hosts to /tmp/hosts .{{ random_number2 }} copy: src= /etc/hosts dest= /tmp/hosts .{{ random_number2 }} notify: - define the 2nd handler - define the 1nd handler handlers: - name: define the 1nd handler debug: msg= "define the 1nd handler" - name: define the 2nd handler debug: msg= "define the 2nd handler" - name: define the 3nd handler debug: msg= "define the 3nd handler" |
4、變量
playbook中常用變量的幾種情況:
用戶自定義的變量
用戶可以在Playbook中,通過vars關鍵字自定義變量,使用時用{{ }}引用以來即可。
示例:
1 2 3 4 5 6 7 8 | --- - hosts: web vars: http_port: 80 remote_user: root tasks: - name: insert firewalld rule for httpd firewalld: port={{ http_port }} /tcp permanent= true state=enabled immediate= yes |
把變量放在單獨的文件中
當變量比較多的時候,或者變量需要在多個playbook中重用的時候,可以把變量放到一個單獨的文件中。通過關鍵字var_files把文件中定義的變量引入playbook中,使用變量的方法和在本文件中定義的變量相同。
1 2 3 4 5 6 7 8 9 10 | - hosts: web remote_user: root vars_files: - vars /server_vars .yml tasks: - name: insert firewalld rule for httpd firewalld: port={{ http_port }} /tcp permanent= true state=enabled immediate= yes #cat vars/server_vars.yml http_port: 80 |
定義複雜的變量
當變量的值不是簡單的字符串或者數字,而是一個字典,語法如下
1 2 3 | foo: field1: one field2: two |
訪問複雜變量中的子屬性,可以利用中括號或者點號:
1 2 3 | foo[ 'field1' ] 或 foo.field1 |
系統變量(facts)
ansible會通過module setup來收集主機的系統信息,這些收集到的系統信息叫做facts,這些facts信息可以直接以變量的形式使用。
有哪些facts變量可以引用呢?在命令行上通過調用setup module命令可以查看:
1 | $ ansible all -m setup -u root |
系統變量在playbook中可以直接使用:
1 2 3 4 5 6 7 8 9 10 11 12 | --- - hosts: all user: root tasks: - name: echo system shell: echo {{ ansible_os_family }} - name install ntp on Debian linux apt: name=git state=installed when: ansible_os_family == "Debian" - name install ntp on redhat linux yum: name=git state=present when: ansible_os_family == "RedHat" |
對於複雜的、多層級的facts變量,可以通過下面的兩種方式的任意一種訪問複雜的變量中的子屬性:
中括號:
1 | {{ ansible_ens3[ "ipv4" ][ "address" ] }} |
點號:
1 | {{ ansible_ens3.ipv4.address }} |
關係facts變量,一旦關閉之後就不用調用了。關閉方法:
1 2 | - hosts: webserver gather_facts: no |
註冊變量
把task的執行結果也可以作爲一個變量值。這個時候就需要用到“註冊變量”,將執行結果註冊到一個變量中,待後面的action使用。
1 2 3 4 5 6 7 8 9 | --- - hosts: web tasks: - shell: ls register: result ignore_errors: True - shell: echo "{{ result.stdout }}" when: result.rc == 5 - debug: msg= "{{ result.stdout }}" |
註冊變量經常和debug module一起使用,這樣可以得到更多action的輸出信息,幫助用戶調試。
命令行中傳遞的變量
爲了使Playbook更靈活、通用性更強,允許用戶在執行的時候傳入變量的值,這個時候就需要用到“額外變量”。
定義命令行變量
在test.yml文件裏,hosts和user都定義爲變量,需要從命令行傳遞變量值。
1 2 3 4 5 | --- - hosts: '{{ hosts }}' remote_user: '{{ user }}' tasks: ... |
在命令行裏面傳值得的方法:
1 | ansible-playbook testyml --extra-vars "hosts=web user=root" |
還可以用json格式傳遞參數:
1 | ansible-playbook test .yml --extra-vars "{'hosts':'vm-rhel7-1', 'user':'root'}" |
還可以將參數放在文件裏面:
1 | ansible-playbook test .yml --extra-vars "@vars.json" |
5、如何執行playbook
語法:
1 | $ ansible-playbook deploy.yml |
查看輸出的細節
1 | $ ansible-playbook playbook.yml --verbose |
查看該腳本影響哪些hosts
1 | $ ansible-playbook playbook.yml --list-hosts |
並行執行腳本
1 | $ ansible-playbook playbook.yml -f 10 |
四、playbooks的高級用法
1、邏輯控制
when: 條件判斷語句,類似於變成語言中的if
主機爲Debian Linux立刻關機:
1 2 3 4 | tasks: - name: "shutdown Debian flavored systems" command : /sbin/shutdown -t now when: ansible_os_family == "Debian" |
根據action的執行結果,來決定接下來執行的action
1 2 3 4 5 6 7 8 9 10 | tasks: - command : /bin/false register: result ignore_errors: True - command : /bin/something when: result|failed - command : /bin/something_else when: result|success - command : /bin/still/something_else when: result|skipped |
遠程中的系統變量facts變量作爲when的條件,用“|int”還可以轉換返回值的類型:
1 2 3 4 5 | --- - hosts: web tasks: - debug: msg= "only on Red Hat 7, derivatives, and later" when: ansible_os_family == "RedHat" and ansible_lsb.major_release|int >= 6 |
條件表達式
基本:
1 2 3 | tasks: - shell: echo "This certainly is epic!" when: epic |
否定:
1 2 3 | tasks: - shell: echo "This certainly isn't epic!" when: not epic |
變量定義:
1 2 3 4 5 | tasks: - shell: echo "I've got '{{ foo }}' and am not afraid to use it!" when: foo is defined - fail: msg= "Bailing out. this play requires 'bar'" when: bar is not defined |
數值表達:
1 2 3 4 | tasks: - command : echo {{ item }} with_items: [ 0, 2, 4, 6, 8, 10 ] when: item > 5 |
與Include一起用:
1 2 | - include: tasks /sometasks .yml when: "'reticulating splines' in output" |
與Role一起用:
1 2 3 | - hosts: webservers roles: - { role: debian_stock_config, when: ansible_os_family == 'Debian' } |
loop: 循環語句,類似於編程語言的中的while
標準循環
爲了保持簡潔,重複的任務可以用以下簡寫的方式:
1 2 3 4 | - name: add several users user: name={{ item }} state=present groups =wheel with_items: - testuser1 |
如果你在變量文件中或者 'vars' 區域定義了一組YAML列表,你也可以這樣做:
1 2 3 4 5 6 | vars: somelist: [ "testuser1" , "testuser2" ] tasks: -name: add several user user: name={{ item }} state=present groups =wheel with_items: "{{somelist}}" |
使用 'with_items' 用於迭代的條目類型不僅僅支持簡單的字符串列表.如果你有一個哈希列表,那麼你可以用以下方式來引用子項:
1 2 3 4 5 | - name: add several users user: name={{ item.name }} state=present groups ={{ item. groups }} with_items: - { name: 'testuser1' , groups : 'wheel' } - { name: 'testuser2' , groups : 'root' } |
注意:如果同時使用 when 和 with_items (或其它循環聲明),when聲明會爲每個條目單獨執行。
嵌套循環:
1 2 3 4 5 6 7 8 9 10 11 | - name: give users access to multiple databases mysql_user: name={{ item[0] }} priv={{ item[1] }}.*:ALL append_privs= yes password=foo with_nested: - [ 'alice' , 'bob' ] - [ 'clientdb' , 'employeedb' , 'providerd' ] 或者 - name: give users access to multiple databases mysql_user: name={{ item.0 }} priv={{ item.1 }}.*:ALL append_privs= yes password=foo with_nested: - [ 'alice' , 'bob' ] - [ 'clientdb' , 'employeedb' , 'providerd' ] |
對字典使用循環:
1 2 3 4 5 6 7 8 9 10 11 12 13 | --- vars: users : alice: name: Alice Appleworth telephone: 123-456-7890 bob: name: Bob Bananarama telephone: 987-654-3210 tasks: - name: Print phone records debug: msg= "User {{ item.key }} is {{ item.value.name }} ({{ item.value.telephone }})" with_dict: "{{users}}" |
對文件列表使用循環
with_fileglob 可以以非遞歸的方式來模式匹配單個目錄中的文件.如下面所示:
1 2 3 4 5 6 7 | tasks: # first ensure our target directory exists - file : dest= /etc/fooapp state=directory # copy each file over that matches the given pattern - copy: src={{ item }} dest= /etc/fooapp/ owner=root mode=600 with_fileglob: - /playbooks/files/fooapp/ * |
block: 把幾個tasks組成一塊代碼,便於針對一組操作的異常處理等操作。
多個action組裝成塊,可以根據不同條件執行一段語句 :
1 2 3 4 5 6 7 8 9 10 11 | tasks: - block: - yum: name={{ item }} state=installed with_items: - httpd - memcached - template: src=templates /src .j2 dest= /etc/foo .conf - service: name=bar state=started enabled=True when: ansible_distribution == 'CentOS' become: true become_user: root |
組裝成塊處理異常更方便:
1 2 3 4 5 6 7 8 9 10 11 | tasks: - block: - debug: msg= 'i execute normally' - command : /bin/false - debug: msg= 'i never execute, cause ERROR!' rescue: - debug: msg= 'I caught an error' - command : /bin/false - debug: msg= 'I also never execute :-(' always: - debug: msg= "this always executes" |
2、重用playbook
Playbook支持兩種重用機制,一種是重用靜態Playbook腳本,另外一種是類似於編程語言中函數的機制。
include語句 - 重用靜態的Playbook腳本,使用起來簡單、直接。
Include語句的功能,基本的代碼重用機制。主要重用tasks。同時Include可將tasks分割成多個文件,避免Playbook過於臃腫,使用戶更關注於整體的架構,而不是實現的細節上。
普通用法
像其它語言的Include語句一樣,直接Include:
1 2 3 4 5 6 7 8 | --- # possibly saved as tasks/firewall_httpd_default.yml - name: insert firewalld rule for httpd firewalld: port=80 /tcp permanent= true state=enabled immediate= yes main.yml文件中調用include的方法: tasks: - include: tasks /firewall_httpd_default .yml |
高級用法-使用參數
include文件中還可以定義參數
被include的文件tasks/firewall_httpd_default.yml中,使用{{ port }}定義了一個名字爲port的參數。
1 2 3 | --- - name: insert firewalld rule for httpd firewalld: port={{ port }} /tcp permanent= true state=enabled immediate= yes |
傳參數的各種方法
在執行的playbook傳參數,可以加在行尾,使用空格分隔:
1 2 3 4 | tasks: - include: tasks /firewall .yml port=80 - include: tasks /firewall .yml port=3260 - include: tasks /firewall .yml port=423 |
還可以使用yml的字典傳參數:
1 2 3 4 5 6 7 | tasks: - include: wordpress.yml vars: wp_user: timmy ssh_keys: - keys /one .txt - keys /two .txt |
還可以把一條task簡寫成成一個類JSON的形式傳參數:
1 | - { include: wordpress.yml, wp_user: timmy, ssh_keys: [ 'keys/one.txt' , 'keys/two.txt' ] } |
當然在playbook中已經定義了的參數,就不需要再顯示傳入值了,可以直接寫成下面的:
1 2 3 4 5 6 7 | --- - hosts: lb vars: port: 3206 remote_user: root tasks: - include: tasks /firewall .yml |
role語言 - Playbook的"函數機制",使用方法稍複雜、功能強大。是Playbook腳本的共享平臺ansible galaxy主要的分享方式
Role是比include更強大靈活的代碼重用和分享機制。Include類似於編程語言中的include,是重用單個文件的,功能有限。
而Role類似於編程語言中的“Package”,可以重用一組文件形成完整的功能。例如安裝和配置apache,需要tasks實現安裝包和拷貝模版等,httpd.conf和index.html的模版文件,和handler文件實現重起功能。這些文件都可以放在一個role裏面,供不同的playbook文件重用。
Ansible非常提倡在playbook中使用role,並且提供了一個分享role的平臺Ansible Galaxy, https://galaxy.ansible.com/, 在galaxy上可以找到別人寫好的role。
在ansible中,通過遵循特定的目錄結構,就可以實現對role的定義:
下面的目錄結構定義了一個role:名字爲myrole。在site.yml,調用了這個role。
role的目錄結構:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | site.yml roles/ ├── myrole ├── tasks │ └── main.yml ├── handlers │ └── main.yml ├── defaults │ └── main.yml ├── vars │ └── main.yml ├── files ├── templates ├── README.md ├── meta │ └── main.yml └── tests ├── inventory └── test .yml |
site.yml中調用role
1 2 3 4 | --- - hosts: webservers roles: - myrole |
ansible並不要求role包含上述所有的目錄及文件,根據role的功能需要加入對應的目錄和文件。下面是每個目錄和文件的功能。
如果 roles/x/tasks/main.yml 存在, 其中列出的 tasks 將被添加到 play 中,所以這個文件也可以視作role的入口文件,想看role做了什麼操作,可以從此文件看起。
如果 roles/x/handlers/main.yml 存在, 其中列出的 handlers 將被添加到 play 中
如果 roles/x/vars/main.yml 存在, 其中列出的 variables 將被添加到 play 中
如果 roles/x/meta/main.yml 存在, 其中列出的 “角色依賴” 將被添加到 roles 列表中
roles/x/tasks/main.yml中所有tasks,可以引用 roles/x/{files,templates,tasks}中的文件,不需要指明文件的路徑。
在寫role的時候,一般都要包含role入口文件roles/x/tasks/main.yml,其它的文件和目錄,可以根據需求選擇加入。
參數在role中是如何定義的呢
定義一個帶參數的role,名字是myrole,那麼目錄結構爲:
1 2 3 4 5 | main.yml roles role_with_var tasks main.yml |
在roles/myrole/tasks/main.yml中,使用{{ }}定義的變量就可以了
1 2 3 | --- - name: use param debug: msg= "{{ param }}" |
使用帶參數的role
那麼在main.yml就可以用如下的方法使用myrole
1 2 3 4 5 | --- - hosts: webservers roles: - { role: myrole, param: 'Call some_role for the 1st time' } - { role: myrole, param: 'Call some_role for the 2nd time' } |
或者寫成YAML字典格式:
1 2 3 4 5 6 7 | --- - hosts: webservers roles: - role: myrole param: 'Call some_role for the 1st time' - role: myrole param: 'Call some_role for the 2nd time' |
role指定默認的參數
指定默認參數後,如果在調用時傳參數了,那麼就使用傳入的參數值.如果調用的時候沒有傳參數,那麼就使用默認的參數值.
指定默認參數很簡單,以上面的role_with_var爲例
1 2 3 4 5 6 7 | main.yml roles: myrole tasks main.yml defaults main.yml |
在roles/myrole/defaults/main.yml中,使用yml的字典定義語法定義param的值,如下:
param: "I am the default value"
這樣在main.yml中,下面兩種調用方法都可以
1 2 3 4 5 | --- - hosts: webservers roles: - role_with_var - { role: role_with_var, param: 'I am the value from external' } |
role與條件語句when一起執行,下面的例子中,my_role只有在RedHat系列的server上才執行。
1 2 3 4 5 6 7 8 9 10 11 | --- - hosts: webservers roles: - { role: my_role, when: "ansible_os_family == 'RedHat'" } 同樣也可以寫成YAML字典格式 --- - hosts: webservers roles: - role: my_role when: "ansible_os_family == 'RedHat'" roles和tasks的執行順序 |
如果一個playbook同時出現role和tasks,他們的調用順序如下:
pre_tasks > role > tasks > post_tasks
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | --- - hosts: lb user: root pre_tasks: - name: pre shell: echo 'hello' roles: - { role: some_role } tasks: - name: task shell: echo 'still busy' post_tasks: - name: post shell: echo 'goodbye' 執行的結果爲: PLAY [lb] ********************************************************************** TASK [setup] ******************************************************************* ok: [rhel7u3] TASK [pre] ********************************************************************* changed: [rhel7u3] TASK [some_role : some role] *************************************************** ok: [rhel7u3] => { "msg" : "Im some role" } TASK [task] ******************************************************************** changed: [rhel7u3] TASK [post] ******************************************************************** changed: [rhel7u3] PLAY RECAP ********************************************************************* rhel7u3 : ok=5 changed=3 unreachable=0 failed=0 |
3、tags的用法
如果playbook文件比較大,在執行的時候只是想執行部分功能,這個時候沒有有解決方案呢?Playbook提供了tags便籤可以實現部分運行。
tags的基本用法
例如,文件example.yml如何所示,標記了兩個tag:packages和configuration
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | tasks: - yum: name={{ item }} state=installed with_items: - httpd tags: - packages - name: copy httpd.conf template: src=templates /httpd .conf.j2 dest= /etc/httpd/conf/httpd .conf tags: - configuration - name: copy index.html template: src=templates /index .html.j2 dest= /var/www/html/index .html tags: - configuration |
那麼我們在執行的時候,如果不加任何tag參數,那麼會執行所有的tasks
1 | $ ansible-playbook example.yml |
指定執行安裝部分的tasks,則可以利用關鍵字tags
1 | $ ansible-playbook example.yml --tags "packages" |
指定不執行packages部分的task,則可以利用關鍵字skip-tags
1 | $ ansible-playbook example.yml --skip-tags "configuration" |
特殊的Tags:“always”
tags的名字是用戶自定義的,但是如果你把tags的名字定義爲“always”,那麼就有點特別了。只要在執行playbook時,沒有明確指定不執行always tag,那麼它就會被執行。
在下面的例子中,即使你只指定執行packages,那麼always也會被執行。
1 2 3 4 5 6 7 8 9 10 11 12 | tasks: - debug: msg= "Always print this debug message" tags: - always - yum: name= state=installed with_items: - httpd tags: - packages - template: src=templates /httpd .conf.j2 dest= /etc/httpd/conf/httpd .conf tags: - configuration |
指定運行packages時,還是會執行always tag對應的tasks
1 2 3 4 5 6 7 8 9 10 11 | $ ansible-playbook tags_always.yml --tags "packages" “tagged”,“untagged”和“all” tasks: - debug: msg= "I am not tagged" tags: - tag1 - debug: msg= "I am not tagged" 分別指定--tags爲“tagged”,“untagged”和“all”試下效果吧: $ ansible-playbook tags_tagged_untagged_all.yml --tags tagged $ ansible-playbook tags_tagged_untagged_all.yml --tags untagged $ ansible-playbook tags_tagged_untagged_all.yml --tags all |
在include中和role中使用tags
include語句指定執行的tags的語法:
1 2 | - include: foo.yml tags: [web,foo] |
調用role中的tags的語法爲:
1 2 | roles: - { role: webserver, port: 5000, tags: [ 'web' , 'foo' ] } |
4、playbook文件加密
ansible-vault命令可以對配置文件進行基於密碼的加密,防止敏感信息泄漏。
加密已存在文件
1 | $ ansible-vault encrypt site.yml |
加密並創建文件
1 | $ ansible-vault create filename |
執行加密後的playbook
1 | $ ansible-playbook site.yml --ask-vault-pass |
解密
1 | $ ansible-vault decrypt site.yml |
五、編譯安裝nginx的playbook的實例
playbooks目錄結構:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | $ tree playbooks playbooks ├── group_vars ├── roles │ └── nginx │ ├── files │ │ ├── nginx-1.8.0. tar .gz │ │ └── pcre-8.33. tar .gz │ ├── handlers │ │ └── main.yml │ ├── tasks │ │ └── main.yml │ └── templates │ └── default.conf └── site.yml |
yml文件內內容如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | $ cat playbooks /site .yml --- - name: Install Nginx hosts: test user: admin roles: - nginx $ cat playbooks /roles/nginx/tasks/main .yml --- - name: Copy nginx software copy: src=nginx-1.8.0. tar .gz dest= /app/admin/soft/nginx-1 .8.0. tar .gz - name: Copy pcre software copy: src=pcre-8.33. tar .gz dest= /app/admin/soft/pcre-8 .33. tar .gz - name: Install Pcre shell: cd /app/admin/soft ; tar zxf pcre-8.33. tar .gz; cd pcre-8.33;. /configure ; make ; make install sudo : yes - name: Install Nginx shell: cd /app/admin/soft ; tar zxf nginx-1.8.0. tar .gz; cd nginx-1.8.0;. /configure --user=admin --group=app --prefix= /app/admin/nginx --with-http_stub_status_module --with-http_ssl_module; make ; make install - name: Copy nginx configuration template: src=default.conf dest= /app/admin/nginx/conf/nginx .conf notify: restart nginx [admin@wts-vm-01 ~]$ cat playbooks /roles/nginx/handlers/main .yml --- - name: restart nginx shell: /app/admin/nginx/sbin/nginx sudo : yes |
六、其它
官方例子
Ansible官方提供了一些比較常用的、經過測試的Playbook例子:
https://github.com/ansible/ansible-examples
Playbook分享平臺:
https://galaxy.ansible.com/