自動化運維工具——ansible詳解(二)

Ansible playbook 簡介

  playbook 是 ansible 用於配置,部署,和管理被控節點的劇本。
  經過 playbook 的詳細描述,執行其中的一系列 tasks ,可讓遠端主機達到預期的狀態。playbook 就像 Ansible 控制器給被控節點列出的的一系列 to-do-list ,而被控節點必需要完成。
  也能夠這麼理解,playbook 字面意思,即劇本,現實中由演員按照劇本表演,在Ansible中,此次由計算機進行表演,由計算機安裝,部署應用,提供對外服務,以及組織計算機處理各類各樣的事情。php

Ansible playbook使用場景

  執行一些簡單的任務,使用ad-hoc命令能夠方便的解決問題,可是有時一個設施過於複雜,須要大量的操做時候,執行的ad-hoc命令是不適合的,這時最好使用playbook。
  就像執行shell命令與寫shell腳本同樣,也能夠理解爲批處理任務,不過playbook有本身的語法格式。
  使用playbook你能夠方便的重用這些代碼,能夠移植到不一樣的機器上面,像函數同樣,最大化的利用代碼。在你使用Ansible的過程當中,你也會發現,你所處理的大部分操做都是編寫playbook。能夠把常見的應用都編寫成playbook,以後管理服務器會變得十分簡單。node

Ansible playbook格式

1)格式簡介

  playbook由YMAL語言編寫。YAML( /ˈjæməl/ )參考了其餘多種語言,包括:XML、C語言、Python、Perl以及電子郵件格式RFC2822,Clark Evans在2001年5月在首次發表了這種語言,另外Ingy döt Net與OrenBen-Kiki也是這語言的共同設計者。
  YMAL格式是相似於JSON的文件格式,便於人理解和閱讀,同時便於書寫。首先學習瞭解一下YMAL的格式,對咱們後面書寫playbook頗有幫助。如下爲playbook經常使用到的YMAL格式:
  一、文件的第一行應該以 "---" (三個連字符)開始,代表YMAL文件的開始。
  二、在同一行中,#以後的內容表示註釋,相似於shell,python和ruby。
  三、YMAL中的列表元素以」-」開頭而後緊跟着一個空格,後面爲元素內容。
  四、同一個列表中的元素應該保持相同的縮進。不然會被當作錯誤處理。
  五、play中hosts,variables,roles,tasks等對象的表示方法都是鍵值中間以":"分隔表示,":"後面還要增長一個空格。

  下面是一個舉例:python

---
#安裝與運行mysql服務
- hosts: node1
  remote_user: root
  tasks:
  
    - name: install mysql-server package
      yum: name=mysql-server state=present
    - name: starting mysqld service
      service: name=mysql state=started

  咱們的文件名稱應該以.yml結尾,像咱們上面的例子就是mysql.yml。其中,有三個部分組成:mysql

host部分:使用 hosts 指示使用哪一個主機或主機組來運行下面的 tasks ,每一個 playbook 都必須指定 hosts ,hosts也可使用通配符格式。主機或主機組在 inventory 清單中指定,可使用系統默認的/etc/ansible/hosts,也能夠本身編輯,在運行的時候加上-i選項,指定清單的位置便可。在運行清單文件的時候,–list-hosts選項會顯示那些主機將會參與執行 task 的過程當中。
remote_user:指定遠端主機中的哪一個用戶來登陸遠端系統,在遠端系統執行 task 的用戶,能夠任意指定,也可使用 sudo,可是用戶必需要有執行相應 task 的權限。
tasks指定遠端主機將要執行的一系列動做。tasks 的核心爲 ansible 的模塊,前面已經提到模塊的用法。tasks 包含 name要執行的模塊name 是可選的,只是爲了便於用戶閱讀,不過仍是建議加上去,模塊是必須的,同時也要給予模塊相應的參數。nginx

  使用ansible-playbook運行playbook文件,獲得以下輸出信息,輸出內容爲JSON格式。而且由不一樣顏色組成,便於識別。通常而言
| 綠色表明執行成功,系統保持原樣
| 黃色表明系統表明系統狀態發生改變
| 紅色表明執行失敗,顯示錯誤輸出
  執行有三個步驟:一、收集facts 二、執行tasks 三、報告結果
web

2)核心元素

  Playbook的核心元素:sql

Hosts:主機組;
Tasks:任務列表;
Variables:變量,設置方式有四種;
Templates:包含了模板語法的文本文件;
Handlers:由特定條件觸發的任務;shell

3)基本組件

  Playbooks配置文件的基礎組件:編程

Hosts:運行指定任務的目標主機
remoute_user:在遠程主機上執行任務的用戶;
sudo_user
tasks:任務列表vim

  格式:
    tasks:
      – name: TASK_NAME
       module: arguments
       notify: HANDLER_NAME
       handlers:
      – name: HANDLER_NAME
       module: arguments

模塊,模塊參數

  格式:
    (1) action: module arguments
    (2) module: arguments
    注意:shell和command模塊後面直接跟命令,而非key=value類的參數列表;

handlers:任務,在特定條件下觸發;接收到其它任務的通知時被觸發;

  (1) 某任務的狀態在運行後爲changed時,可經過「notify」通知給相應的handlers;
  (2) 任務能夠經過「tags「打標籤,然後可在ansible-playbook命令上使用-t指定進行調用;

舉例

① 定義playbook

[root@server ~]# cd /etc/ansible
[root@server ansible]# vim nginx.yml
---
- hosts: web
  remote_user: root
  tasks:

    - name: install nginx
      yum: name=nginx state=present
    - name: copy nginx.conf
      copy: src=/tmp/nginx.conf dest=/etc/nginx/nginx.conf backup=yes
      notify: reload    #當nginx.conf發生改變時,通知給相應的handlers
      tags: reloadnginx   #打標籤
    - name: start nginx service
      service: name=nginx state=started
      tags: startnginx   #打標籤

  handlers:  #注意,前面沒有-,是兩個空格
    - name: reload
      service: name=nginx state=restarted  #爲了在進程中能看出來

② 測試運行結果
  寫完了之後,咱們就能夠運行了:

[root@server ansible]# ansible-playbook nginx.yml


  如今咱們能夠看看兩臺機器的端口是否開啓:

[root@server ansible]# ansible web -m shell -a 'ss -nutlp |grep nginx'
192.168.37.122 | SUCCESS | rc=0 >>
tcp    LISTEN     0      128       *:80                    *:*                   users:(("nginx",pid=8304,fd=6),("nginx",pid=8303,fd=6))

192.168.37.133 | SUCCESS | rc=0 >>
tcp    LISTEN     0      128       *:80                    *:*                   users:(("nginx",pid=9671,fd=6),("nginx",pid=9670,fd=6))

③ 測試標籤
  咱們在裏面已經打上了一個標籤,因此能夠直接引用標籤。可是咱們須要先把服務關閉,再來運行劇本並引用標籤:

[root@server ansible]# ansible web -m shell -a 'systemctl stop nginx'
[root@server ansible]# ansible-playbook nginx.yml -t startnginx


④ 測試notify
  咱們還作了一個notify,來測試一下:
  首先,它的觸發條件是配置文件被改變,因此咱們去把配置文件中的端口改一下:

[root@server ansible]# vim /tmp/nginx.conf
    listen       8080;

  而後咱們從新加載一下這個劇本:

  發現咱們執行的就是reload段以及咱們定義的notify部分。
  咱們來看一看咱們的端口號:

[root@server ansible]# ansible web -m shell -a 'ss -ntlp | grep nginx'
192.168.37.122 | SUCCESS | rc=0 >>
LISTEN     0      128          *:8080                     *:*                   users:(("nginx",pid=2097,fd=6),("nginx",pid=2096,fd=6))

192.168.37.133 | SUCCESS | rc=0 >>
LISTEN     0      128          *:8080                     *:*                   users:(("nginx",pid=3061,fd=6),("nginx",pid=3060,fd=6))

  能夠看出,咱們的nginx端口已經變成了8080。
  

4)variables 部分

  上文中,咱們說到了variables是變量,有四種定義方法,如今咱們就來講說這四種定義方法:

① facts :可直接調用

  上一篇中,咱們有說到setup這個模塊,這個模塊就是經過調用facts組件來實現的。咱們這裏的variables也能夠直接調用facts組件。
  具體的facters咱們可使用setup模塊來獲取,而後直接放入咱們的劇本中調用便可。

② 用戶自定義變量

  咱們也能夠直接使用用戶自定義變量,想要自定義變量有如下兩種方式:

經過命令行傳入

  ansible-playbook命令的命令行中的-e VARS, --extra-vars=VARS,這樣就能夠直接把自定義的變量傳入。

在playbook中定義變量

  咱們也能夠直接在playbook中定義咱們的變量:

vars:
  - var1: value1
  - - var2: value2
舉例

① 定義劇本
  咱們就使用全局替換把咱們剛剛編輯的文件修改一下:

[root@server ansible]# vim nginx.yml



  這樣一來,咱們的劇本就定義完成了。
② 拷貝配置文件
  咱們想要在被監管的機器上安裝什麼服務的話,就直接在咱們的server端上把該服務的配置文件拷貝到咱們的/tmp/目錄下。這樣咱們的劇本才能正常運行。
  咱們就以keepalived服務爲例:

[root@server ansible]# cp /etc/keepalived/keepalived.conf /tmp/keepalived.conf

③ 運行劇本,變量由命令行傳入

[root@server ansible]# ansible-playbook nginx.yml -e rpmname=keepalived


④ 修改劇本,直接定義變量
  一樣的,咱們能夠直接在劇本中把變量定義好,這樣就不須要在經過命令行傳入了。之後想要安裝不一樣的服務,直接在劇本里把變量修改一下便可。

[root@server ansible]# vim nginx.yml


⑤ 運行定義過變量的劇本
  咱們剛剛已經把變量定義在劇本里面了。如今咱們來運行一下試試看:

[root@server ansible]# ansible-playbook nginx.yml


  發現這樣也是能夠的~

③ 經過roles傳遞變量

  具體的,咱們下文中說到 roles 的時候再詳細說明。這裏是傳送帶
  

④ Host Inventory

  咱們也能夠直接在主機清單中定義。
  定義的方法以下:

向不一樣的主機傳遞不一樣的變量:

  IP/HOSTNAME varaiable=value var2=value2

向組中的主機傳遞相同的變量:

  [groupname:vars]
  variable=value

5)模板 templates

  模板是一個文本文件,嵌套有腳本(使用模板編程語言編寫)。
  Jinja2:Jinja2是python的一種模板語言,以Django的模板語言爲本來。
模板支持:

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

  一般來講,模板都是經過引用變量來運用的。

舉例

① 定義模板
  咱們直接把以前定義的/tmp/nginx.conf改個名,而後編輯一下,就能夠定義成咱們的模板文件了:

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

② 修改劇本
  咱們如今須要去修改劇原本定義變量:

[root@server ansible]# vim nginx.yml


  須要修改的部分如圖所示。
③ 運行劇本
  上面的準備工做完成後,咱們就能夠去運行劇本了:

[root@server ansible]# ansible-playbook nginx.yml -t reloadnginx

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

TASK [setup] *******************************************************************
ok: [192.168.37.122]
ok: [192.168.37.133]

TASK [copy nginx.conf] *********************************************************
ok: [192.168.37.122]
ok: [192.168.37.133]

PLAY RECAP *********************************************************************
192.168.37.122             : ok=2    changed=0    unreachable=0    failed=0   
192.168.37.133             : ok=2    changed=0    unreachable=0    failed=0

6)條件測試

when語句:在task中使用,jinja2的語法格式。
舉例以下:

tasks:
- name: install conf file to centos7
  template: src=files/nginx.conf.c7.j2
  when: ansible_distribution_major_version == "7"
- name: install conf file to centos6
  template: src=files/nginx.conf.c6.j2
  when: ansible_distribution_major_version == "6"

循環:迭代,須要重複執行的任務;
  對迭代項的引用,固定變量名爲"item",然後,要在task中使用with_items給定要迭代的元素列表;
舉例以下:

tasks:
- name: unstall web packages
  yum: name={{ item }} state=absent
  with_items:
  - httpd
  - php
  - php-mysql

7)字典

  ansible playbook 還支持字典功能。舉例以下:

- name: install some packages
  yum: name={{ item }} state=present
  with_items:
    - nginx
    - memcached
    - php-fpm
- name: add some groups
  group: name={{ item }} state=present
  with_items:
    - group11
    - group12
    - group13
- name: add some users
  user: name={{ item.name }} group={{ item.group }} state=present
  with_items:
    - { name: 'user11', group: 'group11' }
    - { name: 'user12', group: 'group12' }
    - { name: 'user13', group: 'group13' }

8)角色訂製:roles

① 簡介

  對於以上全部的方式有個弊端就是沒法實現複用假設在同時部署Web、db、ha 時或不一樣服務器組合不一樣的應用就須要寫多個yml文件。很難實現靈活的調用。
  roles 用於層次性、結構化地組織playbook。roles 可以根據層次型結構自動裝載變量文件、tasks以及handlers等。要使用roles只須要在playbook中使用include指令便可。簡單來說,roles就是經過分別將變量(vars)、文件(file)、任務(tasks)、模塊(modules)及處理器(handlers)放置於單獨的目錄中,並能夠便捷地include它們的一種機制。角色通常用於基於主機構建服務的場景中,但也能夠是用於構建守護進程等場景中。

② 角色集合

角色集合:roles/
mysql/
httpd/
nginx/
files/
:存儲由copy或script等模塊調用的文件;
tasks/:此目錄中至少應該有一個名爲main.yml的文件,用於定義各task;其它的文件須要由main.yml進行「包含」調用;
handlers/:此目錄中至少應該有一個名爲main.yml的文件,用於定義各handler;其它的文件須要由main.yml進行「包含」調用;
vars/:此目錄中至少應該有一個名爲main.yml的文件,用於定義各variable;其它的文件須要由main.yml進行「包含」調用;
templates/:存儲由template模塊調用的模板文本;
meta/:此目錄中至少應該有一個名爲main.yml的文件,定義當前角色的特殊設定及其依賴關係;其它的文件須要由main.yml進行「包含」調用;
default/:此目錄中至少應該有一個名爲main.yml的文件,用於設定默認變量;

③ 角色定製實例

1. 在roles目錄下生成對應的目錄結構

[root@server ansible]# cd roles/
[root@server roles]# ls
[root@server roles]# mkdir -pv ./{nginx,mysql,httpd}/{files,templates,vars,tasks,handlers,meta,default}
[root@server roles]# tree
.
├── httpd
│   ├── default
│   ├── files
│   ├── handlers
│   ├── meta
│   ├── tasks
│   ├── templates
│   └── vars
├── mysql
│   ├── default
│   ├── files
│   ├── handlers
│   ├── meta
│   ├── tasks
│   ├── templates
│   └── vars
└── nginx
    ├── default
    ├── files
    ├── handlers
    ├── meta
    ├── tasks
    ├── templates
    └── vars

24 directories, 0 files

2. 定義配置文件
  咱們須要修改的配置文件爲/tasks/main.yml,下面,咱們就來修改一下:

[root@server roles]# vim nginx/tasks/main.yml
- name: cp
  copy: src=nginx-1.10.2-1.el7.ngx.x86_64.rpm dest=/tmp/nginx-1.10.2-1.el7.ngx.x86_64.rpm
- name: install
  yum: name=/tmp/nginx-1.10.2-1.el7.ngx.x86_64.rpm state=latest
- name: conf
  template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf
  tags: nginxconf
  notify: new conf to reload
- name: start service
  service: name=nginx state=started enabled=true

3. 放置咱們所須要的文件到指定目錄
  由於咱們定義的角色已經有了新的組成方式,因此咱們須要把文件都放到指定的位置,這樣,才能讓配置文件找到這些並進行加載。
  rpm包放在files目錄下,模板放在templates目錄下:

[root@server nginx]# cp /tmp/nginx-1.10.2-1.el7.ngx.x86_64.rpm ./files/
[root@server nginx]# cp /tmp/nginx.conf.j2 ./templates/
[root@server nginx]# tree
.
├── default
├── files
│   └── nginx-1.10.2-1.el7.ngx.x86_64.rpm
├── handlers
├── meta
├── tasks
│   └── main.yml
├── templates
│   └── nginx.conf.j2
└── vars

7 directories, 3 files

4. 修改變量文件
  咱們在模板中定義的變量,也要去配置文件中加上:

[root@server nginx]# vim vars/main.yml
nginxprot: 9999

5. 定義handlers文件
  咱們在配置文件中定義了notify,因此我麼也須要定義handlers,咱們來修改配置文件:

[root@server nginx]# vim handlers/main.yml
- name: new conf to reload
  service: name=nginx state=restarted

6. 定義劇本文件
  接下來,咱們就來定義劇本文件,因爲大部分設置咱們都單獨配置在了roles裏面,因此,接下來劇本就只須要寫一點點內容便可:

[root@server ansible]# vim roles.yml 
- hosts: web
  remote_user: root
  roles:
    - nginx

7. 啓動服務
  劇本定義完成之後,咱們就能夠來啓動服務了:

[root@server ansible]# ansible-playbook roles.yml

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

TASK [setup] *******************************************************************
ok: [192.168.37.122]
ok: [192.168.37.133]

TASK [nginx : cp] **************************************************************
ok: [192.168.37.122]
ok: [192.168.37.133]

TASK [nginx : install] *********************************************************
changed: [192.168.37.122]
changed: [192.168.37.133]

TASK [nginx : conf] ************************************************************
changed: [192.168.37.122]
changed: [192.168.37.133]

TASK [nginx : start service] ***************************************************
changed: [192.168.37.122]
changed: [192.168.37.133]

RUNNING HANDLER [nginx : new conf to reload] ***********************************
changed: [192.168.37.122]
changed: [192.168.37.133]

PLAY RECAP *********************************************************************
192.168.37.122             : ok=6    changed=4    unreachable=0    failed=0   
192.168.37.133             : ok=6    changed=4    unreachable=0    failed=0

  啓動事後照例查看端口號:

[root@server ansible]# ansible web -m shell -a "ss -ntulp |grep 9999"
192.168.37.122 | SUCCESS | rc=0 >>
tcp    LISTEN     0      128       *:9999                  *:*                   users:(("nginx",pid=7831,fd=6),("nginx",pid=7830,fd=6),("nginx",pid=7829,fd=6))

192.168.37.133 | SUCCESS | rc=0 >>
tcp    LISTEN     0      128       *:9999                  *:*                   users:(("nginx",pid=9654,fd=6),("nginx",pid=9653,fd=6),("nginx",pid=9652,fd=6))

  能夠看出咱們的劇本已經執行成功。

相關文章
相關標籤/搜索