1. 程式人生 > 實用技巧 >ansible-批量-管理

ansible-批量-管理

Ansible--Ansible之Playbook

Ansible之Playbook

Playbook介紹

playbook參考文件

Playbookad-hoc相比,是一種完全不同的運用ansible的方式,類似與saltstackstate狀態檔案。ad-hoc無法持久使用,playbook可以持久使用。
playbook是由一個或多個play組成的列表,play的主要功能在於將事先歸併為一組的主機裝扮成事先通過ansible中的task定義好的角色。從根本上來講,所謂的task無非是呼叫ansible的一個module。將多個play組織在一個playbook

中,即可以讓它們聯合起來按事先編排的機制完成某一任務

Playbook核心元素

  • Hosts 執行的遠端主機列表
  • Tasks 任務集
  • Varniables 內建變數或自定義變數在playbook中呼叫
  • Templates 模板,即使用模板語法的檔案,比如配置檔案等
  • Handlers 和notity結合使用,由特定條件觸發的操作,滿足條件方才執行,否則不執行
  • tags 標籤,指定某條任務執行,用於選擇執行playbook中的部分程式碼。

Playbook語法

playbook使用yaml語法格式,字尾可以是yaml,也可以是yml

  • 在單一一個playbook檔案中,可以連續三個連子號(---
    )區分多個play。還有選擇性的連續三個點好(...)用來表示play的結尾,也可省略。
  • 次行開始正常寫playbook的內容,一般都會寫上描述該playbook的功能。
  • 使用#號註釋程式碼。
  • 縮排必須統一,不能空格和tab混用。
  • 縮排的級別也必須是一致的,同樣的縮排代表同樣的級別,程式判別配置的級別是通過縮排結合換行實現的。
  • YAML檔案內容和Linux系統大小寫判斷方式保持一致,是區分大小寫的,k/v的值均需大小寫敏感
  • k/v的值可同行寫也可以換行寫。同行使用:分隔。
  • v可以是個字串,也可以是一個列表
  • 一個完整的程式碼塊功能需要最少元素包括name: task

一個簡單的示例

# 建立playbook檔案
[root@ansible ~]# cat playbook01.yml
---                       #固定格式
- hosts: 192.168.1.31     #定義需要執行主機
  remote_user: root       #遠端使用者
  vars:                   #定義變數
    http_port: 8088       #變數

  tasks:                             #定義一個任務的開始
    - name: create new file          #定義任務的名稱
      file: name=/tmp/playtest.txt state=touch   #呼叫模組,具體要做的事情
    - name: create new user
      user: name=test02 system=yes shell=/sbin/nologin
    - name: install package
      yum: name=httpd
    - name: config httpd
      template: src=./httpd.conf dest=/etc/httpd/conf/httpd.conf
      notify:                 #定義執行一個動作(action)讓handlers來引用執行,與handlers配合使用
        - restart apache      #notify要執行的動作,這裡必須與handlers中的name定義內容一致
    - name: copy index.html
      copy: src=/var/www/html/index.html dest=/var/www/html/index.html
    - name: start httpd
      service: name=httpd state=started
  handlers:                                    #處理器:更加tasks中notify定義的action觸發執行相應的處理動作
    - name: restart apache                     #要與notify定義的內容相同
      service: name=httpd state=restarted      #觸發要執行的動作

#測試頁面準備
[root@ansible ~]# echo "<h1>playbook test file</h1>" >>/var/www/html/index.html
#配置檔案準備
[root@ansible ~]# cat httpd.conf |grep ^Listen
Listen {{ http_port }}

#執行playbook, 第一次執行可以加-C選項,檢查寫的playbook是否ok
[root@ansible ~]# ansible-playbook playbook01.yml
PLAY [192.168.1.31] *********************************************************************************************
TASK [Gathering Facts] ******************************************************************************************
ok: [192.168.1.31]
TASK [create new file] ******************************************************************************************
changed: [192.168.1.31]
TASK [create new user] ******************************************************************************************
changed: [192.168.1.31]
TASK [install package] ******************************************************************************************
changed: [192.168.1.31]
TASK [config httpd] *********************************************************************************************
changed: [192.168.1.31]
TASK [copy index.html] ******************************************************************************************
changed: [192.168.1.31]
TASK [start httpd] **********************************************************************************************
changed: [192.168.1.31]
PLAY RECAP ******************************************************************************************************
192.168.1.31               : ok=7    changed=6    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0 


# 驗證上面playbook執行的結果
[root@ansible ~]# ansible 192.168.1.31 -m shell -a 'ls /tmp/playtest.txt && id test02'
192.168.1.31 | CHANGED | rc=0 >>
/tmp/playtest.txt
uid=990(test02) gid=985(test02) 組=985(test02)

[root@ansible ~]# curl 192.168.1.31:8088
<h1>playbook test file</h1>

Playbook的執行方式

通過ansible-playbook命令執行
格式:ansible-playbook <filename.yml> ... [options]

[root@ansible PlayBook]# ansible-playbook -h
#ansible-playbook常用選項:
--check  or -C    #只檢測可能會發生的改變,但不真正執行操作
--list-hosts      #列出執行任務的主機
--list-tags       #列出playbook檔案中定義所有的tags
--list-tasks      #列出playbook檔案中定義的所以任務集
--limit           #主機列表 只針對主機列表中的某個主機或者某個組執行
-f                #指定併發數,預設為5個
-t                #指定tags執行,執行某一個或者多個tags。(前提playbook中有定義tags)
-v                #顯示過程  -vv  -vvv更詳細

Playbook中元素屬性

主機與使用者

在一個playbook開始時,最先定義的是要操作的主機和使用者

---
- hosts: 192.168.1.31
  remote_user: root

除了上面的定義外,還可以在某一個tasks中定義要執行該任務的遠端使用者

tasks: 
  - name: run df -h
    remote_user: test
    shell: name=df -h

還可以定義使用sudo授權使用者執行該任務

tasks: 
  - name: run df -h
    sudo_user: test
    sudo: yes
    shell: name=df -h

tasks任務列表

每一個task必須有一個名稱name,這樣在執行playbook時,從其輸出的任務執行資訊中可以很清楚的辨別是屬於哪一個task的,如果沒有定義nameaction的值將會用作輸出資訊中標記特定的task
每一個playbook中可以包含一個或者多個tasks任務列表,每一個tasks完成具體的一件事,(任務模組)比如建立一個使用者或者安裝一個軟體等,在hosts中定義的主機或者主機組都將會執行這個被定義的tasks

tasks:
  - name: create new file
    file: path=/tmp/test01.txt state=touch
  - name: create new user
    user: name=test001 state=present

Handlers與Notify

很多時候當我們某一個配置發生改變,我們需要重啟服務,(比如httpd配置檔案檔案發生改變了)這時候就可以用到handlersnotify了;
(當發生改動時)notify actions會在playbook的每一個task結束時被觸發,而且即使有多個不同task通知改動的發生,notify actions知會被觸發一次;比如多個resources指出因為一個配置檔案被改動,所以apache需要重啟,但是重新啟動的操作知會被執行一次。

[root@ansible ~]# cat httpd.yml 
#用於安裝httpd並配置啟動
---
- hosts: 192.168.1.31
  remote_user: root

  tasks:
  - name: install httpd
    yum: name=httpd state=installed
  - name: config httpd
    template: src=/root/httpd.conf dest=/etc/httpd/conf/httpd.conf
    notify:
      - restart httpd
  - name: start httpd
    service: name=httpd state=started

  handlers:
    - name: restart httpd
      service: name=httpd state=restarted

#這裡只要對httpd.conf配置檔案作出了修改,修改後需要重啟生效,在tasks中定義了restart httpd這個action,然後在handlers中引用上面tasks中定義的notify。

Playbook中變數的使用

環境說明:這裡配置了兩個組,一個apache組和一個nginx組

[root@ansible PlayBook]# cat /etc/ansible/hosts
[apache]
192.168.1.36
192.168.1.33

[nginx]
192.168.1.3[1:2]

命令列指定變數

執行playbook時候通過引數-e傳入變數,這樣傳入的變數在整個playbook中都可以被呼叫,屬於全域性變數

[root@ansible PlayBook]# cat variables.yml 
---
- hosts: all
  remote_user: root

  tasks:
    - name: install pkg
      yum: name={{ pkg }}

#執行playbook 指定pkg
[root@ansible PlayBook]# ansible-playbook -e "pkg=httpd" variables.yml

hosts檔案中定義變數

/etc/ansible/hosts檔案中定義變數,可以針對每個主機定義不同的變數,也可以定義一個組的變數,然後直接在playbook中直接呼叫。注意,組中定義的變數沒有單個主機中的優先順序高。

# 編輯hosts檔案定義變數
[root@ansible PlayBook]# vim /etc/ansible/hosts
[apache]
192.168.1.36 webdir=/opt/test     #定義單個主機的變數
192.168.1.33
[apache:vars]      #定義整個組的統一變數
webdir=/web/test

[nginx]
192.168.1.3[1:2]
[nginx:vars]
webdir=/opt/web


# 編輯playbook檔案
[root@ansible PlayBook]# cat variables.yml 
---
- hosts: all
  remote_user: root

  tasks:
    - name: create webdir
      file: name={{ webdir }} state=directory   #引用變數


# 執行playbook
[root@ansible PlayBook]# ansible-playbook variables.yml

playbook檔案中定義變數

編寫playbook時,直接在裡面定義變數,然後直接引用,可以定義多個變數;注意:如果在執行playbook時,又通過-e引數指定變數的值,那麼會以-e引數指定的為準。

# 編輯playbook
[root@ansible PlayBook]# cat variables.yml 
---
- hosts: all
  remote_user: root
  vars:                #定義變數
    pkg: nginx         #變數1
    dir: /tmp/test1    #變數2

  tasks:
    - name: install pkg
      yum: name={{ pkg }} state=installed    #引用變數
    - name: create new dir
      file: name={{ dir }} state=directory   #引用變數


# 執行playbook
[root@ansible PlayBook]# ansible-playbook variables.yml

# 如果執行時候又重新指定了變數的值,那麼會已重新指定的為準
[root@ansible PlayBook]# ansible-playbook -e "dir=/tmp/test2" variables.yml

呼叫setup模組獲取變數

setup模組預設是獲取主機資訊的,有時候在playbook中需要用到,所以可以直接呼叫。常用的引數參考

# 編輯playbook檔案
[root@ansible PlayBook]# cat variables.yml 
---
- hosts: all
  remote_user: root

  tasks:
    - name: create file
      file: name={{ ansible_fqdn }}.log state=touch   #引用setup中的ansible_fqdn


# 執行playbook
[root@ansible PlayBook]# ansible-playbook variables.yml

獨立的變數YAML檔案中定義

為了方便管理將所有的變數統一放在一個獨立的變數YAML檔案中,laybook檔案直接引用檔案呼叫變數即可。

# 定義存放變數的檔案
[root@ansible PlayBook]# cat var.yml 
var1: vsftpd
var2: httpd

# 編寫playbook
[root@ansible PlayBook]# cat variables.yml 
---
- hosts: all
  remote_user: root
  vars_files:    #引用變數檔案
    - ./var.yml   #指定變數檔案的path(這裡可以是絕對路徑,也可以是相對路徑)

  tasks:
    - name: install package
      yum: name={{ var1 }}   #引用變數
    - name: create file
      file: name=/tmp/{{ var2 }}.log state=touch   #引用變數


# 執行playbook
[root@ansible PlayBook]# ansible-playbook  variables.yml

Playbook中標籤的使用

一個playbook檔案中,執行時如果想執行某一個任務,那麼可以給每個任務集進行打標籤,這樣在執行的時候可以通過-t選擇指定標籤執行,還可以通過--skip-tags選擇除了某個標籤外全部執行等。

# 編輯playbook
[root@ansible PlayBook]# cat httpd.yml 
---
- hosts: 192.168.1.31
  remote_user: root

  tasks:
    - name: install httpd
      yum: name=httpd state=installed
      tags: inhttpd

    - name: start httpd
      service: name=httpd state=started
      tags: sthttpd

    - name: restart httpd
      service: name=httpd state=restarted
      tags: 
        - rshttpd
        - rs_httpd

# 正常執行的結果
[root@ansible PlayBook]# ansible-playbook httpd.yml 

PLAY [192.168.1.31] **************************************************************************************************************************

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

TASK [install httpd] *************************************************************************************************************************
ok: [192.168.1.31]

TASK [start httpd] ***************************************************************************************************************************
ok: [192.168.1.31]

TASK [restart httpd] *************************************************************************************************************************
changed: [192.168.1.31]

PLAY RECAP ***********************************************************************************************************************************
192.168.1.31               : ok=4    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

1)通過-t選項指定tags進行執行

# 通過-t指定tags名稱,多個tags用逗號隔開
[root@ansible PlayBook]# ansible-playbook -t rshttpd httpd.yml 

PLAY [192.168.1.31] **************************************************************************************************************************

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

TASK [restart httpd] *************************************************************************************************************************
changed: [192.168.1.31]

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

2)通過--skip-tags選項排除不執行的tags

[root@ansible PlayBook]# ansible-playbook --skip-tags inhttpd httpd.yml 

PLAY [192.168.1.31] **************************************************************************************************************************

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

TASK [start httpd] ***************************************************************************************************************************
ok: [192.168.1.31]

TASK [restart httpd] *************************************************************************************************************************
changed: [192.168.1.31]

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

Playbook中模板的使用

template模板為我們提供了動態配置服務,使用jinja2語言,裡面支援多種條件判斷、迴圈、邏輯運算、比較操作等。其實說白了也就是一個檔案,和之前配置檔案使用copy一樣,只是使用copy,不能根據伺服器配置不一樣進行不同動態的配置。這樣就不利於管理。
說明:
1、多數情況下都將template檔案放在和playbook檔案同級的templates目錄下(手動建立),這樣playbook檔案中可以直接引用,會自動去找這個檔案。如果放在別的地方,也可以通過絕對路徑去指定。
2、模板檔案字尾名為.j2

迴圈參考

示例:通過template安裝httpd

1)playbook檔案編寫

[root@ansible PlayBook]# cat testtmp.yml 
#模板示例
---
- hosts: all
  remote_user: root
  vars:
    - listen_port: 88    #定義變數

  tasks:
    - name: Install Httpd
      yum: name=httpd state=installed
    - name: Config Httpd
      template: src=httpd.conf.j2 dest=/etc/httpd/conf/httpd.conf    #使用模板
      notify: Restart Httpd
    - name: Start Httpd
      service: name=httpd state=started
      
  handlers:
    - name: Restart Httpd
      service: name=httpd state=restarted

2)模板檔案準備,httpd配置檔案準備,這裡配置檔案埠使用了變數

[root@ansible PlayBook]# cat templates/httpd.conf.j2 |grep ^Listen
Listen {{ listen_port }}

3)檢視目錄結構

# 目錄結構
[root@ansible PlayBook]# tree .
.
├── templates
│ └── httpd.conf.j2
└── testtmp.yml

1 directory, 2 files

4)執行playbook,由於192.168.1.36那臺機器是6的系統,模板檔案裡面的配置檔案是7上面預設的httpd配置檔案,httpd版本不一樣(6預設版本為2.2.15,7預設版本為2.4.6),所以拷貝過去後啟動報錯。下面使用playbook中的判斷語句進行處理;此處先略過

[root@ansible PlayBook]# ansible-playbook testtmp.yml 

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

TASK [Gathering Facts] ******************************************************************************
ok: [192.168.1.36]
ok: [192.168.1.32]
ok: [192.168.1.33]
ok: [192.168.1.31]

TASK [Install Httpd] ********************************************************************************
ok: [192.168.1.36]
ok: [192.168.1.33]
ok: [192.168.1.32]
ok: [192.168.1.31]

TASK [Config Httpd] *********************************************************************************
changed: [192.168.1.31]
changed: [192.168.1.33]
changed: [192.168.1.32]
changed: [192.168.1.36]

TASK [Start Httpd] **********************************************************************************
fatal: [192.168.1.36]: FAILED! => {"changed": false, "msg": "httpd: Syntax error on line 56 of /etc/httpd/conf/httpd.conf: Include directory '/etc/httpd/conf.modules.d' not found\n"}
changed: [192.168.1.32]
changed: [192.168.1.33]
changed: [192.168.1.31]

RUNNING HANDLER [Restart Httpd] *********************************************************************
changed: [192.168.1.31]
changed: [192.168.1.32]
changed: [192.168.1.33]

PLAY RECAP ******************************************************************************************
192.168.1.31               : ok=5    changed=3    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
192.168.1.32               : ok=5    changed=3    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
192.168.1.33               : ok=5    changed=3    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
192.168.1.36               : ok=3    changed=1    unreachable=0    failed=1    skipped=0    rescued=0    ignored=0

template之when

when語句參考

條件測試:如果需要根據變數、facts或此前任務的執行結果來做為某task執行與否的前提時要用到條件測試,通過when語句執行,在task中使用jinja2的語法格式、
when語句:
task後新增when子句即可使用條件測試;when語句支援jinja2表示式語法。

類似這樣:

tasks:
  - command: /bin/false
    register: result
    ignore_errors: True
  - command: /bin/something
    when: result|failed
  - command: /bin/something_else
    when: result|success
  - command: /bin/still/something_else
    when: result|skipped

示例:通過when語句完善上面的httpd配置

1)準備兩個配置檔案,一個centos6系統httpd配置檔案,一個centos7系統httpd配置檔案。

[root@ansible PlayBook]# tree templates/
templates/
├── httpd6.conf.j2     #6系統2.2.15版本httpd配置檔案
└── httpd7.conf.j2     #7系統2.4.6版本httpd配置檔案

0 directories, 2 files

2)修改playbook檔案,通過setup模組獲取系統版本去判斷。setup常用模組

[root@ansible PlayBook]# cat testtmp.yml 
#when示例
---
- hosts: all
  remote_user: root
  vars:
    - listen_port: 88

  tasks:
    - name: Install Httpd
      yum: name=httpd state=installed
    - name: Config System6 Httpd
      template: src=httpd6.conf.j2 dest=/etc/httpd/conf/httpd.conf
      when: ansible_distribution_major_version == "6"   #判斷系統版本,為6便執行上面的template配置6的配置檔案
      notify: Restart Httpd
    - name: Config System7 Httpd
      template: src=httpd7.conf.j2 dest=/etc/httpd/conf/httpd.conf
      when: ansible_distribution_major_version == "7"   #判斷系統版本,為7便執行上面的template配置7的配置檔案
      notify: Restart Httpd
    - name: Start Httpd
      service: name=httpd state=started

  handlers:
    - name: Restart Httpd
      service: name=httpd state=restarted

3)執行playbook

[root@ansible PlayBook]# ansible-playbook testtmp.yml

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

TASK [Gathering Facts] ******************************************************************************
ok: [192.168.1.31]
ok: [192.168.1.32]
ok: [192.168.1.33]
ok: [192.168.1.36]

TASK [Install Httpd] ********************************************************************************
ok: [192.168.1.32]
ok: [192.168.1.33]
ok: [192.168.1.31]
ok: [192.168.1.36]

TASK [Config System6 Httpd] *************************************************************************
skipping: [192.168.1.33]
skipping: [192.168.1.31]
skipping: [192.168.1.32]
changed: [192.168.1.36]

TASK [Config System7 Httpd] *************************************************************************
skipping: [192.168.1.36]
changed: [192.168.1.33]
changed: [192.168.1.31]
changed: [192.168.1.32]

TASK [Start Httpd] **********************************************************************************
ok: [192.168.1.36]
ok: [192.168.1.31]
ok: [192.168.1.32]
ok: [192.168.1.33]

RUNNING HANDLER [Restart Httpd] *********************************************************************
changed: [192.168.1.33]
changed: [192.168.1.31]
changed: [192.168.1.32]
changed: [192.168.1.36]

PLAY RECAP ******************************************************************************************
192.168.1.31               : ok=5    changed=2    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0   
192.168.1.32               : ok=5    changed=2    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0   
192.168.1.33               : ok=5    changed=2    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0   
192.168.1.36               : ok=5    changed=2    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0

template之with_items

with_items迭代,當有需要重複性執行的任務時,可以使用迭代機制。
對迭代項的引用,固定變數名為item,要在task中使用with_items給定要迭代的元素列表。
列表格式:
  字串
  字典

示例1:通過with_items安裝多個不同軟體

編寫playbook

[root@ansible PlayBook]# cat testwith.yml 
# 示例with_items
---
- hosts: all
  remote_user: root

  tasks:
    - name: Install Package
      yum: name={{ item }} state=installed   #引用item獲取值
      with_items:     #定義with_items
        - httpd
        - vsftpd
        - nginx

上面tasks寫法等同於:

---
- hosts: all
  remote_user: root
  tasks:
    - name: Install Httpd
      yum: name=httpd state=installed
    - name: Install Vsftpd
      yum: name=vsftpd state=installed
    - name: Install Nginx
      yum: name=nginx state=installed

示例2:通過巢狀子變數建立使用者並加入不同的組

1)編寫playbook

[root@ansible PlayBook]# cat testwith01.yml 
# 示例with_items巢狀子變數
---
- hosts: all
  remote_user: root

  tasks:
    - name: Create New Group
      group: name={{ item }} state=present
      with_items: 
        - group1
        - group2
        - group3 

    - name: Create New User
      user: name={{ item.name }} group={{ item.group }} state=present
      with_items:
        - { name: 'user1', group: 'group1' } 
        - { name: 'user2', group: 'group2' } 
        - { name: 'user3', group: 'group3' }

2)執行playbook並驗證

# 執行playbook
[root@ansible PlayBook]# ansible-playbook testwith01.yml

# 驗證是否成功建立使用者及組
[root@ansible PlayBook]# ansible all -m shell -a 'tail -3 /etc/passwd'
192.168.1.36 | CHANGED | rc=0 >>
user1:x:500:500::/home/user1:/bin/bash
user2:x:501:501::/home/user2:/bin/bash
user3:x:502:502::/home/user3:/bin/bash

192.168.1.32 | CHANGED | rc=0 >>
user1:x:1001:1001::/home/user1:/bin/bash
user2:x:1002:1002::/home/user2:/bin/bash
user3:x:1003:1003::/home/user3:/bin/bash

192.168.1.31 | CHANGED | rc=0 >>
user1:x:1002:1003::/home/user1:/bin/bash
user2:x:1003:1004::/home/user2:/bin/bash
user3:x:1004:1005::/home/user3:/bin/bash

192.168.1.33 | CHANGED | rc=0 >>
user1:x:1001:1001::/home/user1:/bin/bash
user2:x:1002:1002::/home/user2:/bin/bash
user3:x:1003:1003::/home/user3:/bin/bash

template之for if

通過使用forif可以更加靈活的生成配置檔案等需求,還可以在裡面根據各種條件進行判斷,然後生成不同的配置檔案、或者伺服器配置相關等。

示例1

1)編寫playbook

[root@ansible PlayBook]# cat testfor01.yml 
# template for 示例
---
- hosts: all
  remote_user: root
  vars:
    nginx_vhost_port:
      - 81
      - 82
      - 83

  tasks:
    - name: Templage Nginx Config
      template: src=nginx.conf.j2 dest=/tmp/nginx_test.conf

2)模板檔案編寫

# 迴圈playbook檔案中定義的變數,依次賦值給port
[root@ansible PlayBook]# cat templates/nginx.conf.j2 
{% for port in nginx_vhost_port %}
server{
     listen: {{ port }};
     server_name: localhost;
}
{% endfor %}

3)執行playbook並檢視生成結果

[root@ansible PlayBook]# ansible-playbook testfor01.yml

# 去到一個節點看下生成的結果發現自動生成了三個虛擬主機
[root@linux ~]# cat /tmp/nginx_test.conf 
server{
     listen: 81;
     server_name: localhost;
}
server{
     listen: 82;
     server_name: localhost;
}
server{
     listen: 83;
     server_name: localhost;
}

示例2

1)編寫playbook

[root@ansible PlayBook]# cat testfor02.yml 
# template for 示例
---
- hosts: all
  remote_user: root
  vars:
    nginx_vhosts:
      - web1:
        listen: 8081
        server_name: "web1.example.com"
        root: "/var/www/nginx/web1"
      - web2:
        listen: 8082
        server_name: "web2.example.com"
        root: "/var/www/nginx/web2"
      - web3:
        listen: 8083
        server_name: "web3.example.com"
        root: "/var/www/nginx/web3"

  tasks:
    - name: Templage Nginx Config
      template: src=nginx.conf.j2 dest=/tmp/nginx_vhost.conf

2)模板檔案編寫

[root@ansible PlayBook]# cat templates/nginx.conf.j2 
{% for vhost in nginx_vhosts %}
server{
     listen:    {{ vhost.listen }};
     server_name:    {{ vhost.server_name }};
     root:   {{ vhost.root }}; 
}
{% endfor %}

3)執行playbook並檢視生成結果

[root@ansible PlayBook]# ansible-playbook testfor02.yml

# 去到一個節點看下生成的結果發現自動生成了三個虛擬主機
[root@linux ~]# cat /tmp/nginx_vhost.conf 
server{
     listen:    8081;
     server_name:    web1.example.com;
     root:   /var/www/nginx/web1; 
}
server{
     listen:    8082;
     server_name:    web2.example.com;
     root:   /var/www/nginx/web2; 
}
server{
     listen:    8083;
     server_name:    web3.example.com;
     root:   /var/www/nginx/web3; 
}

示例3

for迴圈中再巢狀if判斷,讓生成的配置檔案更加靈活

1)編寫playbook

[root@ansible PlayBook]# cat testfor03.yml 
# template for 示例
---
- hosts: all
  remote_user: root
  vars:
    nginx_vhosts:
      - web1:
        listen: 8081
        root: "/var/www/nginx/web1"
      - web2:
        server_name: "web2.example.com"
        root: "/var/www/nginx/web2"
      - web3:
        listen: 8083
        server_name: "web3.example.com"
        root: "/var/www/nginx/web3"

  tasks:
    - name: Templage Nginx Config
      template: src=nginx.conf.j2 dest=/tmp/nginx_vhost.conf

2)模板檔案編寫

# 說明:這裡添加了判斷,如果listen沒有定義的話,預設埠使用8888,如果server_name有定義,那麼生成的配置檔案中才有這一項。
[root@ansible PlayBook]# cat templates/nginx.conf.j2 
{% for vhost in nginx_vhosts %}
server{
     {% if vhost.listen is defined %}
     listen:    {{ vhost.listen }};
     {% else %}
     listen: 8888;
     {% endif %}
     {% if vhost.server_name is defined %}
     server_name:    {{ vhost.server_name }};
     {% endif %}
     root:   {{ vhost.root }}; 
}
{% endfor %}

3)執行playbook並檢視生成結果

[root@ansible PlayBook]# ansible-playbook testfor03.yml

# 去到一個節點看下生成的結果發現自動生成了三個虛擬主機
[root@linux ~]# cat /tmp/nginx_vhost.conf 
server{
          listen:    8081;
          root:   /var/www/nginx/web1; 
}
server{
          listen: 8888;
          server_name:    web2.example.com;
          root:   /var/www/nginx/web2; 
}
server{
          listen:    8083;
          server_name:    web3.example.com;
          root:   /var/www/nginx/web3; 
}

上面三個示例的圖片展示效果

例一

例二

例三