Ansible-playbook--配置及使用


一、playbook簡介

1.1、playbook基礎介紹

playbook 是 ansible 用於配置,部署,和管理被控節點的劇本。
通過 playbook 的詳細描述,執行其中的一系列 tasks ,可以讓遠端主機達到預期的狀態。playbook 就像 Ansible 控制器給被控節點列出的的一系列 to-do-list ,而被控節點必須要完成

play: 定義的是主機的角色
task: 定義的是具體執行的任務
playbook: 由一個或多個play組成,一個play可以包含多個task任務

15420965513860

1.2、playbook優勢

1)功能比ad-hoc更全
2)能很好的控制先后執行順序, 以及依賴關系
3)語法展現更加的直觀
4)ad-hoc無法持久使用,playbook可以持久使用

1.3、playbook語法

采用的語法格式是YAML(Yet Another Markup Language)。YAML語法能夠簡單的表示散列表,字典等數據結構

1.3.1、yaml語法格式

縮進: YAML使用一個固定的縮進風格表示層級結構,每個縮進由兩個空格組成, 不能使用tabs;
冒號: 以冒號結尾的除外,其他所有冒號后面所有必須有空格;
短橫線: 表示列表項,使用一個短橫杠加一個空格。多個項使用同樣的縮進級別作為同一列表;

Ansible-playbook采用YAML語法編寫。連續的項目(即列表)用 -減號來表示,key/value(字典)用冒號:分隔。

1)列表:每一個列表成員前面都要有一個短橫線和一個空格

fruits:
    - Apple
    - Orange
    - Strawberry
    - Mango
 
或者:
fruits: ['Apple', 'Orange', 'Strawberry', 'Mango']

2)字典:每一個成員由鍵值對組成,注意冒號后面要有空格

martin:
    name: Martin D'vloper
    job: Developer
    skill: Elite
或者
martin: {name: Martin D'vloper, job: Developer, skill: Elite}

3)列表與字典混合使用

-  martin:
    name: Martin D'vloper
    job: Developer
    skills:
      - python
      - perl
      - pascal
-  tabitha:
    name: Tabitha Bitumen
    job: Developer
    skills:
      - lisp
      - fortran
      - erlang

1.3.2、playbook語法特性

1)以 --- (三個減號)開始,必須頂行寫;
2)次行開始寫Playbook的內容,但是一般要求寫明該playbook的功能;
3)嚴格縮進,並且不能用Tab鍵縮進;
4)縮進級別必須是一致的,同樣的縮進代表同樣的級別,程序判別配置的級別是通過縮進結合換行來實現的;
5)K/V的值可同行寫,也可換行寫。同行使用 :分隔,換行寫需要以 - 分隔;

1.4、playbook基礎組件

Hosts:運行執行任務(task)的目標主機
remote_user:在遠程主機上執行任務的用戶
tasks:任務列表
handlers:任務,與tasks不同的是只有在接受到通知時才會被觸發
templates:使用模板語言的文本文件,使用jinja2語法。
variables:變量,變量替換{{ variable_name }}

1.5、簡單示例

[root@localhost ~]# cat httpd.yaml
---
- hosts: control-node    #將要執行任務的主機,已經在hosts文件中定義好了,可是單個主機或主機組
  remote_user: root      #在目標主機上執行任務時的用戶身份
  vars:
    - pkg: httpd
  tasks:
    - name: "install httpd package."
      yum: name={{ pkg }}  state=installed
    - name: "copy httpd configure file to remote host."
      copy: src=/root/conf/httpd.conf dest=/etc/httpd/conf/httpd.conf
      notify: restart httpd     #當這個任務執行狀態發生改變時,觸發handlers執行.
    - name: "boot httpd service."
      service: name=httpd state=started
  handlers:                     #handlers與tasks是同一級別
    - name: restart httpd
      service: name=httpd state=restarted

1.6、playbook命令及調用方式

用法:ansible-playbook  <filename.yml> ... [options]

<filename.yml>: yaml格式的playbook文件路徑,必須指明
[options]: 選項

Options:
--ask-vault-pass    
             #ask for vault password
             #加密playbook文件時提示輸入密碼
  -C, --check         
             #don't make any changes; instead, try to predict some of the changes that may occur
             #模擬執行,不會真正在機器上執行(查看執行會產生什么變化)。即並不在遠程主機上執行,只是測試。
  -D, --diff          
             #when changing (small) files and templates, show the differences in those files; works great with --check
             #當更新的文件數及內容較少時,該選項可顯示這些文件不同的地方,該選項結合-C用會有較好的效果
  -e EXTRA_VARS, --extra-vars=EXTRA_VARS
             #set additional variables as key=value or YAML/JSON
             #在Playbook中引入外部參數變量
  --flush-cache       
             #clear the fact cache
             #清理fact緩存,將fact清除到的遠程主機緩存
  --force-handlers    
             #run handlers even if a task fails
             #強制運行handlers的任務,即使在任務失敗的情況下
  -f FORKS, --forks=FORKS
             #specify number of parallel processes to use(default=5)
             #並行任務數。FORKS被指定為一個整數,默認是5
  -h, --help          
             #show this help message and exit
             #打開幫助文檔API
  -i INVENTORY, --inventory-file=INVENTORY
             #specify inventory host path (default=/etc/ansible/hosts) or comma separated host list.
             #指定要讀取的Inventory清單文件
  -l SUBSET, --limit=SUBSET
             #further limit selected hosts to an additional pattern
             #限定執行的主機范圍
  --list-hosts        
             #outputs a list of matching hosts; does not execute anything else
             #列出執行匹配到的主機,但並不會執行任何動作。
  --list-tags         
             #list all available tags
             #列出所有可用的tags
  --list-tasks        
             #list all tasks that would be executed
             #列出所有即將被執行的任務
  -M MODULE_PATH, --module-path=MODULE_PATH
             #specify path(s) to module library (default=None)
             #要執行的模塊的路徑
  --new-vault-password-file=NEW_VAULT_PASSWORD_FILE
             #new vault password file for rekey
             #
  --output=OUTPUT_FILE
             #output file name for encrypt or decrypt; use - for stdout
             #
  --skip-tags=SKIP_TAGS
             #only run plays and tasks whose tags do not match these values
             #跳過指定的tags任務
  --start-at-task=START_AT_TASK
             #start the playbook at the task matching this name
             #從第幾條任務(START_AT_TASK)開始執行
  --step              
             #one-step-at-a-time: confirm each task before running
             #逐步執行Playbook定義的任務,並經人工確認后繼續執行下一步任務
  --syntax-check      
             #perform a syntax check on the playbook, but do not execute it
             #檢查Playbook中的語法書寫,並不實際執行
  -t TAGS, --tags=TAGS
             #only run plays and tasks tagged with these values
             #指定執行該tags的任務
  --vault-password-file=VAULT_PASSWORD_FILE
             #vault password file
             #
  -v, --verbose       
             #verbose mode (-vvv for more, -vvvv to enable connection debugging)
             #執行詳細輸出
  --version           
             #show program's version number and exit
             #顯示版本
  
  ############Connection Options,即下面時連接權限############
    control as whom and how to connect to hosts
  
    -k, --ask-pass    
             #ask for connection password
             #
    --private-key=PRIVATE_KEY_FILE, --key-file=PRIVATE_KEY_FILE
             #use this file to authenticate the connection
             #
    -u REMOTE_USER, --user=REMOTE_USER
             #connect as this user (default=None)
             #指定遠程主機以USERNAME運行命令
    -c CONNECTION, --connection=CONNECTION
             #connection type to use (default=smart)
             #指定連接方式,可用選項paramiko (SSH)、ssh、local,local方式常用於crontab和kickstarts
    -T TIMEOUT, --timeout=TIMEOUT
             #override the connection timeout in seconds(default=10)
             #SSH連接超時時間設定,默認10s
    --ssh-common-args=SSH_COMMON_ARGS
             #specify common arguments to pass to sftp/scp/ssh (e.g.ProxyCommand)
             #
    --sftp-extra-args=SFTP_EXTRA_ARGS
             #specify extra arguments to pass to sftp only (e.g. -f, -l)
             #
    --scp-extra-args=SCP_EXTRA_ARGS
             #specify extra arguments to pass to scp only (e.g. -l)
             #
    --ssh-extra-args=SSH_EXTRA_ARGS
             #specify extra arguments to pass to ssh only (e.g. -R)
             #
  
  ############Privilege Escalation Options, 即下面時權限提升權限############
    control how and which user you become as on target hosts
  
    -s, --sudo        
             #run operations with sudo (nopasswd) (deprecated, use become)
             #相當於Linux系統下的sudo命令
    -U SUDO_USER, --sudo-user=SUDO_USER
             #desired sudo user (default=root) (deprecated, use become)
             #使用sudo,相當於Linux下的sudo命令
    -S, --su          
             #run operations with su (deprecated, use become)
             #
    -R SU_USER, --su-user=SU_USER
             #run operations with su as this user (default=root)(deprecated, use become)
    -b, --become      
             #run operations with become (does not imply password prompting)
             #
    --become-method=BECOME_METHOD
             #privilege escalation method to use (default=sudo),valid choices: [ sudo | su | pbrun | pfexec | doas |dzdo | ksu | runas ]
             #
    --become-user=BECOME_USER
             #run operations as this user (default=root)
             #
    --ask-sudo-pass   
             #ask for sudo password (deprecated, use become)
             #傳遞sudo密碼到遠程主機,來保證sudo命令的正常運行
    --ask-su-pass     
             #ask for su password (deprecated, use become)
             #
    -K, --ask-become-pass
             #ask for privilege escalation password
             #

注意的命令

1)檢查語法,只檢查是否是yaml語法格式。並不做邏輯校驗。(常使用)
# ansible-playbook --syntax-check test.yml
2)模擬執行(不是真的執行)
# ansible-playbook -C test.yml

關閉facts

---
- hosts: webserver
  gather_facts: no

二、playbook組件詳解

2.1、variable--變量定義

1)定義在hosts文件中

主機變量:
192.168.200.136 http_port=808 maxRequestsPerChild=808
192.168.200.137 http_port=8080 maxRequestsPerChild=909
 
主機組變量:
[websers]
192.168.200.136
192.168.200.137
 
[websers:vars] 
ntp_server=ntp.exampl.com
proxy=proxy.exampl.com

2)定義在playbook劇本中

- hosts: all
  vars:  #定義變量
    file_name: yaml_vars

  tasks:
  - name: # {{ file_name }}引用上面定義的變量
    file: path=/tmp/{{ file_name }} state=touch

3)使用facts變量

facts變量是由setup模塊獲取遠程主機的信息。
# ansible 192.168.200.136 -m setup

4)命令行傳參

使用 -e或--extra-vars選項傳入參數
# ansible-playbook 192.168.200.136 -e "httpd_port=808" httpd04.yml
# ansible-playbook f2.yml --extra-vars "file_name=bgx_extra-vars"

5)變量定義優先級

1.extra-vars外置傳參的優先級最高 [所有執行的主機都生效]
2.定義在yml文件中的優先級其次 [所有執行的主機都生效]
3.hosts文件中定義的變量優先級最低 [當前主機組定義會生效]

6)變量引用

{{ var_name }}

7)變量注冊

注冊變量: register關鍵字可以存儲指定命令的輸出結果到一個自定義的變量中

[root@Manager playbook]#cat variableRegister.yml 
---
- hosts: web
  tasks:
    - name: print status
      shell: netstat -lntp
      register: System_Status

    - name: Get System_Status
      debug: msg={{System_Status.stdout_lines}}

[root@Manager playbook]#ansible-playbook --syntax-check variableRegister.yml 

playbook: variableRegister.yml
[root@Manager playbook]#ansible-playbook  variableRegister.yml 

PLAY [web] ***********************************************************************************************************

TASK [Gathering Facts] ***********************************************************************************************
ok: [172.16.93.165]

TASK [print status] **************************************************************************************************
changed: [172.16.93.165]

TASK [Get System_Status] *********************************************************************************************
ok: [172.16.93.165] => {
    "msg": [
        "Active Internet connections (only servers)", 
        "Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name    ", 
        "tcp        0      0 127.0.0.1:8005          0.0.0.0:*               LISTEN      31952/java          ", 
        "tcp        0      0 0.0.0.0:8009            0.0.0.0:*               LISTEN      31952/java          ", 
        "tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN      3927/nginx: master  ", 
        "tcp        0      0 0.0.0.0:8080            0.0.0.0:*               LISTEN      31952/java          ", 
        "tcp        0      0 0.0.0.0:2812            0.0.0.0:*               LISTEN      17247/sshd          ", 
        "tcp        0      0 0.0.0.0:10050           0.0.0.0:*               LISTEN      18814/zabbix_agentd ", 
        "tcp6       0      0 :::3306                 :::*                    LISTEN      5993/mysqld         ", 
        "tcp6       0      0 :::21                   :::*                    LISTEN      1846/vsftpd         "
    ]
}

PLAY RECAP ***********************************************************************************************************
172.16.93.165              : ok=3    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

2.2、templates--模板功能

template只能在palybook中使用。采用了jinga2語法,jinga2基本語法如下:

字面量:
  字符串:使用單引號或雙引號
  數字:整型,浮點數
  列表:{item1,item2,...}
  字典:{key1:value1,key2:value2,...}
  布爾型:true/false
算術運算:
  +,-,*,/,//,%,**
比較運算:
  ==,!=,>,>=,<,<=
邏輯運算:
  and,or,not

示例如下:

1)定義模板

[root@server tmp]# mv nginx.conf nginx.conf.j2
[root@server tmp]# vim nginx.conf.j2
    worker_processes  {{ ansible_processor_vcpus }};
    listen       {{ nginxport }};

2)修改劇本,編輯nginx.yml文件

2.3、handlers--任務觸發

在需要被監控的任務(tasks)中定義一個notify,只有當這個任務被執行時,才會觸發notify對應的handlers去執行相應操作。例如配置文件被修改后,有可能需要重啟程序,此時我們可以配置一個handlers,類似觸發器。注意:handlers下的name名稱必須要和它對應的notify名稱相同!否則不會執行!!

[root@localhost ~]# cat httpd.yaml
---
- hosts: control-node
  remote_user: root
  vars:
    - pkg: httpd
  tasks:
    - name: "install httpd package."
      yum: name={{ pkg }}  state=installed
    - name: "copy httpd configure file to remote host."
      copy: src=/root/conf/httpd.conf dest=/etc/httpd/conf/httpd.conf
      notify: restart httpd
    - name: "boot httpd service."
      service: name=httpd state=started
  handlers:
    - name: restart httpd
      service: name=httpd state=restarted

注意事項

1)handlers只有在其所在的任務被執行完時,它才會被運行;如果一個任務中定義了notify調用Handlers,但由於條件判斷等原因,該任務未被執行,則Handlers同樣不會被執行。

2)handlers只會在Play的末尾運行一次;如果想在一個Playbook的中間運行handlers,則需要使用meta模塊來實現,例如:- meta: flush_handlers。

3)可以直接在Handlers中使用notify選項,實現Handlers調用Handlers。

4)可以使用listen關鍵字,在一個tasks任務中一次性notify多個handler。即將多個handler分為"一組",使用相同的"組名"即可,當notify對應的值為"組名"時,"組"內的所有handler都會被notify。

5)如果一個Play在運行到調用handlers的語句之前失敗了,那么這個handlers將不會被執行。但是可以使用mega模塊的--force-handlers選項來強制執行handlers,即使在handlers所在Play中途運行失敗也能執行。需要注意:--force-handlers參數主要針對即使playbook執行失敗,也要執行代碼塊成功了的handlers(即執行成功的task任務), 如果代碼塊本身執行失敗(即執行失敗的task任務),那么它所對應的handlers應當不會被執行!

6)handlers可以理解成另一種tasks,handlers是另一種"任務列表",可以理解handlers和tasks是"平級關系",所以他們的縮進相同。handlers的任務會被tasks中的任務進行"調用",但是,被"調用"並不意味着一定會執行,只有當tasks中的任務"真正執行"以后,handlers中被調用的任務才會執行,如果tasks中的任務並沒有做出任何實際的操作,那么handlers中的任務即使被"調用",也並不會執行。handlers中可以有多個任務,被tasks中不同的任務notify。

使用handlers的場景

1)headlers在所有tasks任務被執行完時才執行。

[root@Manager playbook]#cat handler1.yml 
---
- hosts: all
  remote_user: root
  tasks:
    - name: make file task1
      file: path=/tmp/task1.txt state=touch
      notify: task1
    - name: make file task2
      file: path=/tmp/task2.txt state=touch
      notify: task2
  handlers:
    - name: task1
      file: path=/tmp/task1.txt mode=777 owner=root group=root
    - name: task2
      file: src=/tmp/task2.txt dest=/tmp/heihei state=link force=yes

#執行結果
[root@Manager playbook]#ansible-playbook  handler1.yml 

PLAY [all] ***********************************************************************************************************

TASK [Gathering Facts] ***********************************************************************************************
ok: [172.16.93.165]
ok: [172.16.93.167]

TASK [make file task1] ***********************************************************************************************
changed: [172.16.93.165]
changed: [172.16.93.167]

TASK [make file task2] ***********************************************************************************************
changed: [172.16.93.165]
changed: [172.16.93.167]

RUNNING HANDLER [task1] **********************************************************************************************
changed: [172.16.93.165]
changed: [172.16.93.167]

RUNNING HANDLER [task2] **********************************************************************************************
changed: [172.16.93.165]
changed: [172.16.93.167]

PLAY RECAP ***********************************************************************************************************
172.16.93.165              : ok=5    changed=4    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
172.16.93.167              : ok=5    changed=4    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

2)使用meta模塊,headlers會在它所對應的task任務執行完后立即被觸發並執行,即在playbook的中間環節運行。

[root@Manager playbook]#cat handler2.yml 
---
- hosts: all
  remote_user: root
  tasks:
    - name: make file task1
      file: path=/tmp/task1.txt state=touch
      notify: task1
    - meta: flush_handlers  #添加
    - name: make file task2
      file: path=/tmp/task2.txt state=touch
      notify: task2
  handlers:
    - name: task1
      file: path=/tmp/task1.txt mode=777 owner=root group=root
    - name: task2
      file: src=/tmp/task2.txt dest=/tmp/heihei state=link force=yes

#運行結果
[root@Manager playbook]#ansible-playbook  handler2.yml 

PLAY [all] ***********************************************************************************************************

TASK [Gathering Facts] ***********************************************************************************************
ok: [172.16.93.165]
ok: [172.16.93.167]

TASK [make file task1] ***********************************************************************************************
changed: [172.16.93.167]
changed: [172.16.93.165]

RUNNING HANDLER [task1] **********************************************************************************************
changed: [172.16.93.167]
changed: [172.16.93.165]

TASK [make file task2] ***********************************************************************************************
changed: [172.16.93.165]
changed: [172.16.93.167]

RUNNING HANDLER [task2] **********************************************************************************************
changed: [172.16.93.165]
changed: [172.16.93.167]

PLAY RECAP ***********************************************************************************************************
172.16.93.165              : ok=5    changed=4    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
172.16.93.167              : ok=5    changed=4    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

3)Handlers調用Handlers

[root@Manager playbook]#cat handler3.yml
---
- hosts: all
  remote_user: root
  tasks:
    - name: make file task1
      file: path=/tmp/task1.txt state=touch
      notify: task1
    - name: make file task2
      file: path=/tmp/task2.txt state=touch
  handlers:
    - name: task1
      file: path=/tmp/task1.txt mode=777 owner=root group=root
      notify: task2
    - name: task2
      file: src=/tmp/task2.txt dest=/tmp/heihei state=link force=yes

#執行結果
[root@Manager playbook]#ansible-playbook handler3.yml 

PLAY [all] ***********************************************************************************************************

TASK [Gathering Facts] ***********************************************************************************************
ok: [172.16.93.165]
ok: [172.16.93.167]

TASK [make file task1] ***********************************************************************************************
changed: [172.16.93.167]
changed: [172.16.93.165]

TASK [make file task2] ***********************************************************************************************
changed: [172.16.93.165]
changed: [172.16.93.167]

RUNNING HANDLER [task1] **********************************************************************************************
changed: [172.16.93.165]
changed: [172.16.93.167]

RUNNING HANDLER [task2] **********************************************************************************************
changed: [172.16.93.165]
changed: [172.16.93.167]

PLAY RECAP ***********************************************************************************************************
172.16.93.165              : ok=5    changed=4    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
172.16.93.167              : ok=5    changed=4    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

#----------------------------------------------------------------------------------------------------

[root@Manager playbook]#cat handler3-2.yaml
---
- hosts: all
  remote_user: root
  tasks:
    - name: make file task1
      file: path=/tmp/task1.txt state=touch
      notify: task1
  handlers:
    - name: task1
      file: path=/tmp/task1.txt mode=777 owner=root group=root
      notify: task2
    - name: task2
      file: path=/tmp/task2.txt state=touch
      notify: task3
    - name: task3
      file: src=/tmp/task2.txt dest=/tmp/heihei state=link force=yes

#執行結果
[root@Manager playbook]#ansible-playbook handler3-2.yaml 

PLAY [all] ***********************************************************************************************************

TASK [Gathering Facts] ***********************************************************************************************
ok: [172.16.93.167]
ok: [172.16.93.165]

TASK [make file task1] ***********************************************************************************************
changed: [172.16.93.165]
changed: [172.16.93.167]

RUNNING HANDLER [task1] **********************************************************************************************
changed: [172.16.93.165]
changed: [172.16.93.167]

RUNNING HANDLER [task2] **********************************************************************************************
changed: [172.16.93.165]
changed: [172.16.93.167]

RUNNING HANDLER [task3] **********************************************************************************************
changed: [172.16.93.165]
changed: [172.16.93.167]

PLAY RECAP ***********************************************************************************************************
172.16.93.165              : ok=5    changed=4    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
172.16.93.167              : ok=5    changed=4    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

4)使用listen關鍵字,在一個tasks任務中一次性notify多個handler

listen的名稱要和notify名稱保持一致

[root@Manager playbook]#cat handler4.yml 
---
- hosts: all
  remote_user: root
  tasks:
    - name: make file task1
      file: path=/tmp/task1.txt state=touch
      notify: group_handler
  handlers:
    - name: task1
      listen: group_handler
      file: path=/tmp/task1.txt mode=777 owner=root group=root
    - name: task2
      listen: group_handler
      file: path=/tmp/task2.txt state=touch
    - name: task3
      listen: group_handler
      file: src=/tmp/task2.txt dest=/tmp/heihei state=link force=yes

#執行結果
[root@Manager playbook]#ansible-playbook handler4.yml 

PLAY [all] ***********************************************************************************************************

TASK [Gathering Facts] ***********************************************************************************************
ok: [172.16.93.167]
ok: [172.16.93.165]

TASK [make file task1] ***********************************************************************************************
changed: [172.16.93.167]
changed: [172.16.93.165]

RUNNING HANDLER [task1] **********************************************************************************************
changed: [172.16.93.167]
changed: [172.16.93.165]

RUNNING HANDLER [task2] **********************************************************************************************
changed: [172.16.93.167]
changed: [172.16.93.165]

RUNNING HANDLER [task3] **********************************************************************************************
changed: [172.16.93.167]
changed: [172.16.93.165]

PLAY RECAP ***********************************************************************************************************
172.16.93.165              : ok=5    changed=4    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
172.16.93.167              : ok=5    changed=4    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

5)使用--force-handlers選項來強制執行handlers

--force-handlers參數主要針對即使playbook執行失敗,也要執行代碼塊成功了的handlers(即執行成功的task任務), 如果代碼塊本身執行失敗(即執行失敗的task任務),那么它所對應的handlers應當不會被執行!

[root@Manager playbook]#cat handler5.yml 
---
- hosts: all
  remote_user: root
  tasks:
    - name: make file task1
      file: path=/tmp/task1.txt state=touch
      notify: task1
    - name: make file task2
      file: path=/tmp/lawrence/task2.txt state=touch
      notify: task2
  handlers:
    - name: task1
      file: path=/tmp/task1.txt mode=777 owner=root group=root
    - name: task2
      file: src=/tmp/task2.txt dest=/tmp/heihei state=link force=yes

#執行結果
[root@Manager playbook]#ansible-playbook handler5.yml 

PLAY [all] ***********************************************************************************************************

TASK [Gathering Facts] ***********************************************************************************************
ok: [172.16.93.165]
ok: [172.16.93.167]

TASK [make file task1] ***********************************************************************************************
changed: [172.16.93.167]
changed: [172.16.93.165]

TASK [make file task2] ***********************************************************************************************
fatal: [172.16.93.165]: FAILED! => {"changed": false, "msg": "Error, could not touch target: [Errno 2] No such file or directory: '/tmp/lawrence/task2.txt'", "path": "/tmp/lawrence/task2.txt"}
fatal: [172.16.93.167]: FAILED! => {"changed": false, "msg": "Error, could not touch target: [Errno 2] No such file or directory: '/tmp/lawrence/task2.txt'", "path": "/tmp/lawrence/task2.txt"}

RUNNING HANDLER [task1] **********************************************************************************************

PLAY RECAP ***********************************************************************************************************
172.16.93.165              : ok=2    changed=1    unreachable=0    failed=1    skipped=0    rescued=0    ignored=0   
172.16.93.167              : ok=2    changed=1    unreachable=0    failed=1    skipped=0    rescued=0    ignored=0   

#當沒使用--force-handlers,由於目錄/tmp/lawrence/不存在,導致task的第二個任務執行失敗,這個時候handler根本沒有被觸發,也就不會執行。即使第一個任務執行成功,但是它對應的第一個handler也不會被執行!!

#-------------------------------------------------------------------------------

#使用--force-handlers選項來強制執行handlers(強制執行的是:成功執行的task對應的handler)
[root@Manager playbook]#ansible-playbook handler5.yml --force-handlers

PLAY [all] ***********************************************************************************************************

TASK [Gathering Facts] ***********************************************************************************************
ok: [172.16.93.167]
ok: [172.16.93.165]

TASK [make file task1] ***********************************************************************************************
changed: [172.16.93.167]
changed: [172.16.93.165]

TASK [make file task2] ***********************************************************************************************
fatal: [172.16.93.165]: FAILED! => {"changed": false, "msg": "Error, could not touch target: [Errno 2] No such file or directory: '/tmp/lawrence/task2.txt'", "path": "/tmp/lawrence/task2.txt"}
fatal: [172.16.93.167]: FAILED! => {"changed": false, "msg": "Error, could not touch target: [Errno 2] No such file or directory: '/tmp/lawrence/task2.txt'", "path": "/tmp/lawrence/task2.txt"}

RUNNING HANDLER [task1] **********************************************************************************************
changed: [172.16.93.167]
changed: [172.16.93.165]

PLAY RECAP ***********************************************************************************************************
172.16.93.165              : ok=3    changed=2    unreachable=0    failed=1    skipped=0    rescued=0    ignored=0   
172.16.93.167              : ok=3    changed=2    unreachable=0    failed=1    skipped=0    rescued=0    ignored=0   

6)日常handler應用示例

#playbook安裝Apache示例
[root@m01 ~]# cat webserver.yml 
- hosts: web
  remote_user: root
#1.定義變量,在配置文件中調用
  vars:
    http_port: 8881

#2.安裝httpd服務
  tasks:
    - name: Install Httpd Server
      yum: name=httpd state=present

#3.使用template模板,引用上面vars定義的變量至配置文件中
    - name: Configure Httpd Server
      template: src=./httpd.conf dest=/etc/httpd/conf/httpd.conf
      notify: Restart Httpd Server

#4.啟動Httpd服務
    - name: Start Httpd Server
      service: name=httpd state=started enabled=yes

#5.檢查Httpd服務當前的運行的端口狀態
    - name: Get Httpd Server Port
      shell: netstat -lntp|grep httpd
      register: Httpd_Port

#6.輸出Httpd運行的狀態至面板
    - name: Out Httpd Server Status
      debug: msg={{ Httpd_Port.stdout_lines }}
      ignore_errors: yes

#6.如果配置文件發生變化會調用該handlers下面的模塊
  handlers:
    - name: Restart Httpd Server
      service: name=httpd state=restarted

2.4、tags--任務標簽

tags用於讓用戶選擇運行playbook中的部分代碼。ansible具有冪等性,因此會自動跳過沒有變化的部分,即便如此,有些代碼為測試其確實沒有發生變化的時間依然會非常地長。此時如果確信其沒有變化,就可以通過tags跳過此些代碼片斷。tags可以看作是ansible的任務控制

2.4.1、內置tag

always: 除非--skip-tags指定這個標簽,否則該標記為always的task一直都會執行。"--tags always"只執行標記了always的tasks;
never: 除非--tags指定了這個標簽,否則該標記為never的task一直都不會執行。"--tags never"執行標記了always和never的tasks;
tagged: --tags tagged表示執行所有有tags標簽的tasks任務,但不包括tags標簽是never的tasks任務;--skip-tags tagged表示所有有tags標簽的tasks任務都跳過,即不會執行。
untagged: --tags untagged表示執行所有沒有tags標簽的tasks任務和tags標簽為always的tasks任務;--skip-tags untagged效果相反!
all:--tags all表示執行所有的tags標簽為非never的task,包括有tags標簽和無tags標簽的tasks。

2.4.2、tag相關命令

"--tags 自定義的tag" :表示執行tags為指定的標簽名的tasks和tags為always的tasks。如果執行命令ansible-playbook site.yml 時不指定tags,則會執行所有tags為非never的tasks
"--skip-tags 自定義tag" :表示執行所有非指定tag和非never的tasks

2.4.3、tag配置語法

語法一:
tags:
  - tag_test
  
語法二:
tags: tag_test
  
語法三:
tags: ['tag_test']

#----------------------

#一個任務添加多個tags標簽的語法仍然也有三種:
語法1:
tags:
  - tag1
  - tag2
 
語法2:
tags: tag1,tag2
 
語法3:
tags: ['tag1,tag2']

2.4.4、tags使用場景

1)一個task任務添加一個tags標簽

#官方示例如下:
[root@localhost ansible]# vim example.yml
---
- hosts: all
  remote_user: root
  gather_facts: no
  tasks:
    - yum: name={{ item }} state=installed
      with_items:
         - httpd
         - memcached
      tags:
         - packages
    - template: src=templates/src.j2 dest=/etc/foo.conf
      tags:
         - configuration

#運行
[root@localhost ansible]# ansible-playbook example.yml --tags "configuration,packages"  
[root@localhost ansible]# ansible-playbook example.yml --tags configuration  
[root@localhost ansible]# ansible-playbook example.yml --tags packages
[root@localhost ansible]# ansible-playbook example.yml --tags="configuration,packages"  
[root@localhost ansible]# ansible-playbook example.yml --tags=configuration  
[root@localhost ansible]# ansible-playbook example.yml --tags=packages

#使用--skip-tags跳過某個task任務
[root@localhost ansible]# ansible-playbook example.yml --skip-tags configuration
[root@localhost ansible]# ansible-playbook example.yml --skip-tags=configuration

#-----------------------------------------------------------------------------------

[root@localhost ansible]# cat haha.yaml
---
- hosts: test_host
  remote_user: root
  gather_facts: no
  tasks:
    - name: task1
      file: path=/opt/task1.txt state=touch
      tags: make_task1
    - name: task2
      file: path=/opt/task2.txt state=touch
      tags:
         - make_task2
    - name: task3
      file: path=/opt/task2.txt src=/opt/task2.txt dest=/opt/heihei state=link force=yes
      tags: ['link_task3']

2)一個task任務添加多個tags標簽。

[root@localhost ansible]# vim https.yml
---
- hosts: test_host
  remote_user: root
  tasks:
     - name: install httpd package
       tags: 
         - httpd
         - package
       yum:
         name=httpd
         state=latest
  
     - name: start up httpd service
       tags: httpd,service
       service:
         name: httpd
         state: started

3)tags和include結合使用

通過指定標簽(tags),來說明是安裝tomcat7還是tomcat8

tomcat.yml文件:

---
- include: install_tomcat7.yml
  tags: tomcat7
- include: install_tomcat8.yml
  tags: tomcat8

install_tomcat7.yml文件:

---
- name: "復制文件到遠程主機"
  copy:
    src={{ item.src }}
    dest={{ item.dest }}
  with_items:
    - src: jdk-7u79-linux-x64.rpm
      dest: /usr/local/src/
    - src: java17.sh
      dest: /etc/profile.d/
- name: "安裝jdk"
  yum:
    name: /usr/local/src/jdk-7u79-linux-x64.rpm
    state: present
- name: "重新加載環境變量"
  shell: "source /etc/profile.d/java17.sh"
- name: "復制tomcat文件到遠程服務器並解壓"
  unarchive:
    src=apache-tomcat-7.0.64.zip
    dest=/data/
    copy=yes
    owner=staplesapp
    group=admin
- name: "對解壓后的文件重命名"
  shell: mv /data/apache-tomcat-7.0.64 /data/tomcat7
- name: "對tomcat進行相關配置"
  shell: find /data/tomcat7/bin -name "*.sh" | xargs chmod +x
- name: "啟動tomcat"
  shell: 'nohup /data/tomcat7/bin/startup.sh &'

install_tomcat8.yml文件:

---
- name: "復制文件到遠程主機"
  copy:
    src={{ item.src }}
    dest={{ item.dest }}
  with_items:
    - src: jdk-8u111-linux-x64.rpm
      dest: /usr/local/src/
    - src: java18.sh
      dest: /etc/profile.d/
- name: "安裝jdk"
  yum:
    name: /usr/local/src/jdk-8u111-linux-x64.rpm
    state: present
- name: "配置java環境變量"
  shell: "source /etc/profile.d/java18.sh"
- name: "安裝tomcat"
  unarchive:
      src=apache-tomcat-8.0.30.tar.gz
      dest=/data/
      copy=yes
      owner=staplesapp
      group=admin
- name: "對解壓后的文件重命名"
  shell: mv /data/apache-tomcat-8.0.30 /data/tomcat8
- name: "啟動tomcat"
  shell: 'nohup /data/tomcat8/bin/startup.sh &'

執行命令:

安裝tomcat7:
[root@localhost ansible]# ansible-playbook tomcat.yml --tags tomcat7
 
安裝tomcat8:
[root@localhost ansible]# ansible-playbook tomcat.yml --tags tomcat8

特別注意:在ansible2.8版本之后將會刪除include語法,更改為import_playbook

[root@localhost ansible]# cat tomcat.yml
---
- import_playbook: install_tomcat7.yml
  tags: tomcat7
- import_playbook: install_tomcat8.yml
  tags: tomcat8

2.5、include用法

如果想在playbook中重復使用任務列表,則可以使用include文件來執行此操作。ansible2.8版本之后include語法變成了import_playbook。如果還是使用include,則不會影響執行結果,只不過是有告警信息

include用來動態的包含tasks任務列表,include_tasks新版/include老版

15421898306166

#主入口文件
[root@mha ~]# cat main.yml
- hosts: all
  remote_user: root
  tasks:
    - include_tasks: f20.yml
    - include_tasks: f21.yml

#f20.yml
[root@mha ~]# cat f20.yml
- name: create file1
  command: touch file1

#21.yml
[root@mha ~]# cat f21.yml
- name: create file2
  command: touch file2

2.6、when--條件語句

[root@manager ~]# cat f6.yml
- hosts: all
  remote_user: root
  tasks:
    - name: Create File
      file: path=/tmp/this_is_{{ ansible_hostname }}_file state=touch
      when: (ansible_hostname == "nfs") or (ansible_hostname == "backup")

#系統為centos的主機才會執行
    - name: Centos Install httpd
      yum: name=httpd state=present
      when: (ansible_distribution == "CentOS")

#系統為ubuntu的主機才會執行
    - name: Ubuntu Install httpd
      yum: name=httpd2 state=present
      when: (ansible_distribution == "Ubuntu")

2.7、with_items--循環語句

1)批量安裝軟件

[root@manager ~]# cat f7.yml
---
- hosts: all
  remote_user: root
  tasks:
    - name: Installed Pkg
      yum: name={{ item }} state=present
      with_items:
        - wget
        - tree
        - lrzsz

2)批量創建用戶

[root@manager ~]# cat f7.yml
- hosts: all
  remote_user: root
  tasks:
    - name: Add Users
      user: name={{ item.name }} groups={{ item.groups }} state=present
      with_items:
        - { name: 'testuser1', groups: 'bin' }
        - { name: 'testuser2', groups: 'root' }

3)批量文件拷貝

[root@manager ~]# cat f7.yml
- hosts: all
  remote_user: root
  tasks:
    - name: Configure Rsync Server
      copy: src={{ item.src }} dest=/etc/{{ item.dest }} mode={{ item.mode }}
      with_items:
        - {src: "rsyncd.conf", dest: "rsyncd.conf", mode: "0644"}
        - {src: "rsync.passwd", dest: "rsync.passwd", mode: "0600"}

2.8、異常處理

默認Playbook會檢查命令和模塊的返回狀態,如遇到錯誤就中斷playbook的執行
加入參數: ignore_errors: yes 忽略錯誤

[root@Manager playbook]#cat ErrorIgnore.yml 
---
- hosts: web
  remote_user: root
  tasks:
    - name: Ignore False
      command: /bin/false
      ignore_errors: yes

    - name: touch new file
      file: path=/tmp/ignore.txt state=touch
[root@Manager playbook]#ansible-playbook ErrorIgnore.yml 

PLAY [web] ***********************************************************************************************************

TASK [Gathering Facts] ***********************************************************************************************
ok: [172.16.93.165]

TASK [Ignore False] **************************************************************************************************
fatal: [172.16.93.165]: FAILED! => {"changed": true, "cmd": ["/bin/false"], "delta": "0:00:00.043922", "end": "2020-01-09 17:15:34.985067", "msg": "non-zero return code", "rc": 1, "start": "2020-01-09 17:15:34.941145", "stderr": "", "stderr_lines": [], "stdout": "", "stdout_lines": []}
...ignoring

TASK [touch new file] ************************************************************************************************
changed: [172.16.93.165]

PLAY RECAP ***********************************************************************************************************
172.16.93.165              : ok=3    changed=2    unreachable=0    failed=0    skipped=0    rescued=0    ignored=1   


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM