天天看點

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

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

目錄

  • Ansible playbook 簡介
  • Ansible playbook使用場景
  • Ansible playbook格式
    • 1)格式簡介
    • 2)核心元素
    • 3)基本元件
      • 舉例
    • 4)variables 部分
      • ① facts :可直接調用
      • ② 使用者自定義變量
        • 舉例
      • ③ 通過roles傳遞變量
      • ④ Host Inventory
    • 5)模闆 templates
      • 舉例
    • 6)條件測試
    • 7)字典
    • 8)角色訂制:roles
      • ① 簡介
      • ② 角色集合
      • ③ 角色定制執行個體

正文

回到頂部

Ansible playbook 簡介

  playbook 是 ansible 用于配置,部署,和管理被控節點的劇本。

  通過 playbook 的較長的描述,執行其中的一系列 tasks ,可以讓遠端主機達到預期的狀态。playbook 就像 Ansible 控制器給被控節點列出的的一系列 to-do-list ,而被控節點必須要完成。

  也可以這麼了解,playbook 字面意思,即劇本,現實中由演員按照劇本表演,在Ansible中,這次由計算機進行表演,由計算機安裝,部署應用,提供對外服務,以及組織計算機處理各種各樣的事情。

回到頂部

Ansible playbook使用場景

  執行一些簡單的任務,使用ad-hoc指令可以友善的解決問題,但是有時一個設施過于複雜,需要大量的操作時候,執行的ad-hoc指令是不适合的,這時最好使用playbook。

  就像執行shell指令與寫shell腳本一樣,也可以了解為批處理任務,不過playbook有自己的文法格式。

  使用playbook你可以友善的重用這些代碼,可以移植到不同的機器上面,像函數一樣,最大化的利用代碼。在你使用Ansible的過程中,你也會發現,你所處理的大部分操作都是編寫playbook。可以把常見的應用都編寫成playbook,之後管理伺服器會變得十分簡單。

回到頂部

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格式:

  1、檔案的第一行應該以 "---" (三個連字元)開始,表明YMAL檔案的開始。

  2、在同一行中,#之後的内容表示注釋,類似于shell,python和ruby。

  3、YMAL中的清單元素以”-”開頭然後緊跟着一個空格,後面為元素内容。

  4、同一個清單中的元素應該保持相同的縮進。否則會被當做錯誤處理。

  5、play中hosts,variables,roles,tasks等對象的表示方法都是鍵值中間以":"分隔表示,":"後面還要增加一個空格。

  下面是一個舉例:

---
#安裝與運作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

。其中,有三個部分組成:

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 是可選的,隻是為了便于使用者閱讀,不過還是建議加上去,子產品是必須的,同時也要給予子產品相應的參數。

  使用ansible-playbook運作playbook檔案,得到如下輸出資訊,輸出内容為JSON格式。并且由不同顔色組成,便于識别。一般而言

| 綠色代表執行成功,系統保持原樣

| 黃色代表系統代表系統狀态發生改變

| 紅色代表執行失敗,顯示錯誤輸出

  執行有三個步驟:1、收集facts 2、執行tasks 3、報告結果

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

2)核心元素

  Playbook的核心元素:

Hosts

:主機組;

Tasks

:任務清單;

Variables

:變量,設定方式有四種;

Templates

:包含了模闆文法的文本檔案;

Handlers

:由特定條件觸發的任務;

3)基本元件

  Playbooks配置檔案的基礎元件:

Hosts

:運作指定任務的目标主機

remoute_user

:在遠端主機上執行任務的使用者;

sudo_user

tasks

:任務清單

  格式:

    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

[[email protected] ~]# cd /etc/ansible
[[email protected] 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  #為了在程序中能看出來
           

② 測試運作結果

  寫完了以後,我們就可以運作了:

[[email protected] ansible]# ansible-playbook nginx.yml
           
自動化運維工具——ansible詳解(二)

  現在我們可以看看兩台機器的端口是否開啟:

[[email protected] 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))
           

③ 測試标簽

  我們在裡面已經打上了一個标簽,是以可以直接引用标簽。但是我們需要先把服務關閉,再來運作劇本并引用标簽:

[[email protected] ansible]# ansible web -m shell -a 'systemctl stop nginx'
[[email protected] ansible]# ansible-playbook nginx.yml -t startnginx
           
自動化運維工具——ansible詳解(二)

④ 測試notify

  我們還做了一個

notify

,來測試一下:

  首先,它的觸發條件是配置檔案被改變,是以我們去把配置檔案中的端口改一下:

[[email protected] ansible]# vim /tmp/nginx.conf
	listen       8080;
           

  然後我們重新加載一下這個劇本:

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

  發現我們執行的就是reload段以及我們定義的

notify

部分。

  我們來看一看我們的端口号:

[[email protected] 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
           

舉例

① 定義劇本

  我們就使用全局替換把我們剛剛編輯的檔案修改一下:

[[email protected] ansible]# vim nginx.yml
           
自動化運維工具——ansible詳解(二)
自動化運維工具——ansible詳解(二)

  這樣一來,我們的劇本就定義完成了。

② 拷貝配置檔案

  我們想要在被監管的機器上安裝什麼服務的話,就直接在我們的server端上把該服務的配置檔案拷貝到我們的

/tmp/

目錄下。這樣我們的劇本才能正常運作。

  我們就以

keepalived

服務為例:

[[email protected] ansible]# cp /etc/keepalived/keepalived.conf /tmp/keepalived.conf
           

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

[[email protected] ansible]# ansible-playbook nginx.yml -e rpmname=keepalived
           
自動化運維工具——ansible詳解(二)

④ 修改劇本,直接定義變量

  同樣的,我們可以直接在劇本中把變量定義好,這樣就不需要在通過指令行傳入了。以後想要安裝不同的服務,直接在劇本裡把變量修改一下即可。

[[email protected] ansible]# vim nginx.yml
           
自動化運維工具——ansible詳解(二)

⑤ 運作定義過變量的劇本

  我們剛剛已經把變量定義在劇本裡面了。現在我們來運作一下試試看:

[[email protected] ansible]# ansible-playbook nginx.yml
           
自動化運維工具——ansible詳解(二)

  發現這樣也是可以的~

③ 通過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

改個名,然後編輯一下,就可以定義成我們的模闆檔案了:

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

② 修改劇本

  我們現在需要去修改劇本來定義變量:

[[email protected] ansible]# vim nginx.yml
           
自動化運維工具——ansible詳解(二)

  需要修改的部分如圖所示。

③ 運作劇本

  上面的準備工作完成後,我們就可以去運作劇本了:

[[email protected] 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目錄下生成對應的目錄結構

[[email protected] ansible]# cd roles/
[[email protected] roles]# ls
[[email protected] roles]# mkdir -pv ./{nginx,mysql,httpd}/{files,templates,vars,tasks,handlers,meta,default}
[[email protected] 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

,下面,我們就來修改一下:

[[email protected] 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

目錄下:

[[email protected] nginx]# cp /tmp/nginx-1.10.2-1.el7.ngx.x86_64.rpm ./files/
[[email protected] nginx]# cp /tmp/nginx.conf.j2 ./templates/
[[email protected] 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. 修改變量檔案

  我們在模闆中定義的變量,也要去配置檔案中加上:

[[email protected] nginx]# vim vars/main.yml
nginxprot: 9999
           

5. 定義handlers檔案

  我們在配置檔案中定義了

notify

,是以我麼也需要定義

handlers

,我們來修改配置檔案:

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

6. 定義劇本檔案

  接下來,我們就來定義劇本檔案,由于大部分設定我們都單獨配置在了roles裡面,是以,接下來劇本就隻需要寫一點點内容即可:

[[email protected] ansible]# vim roles.yml 
- hosts: web
  remote_user: root
  roles:
    - nginx
           

7. 啟動服務

  劇本定義完成以後,我們就可以來啟動服務了:

[[email protected] 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   
           

  啟動過後照例檢視端口号:

[[email protected] 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))
           

  可以看出我們的劇本已經執行成功。

繼續閱讀