1. 程式人生 > >Ansible系列(五):playbook應用和roles自動化批量安裝示例

Ansible系列(五):playbook應用和roles自動化批量安裝示例

獲取 agg 真的 deb vhd under ice ddl ssh連接

本文目錄:
1.1 yaml語法和示例
1.2 ansible-playbook命令說明及playbook書寫簡單示例
1.3 playbook基礎
  1.3.1 hosts和remote_user
  1.3.2 task list
  1.3.3 notify和handler
  1.3.4 標簽tags
1.4 include和roles
  1.4.1 include
  1.4.2 roles
1.5 roles示例:批量自動化安裝

playbook是ansible實現批量自動化最重要的手段。在其中可以使用變量、引用、循環等功能,相比ad-hoc而言,其功能要強大的多。

1.1 yaml簡單示例

ansible的playbook采用yaml語法。以下是一個yaml格式的文件:

---
# Members in Bob‘s family
    name: Bob
    age: 30
    gender: Male
    wife: 
        name: Alice
        age: 27
        gender: Female
    children: 
      - name: Jim
        age: 6
        gender: Male
      - name: Lucy
        age: 3
        gender: Female

1.2 ansible-playbook命令說明及playbook書寫簡單示例

以下是一個簡單的playbook示例。該示例執行兩個任務,第一個任務是執行一個/bin/date命令,第二個任務是復制/etc/fstab文件到目標主機上的/tmp下,它們分別使用了ansible的command模塊和copy模塊。

cat /tmp/test.yaml 
---
    - hosts: centos7
      tasks: 
        - name: execute date cmd
          command: /bin/date
        - name: copy fstab to /tmp
          copy: src=/etc/fstab dest=/tmp

書寫好playbook後,使用ansible-playbook命令來執行。ansible-playbook命令的選項和ansible命令選項絕大部分都相同。但也有其特有的選項。以下是截取出來的幫助信息。

ansible-playbook --help
Usage: ansible-playbook playbook.yml

Options:
  -e EXTRA_VARS,--extra-vars=EXTRA_VARS # 設置額外的變量,格式為key/value。-e "key=KEY",
                                        # 如果是文件方式傳入變量,則-e "@param_file"
  --flush-cache          # 清空收集到的fact信息緩存
  --force-handlers       # 即使task執行失敗,也強制執行handlers
  --list-tags            # 列出所有可獲取到的tags
  --list-tasks           # 列出所有將要被執行的tasks
  -t TAGS,--tags=TAGS    # 以tag的方式顯式匹配要執行哪些tag中的任務
  --skip-tags=SKIP_TAGS  # 以tag的方式忽略某些要執行的任務。被此處匹配的tag中的任務都不會執行
  --start-at-task=START_AT_TASK # 從此task開始執行playbook
  --step                 # one-step-at-a-time:在每一個任務執行前都進行交互式確認
  --syntax-check         # 檢查playbook語法

現在執行上面的test.yaml。

ansible-playbook /tmp/test.yaml 

PLAY [centos7] **********************************************************************

TASK [Gathering Facts] **************************************************************
ok: [192.168.100.64]
ok: [192.168.100.65]
ok: [192.168.100.63]

TASK [execute date cmd] *************************************************************
changed: [192.168.100.63]
changed: [192.168.100.64]
changed: [192.168.100.65]

TASK [copy fstab to /tmp] ***********************************************************
changed: [192.168.100.64]
changed: [192.168.100.63]
changed: [192.168.100.65]

PLAY RECAP **************************************************************************
192.168.100.63             : ok=3    changed=2    unreachable=0    failed=0
192.168.100.64             : ok=3    changed=2    unreachable=0    failed=0
192.168.100.65             : ok=3    changed=2    unreachable=0    failed=0

從以上結果中,可以看出:(1)默認情況下,ansible-playbook和ansible是一樣的,都是同步阻塞模式,需要先在所有主機上執行完一個任務,才會繼續下一個任務;(2)在執行前會自動收集fact信息;(3)從顯示結果中可以判斷出任務是否真的執行了,抑或者是因為冪等性而沒有執行。(4)每一個play都包含數個task,且都有響應信息play recap。

1.3 playbook的內容

1.3.1 hosts和remoter_user

對於playbook中的每一個play,使用hosts選項可以定義要執行這些任務的主機或主機組,還可以使用remote_user指定在遠程主機上執行任務的用戶,實際上remote_user是ssh連接到被控主機上的用戶,自然而然執行命令的身份也將是此用戶。

例如:

---
    - hosts: centos6,centos7,192.168.100.59
      remote_user: root
      tasks: XXXXXX

還可以在某個task上單獨定義執行該task的身份,這將覆蓋全局的定義。

---
    - hosts: centos6,centos7,192.168.100.59
      remote_user: root
      tasks: 
        - name: run a command
          shell: /bin/date
        - name: copy a file to /tmp
          copy: src=/etc/fstab dest=/tmp
          remote_user: myuser

也支持權限升級的方式。

---
    - hosts: centos6,centos7,192.168.100.59
      remote_user: yourname
      tasks: 
        - name: run a command
          shell: /bin/date
        - name: copy a file to /tmp
          copy: src=/etc/fstab dest=/tmp
          become: yes
          become_method: sudo
          become_user: root    # 此項默認值就是為root,所以可省

從上面的示例可以看出remote_user實際上並不是執行任務的絕對身份,它只是ssh連接過去的身份,只不過沒有指定become的時候,它正好就用此身份來運行任務。

1.3.2 task list

1.特性
每個play都包含一個hosts和一個tasks,hosts定義的是inventory中待控制的主機,tasks下定義的是一系列task任務列表,比如調用各個模塊。這些task按順序一次執行一個,直到所有被篩選出來的主機都執行了這個task之後才會移動到下一個task上進行同樣的操作。

需要註意的是,雖然只有被篩選出來的主機會執行對應的task,但是所有主機(此處的所有主機表示的是,hosts選項所指定的那些主機)都會收到相同的task指令,所有主機收到指令後,ansible主控端會篩選某些主機,並通過ssh在遠程執行任務。也就是說,如果查看ansible-playbook -vvvv的信息,將會發現臨時任務文件會通過sftp發送到所有的被控主機上,但是只有一部分被篩選(如果進行了篩選)的主機才會ssh過去並遠程執行命令。

當某一臺被控主機執行某個任務出錯或失敗時,它將會被移除出任務輪詢列表。也就是說,對於某主機來說,某任務執行失敗,後續的所有任務都不會再去執行。當然,這不會影響其他的主機執行任務(除非主機的任務之間有依賴關系)。

最重要的是,ansible中的task是冪等性的,多次執行不會影響那些成功執行過的任務。另外冪等性還表現在執行失敗後如果修正了playbook再次執行,將不會影響那些原本已經執行成功的任務,即使是不同主機也不會影響。僅這方面而言,ansible對於排錯來說是極其友好的。當然,某些特殊的模塊或者特殊定義的task並不一定總是冪等的,例如最簡單的,執行一個command或者shell模塊的命令,它會重復執行。但也有辦法使其變得冪等,以command和shell模塊為例,它們有兩個選項:creates和removes,它們分別表示被控主機上指定的文件存在(不存在)時就不執行命令。

2.定義task的細節

  • (1).可以為每個task加上name項,也可以多個task依賴於一個name。

例如下面的兩個例子。從兩個示例中可以看出,兩個task其實都是屬於一個name的,第二個task無需再使用name命名。

示例一:

tasks: 
    - name: do something to initialize mariadb
      file: path=/mydata/data state=directory owner=mysql group=mysql mode=0755
    - shell: /usr/bin/mysql_install_db --datadir=/mydata/data --user=mysql creates=/mydata/data/ibdata1

示例二:

tasks: 
    - name: echo var passed by nginx 
      shell: echo "{{ hi_var }}"
      register: var_result
    - debug: msg="{{ var_result.stdout }}"

實際上,name只是一種描述性語句,它可以定義在任何地方。例如,定義在play的頂端。

---
- name: start a play
  hosts: localhost
  tasks:
  • (2).既然是task,那麽必然會有其要執行的一個或多個任務,其本質是加載並執行ansible對應的模塊。在playbook中,每調用的一個模塊都稱為一個action。

例如,定義一個確保服務是啟動狀態的task,有以下三種方法傳遞模塊參數:

tasks: 
  - name: be sure the sshd is running
    service: name=sshd state=started     # 方法一: 定義為key=value,直接傳遞參數給模塊

    service:                             # 方法二: 定義為key: value方式
      name: sshd
      state: started

    service:                  # 方法三: 使用args內置關鍵字,然後定義為key: value方式
    args: 
      name: sshd
      state: started

但要註意,ping模塊、command和shell模塊是不需要key=value格式的。對於ping命令,可以直接省略key=value。對於command和shell,只需要給定命令路徑和要接上去的選項或參數即可,且無法使用上面的方法二。例如下面定義的是一個ntpdate命令,只需給定它的參數即可。

tasks: 
    - name: execute command ntpdate
      shell: /usr/sbin/ntpdate ntp1.aliyun.com
    - name: ping host
      ping:

對於command或shell模塊來說,有時候要考慮命令的返回狀態碼。如果要忽略非0狀態碼繼續執行任務,可以使用以下兩種方式:

tasks: 
    - name: ignore non_zero return code
      shell: /usr/sbin/ntpdate ntp1.aliyun.com || /bin/true

或者

tasks: 
    - name: another way to ignore the non_zero return code
      shell: /usr/sbin/ntpdate ntp1.aliyun.com
      ignore_errors: true
  • (3).如果action的key=value太多,導致內容太長,可以在上一行的縮進級別基礎上繼續縮進表示續行。

例如,下面的owner比src多縮進了4個空格。

tasks:
  - name: Copy ansible inventory file to client
    copy: src=/etc/fstab dest=/tmp
              owner=root group=root mode=0644
  • (4).在action的value部分,可以引用已經定義的變量,可以是已定義好的自定義的變量,也可以是內置變量。變量相關內容見後文。

  • (5).使用include指令,可以將其他的playbook文件包含到此playbook文件中。include的方式見下文

1.3.3 notify和handler

ansible中幾乎所有的模塊都具有冪等性,這意味著被控主機的狀態是否發生改變是能被捕捉的,即每個任務的changed=true或changed=false。ansible在捕捉到changed=true時,可以觸發notify組件(如果定義了該組件)。

notify是一個組件,並非一個模塊,它可以直接定義action,其主要目的是調用handler。例如:

tasks: 
    - name: copy template file to remote host
      template: src=/etc/ansible/nginx.conf.j2 dest=/etc/nginx/nginx.conf
      notify: 
        - restart nginx
        - test web page
      copy: src=nginx/index.html.j2 dest=/usr/share/nginx/html/index.html
      notify: 
        - restart nginx

這表示當執行template模塊的任務時,如果捕捉到changed=true,那麽就會觸發notify,如果分發的index.html改變了,那麽也重啟nginx(當然這是沒必要的)。notify下定義了兩個待調用的handler。handler主要用於重啟服務或者觸發系統重啟,除此之外很少使用handler。以下是這兩個handler的內容:

handlers: 
    - name: restart nginx
      service: name=nginx state=restarted
    - name: test web page
      shell: curl -I http://192.168.100.10/index.html | grep 200 || /bin/false

handler的定義和tasks的定義完全一樣,唯一需要限定的是handler中task的name必須和notify中定義的名稱相同。

註意,notify是在執行完一個play中所有task後被觸發的,在一個play中也只會被觸發一次。意味著如果一個play中有多個task出現了changed=true,它也只會觸發一次。例如上面的示例中,向nginx復制配置文件和復制index.html時如果都發生了改變,都會觸發重啟apache操作。但是只會在執行完play後重啟一次,以避免多余的重啟。

1.3.4 標簽tag

可以為playbook中的每個任務都打上標簽,標簽的主要作用是可以在ansible-playbook中設置只執行哪些被打上tag的任務或忽略被打上tag的任務。

tasks: 
   - name: make sure apache is running
     service: name=httpd state=started
     tags: apache
   - name: make sure mysql is running
     service: name=mysqld state=started
     tags: mysql

以下是ansible-playbook命令關於tag的選項。

  --list-tags           # list all available tags
  -t TAGS, --tags=TAGS  # only run plays and tasks tagged with these values
  --skip-tags=SKIP_TAGS # only run plays and tasks whose tags do not match these values

1.4 include和roles

如果將所有的play都寫在一個playbook中,很容易導致這個playbook文件變得臃腫龐大,且不易讀。因此,可以將多個不同任務分別寫在不同的playbook中,然後使用include將其包含進去即可。而role則是整合playbook的方式。無論是include還是role,其目的都是分割大playbook以及復用某些細化的play甚至是task。

1.4.1 include

可以將task列表和handlers獨立寫在其他的文件中,然後在某個playbook文件中使用include來包含它們。除此之外,還可以寫獨立的playbook文件,使用include來包含這個文件。

也即是說,include可以導入兩種文件:導入task、導入playbook。

1.一種是任務列表式的文件(沒有tasks或handlers指令),它只能在tasks或handlers指令的子選項處使用include包含。這種方式可以傳遞變量到被包含的文件中。

假設某個task列表文件/yaml/a.yaml內容如下:

---
    - name: execute ntpdate
      shell: /usr/sbin/ntpdate ntp1.aliyun.com

在同目錄/yaml下有一個名為test.yaml的playbook(除了role,playbook中所有相對路徑都是基於playbook或inventory的),在此playbook中使用include來包含它,如果使用相對路徑將會包含同目錄下的文件。

---
    - hosts: centos7
      tasks:
       - include: a.yaml

可以在include的時候傳遞變量給對應的文件,這樣在被包含的文件中就可以引用該變量的值。

---
  - hosts: centos7
    tasks:
      - include: a.yaml sayhi="hello world"

或者

---
  - hosts: centos7
    tasks:
       - include: a.yaml
         vars: 
           sayhi: "hello world"

然後可以在被包含的文件a.yaml中使用該變量。例如:

---
    - name: execute ntpdate
      shell: /usr/sbin/ntpdate ntp1.aliyun.com
    - name: say hi to world
      debug: msg="{{ sayhi }}"

執行該test.yaml,將會輸出對應的變量值。

ansible-playbook /yaml/test.yaml

PLAY [centos7] **************************************************************************

TASK [Gathering Facts] ******************************************************************
ok: [192.168.100.64]
ok: [192.168.100.63]
ok: [192.168.100.65]

TASK [execute ntpdate] *******************************************************************
changed: [192.168.100.64]
changed: [192.168.100.65]
changed: [192.168.100.63]

TASK [sayhi to world] *******************************************************************
ok: [192.168.100.63] => {
    "changed": false, 
    "msg": "hello world"
}
ok: [192.168.100.65] => {
    "changed": false, 
    "msg": "hello world"
}
ok: [192.168.100.64] => {
    "changed": false, 
    "msg": "hello world"
}

PLAY RECAP ******************************************************************************
192.168.100.63             : ok=3    changed=1    unreachable=0    failed=0   
192.168.100.64             : ok=3    changed=1    unreachable=0    failed=0   
192.168.100.65             : ok=3    changed=1    unreachable=0    failed=0

2.另一種是include整個playbook文件,即include的動作是加載一個或多個play,所以寫在頂級列表的層次。

- name: this is a play at the top level of a file
  hosts: all
  remote_user: root

  tasks:

  - name: say hi
    tags: foo
    shell: echo "hi..."

- include: load_balancers.yml  sayhi="hello world"
- include: webservers.yml
- include: dbservers.yml

    any other operations

需要說明的是,在ansible 2.4版本中,添加了includes和imports兩種導入的方式,它們對靜態和動態導入支持的更細化,而ansible 2.3及以前的include語句已經廢棄,但仍可用。相關官方手冊地址

1.4.2 roles

roles意為角色,主要用於封裝playbook實現復用性。在ansible中,roles通過文件的組織結構來展現。

對於一個role,它的文件組織結構如下圖所示。

              技術分享

首先需要有一個roles目錄。同時,在roles目錄所在目錄中,還要有一個playbook文件,此處為nginx.yml,nginx.yml文件是ansible-playbook需要執行的文件,在此文件中定義了角色,當執行到角色時,將會到roles中對應的角色目錄中尋找相關文件。

roles目錄中的子目錄是即是各個role。例如,此處只有一個名為nginx的role,在role目錄中,有幾個固定名稱的目錄(如果沒有則忽略)。在這些目錄中,還要有一些固定名稱的文件,除了固定名稱的文件,其他的文件可以隨意命名。以下是各個目錄的含義:

  • tasks目錄:存放task列表。若role要生效,此目錄必須要有一個主task文件main.yml,在main.yml中可以使用include包含同目錄(即tasks)中的其他文件。
  • handlers目錄:存放handlers的目錄,若要生效,則文件必須名為main.yml文件。
  • files目錄:在task中執行copy或script模塊時,如果使用的是相對路徑,則會到此目錄中尋找對應的文件。
  • templates目錄:在task中執行template模塊時,如果使用的是相對路徑,則會到此目錄中尋找對應的模塊文件。
  • vars目錄:定義專屬於該role的變量,如果要有var文件,則必須為main.yml文件。
  • defaults目錄:定義角色默認變量,角色默認變量的優先級最低,會被任意其他層次的同名變量覆蓋。如果要有var文件,則必須為main.yml文件。
  • meta目錄:用於定義角色依賴,如果要有角色依賴關系,則文件必須為main.yml。

所以,相對完整的role的文件組織結構如下圖。

              技術分享

如果是多個role,則在roles同級目錄下定義多個入站(作用類似於C語言的main函數)文件(如上面的nginx.yml),並在roles目錄下創建對應的role目錄即可。

              技術分享

當然,如果不是使用相對路徑,那麽role的文件結構就無所謂了,但是roles功能開發出來,就是為了解決文件混亂和playbook臃腫問題的。所以如果可以,盡量使用推薦的role文件結構。

另外,如果role中出現的task、var、handler等和單獨定義的對象同名沖突了,則優先執行role中的內容。

以下是nginx role的入站文件nginx.yml的內容。

---
  - hosts: centos7
    roles:
      - nginx

更多更詳細的role用法以及組織結構,見下面的示例。

1.5 roles示例:批量自動化安裝

下面演示的是使用role批量自動安裝nginx和mysql(CentOS 6)或maridb(CentOS 7)的示例。由於被控節點有CentOS 6和CentOS 7兩種發行版的操作系統,因此除了要挑選對應的數據庫,還要讓nginx的配置文件適應各操作系統,因為nginx在這兩個版本的系統上配置內容有所不同。在此,nginx、mysql和mariadb是3個role,且讓nginx role依賴於mysql或mariadb role。

下面的例子中,有些地方是不太合理或多余的行為,但是作為學習示例,可以很好的理解roles之間的組織結構和相關的操作。

首先是文件的結構。

技術分享

技術分享

其中site.yml是入站文件,用於調用nginx、mysql和mariadb這3個role,這個文件中的內容如下。它有3個作用:(1)在調用roles之前,先根據發行版配置好yum源(pre_tasks);(2)調用nginx role,此處沒有調用mysql和mariadb這兩個role,因為在nginx role的meta/main.yml文件中定義了nginx role依賴於這兩個role,所以此處可以不用定義;(3)在執行完nginx role之後,輸出一個提示信息(post_tasks)。

cat /yaml/site.yml
---
  - hosts: centos
    remote_user: root

 # 根據發行版配置好yum源,使用when進行條件判斷   
    pre_tasks: 
        - name: config the yum repo for centos 7
          yum_repository:
              name: epel
              description: epel
              baseurl: http://mirrors.aliyun.com/epel/7/$basearch/
              gpgcheck: no
          when: ansible_distribution_major_version == "7"

        - name: config the yum repo for centos 6
          yum_repository:
              name: epel
              description: epel
              baseurl: http://mirrors.aliyun.com/epel/6/$basearch/
              gpgcheck: no
          when: ansible_distribution_major_version == "6"

    roles: 
        - nginx

# 輸出over消息
    post_tasks:
      - shell: echo ‘deploy nginx/mysql over‘
        register: ok_var
      - debug: msg=‘{{ ok_var.stdout }}‘

以下是nginx role中的各文件內容。其中template復制的源文件都是從centos 6 nginx和centos 7 nginx上提取的,只不過是重新命名了而已。

/yaml/roles/nginx/tasks/main.yml 
---
   - name: make sure nginx state is installed
     yum: name=nginx state=installed

   - name: template nginx.conf
# 基於變量賦值配置文件模板,檢查配置文件語法,並在必要的時候觸發handler
     template: src=nginx{{ ansible_distribution_major_version }}.conf.j2
                  dest=/etc/nginx/nginx.conf
                  validate="/usr/sbin/nginx -t -c %s"  
     notify: 
        - restart nginx

# 基於jinja2渲染模板文件,且改變時也觸發重啟操作
   - name: copy index.html
     template: src=index.html.j2 dest=/usr/share/nginx/html/index.html
     notify: 
        - restart nginx

   - name: make sure nginx service is running
     service: name=nginx state=started

# 引用變量 nginx_port,在vars/main.yml中定義了
   - name: make sure port is open
     wait_for: port="{{ nginx_port }}"

/yaml/roles/nginx/handlers/main.yml 
---
   - name: restart nginx
     service: name=nginx state=restarted

/yaml/roles/nginx/vars/main.yml 
nginx_port: 80

# 定義nginx依賴於MySQL或mariadb,具體依賴於哪個,是通過條件進行判斷的,centos 6表示依賴於mysql,centos 7表示依賴於mariadb
# 同時傳遞了兩個值給變量hi_var,由於是在依賴的時候傳遞的,所以這兩個變量可直接在依賴的role(mysql role或mariadb role)的playbook中引用
/yaml/roles/nginx/meta/main.yml 
---
   dependencies: 
     - { role: mysql,hi_var: "hello mysql",when: "ansible_distribution_major_version == ‘6‘" }
     - { role: mariadb,hi_var: "hello mariadb",when: "ansible_distribution_major_version == ‘7‘" }

上面拷貝了index.html.j2,其內容為:

shell> cat /yaml/roles/nginx/templates/index.html.j2 
<h1>hello from {{ ansible_default_ipv4.address }}<h1>

在template執行時,它會使用jinja2引擎對文件中的變量進行替換,使得在拷貝到不同主機時,該index.html的內容是基於遠程主機ip的。此處使用的變量是收集到的facts中的變量"ansible_default_ipv4.address"。

以下是mysql role中各文件的內容。註意,MySQL的my.cnf和mariadb的my.cnf默認情況下並不一樣(mariadb的my.cnf默認多了一項配置"!includedir /etc/my.cnf.d",MySQL需要取消該項),所以需要分別提供。

/yaml/roles/mysql/tasks/main.yml 
---
    - name: make sure mysql is installed
      yum: name=mysql-server state=installed

# 特別需要註意下面的初始化命令,由於執行的是shell模塊,所以要考慮其冪等性,顯然初始化動作是一定要實現冪等性的
    - name: do something to initialize mysql
      file: path=/mydata/data state=directory owner=mysql group=mysql mode=0755
    - shell: /usr/bin/mysql_install_db --datadir=/mydata/data --user=mysql creates=/mydata/data/ibdata1

    - name: copy my.cnf
      copy: src=my.cnf dest=/etc/my.cnf
      notify: 
         - restart mysql

    - name: make sure mysql is running
      service: name=mysqld state=started

    - name: make sure mysql port is open
      wait_for: 
         port: "{{ mysql_port }}"
         timeout: 10

# 這裏輸出了nginx/meta/main.yml中傳遞的變量
    - name: echo var passed by nginx 
      shell: echo "{{ hi_var }}"
      register: var_result
    - debug: msg="{{ var_result.stdout }}"

/yaml/roles/mysql/handlers/main.yml 
---
   - name: restart mysql
     service: name=mysqld state=restarted

/yaml/roles/mysql/vars/main.yml 
---
    mysql_port: 3306

以下是mariadb role中各文件的內容,和mysql大體上是一致的。註意,MySQL的my.cnf和mariadb的my.cnf默認情況下並不一樣,所以需要分別提供。

/yaml/roles/mariadb/tasks/main.yml 
---
    - name: make sure mariadb is installed
      yum: name=mariadb-server state=installed

    - name: do something to initialize mariadb
      file: path=/mydata/data state=directory owner=mysql group=mysql mode=0755
    - shell: /usr/bin/mysql_install_db --datadir=/mydata/data --user=mysql creates=/mydata/data/ibdata1

    - name: copy my.cnf
      copy: src=my.cnf dest=/etc/my.cnf
      notify: 
         - restart mariadb

    - name: make sure mariadb is running
      service: name=mariadb state=started

    - name: make sure mariadb port is open
      wait_for: 
         port: "{{ mariadb_port }}"
         timeout: 10

    - name: echo var passed by nginx 
      shell: echo "{{ hi_var }}"
      register: var_result
    - debug: msg="{{ var_result.stdout }}"

/yaml/roles/mariadb/handlers/main.yml 
---
    - name: restart mariadb
      service: name=mariadb state=restarted

/yaml/roles/mariadb/vars/main.yml 
---
    mariadb_port: 3306

以下是兩臺機器的測試結果,一臺是centos 7(192.168.100.54),一臺是centos 6(192.168.100.70)。

PLAY [newhosts] *************************************************************************

TASK [Gathering Facts] ******************************************************************
ok: [192.168.100.70]
ok: [192.168.100.54]

TASK [config the yum repo for centos 7] *************************************************
skipping: [192.168.100.70]
changed: [192.168.100.54]

TASK [config the yum repo for centos 6] *************************************************
skipping: [192.168.100.54]
changed: [192.168.100.70]

TASK [mysql : make sure mysql is installed] *********************************************
skipping: [192.168.100.54]
changed: [192.168.100.70]

TASK [mysql : do something to initialize mysql] *****************************************
skipping: [192.168.100.54]
changed: [192.168.100.70]

TASK [mysql : command] ******************************************************************
skipping: [192.168.100.54]
changed: [192.168.100.70]

TASK [mysql : copy my.cnf] **************************************************************
skipping: [192.168.100.54]
changed: [192.168.100.70]

TASK [mysql : make sure mysql is running] ***********************************************
skipping: [192.168.100.54]
changed: [192.168.100.70]

TASK [mysql : make sure mysql port is open] *********************************************
skipping: [192.168.100.54]
ok: [192.168.100.70]

TASK [mysql : echo var passed by nginx] *************************************************
skipping: [192.168.100.54]
changed: [192.168.100.70]

TASK [mysql : debug] ********************************************************************
skipping: [192.168.100.54]
ok: [192.168.100.70] => {
    "changed": false, 
    "msg": "hello mysql"
}

TASK [mariadb : make sure mariadb is installed] *****************************************
skipping: [192.168.100.70]
changed: [192.168.100.54]

TASK [mariadb : do something to initialize mariadb] *************************************
skipping: [192.168.100.70]
changed: [192.168.100.54]

TASK [mariadb : command] ****************************************************************
skipping: [192.168.100.70]
changed: [192.168.100.54]

TASK [mariadb : copy my.cnf] ************************************************************
skipping: [192.168.100.70]
changed: [192.168.100.54]

TASK [mariadb : make sure mariadb is running] *******************************************
skipping: [192.168.100.70]
changed: [192.168.100.54]

TASK [mariadb : make sure mariadb port is open] *****************************************
skipping: [192.168.100.70]
ok: [192.168.100.54]

TASK [mariadb : echo var passed by nginx] ***********************************************
skipping: [192.168.100.70]
changed: [192.168.100.54]

TASK [mariadb : debug] ******************************************************************
skipping: [192.168.100.70]
ok: [192.168.100.54] => {
    "changed": false, 
    "msg": "hello mysql"
}

TASK [nginx : make sure nginx state is installed] ***************************************
changed: [192.168.100.54]
changed: [192.168.100.70]

TASK [nginx : template nginx.conf] ******************************************************
ok: [192.168.100.70]
changed: [192.168.100.54]

TASK [nginx : copy index.html] **********************************************************
changed: [192.168.100.70]
changed: [192.168.100.54]

TASK [nginx : make sure nginx service is running] ***************************************
changed: [192.168.100.54]
changed: [192.168.100.70]

TASK [nginx : make sure port is open] ***************************************************
ok: [192.168.100.70]
ok: [192.168.100.54]

RUNNING HANDLER [mysql : restart mysql] *************************************************
changed: [192.168.100.70]

RUNNING HANDLER [mariadb : restart mariadb] *********************************************
changed: [192.168.100.54]

RUNNING HANDLER [nginx : restart nginx] *************************************************
changed: [192.168.100.54]

TASK [command] **************************************************************************
changed: [192.168.100.54]
changed: [192.168.100.70]

TASK [debug] ****************************************************************************
ok: [192.168.100.54] => {
    "changed": false, 
    "msg": "deploy nginx/mysql over"
}
ok: [192.168.100.70] => {
    "changed": false, 
    "msg": "deploy nginx/mysql over"
}

PLAY RECAP ******************************************************************************
192.168.100.54             : ok=19   changed=14   unreachable=0    failed=0   
192.168.100.70             : ok=18   changed=12   unreachable=0    failed=0

相信看過上面的roles組織示例,對roles的用法和playbook就有了較深的認識。其實,ansible有一個網站專門存放了一大堆的playbook,算是playbook倉庫吧。可以下載下來稍作修改就能使用,即使不使用,借鑒他們的寫法也是很值得的。地址:ansible galaxy

另外,根據不同標準組織role可能會讓playbook寫起來更容易,例如上面的示例中,按照發行版來劃分role比上面按照安裝軟件類型劃分可能會更簡單些。當然,如果在inventory中就劃分好centos 6和centos 7也是可以的。哪種更方便、復用性更好就需要自行考慮了。

回到系列文章大綱:http://www.cnblogs.com/f-ck-need-u/p/7048359.html

轉載請註明出處:http://www.cnblogs.com/f-ck-need-u/p/7567417.html

註:若您覺得這篇文章還不錯請點擊下右下角的推薦,有了您的支持才能激發作者更大的寫作熱情,非常感謝!

Ansible系列(五):playbook應用和roles自動化批量安裝示例