一、playbook簡介
1.1、playbook基礎介紹
playbook 是 ansible 用於配置,部署,和管理被控節點的劇本。
通過 playbook 的詳細描述,執行其中的一系列 tasks ,可以讓遠端主機達到預期的狀態。playbook 就像 Ansible 控制器給被控節點列出的的一系列 to-do-list ,而被控節點必須要完成
play: 定義的是主機的角色
task: 定義的是具體執行的任務
playbook: 由一個或多個play組成,一個play可以包含多個task任務
1.2、playbook優勢
1)功能比ad-hoc更全
2)能很好的控制先后執行順序, 以及依賴關系
3)語法展現更加的直觀
4)ad-hoc
無法持久使用,playbook
可以持久使用
1.3、playbook語法
采用的語法格式是YAML(Yet Another Markup Language)。YAML語法能夠簡單的表示散列表,字典等數據結構
1.3.1、yaml語法格式
縮進: YAML使用一個固定的縮進風格表示層級結構,每個縮進由兩個空格組成, 不能使用tabs;
冒號: 以冒號結尾的除外,其他所有冒號后面所有必須有空格;
短橫線: 表示列表項,使用一個短橫杠加一個空格。多個項使用同樣的縮進級別作為同一列表;
Ansible-playbook采用YAML語法編寫。連續的項目(即列表)用 -
減號來表示,key/value(字典)用冒號:
分隔。
1)列表:每一個列表成員前面都要有一個短橫線和一個空格
fruits: - Apple - Orange - Strawberry - Mango 或者: fruits: ['Apple', 'Orange', 'Strawberry', 'Mango']
2)字典:每一個成員由鍵值對組成,注意冒號后面要有空格
martin: name: Martin D'vloper job: Developer skill: Elite 或者 martin: {name: Martin D'vloper, job: Developer, skill: Elite}
3)列表與字典混合使用
- martin: name: Martin D'vloper job: Developer skills: - python - perl - pascal - tabitha: name: Tabitha Bitumen job: Developer skills: - lisp - fortran - erlang
1.3.2、playbook語法特性
1)以 --- (三個減號)開始,必須頂行寫;
2)次行開始寫Playbook的內容,但是一般要求寫明該playbook的功能;
3)嚴格縮進,並且不能用Tab鍵縮進;
4)縮進級別必須是一致的,同樣的縮進代表同樣的級別,程序判別配置的級別是通過縮進結合換行來實現的;
5)K/V的值可同行寫,也可換行寫。同行使用 :分隔,換行寫需要以 - 分隔;
1.4、playbook基礎組件
Hosts:運行執行任務(task)的目標主機
remote_user:在遠程主機上執行任務的用戶
tasks:任務列表
handlers:任務,與tasks不同的是只有在接受到通知時才會被觸發
templates:使用模板語言的文本文件,使用jinja2語法。
variables:變量,變量替換{{ variable_name }}
1.5、簡單示例
[root@localhost ~]# cat httpd.yaml --- - hosts: control-node #將要執行任務的主機,已經在hosts文件中定義好了,可是單個主機或主機組 remote_user: root #在目標主機上執行任務時的用戶身份 vars: - pkg: httpd tasks: - name: "install httpd package." yum: name={{ pkg }} state=installed - name: "copy httpd configure file to remote host." copy: src=/root/conf/httpd.conf dest=/etc/httpd/conf/httpd.conf notify: restart httpd #當這個任務執行狀態發生改變時,觸發handlers執行. - name: "boot httpd service." service: name=httpd state=started handlers: #handlers與tasks是同一級別 - name: restart httpd service: name=httpd state=restarted
1.6、playbook命令及調用方式
用法:ansible-playbook <filename.yml> ... [options]
<filename.yml>: yaml格式的playbook文件路徑,必須指明
[options]: 選項
Options: --ask-vault-pass #ask for vault password #加密playbook文件時提示輸入密碼 -C, --check #don't make any changes; instead, try to predict some of the changes that may occur #模擬執行,不會真正在機器上執行(查看執行會產生什么變化)。即並不在遠程主機上執行,只是測試。 -D, --diff #when changing (small) files and templates, show the differences in those files; works great with --check #當更新的文件數及內容較少時,該選項可顯示這些文件不同的地方,該選項結合-C用會有較好的效果 -e EXTRA_VARS, --extra-vars=EXTRA_VARS #set additional variables as key=value or YAML/JSON #在Playbook中引入外部參數變量 --flush-cache #clear the fact cache #清理fact緩存,將fact清除到的遠程主機緩存 --force-handlers #run handlers even if a task fails #強制運行handlers的任務,即使在任務失敗的情況下 -f FORKS, --forks=FORKS #specify number of parallel processes to use(default=5) #並行任務數。FORKS被指定為一個整數,默認是5 -h, --help #show this help message and exit #打開幫助文檔API -i INVENTORY, --inventory-file=INVENTORY #specify inventory host path (default=/etc/ansible/hosts) or comma separated host list. #指定要讀取的Inventory清單文件 -l SUBSET, --limit=SUBSET #further limit selected hosts to an additional pattern #限定執行的主機范圍 --list-hosts #outputs a list of matching hosts; does not execute anything else #列出執行匹配到的主機,但並不會執行任何動作。 --list-tags #list all available tags #列出所有可用的tags --list-tasks #list all tasks that would be executed #列出所有即將被執行的任務 -M MODULE_PATH, --module-path=MODULE_PATH #specify path(s) to module library (default=None) #要執行的模塊的路徑 --new-vault-password-file=NEW_VAULT_PASSWORD_FILE #new vault password file for rekey # --output=OUTPUT_FILE #output file name for encrypt or decrypt; use - for stdout # --skip-tags=SKIP_TAGS #only run plays and tasks whose tags do not match these values #跳過指定的tags任務 --start-at-task=START_AT_TASK #start the playbook at the task matching this name #從第幾條任務(START_AT_TASK)開始執行 --step #one-step-at-a-time: confirm each task before running #逐步執行Playbook定義的任務,並經人工確認后繼續執行下一步任務 --syntax-check #perform a syntax check on the playbook, but do not execute it #檢查Playbook中的語法書寫,並不實際執行 -t TAGS, --tags=TAGS #only run plays and tasks tagged with these values #指定執行該tags的任務 --vault-password-file=VAULT_PASSWORD_FILE #vault password file # -v, --verbose #verbose mode (-vvv for more, -vvvv to enable connection debugging) #執行詳細輸出 --version #show program's version number and exit #顯示版本 ############Connection Options,即下面時連接權限############ control as whom and how to connect to hosts -k, --ask-pass #ask for connection password # --private-key=PRIVATE_KEY_FILE, --key-file=PRIVATE_KEY_FILE #use this file to authenticate the connection # -u REMOTE_USER, --user=REMOTE_USER #connect as this user (default=None) #指定遠程主機以USERNAME運行命令 -c CONNECTION, --connection=CONNECTION #connection type to use (default=smart) #指定連接方式,可用選項paramiko (SSH)、ssh、local,local方式常用於crontab和kickstarts -T TIMEOUT, --timeout=TIMEOUT #override the connection timeout in seconds(default=10) #SSH連接超時時間設定,默認10s --ssh-common-args=SSH_COMMON_ARGS #specify common arguments to pass to sftp/scp/ssh (e.g.ProxyCommand) # --sftp-extra-args=SFTP_EXTRA_ARGS #specify extra arguments to pass to sftp only (e.g. -f, -l) # --scp-extra-args=SCP_EXTRA_ARGS #specify extra arguments to pass to scp only (e.g. -l) # --ssh-extra-args=SSH_EXTRA_ARGS #specify extra arguments to pass to ssh only (e.g. -R) # ############Privilege Escalation Options, 即下面時權限提升權限############ control how and which user you become as on target hosts -s, --sudo #run operations with sudo (nopasswd) (deprecated, use become) #相當於Linux系統下的sudo命令 -U SUDO_USER, --sudo-user=SUDO_USER #desired sudo user (default=root) (deprecated, use become) #使用sudo,相當於Linux下的sudo命令 -S, --su #run operations with su (deprecated, use become) # -R SU_USER, --su-user=SU_USER #run operations with su as this user (default=root)(deprecated, use become) -b, --become #run operations with become (does not imply password prompting) # --become-method=BECOME_METHOD #privilege escalation method to use (default=sudo),valid choices: [ sudo | su | pbrun | pfexec | doas |dzdo | ksu | runas ] # --become-user=BECOME_USER #run operations as this user (default=root) # --ask-sudo-pass #ask for sudo password (deprecated, use become) #傳遞sudo密碼到遠程主機,來保證sudo命令的正常運行 --ask-su-pass #ask for su password (deprecated, use become) # -K, --ask-become-pass #ask for privilege escalation password #
注意的命令:
1)檢查語法,只檢查是否是yaml語法格式。並不做邏輯校驗。(常使用) # ansible-playbook --syntax-check test.yml 2)模擬執行(不是真的執行) # ansible-playbook -C test.yml
關閉facts
--- - hosts: webserver gather_facts: no
二、playbook組件詳解
2.1、variable--變量定義
1)定義在hosts文件中
主機變量: 192.168.200.136 http_port=808 maxRequestsPerChild=808 192.168.200.137 http_port=8080 maxRequestsPerChild=909 主機組變量: [websers] 192.168.200.136 192.168.200.137 [websers:vars] ntp_server=ntp.exampl.com proxy=proxy.exampl.com
2)定義在playbook劇本中
- hosts: all vars: #定義變量 file_name: yaml_vars tasks: - name: # {{ file_name }}引用上面定義的變量 file: path=/tmp/{{ file_name }} state=touch
3)使用facts變量
facts變量是由setup模塊獲取遠程主機的信息。 # ansible 192.168.200.136 -m setup
4)命令行傳參
使用 -e或--extra-vars選項傳入參數 # ansible-playbook 192.168.200.136 -e "httpd_port=808" httpd04.yml # ansible-playbook f2.yml --extra-vars "file_name=bgx_extra-vars"
5)變量定義優先級
1.extra-vars外置傳參的優先級最高 [所有執行的主機都生效]
2.定義在yml文件中的優先級其次 [所有執行的主機都生效]
3.hosts文件中定義的變量優先級最低 [當前主機組定義會生效]
6)變量引用
{{ var_name }}
7)變量注冊
注冊變量: register關鍵字可以存儲指定命令的輸出結果到一個自定義的變量中
[root@Manager playbook]#cat variableRegister.yml --- - hosts: web tasks: - name: print status shell: netstat -lntp register: System_Status - name: Get System_Status debug: msg={{System_Status.stdout_lines}} [root@Manager playbook]#ansible-playbook --syntax-check variableRegister.yml playbook: variableRegister.yml [root@Manager playbook]#ansible-playbook variableRegister.yml PLAY [web] *********************************************************************************************************** TASK [Gathering Facts] *********************************************************************************************** ok: [172.16.93.165] TASK [print status] ************************************************************************************************** changed: [172.16.93.165] TASK [Get System_Status] ********************************************************************************************* ok: [172.16.93.165] => { "msg": [ "Active Internet connections (only servers)", "Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name ", "tcp 0 0 127.0.0.1:8005 0.0.0.0:* LISTEN 31952/java ", "tcp 0 0 0.0.0.0:8009 0.0.0.0:* LISTEN 31952/java ", "tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 3927/nginx: master ", "tcp 0 0 0.0.0.0:8080 0.0.0.0:* LISTEN 31952/java ", "tcp 0 0 0.0.0.0:2812 0.0.0.0:* LISTEN 17247/sshd ", "tcp 0 0 0.0.0.0:10050 0.0.0.0:* LISTEN 18814/zabbix_agentd ", "tcp6 0 0 :::3306 :::* LISTEN 5993/mysqld ", "tcp6 0 0 :::21 :::* LISTEN 1846/vsftpd " ] } PLAY RECAP *********************************************************************************************************** 172.16.93.165 : ok=3 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
2.2、templates--模板功能
template只能在palybook中使用。采用了jinga2語法,jinga2基本語法如下:
字面量: 字符串:使用單引號或雙引號 數字:整型,浮點數 列表:{item1,item2,...} 字典:{key1:value1,key2:value2,...} 布爾型:true/false 算術運算: +,-,*,/,//,%,** 比較運算: ==,!=,>,>=,<,<= 邏輯運算: and,or,not
示例如下:
1)定義模板
[root@server tmp]# mv nginx.conf nginx.conf.j2 [root@server tmp]# vim nginx.conf.j2 worker_processes {{ ansible_processor_vcpus }}; listen {{ nginxport }};
2)修改劇本,編輯nginx.yml文件
2.3、handlers--任務觸發
在需要被監控的任務(tasks)中定義一個notify,只有當這個任務被執行時,才會觸發notify對應的handlers去執行相應操作。例如配置文件被修改后,有可能需要重啟程序,此時我們可以配置一個handlers,類似觸發器。注意:handlers下的name名稱必須要和它對應的notify名稱相同!否則不會執行!!
[root@localhost ~]# cat httpd.yaml --- - hosts: control-node remote_user: root vars: - pkg: httpd tasks: - name: "install httpd package." yum: name={{ pkg }} state=installed - name: "copy httpd configure file to remote host." copy: src=/root/conf/httpd.conf dest=/etc/httpd/conf/httpd.conf notify: restart httpd - name: "boot httpd service." service: name=httpd state=started handlers: - name: restart httpd service: name=httpd state=restarted
注意事項:
1)handlers只有在其所在的任務被執行完時,它才會被運行;如果一個任務中定義了notify調用Handlers,但由於條件判斷等原因,該任務未被執行,則Handlers同樣不會被執行。
2)handlers只會在Play的末尾運行一次;如果想在一個Playbook的中間運行handlers,則需要使用meta模塊來實現,例如:- meta: flush_handlers。
3)可以直接在Handlers中使用notify選項,實現Handlers調用Handlers。
4)可以使用listen關鍵字,在一個tasks任務中一次性notify多個handler。即將多個handler分為"一組",使用相同的"組名"即可,當notify對應的值為"組名"時,"組"內的所有handler都會被notify。
5)如果一個Play在運行到調用handlers的語句之前失敗了,那么這個handlers將不會被執行。但是可以使用mega模塊的--force-handlers選項來強制執行handlers,即使在handlers所在Play中途運行失敗也能執行。需要注意:--force-handlers參數主要針對即使playbook執行失敗,也要執行代碼塊成功了的handlers(即執行成功的task任務), 如果代碼塊本身執行失敗(即執行失敗的task任務),那么它所對應的handlers應當不會被執行!
6)handlers可以理解成另一種tasks,handlers是另一種"任務列表",可以理解handlers和tasks是"平級關系",所以他們的縮進相同。handlers的任務會被tasks中的任務進行"調用",但是,被"調用"並不意味着一定會執行,只有當tasks中的任務"真正執行"以后,handlers中被調用的任務才會執行,如果tasks中的任務並沒有做出任何實際的操作,那么handlers中的任務即使被"調用",也並不會執行。handlers中可以有多個任務,被tasks中不同的任務notify。
使用handlers的場景:
1)headlers在所有tasks任務被執行完時才執行。
[root@Manager playbook]#cat handler1.yml --- - hosts: all remote_user: root tasks: - name: make file task1 file: path=/tmp/task1.txt state=touch notify: task1 - name: make file task2 file: path=/tmp/task2.txt state=touch notify: task2 handlers: - name: task1 file: path=/tmp/task1.txt mode=777 owner=root group=root - name: task2 file: src=/tmp/task2.txt dest=/tmp/heihei state=link force=yes #執行結果 [root@Manager playbook]#ansible-playbook handler1.yml PLAY [all] *********************************************************************************************************** TASK [Gathering Facts] *********************************************************************************************** ok: [172.16.93.165] ok: [172.16.93.167] TASK [make file task1] *********************************************************************************************** changed: [172.16.93.165] changed: [172.16.93.167] TASK [make file task2] *********************************************************************************************** changed: [172.16.93.165] changed: [172.16.93.167] RUNNING HANDLER [task1] ********************************************************************************************** changed: [172.16.93.165] changed: [172.16.93.167] RUNNING HANDLER [task2] ********************************************************************************************** changed: [172.16.93.165] changed: [172.16.93.167] PLAY RECAP *********************************************************************************************************** 172.16.93.165 : ok=5 changed=4 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 172.16.93.167 : ok=5 changed=4 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
2)使用meta模塊,headlers會在它所對應的task任務執行完后立即被觸發並執行,即在playbook的中間環節運行。
[root@Manager playbook]#cat handler2.yml --- - hosts: all remote_user: root tasks: - name: make file task1 file: path=/tmp/task1.txt state=touch notify: task1 - meta: flush_handlers #添加 - name: make file task2 file: path=/tmp/task2.txt state=touch notify: task2 handlers: - name: task1 file: path=/tmp/task1.txt mode=777 owner=root group=root - name: task2 file: src=/tmp/task2.txt dest=/tmp/heihei state=link force=yes #運行結果 [root@Manager playbook]#ansible-playbook handler2.yml PLAY [all] *********************************************************************************************************** TASK [Gathering Facts] *********************************************************************************************** ok: [172.16.93.165] ok: [172.16.93.167] TASK [make file task1] *********************************************************************************************** changed: [172.16.93.167] changed: [172.16.93.165] RUNNING HANDLER [task1] ********************************************************************************************** changed: [172.16.93.167] changed: [172.16.93.165] TASK [make file task2] *********************************************************************************************** changed: [172.16.93.165] changed: [172.16.93.167] RUNNING HANDLER [task2] ********************************************************************************************** changed: [172.16.93.165] changed: [172.16.93.167] PLAY RECAP *********************************************************************************************************** 172.16.93.165 : ok=5 changed=4 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 172.16.93.167 : ok=5 changed=4 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
3)Handlers調用Handlers
[root@Manager playbook]#cat handler3.yml --- - hosts: all remote_user: root tasks: - name: make file task1 file: path=/tmp/task1.txt state=touch notify: task1 - name: make file task2 file: path=/tmp/task2.txt state=touch handlers: - name: task1 file: path=/tmp/task1.txt mode=777 owner=root group=root notify: task2 - name: task2 file: src=/tmp/task2.txt dest=/tmp/heihei state=link force=yes #執行結果 [root@Manager playbook]#ansible-playbook handler3.yml PLAY [all] *********************************************************************************************************** TASK [Gathering Facts] *********************************************************************************************** ok: [172.16.93.165] ok: [172.16.93.167] TASK [make file task1] *********************************************************************************************** changed: [172.16.93.167] changed: [172.16.93.165] TASK [make file task2] *********************************************************************************************** changed: [172.16.93.165] changed: [172.16.93.167] RUNNING HANDLER [task1] ********************************************************************************************** changed: [172.16.93.165] changed: [172.16.93.167] RUNNING HANDLER [task2] ********************************************************************************************** changed: [172.16.93.165] changed: [172.16.93.167] PLAY RECAP *********************************************************************************************************** 172.16.93.165 : ok=5 changed=4 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 172.16.93.167 : ok=5 changed=4 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 #---------------------------------------------------------------------------------------------------- [root@Manager playbook]#cat handler3-2.yaml --- - hosts: all remote_user: root tasks: - name: make file task1 file: path=/tmp/task1.txt state=touch notify: task1 handlers: - name: task1 file: path=/tmp/task1.txt mode=777 owner=root group=root notify: task2 - name: task2 file: path=/tmp/task2.txt state=touch notify: task3 - name: task3 file: src=/tmp/task2.txt dest=/tmp/heihei state=link force=yes #執行結果 [root@Manager playbook]#ansible-playbook handler3-2.yaml PLAY [all] *********************************************************************************************************** TASK [Gathering Facts] *********************************************************************************************** ok: [172.16.93.167] ok: [172.16.93.165] TASK [make file task1] *********************************************************************************************** changed: [172.16.93.165] changed: [172.16.93.167] RUNNING HANDLER [task1] ********************************************************************************************** changed: [172.16.93.165] changed: [172.16.93.167] RUNNING HANDLER [task2] ********************************************************************************************** changed: [172.16.93.165] changed: [172.16.93.167] RUNNING HANDLER [task3] ********************************************************************************************** changed: [172.16.93.165] changed: [172.16.93.167] PLAY RECAP *********************************************************************************************************** 172.16.93.165 : ok=5 changed=4 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 172.16.93.167 : ok=5 changed=4 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
4)使用listen關鍵字,在一個tasks任務中一次性notify多個handler
listen的名稱要和notify名稱保持一致!
[root@Manager playbook]#cat handler4.yml --- - hosts: all remote_user: root tasks: - name: make file task1 file: path=/tmp/task1.txt state=touch notify: group_handler handlers: - name: task1 listen: group_handler file: path=/tmp/task1.txt mode=777 owner=root group=root - name: task2 listen: group_handler file: path=/tmp/task2.txt state=touch - name: task3 listen: group_handler file: src=/tmp/task2.txt dest=/tmp/heihei state=link force=yes #執行結果 [root@Manager playbook]#ansible-playbook handler4.yml PLAY [all] *********************************************************************************************************** TASK [Gathering Facts] *********************************************************************************************** ok: [172.16.93.167] ok: [172.16.93.165] TASK [make file task1] *********************************************************************************************** changed: [172.16.93.167] changed: [172.16.93.165] RUNNING HANDLER [task1] ********************************************************************************************** changed: [172.16.93.167] changed: [172.16.93.165] RUNNING HANDLER [task2] ********************************************************************************************** changed: [172.16.93.167] changed: [172.16.93.165] RUNNING HANDLER [task3] ********************************************************************************************** changed: [172.16.93.167] changed: [172.16.93.165] PLAY RECAP *********************************************************************************************************** 172.16.93.165 : ok=5 changed=4 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 172.16.93.167 : ok=5 changed=4 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
5)使用--force-handlers選項來強制執行handlers
--force-handlers參數主要針對即使playbook執行失敗,也要執行代碼塊成功了的handlers(即執行成功的task任務), 如果代碼塊本身執行失敗(即執行失敗的task任務),那么它所對應的handlers應當不會被執行!
[root@Manager playbook]#cat handler5.yml --- - hosts: all remote_user: root tasks: - name: make file task1 file: path=/tmp/task1.txt state=touch notify: task1 - name: make file task2 file: path=/tmp/lawrence/task2.txt state=touch notify: task2 handlers: - name: task1 file: path=/tmp/task1.txt mode=777 owner=root group=root - name: task2 file: src=/tmp/task2.txt dest=/tmp/heihei state=link force=yes #執行結果 [root@Manager playbook]#ansible-playbook handler5.yml PLAY [all] *********************************************************************************************************** TASK [Gathering Facts] *********************************************************************************************** ok: [172.16.93.165] ok: [172.16.93.167] TASK [make file task1] *********************************************************************************************** changed: [172.16.93.167] changed: [172.16.93.165] TASK [make file task2] *********************************************************************************************** fatal: [172.16.93.165]: FAILED! => {"changed": false, "msg": "Error, could not touch target: [Errno 2] No such file or directory: '/tmp/lawrence/task2.txt'", "path": "/tmp/lawrence/task2.txt"} fatal: [172.16.93.167]: FAILED! => {"changed": false, "msg": "Error, could not touch target: [Errno 2] No such file or directory: '/tmp/lawrence/task2.txt'", "path": "/tmp/lawrence/task2.txt"} RUNNING HANDLER [task1] ********************************************************************************************** PLAY RECAP *********************************************************************************************************** 172.16.93.165 : ok=2 changed=1 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0 172.16.93.167 : ok=2 changed=1 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0 #當沒使用--force-handlers,由於目錄/tmp/lawrence/不存在,導致task的第二個任務執行失敗,這個時候handler根本沒有被觸發,也就不會執行。即使第一個任務執行成功,但是它對應的第一個handler也不會被執行!! #------------------------------------------------------------------------------- #使用--force-handlers選項來強制執行handlers(強制執行的是:成功執行的task對應的handler) [root@Manager playbook]#ansible-playbook handler5.yml --force-handlers PLAY [all] *********************************************************************************************************** TASK [Gathering Facts] *********************************************************************************************** ok: [172.16.93.167] ok: [172.16.93.165] TASK [make file task1] *********************************************************************************************** changed: [172.16.93.167] changed: [172.16.93.165] TASK [make file task2] *********************************************************************************************** fatal: [172.16.93.165]: FAILED! => {"changed": false, "msg": "Error, could not touch target: [Errno 2] No such file or directory: '/tmp/lawrence/task2.txt'", "path": "/tmp/lawrence/task2.txt"} fatal: [172.16.93.167]: FAILED! => {"changed": false, "msg": "Error, could not touch target: [Errno 2] No such file or directory: '/tmp/lawrence/task2.txt'", "path": "/tmp/lawrence/task2.txt"} RUNNING HANDLER [task1] ********************************************************************************************** changed: [172.16.93.167] changed: [172.16.93.165] PLAY RECAP *********************************************************************************************************** 172.16.93.165 : ok=3 changed=2 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0 172.16.93.167 : ok=3 changed=2 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0
6)日常handler應用示例
#playbook安裝Apache示例 [root@m01 ~]# cat webserver.yml - hosts: web remote_user: root #1.定義變量,在配置文件中調用 vars: http_port: 8881 #2.安裝httpd服務 tasks: - name: Install Httpd Server yum: name=httpd state=present #3.使用template模板,引用上面vars定義的變量至配置文件中 - name: Configure Httpd Server template: src=./httpd.conf dest=/etc/httpd/conf/httpd.conf notify: Restart Httpd Server #4.啟動Httpd服務 - name: Start Httpd Server service: name=httpd state=started enabled=yes #5.檢查Httpd服務當前的運行的端口狀態 - name: Get Httpd Server Port shell: netstat -lntp|grep httpd register: Httpd_Port #6.輸出Httpd運行的狀態至面板 - name: Out Httpd Server Status debug: msg={{ Httpd_Port.stdout_lines }} ignore_errors: yes #6.如果配置文件發生變化會調用該handlers下面的模塊 handlers: - name: Restart Httpd Server service: name=httpd state=restarted
2.4、tags--任務標簽
tags用於讓用戶選擇運行playbook中的部分代碼。ansible具有冪等性,因此會自動跳過沒有變化的部分,即便如此,有些代碼為測試其確實沒有發生變化的時間依然會非常地長。此時如果確信其沒有變化,就可以通過tags跳過此些代碼片斷。tags可以看作是ansible的任務控制
2.4.1、內置tag
always: 除非--skip-tags指定這個標簽,否則該標記為always的task一直都會執行。"--tags always"只執行標記了always的tasks;
never: 除非--tags指定了這個標簽,否則該標記為never的task一直都不會執行。"--tags never"執行標記了always和never的tasks;
tagged: --tags tagged表示執行所有有tags標簽的tasks任務,但不包括tags標簽是never的tasks任務;--skip-tags tagged表示所有有tags標簽的tasks任務都跳過,即不會執行。
untagged: --tags untagged表示執行所有沒有tags標簽的tasks任務和tags標簽為always的tasks任務;--skip-tags untagged效果相反!
all:--tags all表示執行所有的tags標簽為非never的task,包括有tags標簽和無tags標簽的tasks。
2.4.2、tag相關命令
"--tags 自定義的tag" :表示執行tags為指定的標簽名的tasks和tags為always的tasks。如果執行命令ansible-playbook site.yml 時不指定tags,則會執行所有tags為非never的tasks
"--skip-tags 自定義tag" :表示執行所有非指定tag和非never的tasks
2.4.3、tag配置語法
語法一: tags: - tag_test 語法二: tags: tag_test 語法三: tags: ['tag_test'] #---------------------- #一個任務添加多個tags標簽的語法仍然也有三種: 語法1: tags: - tag1 - tag2 語法2: tags: tag1,tag2 語法3: tags: ['tag1,tag2']
2.4.4、tags使用場景
1)一個task任務添加一個tags標簽
#官方示例如下: [root@localhost ansible]# vim example.yml --- - hosts: all remote_user: root gather_facts: no tasks: - yum: name={{ item }} state=installed with_items: - httpd - memcached tags: - packages - template: src=templates/src.j2 dest=/etc/foo.conf tags: - configuration #運行 [root@localhost ansible]# ansible-playbook example.yml --tags "configuration,packages" [root@localhost ansible]# ansible-playbook example.yml --tags configuration [root@localhost ansible]# ansible-playbook example.yml --tags packages [root@localhost ansible]# ansible-playbook example.yml --tags="configuration,packages" [root@localhost ansible]# ansible-playbook example.yml --tags=configuration [root@localhost ansible]# ansible-playbook example.yml --tags=packages #使用--skip-tags跳過某個task任務 [root@localhost ansible]# ansible-playbook example.yml --skip-tags configuration [root@localhost ansible]# ansible-playbook example.yml --skip-tags=configuration #----------------------------------------------------------------------------------- [root@localhost ansible]# cat haha.yaml --- - hosts: test_host remote_user: root gather_facts: no tasks: - name: task1 file: path=/opt/task1.txt state=touch tags: make_task1 - name: task2 file: path=/opt/task2.txt state=touch tags: - make_task2 - name: task3 file: path=/opt/task2.txt src=/opt/task2.txt dest=/opt/heihei state=link force=yes tags: ['link_task3']
2)一個task任務添加多個tags標簽。
[root@localhost ansible]# vim https.yml --- - hosts: test_host remote_user: root tasks: - name: install httpd package tags: - httpd - package yum: name=httpd state=latest - name: start up httpd service tags: httpd,service service: name: httpd state: started
3)tags和include結合使用
通過指定標簽(tags),來說明是安裝tomcat7還是tomcat8
tomcat.yml文件:
--- - include: install_tomcat7.yml tags: tomcat7 - include: install_tomcat8.yml tags: tomcat8
install_tomcat7.yml文件:
--- - name: "復制文件到遠程主機" copy: src={{ item.src }} dest={{ item.dest }} with_items: - src: jdk-7u79-linux-x64.rpm dest: /usr/local/src/ - src: java17.sh dest: /etc/profile.d/ - name: "安裝jdk" yum: name: /usr/local/src/jdk-7u79-linux-x64.rpm state: present - name: "重新加載環境變量" shell: "source /etc/profile.d/java17.sh" - name: "復制tomcat文件到遠程服務器並解壓" unarchive: src=apache-tomcat-7.0.64.zip dest=/data/ copy=yes owner=staplesapp group=admin - name: "對解壓后的文件重命名" shell: mv /data/apache-tomcat-7.0.64 /data/tomcat7 - name: "對tomcat進行相關配置" shell: find /data/tomcat7/bin -name "*.sh" | xargs chmod +x - name: "啟動tomcat" shell: 'nohup /data/tomcat7/bin/startup.sh &'
install_tomcat8.yml文件:
--- - name: "復制文件到遠程主機" copy: src={{ item.src }} dest={{ item.dest }} with_items: - src: jdk-8u111-linux-x64.rpm dest: /usr/local/src/ - src: java18.sh dest: /etc/profile.d/ - name: "安裝jdk" yum: name: /usr/local/src/jdk-8u111-linux-x64.rpm state: present - name: "配置java環境變量" shell: "source /etc/profile.d/java18.sh" - name: "安裝tomcat" unarchive: src=apache-tomcat-8.0.30.tar.gz dest=/data/ copy=yes owner=staplesapp group=admin - name: "對解壓后的文件重命名" shell: mv /data/apache-tomcat-8.0.30 /data/tomcat8 - name: "啟動tomcat" shell: 'nohup /data/tomcat8/bin/startup.sh &'
執行命令:
安裝tomcat7: [root@localhost ansible]# ansible-playbook tomcat.yml --tags tomcat7 安裝tomcat8: [root@localhost ansible]# ansible-playbook tomcat.yml --tags tomcat8
特別注意:在ansible2.8版本之后將會刪除include語法,更改為import_playbook
[root@localhost ansible]# cat tomcat.yml --- - import_playbook: install_tomcat7.yml tags: tomcat7 - import_playbook: install_tomcat8.yml tags: tomcat8
2.5、include用法
如果想在playbook中重復使用任務列表,則可以使用include文件來執行此操作。ansible2.8版本之后include語法變成了import_playbook。如果還是使用include,則不會影響執行結果,只不過是有告警信息
include用來動態的包含tasks任務列表,include_tasks新版/include老版
#主入口文件 [root@mha ~]# cat main.yml - hosts: all remote_user: root tasks: - include_tasks: f20.yml - include_tasks: f21.yml #f20.yml [root@mha ~]# cat f20.yml - name: create file1 command: touch file1 #21.yml [root@mha ~]# cat f21.yml - name: create file2 command: touch file2
2.6、when--條件語句
[root@manager ~]# cat f6.yml - hosts: all remote_user: root tasks: - name: Create File file: path=/tmp/this_is_{{ ansible_hostname }}_file state=touch when: (ansible_hostname == "nfs") or (ansible_hostname == "backup") #系統為centos的主機才會執行 - name: Centos Install httpd yum: name=httpd state=present when: (ansible_distribution == "CentOS") #系統為ubuntu的主機才會執行 - name: Ubuntu Install httpd yum: name=httpd2 state=present when: (ansible_distribution == "Ubuntu")
2.7、with_items--循環語句
1)批量安裝軟件
[root@manager ~]# cat f7.yml --- - hosts: all remote_user: root tasks: - name: Installed Pkg yum: name={{ item }} state=present with_items: - wget - tree - lrzsz
2)批量創建用戶
[root@manager ~]# cat f7.yml - hosts: all remote_user: root tasks: - name: Add Users user: name={{ item.name }} groups={{ item.groups }} state=present with_items: - { name: 'testuser1', groups: 'bin' } - { name: 'testuser2', groups: 'root' }
3)批量文件拷貝
[root@manager ~]# cat f7.yml - hosts: all remote_user: root tasks: - name: Configure Rsync Server copy: src={{ item.src }} dest=/etc/{{ item.dest }} mode={{ item.mode }} with_items: - {src: "rsyncd.conf", dest: "rsyncd.conf", mode: "0644"} - {src: "rsync.passwd", dest: "rsync.passwd", mode: "0600"}
2.8、異常處理
默認Playbook會檢查命令和模塊的返回狀態,如遇到錯誤就中斷playbook的執行
加入參數: ignore_errors: yes 忽略錯誤
[root@Manager playbook]#cat ErrorIgnore.yml --- - hosts: web remote_user: root tasks: - name: Ignore False command: /bin/false ignore_errors: yes - name: touch new file file: path=/tmp/ignore.txt state=touch [root@Manager playbook]#ansible-playbook ErrorIgnore.yml PLAY [web] *********************************************************************************************************** TASK [Gathering Facts] *********************************************************************************************** ok: [172.16.93.165] TASK [Ignore False] ************************************************************************************************** fatal: [172.16.93.165]: FAILED! => {"changed": true, "cmd": ["/bin/false"], "delta": "0:00:00.043922", "end": "2020-01-09 17:15:34.985067", "msg": "non-zero return code", "rc": 1, "start": "2020-01-09 17:15:34.941145", "stderr": "", "stderr_lines": [], "stdout": "", "stdout_lines": []} ...ignoring TASK [touch new file] ************************************************************************************************ changed: [172.16.93.165] PLAY RECAP *********************************************************************************************************** 172.16.93.165 : ok=3 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=1