爲何引入playbook?
通常運維人員完成一個任務, 好比安裝部署一個httpd服務會須要多個模塊(一個模塊也能夠稱之爲task)提供功能來完成。而playbook就是組織多個task的容器,它的實質就是一個文件,有着特定的組織格式,它採用的語法格式是YAML(Yet Another Markup Language)。YAML語法可以簡單的表示散列表,字典等數據結構。簡單來講, playbook是由一個或多個模塊組成的,使用多個不一樣的模塊,完成一件事情。
php
Ansible核心功能
- pyYAML用於ansible編寫劇本所使用的語言格式(saltstack---python);
- rsync-ini語法, sersync-xml語法, nsible-pyYAML語法;
- paramiko遠程鏈接與數據傳輸;
- Jinja2用於編寫ansible的模板信息;
html
YAML三板斧
縮進: YAML使用一個固定的縮進風格表示層級結構,每一個縮進由兩個空格組成, 不能使用tabs;
冒號: 以冒號結尾的除外,其餘全部冒號後面全部必須有空格;
短橫線: 表示列表項,使用一個短橫槓加一個空格。多個項使用一樣的縮進級別做爲同一列表;
java
YAML基本語法
Ansible-playbook採用YAML語法編寫。連續的項目(即列表)用 -
減號來表示,key/value(字典)用冒號:
分隔。
node
列表:每個列表成員前面都要有一個短橫線和一個空格python
1mysql 2linux 3nginx 4web 5redis 6 7 8 |
fruits: - Apple - Orange - Strawberry - Mango 或者: fruits: [ 'Apple' , 'Orange' , 'Strawberry' , 'Mango' ] |
字典:每個成員由鍵值對組成,注意冒號後面要有空格
1 2 3 4 5 6 |
martin: name: Martin D'vloper job: Developer skill: Elite 或者 martin: {name: Martin D'vloper, job: Developer, skill: Elite} |
列表和字典能夠混合使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
- martin: name: Martin D'vloper job: Developer skills: - python - perl - pascal - tabitha: name: Tabitha Bitumen job: Developer skills: - lisp - fortran - erlang |
示例以下:
[root@localhost ~]# cat httpd.yaml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
--- - 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 |
playbook語法特性
1. 以 --- (三個減號)開始,必須頂行寫;
2. 次行開始寫Playbook的內容,可是通常要求寫明該playbook的功能;
3. 嚴格縮進,而且不能用Tab鍵縮進;
4. 縮進級別必須是一致的,一樣的縮進表明一樣的級別,程序判別配置的級別是經過縮進結合換行來實現的;
5. K/V的值可同行寫,也可換行寫。同行使用 :分隔,換行寫須要以 - 分隔;
playbook基礎組件
Hosts:運行執行任務(task)的目標主機
remote_user:在遠程主機上執行任務的用戶
tasks:任務列表
handlers:任務,與tasks不一樣的是隻有在接受到通知時纔會被觸發
templates:使用模板語言的文本文件,使用jinja2語法。
variables:變量,變量替換{{ variable_name }}
整個playbook是以task爲中心,代表要執行的任務。hosts和remote_user代表在遠程主機以何種身份執行,其餘組件讓其可以更加靈活。下面介紹插件:
1. variable
變量定義在資產 (inventory) 中, 默認就是/etc/ansible/hosts文件中
1 2 3 4 5 6 7 8 9 10 11 12 |
主機變量: 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 |
變量定義在playbook中
1 2 3 |
- hosts: webservers vars: http_port: 80 |
使用facts變量
1 2 3 4 |
facts變量是由setup模塊獲取遠程主機的信息。 用法: # ansible 192.168.200.136 -m setup |
在roles中定義變量, 這個後面會介紹到.
ansible-playbook 命令中傳入參數
1 2 |
使用 -e選項傳入參數 # ansible-playbook 192.168.200.136 -e "httpd_port=808" httpd04.yml |
變量的引用
2. templates
它是一個模塊功能,與copy不一樣的是他的文本文件採用了jinga2語法,jinga2基本語法以下:
1 2 3 4 5 6 7 8 9 10 11 12 |
字面量: 字符串:使用單引號或雙引號 數字:整型,浮點數 列表:{item1,item2,...} 字典:{key1:value1,key2:value2,...} 布爾型: true /false 算術運算: +,-,*,/, // ,%,** 比較運算: ==,!=,>,>=,<,<= 邏輯運算: and,or,not |
注意:template只能在palybook中使用。
3. tasks
執行的模塊命令
1 2 3 4 5 6 7 8 9 10 11 12 13 |
格式: action:模塊參數(此種方式只在較新的版本中出現) module:參數(已鍵值對的形式出現) 每個task都有一個名稱,用於標記此任務。任務示例: name: install httpd yum: name=httpd state=present 注意:shell和 command 沒有參數,可在後面直接跟命令 shell: ss -tnl | grep :80 1)某任務的運行狀態爲changed後,可經過相應的notify通知相應的handlers 2)任務能夠經過tags打標籤,而後經過palybook命令-t選項調用. |
playbook命令及調用方式
用法:
ansible-playbook <filename.yml> ... [options]
<filename.yml>: yaml格式的playbook文件路徑,必須指明
[options]: 選項
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 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 |
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 # |
ansible-playbook須要注意的兩個命令
1)檢查語法,只檢查是不是yaml語法格式。並不作邏輯校驗。(記住這個要常用, 它是判斷語法是否正確!!!)
# ansible-playbook --syntax-check kevin.yml
2)模擬執行(不是真的執行)
# ansible-playbook -C kevin.yml
關閉Facts
若是不須要使用主機的任何fact數據,能夠選擇關閉fact數據的獲取,這樣有利於加強Ansible面對大量系統的push模塊。
在playbook中關閉Facts方法(gather_facts: no):
1 2 3 |
--- - hosts: webserver gather_facts: no |
palybook書寫格式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
--- # 也能夠不使用這一行。能夠省略。 - hosts: 172.16.60.211 #處理指定服務器. - (空格)hosts:(空格)172.16.20.211 task: #劇本所要乾的事情; (空格)(空格)task: - name: #(兩個空格)-(空格)name。 command : echo hello clsn linux #(四個空格)command:(空格) 須要注意: Task任務裏的name能夠省略不寫,將-(空格)放到下一行模塊牆面。例如: --- - hosts: 172.16.60.211 task: - command : echo hello clsn linux 小示例: [root@localhost ansible] # cat haha.yaml --- - hosts: test_host remote_user: root gather_facts: no tasks: - file : path= /opt/task1 .txt state= touch |
palybook格式示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
[root@ansible-server ~] # vim /etc/ansible/test.yaml - hosts: 172.16.60.213 tasks: - name: Install Rsync yum: name= rsync state=installed playbook檢查方法 [root@ansible-server ~] # ansible-playbook --syntax-check /etc/ansible/test.yaml playbook: /etc/ansible/test .yaml [root@ansible-server ~] # ansible-playbook -C /etc/ansible/test.yaml PLAY [172.16.60.213] ******************************************************************************************************************* TASK [Gathering Facts] ***************************************************************************************************************** ok: [172.16.60.213] TASK [Install Rsync] ******************************************************************************************************************* ok: [172.16.60.213] PLAY RECAP ***************************************************************************************************************************** 172.16.60.213 : ok=2 changed=0 unreachable=0 failed=0 上面兩個檢查命令, 第一個是進行playbook劇本配置信息語法檢查; 第二個是模擬playbook劇本執行(彩排) |
palybook劇本文件示例
ansible-playbook編寫內容擴展:劇本任務編寫多個任務
1 2 3 4 5 6 |
- hosts: all tasks: - name: restart-network cron : name= 'restart network' minute=00 hour=00 job= '/usr/sbin/ntpdate time.nist.gov >/dev/null 2>&1' - name: sync time cron : name= 'sync time' minute=* /5 job= "/usr/sbin/ntpdate pool.ntp.com >/dev/null 2>&1" |
劇本編寫內容擴展:劇本任務編寫多個主機
1 2 3 4 5 6 7 8 9 10 11 |
- hosts: 172.16.60.7 tasks: - name: restart-network cron : name= 'restart network' minute=00 hour=00 job= '/usr/sbin/ntpdate time.nist.gov >/dev/null 2>&1' - name: sync time cron : name= 'sync time' minute=* /5 job= "/usr/sbin/ntpdate pool.ntp.com >/dev/null 2>&1" - hosts: 172.16.60.31 tasks: - name: show ip addr to file shell: echo $( hostname -i) >> /tmp/ip .txt |
playbook劇本編寫方式
- 多主機單任務編寫方式
- 多主機多任務編寫方式
- 不一樣主機多任務編寫方式
來看一個比較完整的ansible的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 33 34 35 36 37 38 39 40 41 42 43 44 |
--- - host: webservers ###要管理的遠程服務器組名稱, 服務器地址維護在/etc/ansible/hosts 裏, 也能夠直接寫地址 vars: port: 8081 ###定義了一個變量 端口號 remote_user: root ###遠程登陸後用什麼用戶執行 pre_tasks: ###執行正式 task 以前執行的任務 - name: pre task ###任務名稱 shell: echo 'execute pre task' ###執行一行 shell 命令, 支持 >> 等符號 roles: ###引入 roles, 能夠理解爲引用了一個其餘項目 ansible 包, 引用的 roles 能夠是另外一個完整的 ansible 腳本 - role: my_role ###要引用的 role 名稱 when: "ansible_os_family == 'RedHat'" ###判斷條件, ansible_os_family 是一個內置變量, 可直接使用 tasks: ###按順序執行如下 task - include: my_tasks /some_task .yml ###能夠引入其餘 yml 文件 - name: get hostname ###這是一個 task, 名稱 command : cat log.log ###執行一行 command , 和 shell 相似, 可是不支持 >> 等操做符 register: result ###執行的結果, 設到 result 這個變量中, 後面可使用 - name: set hostname shell: cat {{result.stdout}} >> host.text - name: task1 command : echo 'execute task1' - name: task2 start apache service: ###啓動 httpd 服務器, service 是一個 ansible 內置模塊, 讀者能夠自行查看更多模塊, 包括下載複製等等 name: httpd state: started tags: - apache ###這是一個標籤, 能夠用 ansible-playbook main.yml --tags "apache" 指定只執行這個任務 - name: copy and set value of index.html template: ###這是一個複製方法, 也叫模塊, 而且.j2文件中可使用{{}}來設置須要替換的變量 src: templates /index .html.j2 dest: /etc/httpd/index .html notify: ###喚醒執行後面的 handlers 中名字叫 restart apache 的任務 - restart apache post_tasks: ###最後須要執行的任務 - name: posy task shell: echo 'execute post task' handlers: - name: restart apache debug: ###這是一個打印模塊 msg: start restart apche |
palybook劇本中的方法
1. handlers 任務觸發
在須要被監控的任務(tasks)中定義一個notify,只有當這個任務被執行時,纔會觸發notify對應的handlers去執行相應操做。例如配置文件被修改後,有可能須要重啓程序,此時咱們能夠配置一個handlers,相似觸發器。注意:handlers下的name名稱必需要和它對應的notify名稱相同!不然不會執行!!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
[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 |
######## 在使用handlers的過程當中,須要注意下面幾點 ########
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應當不會被執行!
handlers能夠理解成另外一種tasks,handlers是另外一種"任務列表",能夠理解handlers和tasks是"平級關係",因此他們的縮進相同。handlers的任務會被tasks中的任務進行"調用",可是,被"調用"並不意味着必定會執行,只有當tasks中的任務"真正執行"之後,handlers中被調用的任務纔會執行,若是tasks中的任務並無作出任何實際的操做,那麼handlers中的任務即便被"調用",也並不會執行。handlers中能夠有多個任務,被tasks中不一樣的任務notify。
場景1:headlers在全部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 40 41 42 43 44 45 46 47 |
[root@localhost ansible] # cat haha.yaml --- - hosts: test_host remote_user: root become: yes become_method: sudo tasks: - name: make file task1 file : path= /opt/task1 .txt state= touch notify: task1 - name: make file task2 file : path= /opt/task2 .txt state= touch notify: task2 handlers: - name: task1 file : path= /opt/task1 .txt mode=777 owner=root group=root - name: task2 file : path= /opt/task2 .txt src= /opt/task2 .txt dest= /opt/heihei state=link force= yes 執行結果: [root@localhost ansible] # ansible-playbook haha.yaml PLAY [test_host] ********************************************************************************************************************************* TASK [Gathering Facts] *************************************************************************************************************************** ok: [172.16.60.233] ok: [172.16.60.234] TASK [ make file task1] *************************************************************************************************************************** changed: [172.16.60.234] changed: [172.16.60.233] TASK [ make file task2] *************************************************************************************************************************** changed: [172.16.60.233] changed: [172.16.60.234] RUNNING HANDLER [task1] ************************************************************************************************************************** changed: [172.16.60.234] changed: [172.16.60.233] RUNNING HANDLER [task2] ************************************************************************************************************************** changed: [172.16.60.233] changed: [172.16.60.234] PLAY RECAP *************************************************************************************************************************************** 172.16.60.233 : ok=5 changed=4 unreachable=0 failed=0 172.16.60.234 : ok=5 changed=4 unreachable=0 failed=0 |
從上面運行結果看出,Handlers執行的順序與Handlers在playbook中定義的順序是相同的,與"handler"被notify的順序無關。
場景2:使用meta模塊,headlers會在它所對應的task任務執行完後當即被觸發並執行,即在playbook的中間環節運行。
默認狀況下,全部的task執行完畢後,纔會執行各個handles,並非執行完某個task後,當即執行相應的handler,若是想要在執行完某些task之後當即執行對應的handlre,那麼須要使用meta模塊。
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 40 41 42 43 44 45 46 47 48 |
[root@localhost ansible] # cat haha.yaml --- - hosts: test_host remote_user: root become: yes become_method: sudo tasks: - name: make file task1 file : path= /opt/task1 .txt state= touch notify: task1 - meta: flush_handlers - name: make file task2 file : path= /opt/task2 .txt state= touch notify: task2 handlers: - name: task1 file : path= /opt/task1 .txt mode=777 owner=root group=root - name: task2 file : path= /opt/task2 .txt src= /opt/task2 .txt dest= /opt/heihei state=link force= yes 執行結果: [root@localhost ansible] # ansible-playbook haha.yaml PLAY [test_host] ********************************************************************************************************************************* TASK [Gathering Facts] *************************************************************************************************************************** ok: [172.16.60.234] ok: [172.16.60.233] TASK [ make file task1] *************************************************************************************************************************** changed: [172.16.60.234] changed: [172.16.60.233] RUNNING HANDLER [task1] ************************************************************************************************************************** changed: [172.16.60.234] changed: [172.16.60.233] TASK [ make file task2] *************************************************************************************************************************** changed: [172.16.60.234] changed: [172.16.60.233] RUNNING HANDLER [task2] ************************************************************************************************************************** changed: [172.16.60.234] changed: [172.16.60.233] PLAY RECAP *************************************************************************************************************************************** 172.16.60.233 : ok=5 changed=4 unreachable=0 failed=0 172.16.60.234 : ok=5 changed=4 unreachable=0 failed=0 |
上面使用了meta模塊後,注意它的執行順序於場景1作下對比!
場景3:Handlers調用Handlers
若實現Handlers調用Handlers,則直接在Handlers中使用notify選項便可以。
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 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 |
[root@localhost ansible] # cat haha.yaml --- - hosts: test_host remote_user: root become: yes become_method: sudo tasks: - name: make file task1 file : path= /opt/task1 .txt state= touch notify: task1 - name: make file task2 file : path= /opt/task2 .txt state= touch handlers: - name: task1 file : path= /opt/task1 .txt mode=777 owner=root group=root notify: task2 - name: task2 file : path= /opt/task2 .txt src= /opt/task2 .txt dest= /opt/heihei state=link force= yes 執行結果: [root@localhost ansible] # ansible-playbook haha.yaml PLAY [test_host] ********************************************************************************************************************************* TASK [Gathering Facts] *************************************************************************************************************************** ok: [172.16.60.234] ok: [172.16.60.233] TASK [ make file task1] *************************************************************************************************************************** changed: [172.16.60.233] changed: [172.16.60.234] TASK [ make file task2] *************************************************************************************************************************** changed: [172.16.60.234] changed: [172.16.60.233] RUNNING HANDLER [task1] ************************************************************************************************************************** changed: [172.16.60.234] changed: [172.16.60.233] RUNNING HANDLER [task2] ************************************************************************************************************************** changed: [172.16.60.234] changed: [172.16.60.233] PLAY RECAP *************************************************************************************************************************************** 172.16.60.233 : ok=5 changed=4 unreachable=0 failed=0 172.16.60.234 : ok=5 changed=4 unreachable=0 failed=0 注意:上面執行的順序是: make file task1 > make file task2 > task1 > task2 ==================================================================== 也能夠改爲下面的方式:實現Handlers調用Handlers [root@localhost ansible] # cat haha.yaml --- - hosts: test_host remote_user: root become: yes become_method: sudo tasks: - name: make file task1 file : path= /opt/task1 .txt state= touch notify: task1 handlers: - name: task1 file : path= /opt/task1 .txt mode=777 owner=root group=root notify: task2 - name: task2 file : path= /opt/task2 .txt state= touch notify: task3 - name: task3 file : path= /opt/task2 .txt src= /opt/task2 .txt dest= /opt/heihei state=link force= yes 執行結果: [root@localhost ansible] # ansible-playbook haha.yaml PLAY [test_host] ********************************************************************************************************************************* TASK [Gathering Facts] *************************************************************************************************************************** ok: [172.16.60.233] ok: [172.16.60.234] TASK [ make file task1] *************************************************************************************************************************** changed: [172.16.60.233] changed: [172.16.60.234] RUNNING HANDLER [task1] ************************************************************************************************************************** changed: [172.16.60.233] changed: [172.16.60.234] RUNNING HANDLER [task2] ************************************************************************************************************************** changed: [172.16.60.234] changed: [172.16.60.233] RUNNING HANDLER [task3] ************************************************************************************************************************** changed: [172.16.60.234] changed: [172.16.60.233] PLAY RECAP *************************************************************************************************************************************** 172.16.60.233 : ok=5 changed=4 unreachable=0 failed=0 172.16.60.234 : ok=5 changed=4 unreachable=0 failed=0 注意:上面的執行順序是: make file task1 > task1 > task2 > task3 |
場景4:使用listen關鍵字,在一個tasks任務中一次性notify多個handler
怎麼才能一次性notify多個handler呢?若是嘗試將多個handler使用相同的name呢?其實這樣並不可行!由於當多個handler的name相同時,只有一個handler會被執行。要想實現一次notify多個handler,須要藉助一個關鍵字,它就是"listen",能夠把listen理解成"組名",能夠把多個handler分紅"組",當須要一次性notify多個handler時,只要將多個handler分爲"一組",使用相同的"組名"便可,當notify對應的值爲"組名"時,"組"內的全部handler都會被notify。須要注意:listen的名稱要和notify名稱保持一致!
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 40 41 42 43 44 45 46 47 48 49 |
[root@localhost ansible] # cat haha.yaml --- - hosts: test_host remote_user: root become: yes become_method: sudo tasks: - name: make file task1 file : path= /opt/task1 .txt state= touch notify: group1_handler handlers: - name: task1 listen: group1_handler file : path= /opt/task1 .txt mode=777 owner=root group=root - name: task2 listen: group1_handler file : path= /opt/task1 .txt src= /opt/task1 .txt dest= /opt/heihei state=link force= yes - name: task3 listen: group1_handler shell: echo "this is test,haha...." >> /opt/task1 .txt 執行結果: [root@localhost ansible] # ansible-playbook haha.yaml PLAY [test_host] ********************************************************************************************************************************* TASK [Gathering Facts] *************************************************************************************************************************** ok: [172.16.60.233] ok: [172.16.60.234] TASK [ make file task1] *************************************************************************************************************************** changed: [172.16.60.234] changed: [172.16.60.233] RUNNING HANDLER [task1] ************************************************************************************************************************** changed: [172.16.60.234] changed: [172.16.60.233] RUNNING HANDLER [task2] ************************************************************************************************************************** changed: [172.16.60.234] changed: [172.16.60.233] RUNNING HANDLER [task3] ************************************************************************************************************************** changed: [172.16.60.234] changed: [172.16.60.233] PLAY RECAP *************************************************************************************************************************************** 172.16.60.233 : ok=5 changed=4 unreachable=0 failed=0 172.16.60.234 : ok=5 changed=4 unreachable=0 failed=0 |
場景5:使用--force-handlers選項來強制執行handlers
當playbook劇本執行失敗之後,handlers可能並無被觸發,也就不會執行了!若是想無論task任務是否成功執行,都強制執行handlers。在這個時候,能夠在執行playbook的時候,添加--force-handlers來強制執行handlers!可是必需要注意的是:--force-handlers參數主要針對即便playbook執行失敗,也要執行代碼塊成功了的handlers(即執行成功的task任務), 若是代碼塊自己執行失敗(即執行失敗的task任務),那麼它所對應的handlers應當不會被執行!
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 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 |
[root@localhost ansible] # cat haha.yaml --- - hosts: test_host remote_user: root become: yes become_method: sudo tasks: - name: make file task1 file : path= /opt/task1 .txt state= touch notify: task1 - name: make file task2 file : path= /opt/kevin/task2 .txt state= touch notify: task2 handlers: - name: task1 file : path= /opt/task1 .txt mode=777 owner=root group=root - name: task2 shell: ln -s /opt/task1 .txt /opt/task2 .txt 執行結果: [root@localhost ansible] # ansible-playbook haha.yaml PLAY [test_host] ********************************************************************************************************************************* TASK [Gathering Facts] *************************************************************************************************************************** ok: [172.16.60.234] ok: [172.16.60.233] TASK [ make file task1] *************************************************************************************************************************** changed: [172.16.60.233] changed: [172.16.60.234] TASK [ make file task2] *************************************************************************************************************************** fatal: [172.16.60.234]: FAILED! => { "changed" : false , "module_stderr" : "" , "module_stdout" : "Traceback (most recent call last):\r\n File \"/tmp/ansible_iNMDpU/ansible_module_file.py\", line 474, in <module>\r\n main()\r\n File \"/tmp/ansible_iNMDpU/ansible_module_file.py\", line 448, in main\r\n open(b_path, 'wb').close()\r\nIOError: [Errno 2] No such file or directory: '/opt/kevin/task2.txt'\r\n" , "msg" : "MODULE FAILURE" , "rc" : 0} fatal: [172.16.60.233]: FAILED! => { "changed" : false , "module_stderr" : "" , "module_stdout" : "Traceback (most recent call last):\r\n File \"/tmp/ansible_OvTacW/ansible_module_file.py\", line 474, in <module>\r\n main()\r\n File \"/tmp/ansible_OvTacW/ansible_module_file.py\", line 448, in main\r\n open(b_path, 'wb').close()\r\nIOError: [Errno 2] No such file or directory: '/opt/kevin/task2.txt'\r\n" , "msg" : "MODULE FAILURE" , "rc" : 0} RUNNING HANDLER [task1] ************************************************************************************************************************** to retry, use: --limit @ /etc/ansible/haha .retry PLAY RECAP *************************************************************************************************************************************** 172.16.60.233 : ok=2 changed=1 unreachable=0 failed=1 172.16.60.234 : ok=2 changed=1 unreachable=0 failed=1 如上執行結果,因爲 /opt/kevin 目錄不存在,致使task的第二個任務執行失敗,這個時候handler根本沒有被觸發,也就不會執行。 即便第一個任務執行成功,可是它對應的第一個handler也不會被執行!! ################################################################################### 接下來使用--force-handlers選項來強制執行handlers(強制執行的是:成功執行的task對應的handler) [root@localhost ansible] # ansible-playbook haha.yaml --force-handlers PLAY [test_host] ********************************************************************************************************************************* TASK [Gathering Facts] *************************************************************************************************************************** ok: [172.16.60.234] ok: [172.16.60.233] TASK [ make file task1] *************************************************************************************************************************** changed: [172.16.60.234] changed: [172.16.60.233] TASK [ make file task2] *************************************************************************************************************************** fatal: [172.16.60.233]: FAILED! => { "changed" : false , "module_stderr" : "" , "module_stdout" : "Traceback (most recent call last):\r\n File \"/tmp/ansible_rEJQHm/ansible_module_file.py\", line 474, in <module>\r\n main()\r\n File \"/tmp/ansible_rEJQHm/ansible_module_file.py\", line 448, in main\r\n open(b_path, 'wb').close()\r\nIOError: [Errno 2] No such file or directory: '/opt/kevin/task2.txt'\r\n" , "msg" : "MODULE FAILURE" , "rc" : 0} fatal: [172.16.60.234]: FAILED! => { "changed" : false , "module_stderr" : "" , "module_stdout" : "Traceback (most recent call last):\r\n File \"/tmp/ansible_7CDxpp/ansible_module_file.py\", line 474, in <module>\r\n main()\r\n File \"/tmp/ansible_7CDxpp/ansible_module_file.py\", line 448, in main\r\n open(b_path, 'wb').close()\r\nIOError: [Errno 2] No such file or directory: '/opt/kevin/task2.txt'\r\n" , "msg" : "MODULE FAILURE" , "rc" : 0} RUNNING HANDLER [task1] ************************************************************************************************************************** changed: [172.16.60.234] changed: [172.16.60.233] to retry, use: --limit @ /etc/ansible/haha .retry PLAY RECAP *************************************************************************************************************************************** 172.16.60.233 : ok=3 changed=2 unreachable=0 failed=1 172.16.60.234 : ok=3 changed=2 unreachable=0 failed=1 如上執行結果,即便playbook執行中有task任務執行失敗,可是執行成功的task任務所調用的handler依然會被強制觸發並執行!可是執行失敗的task任務所調用的handler依然不會被執行。 即handlers中的task1會被執行,task2不會被執行! |
2. tags任務標籤
tags用於讓用戶選擇運行playbook中的部分代碼。ansible具備冪等性,所以會自動跳過沒有變化的部分,即使如此,有些代碼爲測試其確實沒有發生變化的時間依然會很是地長。此時若是確信其沒有變化,就能夠經過tags跳過此些代碼片段。tags能夠看做是ansible的任務控制!
ansible的標籤(Tags)功能能夠給角色(Roles)、文件、單獨的任務,甚至整個Playbook打上標籤,而後利用這些標籤來指定要運行Playbook中的個別任務,或不執行指定的任務。若是有一個很大的playbook劇本,而只想運行playbook其中的某個或部分task任務,而不是運行playbook中全部的任務,這個時候tags是你的最佳選擇。
2.1 ansible支持"tags:"屬性,執行playbook時,能夠經過兩種方式根據"tags"過濾任務:
1. 在命令行上,使用或選項"--tags或 --skip-tags",後面使用空格或"="均可以。
2. 在ansible配置設置中,使用和選項"TAGS_RUN或TAGS_SKIP";
3. 可使用"--list-tags"查看playbook中有哪些tags會被執行;
2.2 ansible系統中內置的特殊tags(目前有5個特殊的tags)
到ansible 2.5版本之後,目前系統內置的tags有如下幾個:
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。
執行ansible-playbook命令時,使用下面兩個參數的含義(自定義的tags能夠是單個,也能夠是多個,多個之間使用逗號隔開):
"--tags 自定義的tag" 表示執行tags爲指定的標籤名的tasks和tags爲always的tasks。若是執行命令ansible-playbook site.yml 時不指定tags,則會執行全部tags爲非never的tasks
"--skip-tags 自定義tag" 表示執行全部非指定tag和非never的tasks
2.3 tags標籤配置語法有下面三種:
1 2 3 4 5 6 7 8 9 |
語法一: tags: - tag_test 語法二: tags: tag_test 語法三: tags: [ 'tag_test' ] |
2.3 ansible的tags使用
1)最多見的使用形式。一個task任務添加一個tags標籤。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
官方示例以下: [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 |
此時若是但願只run其中的某個task,則run的時候指定tags便可。能夠運行多個tags,中間使用逗號隔開;也能夠運行單個tags。
1 2 3 4 5 6 7 |
[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任務。
1 2 3 |
[root@localhost ansible] # ansible-playbook example.yml --skip-tags configuration 或者 [root@localhost ansible] # ansible-playbook example.yml --skip-tags=configuration |
具體看下面示例(tags三種語法都用上):
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 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
[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' ] 只運行make_task1標籤的task任務 [root@localhost ansible] # ansible-playbook haha.yaml --tags make_task1 PLAY [test_host] ********************************************************************************************************************************* TASK [task1] ************************************************************************************************************************************* changed: [172.16.60.234] PLAY RECAP *************************************************************************************************************************************** 172.16.60.234 : ok=1 changed=1 unreachable=0 failed=0 運行多個tags [root@localhost ansible] # ansible-playbook haha.yaml --tags make_task1,make_task2 PLAY [test_host] ********************************************************************************************************************************* TASK [task1] ************************************************************************************************************************************* changed: [172.16.60.234] TASK [task2] ************************************************************************************************************************************* changed: [172.16.60.234] PLAY RECAP *************************************************************************************************************************************** 172.16.60.234 : ok=2 changed=2 unreachable=0 failed=0 跳過make_task2標籤的任務,其餘任務正常執行 [root@localhost ansible] # ansible-playbook haha.yaml --skip-tags make_task2 PLAY [test_host] ********************************************************************************************************************************* TASK [task1] ************************************************************************************************************************************* changed: [172.16.60.234] TASK [task3] ************************************************************************************************************************************* changed: [172.16.60.234] PLAY RECAP *************************************************************************************************************************************** 172.16.60.234 : ok=2 changed=2 unreachable=0 failed=0 |
2)一個task任務添加多個tags標籤。
上面是一個task任務添加一個tags標籤,其實一個task任務能夠添加多個標籤,並且不一樣的task任務可使用相同的tags標籤。
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 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
一個任務添加多個tags標籤的語法仍然也有三種: 語法1: tags: - tag1 - tag2 語法2: tags: tag1,tag2 語法3: tags: [ 'tag1,tag2' ] ======================================================== 具體示例以下: [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 上面例子中每一個任務都有多個標籤,並且上例中兩個任務都有一個共同的標籤,就是httpd標籤。 因此當執行 "ansible-playbook httpd.yml --tags=httpd" 時,上面兩個task任務都會被執行。 因爲上面例子中的全部任務都有共同的httpd標籤,因此像這種狀況,能夠把httpd標籤提取出來並寫在play劇本中,示例以下: [root@localhost ansible] # vim https.yml --- - hosts: test_host remote_user: root tags:httpd tasks: - name: install httpd package tags: - package yum: name=httpd state=latest - name: start up httpd service tags: [ 'service' ] service: name: httpd state: started |
須要注意:當tags寫在play劇本中而非寫在task任務中時,play中的全部task任務都會繼續當前paly中的tags,就像上例中,兩個任務都會繼承httpds的tag標籤,同時還擁有本身的tag標籤。
3)內置的特殊tags的用法
上面已經介紹了5個內置的特殊的tags,每一個都有其自身的用意。以下以always關鍵字的tags爲例:若是把任務的tags值指定爲always時,那麼這個任務就老是被執行,除非使用"--skip-tags"選項明確指定不執行對應任務的tags標籤。
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 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
[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: - always - name: task3 file : path= /opt/task2 .txt src= /opt/task2 .txt dest= /opt/heihei state=link force= yes tags: [ 'link_task3' ] 執行1:以下,雖然tags指定了執行標籤爲make_task1的任務,可是因爲任務2的標籤有關鍵字always,因此任務2也會被執行,這就是always的做用! [root@localhost ansible] # ansible-playbook haha.yaml --tags=make_task1 PLAY [test_host] ********************************************************************************************************************************* TASK [task1] ************************************************************************************************************************************* changed: [172.16.60.234] TASK [task2] ************************************************************************************************************************************* changed: [172.16.60.234] PLAY RECAP *************************************************************************************************************************************** 172.16.60.234 : ok=2 changed=2 unreachable=0 failed=0 執行2: 只執行標籤爲always的任務 [root@localhost ansible] # ansible-playbook haha.yaml --tags always 或者 [root@localhost ansible] # ansible-playbook haha.yaml --tags=always PLAY [test_host] ********************************************************************************************************************************* TASK [task2] ************************************************************************************************************************************* changed: [172.16.60.234] PLAY RECAP *************************************************************************************************************************************** 172.16.60.234 : ok=1 changed=1 unreachable=0 failed=0 執行3: 跳過標籤爲always關鍵字的任務,這裏明確指出跳過執行always標籤。 [root@localhost ansible] # ansible-playbook haha.yaml --skip-tags always PLAY [test_host] ********************************************************************************************************************************* TASK [task1] ************************************************************************************************************************************* changed: [172.16.60.234] TASK [task3] ************************************************************************************************************************************* ok: [172.16.60.234] PLAY RECAP *************************************************************************************************************************************** 172.16.60.234 : ok=2 changed=1 unreachable=0 failed=0 其餘四個特殊的tags標籤在這裏就不作示例說明了。特殊tags標籤能夠在ansible-playbook命令執行時直接使用。 |
4)tags標籤能夠和role 結合使用
1 2 3 4 |
[root@localhost ansible] # cat test.yml --- roles: - { role: webserver, port: 5000, tags: [ 'web' , 'foo' ] } |
5)tags和include結合使用。
1 2 3 |
[root@localhost ansible] # cat test.yml --- - include: kevin.yml tags=web,foo |
如上,對一個include任務打了兩個tags標籤,直接執行"ansible_playbook test.yml" 或 "ansible_playbook test.yml --tags=web" 或 "ansible_playbook test.yml --tags=foo" 命令則會將kevin.yml文件中全部task任務都執行。
再來看看一個include結合tags的示例:經過指定標籤(tags),來講明是安裝tomcat7仍是tomcat8
tomcat.yml文件
1 2 3 4 5 |
--- - include: install_tomcat7.yml tags: tomcat7 - include: install_tomcat8.yml tags: tomcat8 |
install_tomcat7.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 |
--- - 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文件
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 |
--- - 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 &' |
下面開始執行命令:
1 2 3 4 5 |
安裝tomcat7: [root@localhost ansible] # ansible-playbook tomcat.yml --tags tomcat7 安裝tomcat8: [root@localhost ansible] # ansible-playbook tomcat.yml --tags tomcat8 |
這裏須要特別注意:
在以前ansible版本中使用include 整合多個roles至統一入口結合tags標籤來管理roles劇本,但在ansible2.8版本以後將會刪除include語法,更改成import_playbook。若是還使用include語法也能夠,只不過ansible-playbook執行結果中會有告警信息:"DEPRECATION WARNING]:'include' for playbook includes. You should use 'import_playbook' instead. This feature will be removed in version 2.8. Deprecation warnings can be disabled by setting deprecation_warnings=False in ansible.cfg."。因此,最好將上面tomcat.yml文件中的include語法改爲import_playbook,以下:
1 2 3 4 5 6 |
[root@localhost ansible] # cat tomcat.yml --- - import_playbook: install_tomcat7.yml tags: tomcat7 - import_playbook: install_tomcat8.yml tags: tomcat8 |
3. include用法
若是想在playbook中重複使用任務列表,則可使用include文件來執行此操做。 使用include的任務列表是定義系統將要實現的角色的好方法。主要清楚:ansible2.8版本以後include語法變成了import_playbook。若是仍是使用include,則不會影響執行結果,只不過是有告警信息。ansible也能夠將變量傳遞給include。示例以下:
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 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 |
示例1: 經過Include,能夠在playbook中引用另外一個playbook或者tasks ============================================================== [root@localhost ansible] # cat install_MysqlAndPhp.yml - yum: name: mysql state: present - yum: name: php-fpm state: present [root@localhost ansible] # cat lamp.yml --- - hosts: test_host remote_user: root gather_facts: no tasks: - include: install_MysqlAndPhp.yml - yum: name: httpd state: present [root@localhost ansible] # cat lnmp.yml --- - hosts: test_host remote_user: root gather_facts: no tasks: - include: install_MysqlAndPhp.yml - yum: name: nginx state: present 示例2: 能夠在handler中引用include ============================================================== [root@localhost ansible] # cat test_include.yml --- - hosts: test_host remote_user: root gather_facts: no tasks: - file : path: /opt/ttt state: touch notify: test include handlers handlers: - name: test include handlers include: include_handler.yml [root@localhost ansible] # cat include_handler.yml - debug: msg: "task1 of handlers" - debug: msg: "task2 of handlers" - debug: msg: "task3 of handlers" 示例3: when在include中使用 ============================================================== [root@localhost ansible] # cat /etc/ansible/hosts [db] 192.168.24.10 [app] 192.168.24.11 [root@localhost ansible] # cat install_client.yml --- - hosts: '` hosts `' user: ansible sudo : yes sudo_user:root roles: - install_client [root@localhost ansible] # cat roles/install_client/tasks/main.yml --- - include: db.yml when: "hosts == 'db'" - include: app.yml when: "hosts == 'app'" [root@localhost ansible] # cat roles/install_client/tasks/db.yml --- - name: Touchdb file shell: touch /tmp/db .txt [root@localhost ansible] # cat roles/install_client/tasks/app.yml --- - name: Touchdb file shell: touch /tmp/db .txt 執行命令: [root@localhost ansible] # ansible-playbook -i hosts install_client.yml --extra-vars "hosts=db" [root@localhost ansible] # ansible-playbook -i hosts install_client.yml --extra-vars "hosts=app" 示例4: 能夠在include中使用tags標籤,這個在上面已經介紹過了 ============================================================== |
4. role用法
角色(roles)是ansible自1.2版本開始引入的新特性,用於層次性,結構化地組織playbook。roles可以根據層次型結構自動裝載變量文件、tasks以及handlers等。要使用roles只須要在playbook中使用include指令便可。簡單的說,roles就是經過分別將變量、文件、任務、模塊及處理器放置於單獨的目錄中、並能夠便捷地include他們的一種機制。角色通常用於基於主機構建服務的場景中、但也能夠是用於構建守護進程等場景中。role主要做用是重用playbook,例如不管安裝什麼軟件都會安裝時間同步服務,那麼每一個playbook都要編寫ntp task,能夠將ntp task寫好,等到用的時候再調用就好了。ansible中將其組織成role,它有着固定的組織格式,以便playbook調用。
4.1 role層級目錄結構
role以特定的層級目錄結構進行組織的tasks、variables、handlers、templates、files等;至關於函數的調用把各個功能切割成片斷來執行。
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 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 |
roles/ role_name/:定義的role的名字 file /: 用於存放copy或script等模塊調用的函數 tasks/: 用於定義各類task,此目錄必定要有main.yml;其餘文件須要main.yml包含調用 handlers/: 用於定義各類handlers,此目錄必定要有main.yml;其餘文件須要main.yml包含調用 vars/: 用於定義variables,此目錄必定要有main.yml;其餘文件須要main.yml包含調用 templates/:存儲由template模塊調用的模板文本; meta/: 定義當前角色的特殊設定及其依賴關係,此目錄中至少應該有一個名爲main.yml的文件;其它的文件須要由main.yml進行 "包含" 調用; default/: 此目錄中至少應該有一個名爲main.yml的文件,用於設定默認變量; [root@localhost ansible] # ll roles/ total 40 drwkebor-kebor-kebo 8 root root 4096 Jul 29 22:13 web_Deploy drwkebor-kebor-kebo 8 root root 4096 May 7 2019 web_Deploy_af [root@localhost ansible] # ll roles/web_Deploy total 25 -rw-r--r-- 1 root root 45 May 7 2019 web_Deploy.yml drwkebor-kebor-kebo 2 root root 4096 Jul 10 19:09 defaults drwkebor-kebor-kebo 2 root root 4096 May 7 2019 handlers drwkebor-kebor-kebo 2 root root 4096 May 7 2019 meta drwkebor-kebor-kebo 2 root root 4096 Dec 26 19:42 tasks drwkebor-kebor-kebo 2 root root 4096 May 7 2019 templates drwkebor-kebor-kebo 2 root root 4096 May 7 2019 vars [root@localhost ansible] # ll roles/web_Deploy/tasks/ total 35 -rwkebor-kebor-kebo 1 root root 1542 Jun 24 2019 Auth.yml -rwkebor-kebor-kebo 1 root root 1482 Oct 11 16:13 StartService.yml -rwkebor-kebor-kebo 1 root root 963 Jun 18 2019 main.yml -rwkebor-kebor-kebo 1 root root 1415 May 7 2019 StopService.yml [root@localhost ansible] # cat roles/web_Deploy/tasks/main.yml --- - include_tasks: Auth.yml tags: userauth - include_tasks: StopService.yml tags: stopservice - include_tasks: StartService.yml tags: startservice [root@localhost ansible] # cat roles/web_Deploy/web_Deploy.yml --- - hosts: all roles: - web_Deploy =================================================================================== 再以下一個項目的role目錄結構: site.yml webservers.yml fooservers.yml roles/ common/ files/ templates/ tasks/ handlers/ vars/ defaults/ meta/ webservers/ files/ templates/ tasks/ handlers/ vars/ defaults/ meta/ 再看下目錄解釋: yml文件:用於定義此角色用到的各handler:在handler中使用include包含的其餘的handler文件也應該位於此目錄中; files目錄:存放由copy或script等模塊調用的文件; templates目錄:templates模塊會自動在此目錄中尋找Jinja2模板文件; tasks目錄:至少應該包含一個名爲main.yml的文件,其定義了此角色的任務列表;此文件可使用include包含其餘的位於此目錄中的task文件; handlers目錄:此目錄中應當包含一個main; vars目錄:應當包含一個main.yml文件,用於定義此角色用到的變量; meta目錄:應當包含一個main.yml文件,用於定義此角色的特殊設定及其依賴關係;ansible 1.3及其之後的版本才支持 default目錄:爲當前角色設定默認變量時使用此目錄;應當包含一個main.yml文件; 那麼一個playbook就能夠這樣寫: --- - hosts: webservers roles: - common - webservers 這個playbook爲一個角色 "kebo" 指定了以下的行爲: 若是 roles /kebo/tasks/main .yml 存在, 其中列出的tasks將被添加到play中 若是roles /kebo/handlers/main .yml 存在, 其中列出的handlers將被添加到play中 若是roles /kebo/vars/main .yml 存在, 其中列出的variables將被添加到play中 若是roles /kebo/meta/main .yml 存在, 其中列出的 "角色依賴" 將被添加到roles列表中 (1.3 andlater) 全部 copy tasks 能夠引用 roles /kebo/files/ 中的文件,不須要指明文件的路徑。 全部 scripttasks 能夠引用 roles /kebo/files/ 中的腳本,不須要指明文件的路徑。 全部 template tasks 能夠引用roles /kebo/templates/ 中的文件,不須要指明文件的路徑。 全部 include tasks 能夠引用roles /kebo/tasks/ 中的文件,不須要指明文件的路徑。 若是roles目錄下有文件不存在,這些文件將被忽略。好比 roles目錄下面缺乏了 "vars/" 目錄,這也不要緊。 須要注意: 仍然能夠在playbook中鬆散地列出tasks,vars_files 以及 handlers,這種方式仍然可用,可是roles是一種很好的具備組織性的功能特性,強烈建議使用它。 若是在playbook中同時使用roles和tasks,vars_files 或者 handlers,roles 將優先執行。 並且也可使用參數化的roles,這種方式經過添加變量來實現,好比: -- - hosts: webservers roles: - common - { role: foo_app_instance, dir : '/opt/a' , port: 5000 } - { role: foo_app_instance, dir : '/opt/b' , port: 5001 } 當一些事情不須要頻繁去作時,也能夠爲 roles 設置觸發條件,像這樣: --- - hosts: webservers roles: - { role: some_role, when: "ansible_os_family == 'RedHat'" } 它的工做方式是:將條件子句應用到 role 中的每個 task 上。 也能夠給role分配指定的標籤,好比: --- - hosts: webservers roles: - { role: foo, tags: [ "bar" , "baz" ] } 若是play仍然包含有 "tasks" section,這些 tasks 將在全部 roles 應用完成以後才被執行。也可定義一些tasks,讓它們在roles以前以及以後執行,能夠這樣作: --- - hosts: webservers pre_tasks: - shell: echo 'hello' roles: - { role: some_role } tasks: - shell: echo 'still busy' post_tasks: - shell: echo 'goodbye' 注意: pre_tasks: 執行正式 task 以前執行的任務 post_tasks:最後須要執行的任務 |
4.2 在playbook中調用role
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
role存放的路徑在配置文件 /etc/ansible/ansible .cfg中定義。以下,發現ansible的roles目錄定義到 /root/app/script/ansible/roles 路徑下了!! [root@localhost ansible] # cat /etc/ansible/ansible.cfg |grep roles_path roles_path = /etc/ansible/roles : /root/app/script/ansible/roles 在playbook中調用role的方式有三種,以下: 第一種: - hosts: HOSTS remote_user: root roles: - ROLE_NAME1 - ROLE_NAME2 第二種:除了字典第一個元素指明調用的role,後面是傳遞給role的變量 - hosts: HOSTS remote_user: root roles: - { role: ROLE_NAME1, VARIABLE1: VALUE1, ... } 第三種:when指明role調用的條件 - hosts: HOSTS remote_user: root roles: - { role: ROLE_NAME1, when: CONDITIONS } |
4.3 調用role示例
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 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 |
0) 先來看看role的路徑定義 [root@localhost ansible] # cat /etc/ansible/ansible.cfg|grep roles_path roles_path = /etc/ansible/roles : /etc/ansible/roles 1)目錄結構 [root@localhost ansible] # tree /etc/ansible/roles /etc/ansible/roles └── httpd #palybook調用時role的名稱 ├── defaults ├── files └── handlers │ └── main.yml #全部的目錄文件,並不必定要有,用時才建立 └── mata └── tasks │ └── main.yml └── tamplates └── httpd.conf.c6.j2 #centos6,centos7的配置文件 └── httpd.conf.c7.j2 2)tasks文件 [root@localhost ansible] # cat /etc/ansible/roles/httpd/tasks/main.yml - name: install httpd package yum: name=httpd state=present - name: install configure file template: src=httpd.conf.c{{ ansible_distribution_major_version }}.j2 dest= /etc/httpd/conf/httpd .conf tags: instconf notify: restart httpd service - name: start httpd service service: name=httpd state=started enabled= true 3) handlers文件 [root@localhost ansible] # cat /etc/ansible/roles/httpd/handlers/main.yml - name: restart httpd service service: name=httpd state=restarted 4) 模板文件 [root@localhost ansible] # grep ^Listen /etc/ansible/roles/httpd/templates/httpd.conf.c6.j2 Lister {{ httpd_port }} 5) 變量 [root@localhost ansible] # cat /etc/ansible/roles/httpd/vars/main.yml httpd_port: 8088 6) playbook文件 [root@localhost ansible] # cat /etc/ansible/httpd_conf.yml --- - hosts: webservers remote_user: root roles: - { role: httpd } 7) 執行playbook文件,並查看httpd端口 [root@localhost ansible] # ansible-playbook -i /etc/ansible/hosts /etc/ansible/httpd_conf.yml [root@localhost ansible] # ansible -i /etc/ansible/hosts webservers -m shell -a "ss -tnlp|grep :80" ======================================================================================================== 再來看一例: 1.group: 建立用戶組nginx 2.user: 建立用戶nginx 3.yum: 安裝nginx 4.template: 配置文件更新nginx.conf 5.service: 啓動nginx [root@localhost ~] # cat /etc/ansible/ansible.cfg|grep roles_path roles_path = /etc/ansible/roles : /root/ansible/roles [root@localhost ~] # cd /root/ansible/roles/nginx [root@localhost nginx] # mkdir tasks templates [root@localhost nginx] # cd tasks [root@localhost tasks] # vim group.yml - name: create group nginx group: name=nginx gid=80 [root@localhost tasks] # vim user.yml -name: create user nginx user: name=nginx uid=80 group=nginx system= yes shell= /sbi/nologin [root@localhost tasks] # vim install.yml - name: install package yum: name=nginx [root@localhost tasks] # vim start.yml - name: start service service: name=nginx state=started enabled= yes [root@localhost tasks] # vim restart.yml - name: restart service service: name=nginx state=restarted [root@localhost tasks] # vim templ.yml - name: copy conf template: src=nginx.conf.j2 dest= /etc/nginx/conf/nginx .conf [root@localhost tasks] # vim main.yml - include: group.yml - include: user.yml - include: install .yml - include: templ.yml - include: start.yml [root@localhost tasks] # cd ../templates && ls nginx.conf.j2 [root@localhost tasks] # cd /root/ansible [root@localhost ansible] # vim nginx_role.yml - hosts: websrvs remote_user: root roles: - role: nginx 執行命令: [root@localhost ansible] # ansible-playbook nginx_role.yml |
5. loop列表循環用法
在ansible 2.5版本以前,大多數人習慣使用"with_X"風格的關鍵字操做循環,從ansible 2.6版本開始,官方開始推薦使用"loop"關鍵字代替"with_X"風格關鍵字。下面經過一些小示例來講明使用loop關鍵字進行的列表循環操做。[loop、with_items、with_list 三者等同,效果是同樣的!]。ansible的循環使用,能夠參考下面"循環變量"以及參考這裏
playbook中的變量設置
######## 變量的優先級 ########
1. extra vars變量(在命令行中使用 -e);優先級最高
2. 在inventory中定義的鏈接變量(好比ansible_ssh_user);優先級第二
3. 大多數的其餘變量(命令行轉換,play中的變量,include的變量,role的變量等);優先級第三
4. 在inventory定義的其餘變量;優先級第四
5. 有系統發現的facts;優先級第五
6. "role默認變量",這個是最默認的值,很容易喪失優先權。優先級最小。
另外:在inventory清單列表裏定義的變量:單個主機定義的變量優先級高於主機組定義的變量
通過實驗,ansible使用inventory定義變量的優先級順序從高到低爲:
1. host_vars下定義變量
2. inventory中單個主機定義變量
3. group_vars下定義變量
4. inventory中組定義變量
playbook中定義變量,以下:
1 2 3 |
- hosts: webservers vars: http_port: 80 |
YAML陷阱
YAML語法要求若是值以{{ foo }}開頭的話,那麼就須要將整行用雙引號包起來,這是爲了確認你不是想聲明一個YAML字典。
以下面配置是不行的!!!
1 2 3 4 |
--- - hosts: app_servers vars: app_path: {{ base_path }} /data/web |
應該改爲下面這樣:
1 2 3 4 |
--- - hosts: app_servers vars: app_path: "{{ base_path }}/data/web" |
######## Ansbile-playbook變量配置方法 ########
1. 在inventory主機清單文件中定義變量
能夠直接定義在主機清單文件/etc/ansible/hosts中,代表該變量只對對應的主機或者組有效,對其他的主機和組無效。
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 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 |
有針對單個主機定義變量和組定義變量兩種方式。 1)向不一樣的單個主機傳遞不一樣的變量; IP /HOSTNAME var1=value1 var2=value2 2)向組中的主機傳遞相同的變量; [groupname:vars] var1=value1 var2=value2 可是注意: 組定義變量的做用範圍是組下的全部主機。 當兩種定義方式同時存在時,ansible會優先採用單個主機定義的變量值! [root@ss-server ansible] # pwd /etc/ansible [root@ss-server ansible] # cat hosts|egrep -v "^#|^$" [kevin] 172.16.60.20 key=20180101 172.16.60.22 ansible_ssh_port=22288 key= "niubility" [root@ss-server ansible] # cat ansi.yml --- - hosts: kevin gather_facts: False tasks: - name: haha debug: msg= "the {{ inventory_hostname }} value is {{ key }}" 執行結果(注意inventory_hostname表明inventory列表列表裏被控節點的主機名): [root@ss-server ansible] # ansible-playbook ansi.yml PLAY [kevin] ************************************************************************************************************************************* TASK [haha] ************************************************************************************************************************************** ok: [172.16.60.20] => { "msg" : "the 172.16.60.20 value is 20180101" } ok: [172.16.60.22] => { "msg" : "the 172.16.60.22 value is niubility" } PLAY RECAP *************************************************************************************************************************************** 172.16.60.20 : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 172.16.60.22 : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 再看下面一示例 [root@ss-server ansible] # tail -n 10 /etc/ansible/hosts [webserver] 172.16.60.51 dir = /root/node2 172.16.60.80 dir = /root/node1 [node1] 172.16.60.80 [webserver:vars] file = hostname .txt [root@ss-server ansible] # cat playbook.yml --- - hosts: webserver remote_user: root tasks: - name: Create New Folder file : name={{ dir }} state=directory - name: Create New Folder shell: echo ` hostname ` > {{ dir }}/{{ file }} 執行結果: [root@ss-server ansible] # ansible-playbook playbook.yml PLAY [webserver] ************************************************************************ TASK [Gathering Facts] *************************************************************** ok: [172.16.60.80] ok: [172.16.60.51] TASK [Create New Folder] ************************************************************* changed: [172.16.60.51] changed: [172.16.60.80] TASK [Create New Folder] ************************************************************* changed: [172.16.60.51] changed: [172.16.60.80] PLAY RECAP *************************************************************************** 172.16.60.51 : ok=3 changed=2 unreachable=0 failed=0 172.16.60.80 : ok=3 changed=2 unreachable=0 failed=0 |
此外:ansible還內置了一些固定的主機變量名,在inventory中定義其值, 在另外一篇文章中介紹過。
2. 經過host_vars和group_vars目錄來定義變量
/etc/ansible/目錄是linux系統上ansible默認的配置文件目錄(Mac系統上的話,其默認配置目錄是在/usr/local/etc/ansible/),在該目錄下建立host_vars和group_vars兩個目錄用來存放定義變量的文件。
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 40 41 42 43 44 45 46 47 48 49 50 51 52 |
1)針對單個主機的變量 [root@ss-server ansible] # pwd /etc/ansible [root@ss-server ansible] # cat host_vars/172.16.60.20 --- user: root pass: root@123 2)針對 test 組的變量 [root@ss-server ansible] # cat group_vars/kevin --- user: work pass: work@123 ############ 在inventory清單列表文件裏,單個主機定義的變量優先級高於主機組定義的變量 ############ ############ 通過實驗,ansible使用變量的優先級順序從高到低爲 ############# 1. host_vars下定義變量 2. inventory中單個主機定義變量 3. group_vars下定義變量 4. inventory中組定義變量 示例以下: [root@ss-server ~] # cat /root/ansible/hosts [kevin] 172.16.60.20 ansible_ssh_port=22222 172.16.60.21 ansible_ssh_port=22288 [root@ss-server ~] # cat /root/ansible/group_vars/kevin key=20191010 [root@ss-server ~] # cat /root/ansible/bo.yml --- - hosts: kevin remote_user: root tasks: - debug: msg= 'The key is {{key}} ' [root@ss-server ~] # ansible-playbook /root/ansible/bo.yml PLAY [kevin] ************************************************************************************************************************************* TASK [haha] ************************************************************************************************************************************** ok: [172.16.60.20] => { "msg" : "The key is 20191010" } ok: [172.16.60.22] => { "msg" : "The key is 20191010" } PLAY RECAP *************************************************************************************************************************************** 172.16.60.20 : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 172.16.60.22 : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 |
3. 經過var_files定義變量
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 |
[root@ss-server ansible] # cat laoji.yml --- key: jiayou [root@ss-server ansible] # cat bo.yml --- - hosts: kevin gather_facts: False vars_files: - laoji.yml tasks: - name: display debug: msg= "the {{ inventory_hostname }} valus is {{ key }}" 執行結果: [root@ss-server ansible] # ansible-playbook bo.yml PALY [kevin] **************************************************** TASK [display] **************************************************** ok: [172.16.60.20] => { "changed" : false "msg" : "the 172.16.60.20 value is jiayou" } PLAY RECAP **************************************************** 172.16.60.20 : ok=1 changed=0 unreachable=0 failed=0 |
4. 經過vars_prompt交互式傳入變量
在playbook中定義vars_prompt的變量名和交互式提示信息,就能夠實如今運行playbook時,經過交互的傳入變量值。
private字段:用來定義交互時是否回顯輸入的值,默認private爲yes;
default字段:用來定義變量的默認值。
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 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 |
[root@ss-server ansible] # cat prom.yml --- - hosts: kevin remote_user: root vars_prompt: - name: "var1" prompt: "please input you name" private: no - name: "var2" prompt: "please input you age" private: yes default: 'kevin var' tasks: - name: display var1 debug: msg= "your name of var1 is {{ var1 }}" - name: display var2 debug: msg= "you age of var2 is {{ var2 }}" 執行結果: [root@ss-server ansible] # ansible-playbook prom.yml your name of var1: wangzhaojun #把輸入的內容傳遞給變量var1。輸入的值顯示出來!! you age of var2 [kevin var]: #把輸入的內容傳遞給默認變量kevin var。可是輸入的值不顯示出來!! 好比這裏輸入的30 PALY [kevin] **************************************************** TASK [Gathering Facts] **************************************************** OK: [172.16.60.20] TASK [display var1] **************************************************** ok: [172.16.60.20] =>{ "msg" : "youn name of var1 is wangzhaojun" } TASK [display var2] **************************************************** ok: [172.16.60.20] =>{ "msg" : "youn name of var2 is 30" } PLAY RECAP **************************************************** 172.16.60.20 : ok=3 changed=0 unreachable=0 failed=0 接下來再來看一個 "ansible 中prompt 交互變量的使用" 的示例 [root@ss-server ansible] # cat haha.yml --- - hosts: kevin remote_user: root vars_prompt: - name: "your_name" prompt: "what is your name" private: no - name: "your_age" prompt: "how old are you" private: no - name: "solution" prompt: "Choose the solution you want \n A: solutionA\n B: solutionB\n C: solutionC\n" private: no default: A - name: "user_name" prompt: "Enter user name" private: no - name: "user_password" prompt: "Enter user password" private: no encrypt: "sha512_crypt" confirm: yes tasks: - name: "output vars" debug: msg= "your name is {{ your_name }},you are {{ your_age }} years old" - name: "output solution" debug: msg= "the final solution is {{solution}}" - name: "create_user" user: name: "{{user_name}}" password: "{{user_password}}" - name: "debug_create user" debug: msg= "create user {{user_name}} in" 執行結果爲: [root@ss-server ansible] # ansible-playbook haha.yml what is your name: wangshibo how old are you: 29 Choose the solution you want A: solutionA B: solutionB C: solutionC [A]: C Enter user name: bobo Enter user password: bobo123 confirm Enter user password: bobo123 PLAY [kevin] ************************************************************************************************************************************* TASK [Gathering Facts] *************************************************************************************************************************** ok: [172.16.60.20] TASK [output vars] ******************************************************************************************************************************* ok: [172.16.60.20] => { "msg" : "your name is wangshibo,you are 29 years old" } TASK [output solution] *************************************************************************************************************************** ok: [172.16.60.20] => { "msg" : "the final solution is C" } TASK [create_user] ******************************************************************************************************************************* changed: [172.16.60.20] TASK [debug_create user] ************************************************************************************************************************* ok: [172.16.60.20] => { "msg" : "create user bobo in" } PLAY RECAP *************************************************************************************************************************************** 172.16.60.20 : ok=5 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 |
5. 經過ansible-playbook命令行定義變量!即參數傳入變量
除了"vars_prompt"和"vars_files",也能夠經過Ansible命令行發送變量。若是想要編寫一個通用的發佈playbook時則特別有用!你能夠傳遞應用的版本以便部署。例以下面命令(注意: --extra-vars 相等於 -e)
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 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 |
[root@ss-server ~] # ansible-playbook release.yml --extra-vars "version=1.78.34 other_variable=fos" 其餘場景中,經過參數傳入變量也是頗有用的。好比爲playbook設置主機羣組或用戶。以下: [root@ss-server ~] # vim exap.yml --- - hosts: '{{hosts}}' remote_user: '{{user}}' tasks: - name: "一個測試" debug: msg= "your hosts is {{hosts}}, user is {{user}}" 執行的時候,經過參數傳入變量(-e)。變量{{hosts}}能夠是主機羣組名稱,也能夠是主機ip。 [root@ss-server ansible] # ansible-playbook exap.yml -e "hosts=kevin user=root" [WARNING]: Found variable using reserved name: hosts PLAY [kevin] ************************************************************************************************************************************* TASK [Gathering Facts] *************************************************************************************************************************** ok: [172.16.60.20] TASK [一個測試] ************************************************************************************************************************************** ok: [172.16.60.20] => { "msg" : "your hosts is kevin, user is root" } PLAY RECAP *************************************************************************************************************************************** 172.16.60.20 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 在命令行裏面傳值的方法: [root@ss-server ansible] # ansible-playbook amp.yml --extra-vars "hosts=webserver user=root" 還可使用json格式傳遞參數: [root@ss-server ansible] # ansible-playbook amp.yml --extra-vars "{'hosts':'webserver', 'user':'root'}" 還能夠將參數放在文件裏面進行傳遞(注意命令行裏要是用 "@文件名" ): [root@ss-server ansible] # ansible-playbook amp.yml --extra-vars "@anhui.yml" [root@ss-server ansible] # cat anhui.yml --- hosts: webserver user: root 例以下面這個添加用戶的plakbook劇本配置,用傳遞了json文件: [root@ss-server ansible] # cat useradd.yml --- - hosts: "{{ host }}" gather_facts: no remote_user: root vars: UserName: "{{ user }}" UserPassword: "{{ pass }}" tasks: - name: create new user {{ UserName }} user: name={{ UserName }} shell= /bin/bash password={{ UserPassword |password_hash( 'sha512' ) }} update_password=always append= yes - name: Config /etc/sudoers lineinfile: dest= /etc/sudoers state=present line= '{{ item }}' validate= 'visudo -cf %s' with_items: - "{{ user }} ALL=(ALL) NOPASSWD:ALL,!/bin/rm,!/bin/su,!/usr/bin/passwd,!/usr/sbin/visudo,!/sbin/shutdown,!/sbin/reboot,!/sbin/halt" - "Defaults: {{ user }} !requiretty" [root@ss-server ansible] # ansible-playbook useradd.yml -e "host=172.16.60.20 user=kevin_bo pass=kevin@bo123" 在上例中,變量pass是密碼,若是變量pass裏有特殊的字符,或者變量pass是一串數組的話,它將被轉義。若不想被轉義,可使用以下方法: [root@ss-server ansible] # cat user.json host: webserver #ansible裏面定義的主機組或者直接配置主機ip,如172.16.60.20 user: kevin_bo #添加的用戶名 pass: 'Fxx6unM$R%I$Jna&' #添加的用戶的密碼,能夠用百度上隨機密碼生成器生成 指定user,json文件執行劇本 (使用JSON格式的文件便可,-e 傳遞變量,優先級最高) [root@ss-server ansible] # ansible-playbook useradd.yml -e "@user.json" 刪除web組中全部用戶 [root@ss-server ansible] # ansible webserver -m user -a 'name=zhangsan state=absent remove=yes' |
6. 在playbook劇本中定義變量
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 40 41 42 |
在playbook中定義變量須要用到Ansible的vars模塊,能夠將全部須要用到的變量統一在vars模塊下定義,定義格式須要遵循YAML語言格式: vars: - var1: value1 - var2: value2 - var3: value3 - ....: ..... 示例以下: [root@ss-server ansible] # cat playbook.yml --- - hosts: kevin remote_user: root vars: - dir1: /root/Ansible - dir2: /root/Ansible/test1 - dir3: /root/Ansible/test2 tasks: - name: Create New Folder file : name={{ dir1 }} state=directory - name: Create New Folder file : name={{ dir2 }} state=directory - name: Create New Folder file : name={{ dir3 }} state=directory [root@ss-server ansible] # ansible-playbook playbook.yml PLAY [kevin] ************************************************************************* TASK [Gathering Facts] *************************************************************** ok: [172.16.60.20] TASK [Create New Folder] ************************************************************* changed: [172.16.60.20] TASK [Create New Folder] ************************************************************* changed: [172.16.60.20] TASK [Create New Folder] ************************************************************* changed: [172.16.60.20] PLAY RECAP *************************************************************************** [172.16.60.20] : ok=4 changed=3 unreachable=0 failed=0 |
7. 經過roles角色定義變量
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 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
在Ansible的roles中定義變量,須要將變量及值的鍵值對形式寫到roles的vars目錄下的main.yml文件中,一樣適用YAML語言格式,格式以下: var1: value1 var2: value2 var3: value3 可是請注意: 經過Roles定義的變量只適用於當前roles。以下是roles文件組織結構: [root@ss-server roles] # tree test/ test / ├── files ├── handlers ├── playbook.retry ├── playbook.yml ├── tasks │ └── main.yml ├── templates └── vars └── main.yml 5 directories, 4 files [root@ss-server roles] # cat test/tasks/main.yml #任務文件 - name: Get IP Address shell: echo `{{ cmd }}` >> {{ dir }}/{{ file }} [root@ss-server roles] # cat test/vars/main.yml #定義變量cmd cmd: hostname -I [root@ss-server roles] # cat test/playbook.yml --- - hosts: webserver remote_user: root roles: - test hosts清單列表裏定義的變量,適用於全部roles。 [root@ss-server roles] # cat /etc/ansible/hosts [webserver] 172.16.60.51 dir = /root/node2 172.16.60.80 dir = /root/node1 [node1] 172.16.60.80 [webserver:vars] file = hostname .txt playbook調用Roles,執行結果爲: [root@Centos7T test ] #ansible-playbook playbook.yml PLAY [websvr] ************************************************************************ TASK [Gathering Facts] *************************************************************** ok: [172.16.60.80] ok: [172.16.60.51] TASK [ test : Get IP Address] ********************************************************* changed: [172.16.60.51] changed: [172.16.60.80] PLAY RECAP *************************************************************************** 172.16.60.51 : ok=2 changed=1 unreachable=0 failed=0 172.16.60.80 : ok=2 changed=1 unreachable=0 failed=0 |
8. 使用Facts獲取的信息
還有其它地方能夠獲取變量, 這些變量是自動發現的,而不是用戶本身設置的。Facts經過訪問遠程系統獲取相應的信息,一個很好的例子就是遠程主機的IP地址或者操做系統是什麼。
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 |
使用如下命令能夠查看哪些信息是可用的(kevin是上面在 /etc/ansible/hosts 列表文件中配置的主機羣組): [root@ss-server ansible] # ansible kevin -m setup [root@ss-server ansible] # ansible kevin -m setup|grep "ansible_python_version" "ansible_python_version" : "2.7.5" , 能夠在playbook中這樣引用上面被控制主機的python版本: {{ ansible_python_version }} [root@ss-server ansible] # ansible kevin -m setup|grep "ansible_nodename" "ansible_nodename" : "ss-server" , 能夠在playbook中這樣引用上面被控制主機的主機名: {{ ansible_nodename }} [root@ss-server ansible] # ansible kevin -m setup|grep "ansible_hostname" "ansible_hostname" : "ss-server" , 被控制主機的主機名變量還能夠是: {{ ansible_hostname }} 訪問複雜變量數據 有些提供的facts, 好比網絡信息等, 是一個嵌套的數據結構。訪問它們使用簡單的 {{ foo }} 語法並不夠用, 可是也仍然很容易.以下所示: {{ ansible_eth0[ "ipv4" ][ "address" ] }} 或者這樣寫: {{ ansible_eth0.ipv4.address }} ############ 若是關閉Facts,能夠大大提升ansible的執行速度 ########### 關閉方法以下: [root@ss-server ansible] # cat anhui.yml --- - hosts: kevin gather_facts: no |
9. register註冊變量
變量的另外一個主要用途是在運行命令時,把命令結果存儲到一個變量中,不一樣模塊的執行結果是不一樣的。運行playbook時使用-v選項能夠看到可能的結果值,ansible執行任務的結果值能夠保存在變量中,以便稍後使用它。register方式主要用於在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 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 |
示例以下: [root@ss-server ansible] # cat /etc/ansible/hosts [kevin] 172.16.60.237 172.16.60.238 [root@ss-server ansible] # cat /root/register.yml --- - hosts: kevin remote_user: root tasks: - name: register bo_test shell: hostname -I register: info - name: display info debug: msg= "this host ip is {{ info }}" [root@ss-server ansible] # ansible-playbook /root/register.yml PLAY [kevin] ************************************************************************************************************************************* TASK [Gathering Facts] *************************************************************************************************************************** ok: [172.16.60.238] ok: [172.16.60.237] TASK [register bo_test] ************************************************************************************************************************** changed: [172.16.60.238] changed: [172.16.60.237] TASK [display info] ****************************************************************************************************************************** ok: [172.16.60.237] => { "msg" : "this host ip is {'stderr_lines': [], u'changed': True, u'end': u'2019-12-15 22:07:18.431549', 'failed': False, u'stdout': u'172.16.60.237 ', u'cmd': u'hostname -I', u'rc': 0, u'start': u'2019-12-15 22:07:18.408235', u'stderr': u'', u'delta': u'0:00:00.023314', 'stdout_lines': [u'172.16.60.237 ']}" } ok: [172.16.60.238] => { "msg" : "this host ip is {'stderr_lines': [], u'changed': True, u'end': u'2019-12-15 22:07:18.430108', 'failed': False, u'stdout': u'172.16.60.238 ', u'cmd': u'hostname -I', u'rc': 0, u'start': u'2019-12-15 22:07:18.407184', u'stderr': u'', u'delta': u'0:00:00.022924', 'stdout_lines': [u'172.16.60.238 ']}" } PLAY RECAP *************************************************************************************************************************************** 172.16.60.237 : ok=3 changed=1 unreachable=0 failed=0 172.16.60.238 : ok=3 changed=1 unreachable=0 failed=0 這裏注意下: register定義的info變量在第二個task中用來查看前一個task中執行的 hostname 命令的結果。 能夠看到playbook運行後的結果中,info返回的是一段python字典數據,若是隻想看到stdout部分的信息的話,能夠經過info[‘stdout’]來引用。 [root@ss-server ansible] # cat /root/register.yml --- - hosts: kevin remote_user: root tasks: - name: register bo_test shell: hostname -I register: info - name: display info debug: msg= "this host ip is {{ info['stdout'] }}" [root@ss-server ansible] # ansible-playbook /root/register.yml PLAY [kevin] ************************************************************************************************************************************* TASK [Gathering Facts] *************************************************************************************************************************** ok: [172.16.60.238] ok: [172.16.60.237] TASK [register bo_test] ************************************************************************************************************************** changed: [172.16.60.237] changed: [172.16.60.238] TASK [display info] ****************************************************************************************************************************** ok: [172.16.60.237] => { "msg" : "this host ip is 172.16.60.237 " } ok: [172.16.60.238] => { "msg" : "this host ip is 172.16.60.238 " } PLAY RECAP *************************************************************************************************************************************** 172.16.60.237 : ok=3 changed=1 unreachable=0 failed=0 172.16.60.238 : ok=3 changed=1 unreachable=0 failed=0 |
10. hostvars 變量
該變量用於引用其餘主機上收集的facts中的數據,或者引用其餘主機的主機變量、主機組變量。即從一臺遠程主機獲取另外一臺遠程主機的變量。
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 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 |
以下示例: [root@ss-server ansible] # cat /etc/ansible/hosts [kevin] 172.16.60.237 addr=beijing 172.16.60.238 user=shibo age=39 [root@ss-server ansible] # cat test.yml --- - hosts: kevin remote_user: root gather_facts: False tasks: - name: this is test1 debug: msg= "She is come from {{ hostvars['172.16.60.237']['addr'] }}" - name: this is test2 debug: msg= "I am {{ hostvars['172.16.60.238']['user'] }}, and age is {{ hostvars['172.16.60.238']['age'] }}" 或者將 test .yml文件配置以下,即由 "[變量]" " 改成 " .變量" 兩種配置的執行結果都是同樣的! [root@ss-server ansible] # cat test.yml --- - hosts: kevin remote_user: root gather_facts: False tasks: - name: this is test1 debug: msg= "She is come from {{ hostvars['172.16.60.237'].addr }}" - name: this is test2 debug: msg= "I am {{ hostvars['172.16.60.238'].user }}, and age is {{ hostvars['172.16.60.238'].age }}" 執行結果爲: [root@ss-server ansible] # ansible-playbook test.yml PLAY [kevin] ************************************************************************************************************************************* TASK [this is test1] ***************************************************************************************************************************** ok: [172.16.60.237] => { "msg" : "She is come from beijing" } ok: [172.16.60.238] => { "msg" : "She is come from beijing" } TASK [this is test2] ***************************************************************************************************************************** ok: [172.16.60.237] => { "msg" : "I am shibo, and age is 39" } ok: [172.16.60.238] => { "msg" : "I am shibo, and age is 39" } PLAY RECAP *************************************************************************************************************************************** 172.16.60.237 : ok=2 changed=0 unreachable=0 failed=0 172.16.60.238 : ok=2 changed=0 unreachable=0 failed=0 ############################# 這裏須要注意下 ########################### 除了上面的配置,還能夠以下配置,可是請注意: 1)debug後面必須使用 "var" 字段,即hostvar變量傳遞給var字段的變量。 2)var=hostvars[....],等於兩邊不能有空格! [root@ss-server ansible] # cat test.yml --- - hosts: kevin remote_user: root gather_facts: False tasks: - name: this is test1 debug: var=hostvars[ '172.16.60.237' ][ 'addr' ] - name: this is test2 debug: var=hostvars[ '172.16.60.238' ][ 'user' ] 或者將 test .yml文件配置以下,這兩個配置方法的執行結果是同樣的! [root@ss-server ansible] # cat test.yml --- - hosts: kevin remote_user: root gather_facts: False tasks: - name: this is test1 debug: var=hostvars[ '172.16.60.237' ].addr - name: this is test2 debug: var=hostvars[ '172.16.60.238' ].user 執行結果爲: [root@ss-server ansible] # ansible-playbook test.yml PLAY [kevin] ************************************************************************************************************************************* TASK [this is test1] ***************************************************************************************************************************** ok: [172.16.60.237] => { "hostvars['172.16.60.237']['addr']" : "beijing" } ok: [172.16.60.238] => { "hostvars['172.16.60.237']['addr']" : "beijing" } TASK [this is test2] ***************************************************************************************************************************** ok: [172.16.60.237] => { "hostvars['172.16.60.238']['user']" : "shibo" } ok: [172.16.60.238] => { "hostvars['172.16.60.238']['user']" : "shibo" } PLAY RECAP *************************************************************************************************************************************** 172.16.60.237 : ok=2 changed=0 unreachable=0 failed=0 172.16.60.238 : ok=2 changed=0 unreachable=0 failed=0 注意:若是同一個name裏配置了多個debug,則默認執行最後一個debug內容! (多個task的話,也是執行最後一個task) [root@ss-server ansible] # cat test.yml --- - hosts: kevin remote_user: root gather_facts: False tasks: - name: this is test1 debug: var=hostvars[ '172.16.60.237' ][ 'addr' ] - name: this is test2 debug: var=hostvars[ '172.16.60.238' ][ 'user' ] debug: var=hostvars[ '172.16.60.238' ][ 'age' ] 執行結果: [root@ss-server ansible] # ansible-playbook test.yml [WARNING]: While constructing a mapping from /etc/ansible/test .yml, line 8, column 7, found a duplicate dict key (debug). Using last defined value only. PLAY [kevin] ************************************************************************************************************************************* TASK [this is test1] ***************************************************************************************************************************** ok: [172.16.60.237] => { "hostvars['172.16.60.237']['addr']" : "beijing" } ok: [172.16.60.238] => { "hostvars['172.16.60.237']['addr']" : "beijing" } TASK [this is test2] ***************************************************************************************************************************** ok: [172.16.60.237] => { "hostvars['172.16.60.238']['age']" : "39" } ok: [172.16.60.238] => { "hostvars['172.16.60.238']['age']" : "39" } PLAY RECAP *************************************************************************************************************************************** 172.16.60.237 : ok=2 changed=0 unreachable=0 failed=0 172.16.60.238 : ok=2 changed=0 unreachable=0 failed=0 |
11. 列表變量、循環變量、字典變量
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 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 |
1)ansible的變量不只能夠是單個的值,也能夠爲列表,即ansible傳列表做爲變量。以下示例: ################################################################################################################# [root@ss-server ansible] # vim test.yml --- - hosts: test_host gather_facts: no vars: - list: [1,2,3] tasks: - name: echo debug: msg= "{{ list }}" 執行結果: [root@ss-server ansible] # ansible-palybook test.yml TASK [ echo ] ******************************************************************** ok: [172.16.60.220] => { "msg" : [ 1, 2, 3 ] } 再來看一例: linux建立用戶,須要獲取的變量有用戶名,用戶密碼,用戶組,有時候須要建立多個用戶,那麼傳遞給ansible的用戶確定是列表,但每一組又有用戶名、密碼、組這些變量值。 作法以下: [root@ss-server ~] # cat /etc/ansible/test.yml --- - hosts: test_host gather_facts: no tasks: - name: create or update account user: name={{ item.user }} password={{ item.password }} groups ={{ item.group }} system=no with_items: - '{{ user_list }}' 執行結果: [root@ss-server ansible] # ansible-playbook /etc/ansible/test.yml -e '{"user_list":[{"user":"user1","password":"*******","group":"user1"}]}' ################################################################################################################# 2)循環列表 結合循環,這個特性就變得頗有用;以參數傳遞列表給playbook,不用在playbook中固定循環的次數與內容。以下示例: [root@ss-server ansible] # vim test.yml --- - hosts: test_host gather_facts: no vars: - list: [1,2,3] tasks: - name: this is loop debug: msg= "{{ item }}" with_items: '{{list}}' 執行結果: [root@ss-server ansible] # ansible-palybook test.yml TASK [this is loop] ******************************************************************** ok: [172.16.60.220] => (item=1) => { "item" : 1, "msg" : 1 } ok: [localhost] => (item=2) => { "item" : 2, "msg" : 2 } ok: [localhost] => (item=3) => { "item" : 3, "msg" : 3 } 接着看下面一例: loop 關鍵字表示循環,去讀循環體裏的變量固定使用{{item}},item是個字典對象item.key=value。 須要注意:下面 test .yml文件中的 "loop" 關鍵字 改成 "with_items" 關鍵字,效果是同樣的! ansible的循環用法:在ansible 2.5版本以前,大多數人習慣使用 "with_X" 風格的關鍵字操做循環, 從ansible 2.6版本開始,官方開始推薦使用 "loop" 關鍵字代替 "with_X" 風格關鍵字。 [root@ss-server ~] # cat /etc/ansible/test.yml --- - name: this is test hosts: test_host connection: local gather_facts: no tasks: - name: debug loop debug: msg: "{{item.A1}}" loop: #這裏將"loop"關鍵字 改成 "with_items"關鍵字,效果是同樣的! - A: a A1: a1 A2: a2 - B: b A1: b1 A2: b2 - C: c A1: c1 A2: c2 - D: d A1: d1 A2: d2 執行結果:以上loop下的四個變量分別稱爲一塊,即一個item,符號 "-" 爲循環體塊的標誌,{{item.A1}}的值,即分別爲a1,b1,c1,d1 [root@ss-server ~] # ansible-playbook /etc/ansible/test.yml PLAY [this is test ] ********************************************************************************************************************************* TASK [debug loop] ******************************************************************************************************************************** ok: [172.16.60.20] => (item={u 'A' : u 'a' , u 'A1' : u 'a1' , u 'A2' : u 'a2' }) => { "msg" : "a1" } ok: [172.16.60.20] => (item={u 'A1' : u 'b1' , u 'B' : u 'b' , u 'A2' : u 'b2' }) => { "msg" : "b1" } ok: [172.16.60.20] => (item={u 'A1' : u 'c1' , u 'C' : u 'c' , u 'A2' : u 'c2' }) => { "msg" : "c1" } ok: [172.16.60.20] => (item={u 'A1' : u 'd1' , u 'A2' : u 'd2' , u 'D' : u 'd' }) => { "msg" : "d1" } PLAY RECAP *************************************************************************************************************************************** 172.16.60.20 : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 再來看一例: [root@ss-server ~] # cat /etc/ansible/test.yml --- - name: this is test hosts: test_host connection: local gather_facts: no vars: my_list: - a - b - c - 1 tasks: - name: debug loop output debug: msg: "The {{index}} one is {{item}}" loop: "{{my_list}}" # 或者使用with_items: "{{my_list}}" 或者 with_list: "{{my_list}}" loop_control: index_var: index 執行結果: [root@ss-server ~] # ansible-playbook /etc/ansible/test.yml PLAY [this is test ] ****************************************************************************************************************************** TASK [debug loop output] ************************************************************************************************************************* ok: [172.16.60.20] => (item=a) => { "msg" : "The 0 one is a" } ok: [172.16.60.20] => (item=b) => { "msg" : "The 1 one is b" } ok: [172.16.60.20] => (item=c) => { "msg" : "The 2 one is c" } ok: [172.16.60.20] => (item=1) => { "msg" : "The 3 one is 1" } PLAY RECAP *************************************************************************************************************************************** 172.16.60.20 : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 ################################################################################################################# 3)字典變量 變量也能夠爲字典。以下示例, 用到了ansible的循環,循環關鍵字是 "with_X" , 改成loop關鍵字,效果是同樣的! 注意:在變量中使用循環時,vars下必需要有 "-" ,符號 "-" 爲循環體塊的標誌!! [root@ss-server ansible] # vim test.yml --- - hosts: test_host gather_facts: no vars: - lists: list1: [1,2,3] list2: [4,5] tasks: - name: loop debug: msg= "{{ item }}" with_items: '{{lists["list1"]}}' #替換爲 loop: '{{lists["list1"]}}', 或者 with_list: '{{lists["list1"]}}' 效果是同樣的 執行結果: [root@ss-server ansible] # ansible-palybook test.yml TASK [loop] ******************************************************************** ok: [172.16.60.220] => (item=1) => { "item" : 1, "msg" : 1 } ok: [localhost] => (item=2) => { "item" : 2, "msg" : 2 } ok: [localhost] => (item=3) => { "item" : 3, "msg" : 3 } 接着看下面一例: [root@ss-server ~] # cat /etc/ansible/test.yml --- - hosts: test_host gather_facts: no vars: - users : name: [xiaoming] address: [anhui] age: [28] tasks: - name: this is loop debug: msg= "{{ item }}" loop: '{{users["name"]}}' [root@ss-server ~] # ansible-playbook /etc/ansible/test.yml PLAY [test_host] ************************************************************************************************************************************* TASK [this is loop] ************************************************************************************************************************************** ok: [172.16.60.20] => (item=xiaoming) => { "msg" : "xiaoming" } PLAY RECAP *************************************************************************************************************************************** 172.16.60.20 : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 上面的示例,若是要想打印多個字典變量,修改以下: [root@ss-server ~] # cat /etc/ansible/test.yml --- - hosts: test_host gather_facts: no vars: - users : name: [xiaoming] address: [anhui] age: [28] tasks: - name: this is loop debug: msg= "{{ item }}" loop: #這裏用loop,with_items,with_list均可以 - '{{users["name"]}}' - '{{users["address"]}}' - '{{users["age"]}}' 執行結果: [root@ss-server ~] # ansible-playbook /etc/ansible/test.yml PLAY [test_host] ********************************************************************************************************************************* TASK [this is loop] ****************************************************************************************************************************** ok: [172.16.60.20] => (item=[u 'xiaoming' ]) => { "msg" : [ "xiaoming" ] } ok: [172.16.60.20] => (item=[u 'anhui' ]) => { "msg" : [ "anhui" ] } ok: [172.16.60.20] => (item=[28]) => { "msg" : [ 28 ] } PLAY RECAP *************************************************************************************************************************************** 172.16.60.20 : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 |
###### 能夠在一個yaml文件裏放置多個hosts,將多個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 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 |
[root@ss-server ansible] # cat /etc/ansible/hosts 172.16.60.237 [kevin] 172.16.60.238 [grace] 172.16.60.236 [root@ss-server ansible] # cat bo.yml --- - hosts: kevin remote_user: root gather_facts: False tasks: - name: this is test1 shell: hostname -I - hosts: 172.16.60.237 remote_user: root tasks: - name: this is test2 debug: msg= "this server is {{ info }} " - hosts: 172.16.60.238 remote_user: root tasks: - name: this is test3 debug: msg= "this key is {{ haha }} " 執行結果: [root@ss-server ansible] # ansible-playbook bo.yml -e "{'info':'my server','haha':'123123213123'}" PLAY [kevin] ************************************************************************************************************************************* TASK [this is test1] ***************************************************************************************************************************** changed: [172.16.60.238] PLAY [172.16.60.237] ***************************************************************************************************************************** TASK [Gathering Facts] *************************************************************************************************************************** ok: [172.16.60.237] TASK [this is test2] ***************************************************************************************************************************** ok: [172.16.60.237] => { "msg" : "this server is my server " } PLAY [172.16.60.238] ***************************************************************************************************************************** TASK [Gathering Facts] *************************************************************************************************************************** ok: [172.16.60.238] TASK [this is test3] ***************************************************************************************************************************** ok: [172.16.60.238] => { "msg" : "this key is 123123213123 " } PLAY RECAP *************************************************************************************************************************************** 172.16.60.237 : ok=2 changed=0 unreachable=0 failed=0 172.16.60.238 : ok=3 changed=1 unreachable=0 failed=0 ############# 再來看下面一個測試環境用過的部署腳本配置 ######################### [root@localhost ansible] # cat /opt/ansible_cfg/deploy.yml --- - hosts: webservers tasks: - name: Installed Httpd Server yum: name=httpd state=present - name: Start Httpd Server systemd: name=httpd state=started enabled= yes - name: Start Firewalld Server systemd: name=firewalld state=started enabled= yes - name: Configure Firewalld Server firewalld: service=http immediate= yes permanent= yes state=enabled - hosts: web01 tasks: - name: Configure web01 Website copy: content= 'This is Web01' dest= /var/www/html/index .html - hosts: web02 tasks: - name: Cofnigure webi-2 weisite copy: content= 'This is Web02' dest= /var/www/html/index .html - hosts: nfs01 tasks: - name: Install NFS-utils Server yum: name=nfs-utils state=present - name: Configure Nfs-utils Server copy: src=. /exports .j2 dest= /etc/exports owner=root group=root mode=0644 - name: Create NFS Group group: name=www gid=666 - name: Create NFS User user: name=www uid=666 group=www create_home=no shell= /sbin/nologin - name: Create Data Directory file : path= /data state=directory owner=www group=www mode=0755 recurse= yes - name: Start NFS Server systemd: name=nfs state=started enabled= yes - hosts: nfs01 tasks: - name: Mount NFS Server mount : path= /opt src=172.16.60.23: /data fstype=nfs opts=defaults state=mounted |
###### Ansible-playbook如何正確獲取ip ######
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 |
[root@ansible ~] # vim /etc/ansible/hosts_all.yaml --- - hosts: all tasks: - name: 將原有的hosts文件備份 shell: mv /etc/hosts /etc/hosts_bak - name: 將ansible端的hosts複製到各自機器上 copy: src= /root/hosts dest= /etc/ owner=root group=root mode=0644 - name: 在新的hosts文件後面追加各自機器內網ip和 hostname lineinfile: dest= /etc/hosts line= "`ansible_all_ipv4_addresses` `ansible_hostname`" 可是執行完ansible-playbook以後,ansible客戶機器上的 /etc/hosts 文件裏ip和主機名對應關係以下( cat /etc/hosts ): 127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4 ::1 localhost localhost.localdomain localhost6 localhost6.localdomain6 [u '172.16.60.210' ] redis-fun01.kevin.cn 實際想要的結果是( cat /etc/hosts ): 127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4 ::1 localhost localhost.localdomain localhost6 localhost6.localdomain6 172.16.60.210 redis-fun01.kevin.cn 解決辦法: 調整ansible服務端的hosts_all.yaml文件中獲取ip的變量 變量用 IP: "{{ ansible_eth0['ipv4']['address'] }}" ,而不是`ansible_all_ipv4_addresses` 修改後的yaml文件配置以下: [root@ansible ~] # vim /etc/ansible/hosts_all.yaml --- - hosts: all vars: IP: "{{ ansible_eth0['ipv4']['address'] }}" tasks: - name: 將原有的hosts文件備份 shell: mv /etc/hosts /etc/hosts_bak - name: 將ansible端的hosts複製到各自機器上 copy: src= /root/hosts dest= /etc/ owner=root group=root mode=0644 - name: 在新的hosts文件後面追加各自機器內網ip和 hostname lineinfile: dest= /etc/hosts line= "`IP` `ansible_hostname`" |
######## 獲取ansible清單列表裏對應組的ip、指定機器執行操做 [ --list-hosts、--limit ] ########
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 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 |
注意下面兩個參數的使用: 1)獲取hosts清單文件裏指定組內的ip,使用 "--list-hosts" 2)指定hosts清單文件裏的ip執行操做,使用 "--limit" 以下是ansible的一個清單文件: [root@localhost ~] # cat /opt/kevin-bo.cfg [kevin-bo_F] 172.16.60.65 [kevin-bo_A] 172.16.60.140 172.16.60.141 [kevin-bo:children] kevin-bo_D kevin-bo_F kevin-bo_A [kevin-bo:vars] deploy_path= /opt/web/kevin-bo/ start_time_out=90 stop_time_out=60 module=kevin-bo [kevin-bo_D] 172.16.60.195 如今須要獲取 "kevin-bo_A" 和 "kevin-bo_D" 組下的ip,--list-hosts後面加不加引號均可以。 [root@localhost ~] # ansible -i /opt/kevin-bo.cfg --list-hosts kevin-bo_A hosts (2): 172.16.60.140 172.16.60.141 [root@localhost ~] # ansible -i /opt/kevin-bo.cfg --list-hosts "kevin-bo_A"|grep -v "hosts" 172.16.60.140 172.16.60.141 [root@localhost ~] # ansible -i /opt/kevin-bo.cfg --list-hosts kevin-bo_D|grep -v "hosts" 172.16.60.195 獲取多個機器組內的ip,中間使用逗號隔開 [root@localhost ~] # ansible -i /opt/kevin-bo.cfg --list-hosts "kevin-bo_A,kevin-bo_D" hosts (3): 172.16.60.140 172.16.60.141 172.16.60.195 [root@localhost ~] # ansible -i /opt/kevin-bo.cfg --list-hosts "kevin-bo_A,kevin-bo_D"|grep -v "hosts" 172.16.60.140 172.16.60.141 172.16.60.195 在執行ansible-playbook時,能夠指定單個ip或group,也能夠指定多個ip或group,也能夠一塊兒指定ip和group,多箇中間使用逗號隔開! --limit後面加不加引號均可以。 # ansible-playbook -i 清單文件 yml文件 --limit ip # ansible-playbook -i 清單文件 yml文件 --limit ip1,iP2,ipn # ansible-playbook -i 清單文件 yml文件 --limit group # ansible-playbook -i 清單文件 yml文件 --limit group1,group2,groupn # ansible-playbook -i 清單文件 yml文件 --limit ip1,ip2,group1,groupn 還能夠將制定的ip或group放在一個文件裏,如ip.txt,而後--limit後面跟 "@ip.txt" # ansible-playbook -i 列表文件 yml文件 --limit @ip.txt # cat ip.txt 172.16.60.140 172.16.60.141 kevin-bo_F 如上,須要對清單文件 "kevin-bo_A" 組下的機器進行發佈操做,因爲發佈過程當中涉及服務啓停,爲了保證發佈中總體服務不中斷,須要一臺一臺的執行,不能全部機器一塊兒執行。以下: [root@localhost ~] # vim deploy.sh #!/bin/bash #設置變量,傳參等 BRANCH=$1 MODULE_NAME=$2 PRODUCT_PATH=$3 USER=$4 APP_NANE=${Deploy_App} ..... for Next_Deploy_IP in $(ansible -i /opt/kevin-bo .cfg --list-hosts kevin-bo_A| grep - v "hosts" ) do ansible-playbook -i /opt/kevin-bo .cfg /root/ansible/web_deploy .yml --limit "${Next_Deploy_IP}" -e "user=${USER} app_name=${APP_NANE} package_name=... ..." if [ $? - eq 0 ]; then echo "[`date +%Y%m%d-%H%M%S`]++++++++++++++++++++++++${Next_Deploy_IP}部署成功!++++++++++++++++++++++++++++++" sleep 10 else echo "[`date +%Y%m%d-%H%M%S`]++++++++++++++++++++++++${Next_Deploy_IP}部署失敗!++++++++++++++++++++++++++++++" exit 1 fi done |