運維自動化-Ansible ( 三 )

ansible-galaxy

鏈接 https://galaxy.ansible.com 下載相應的roles,此網站是Ansible愛好者將平常使用較好的playbooks打包上傳,其餘人能夠免費下載
到Ansible PlayBooks並當即投入使用。

ansible-galaxy 語法:php

ansible-galaxy [delete|import|info|init|install|list|login|remove|search|setup] [--help] [options] 

 列出已安裝的galaxy
#ansible-galaxy list geerlingguy.mysql
- geerlingguy.mysql, 2.8.1

 安裝galaxy
ansible-galaxy install geerlingguy.redis

 刪除galaxy
ansible-galaxy remove geerlingguy.redis

進入網站後找到這時標記的地方mysql

image

把名字複製下來nginx

image

就能夠在你的ansible主機上進行安裝劇本了。git

#ansible-galaxy install geerlingguy.mysql
- downloading role 'mysql', owned by geerlingguy
- downloading role from https://github.com/geerlingguy/ansible-role-mysql/archive/2.8.1.tar.gz
- extracting geerlingguy.mysql to /root/.ansible/roles/geerlingguy.mysql
- geerlingguy.mysql (2.8.1) was installed successfully

安裝的劇本默認是存放在家目錄的隱藏文件中。
/root/.ansiblegithub

#tree -L 2
.
└── geerlingguy.mysql
    ├── defaults
    ├── handlers
    ├── LICENSE
    ├── meta
    ├── README.md
    ├── tasks
    ├── templates
    ├── tests
    └── vars

固然,本機的galaxy命令也提供在線搜索劇本。web

#ansible-galaxy search --author geerlingguy

Found 90 roles matching your search:

 Name                              Description
 ----                              -----------
 geerlingguy.raspberry-pi          Configures a Raspberry Pi.
 geerlingguy.php-redis             PhpRedis support for Linux
 geerlingguy.drupal-console        Drupal Console
 geerlingguy.adminer               Installs Adminer for Database management.
 geerlingguy.blackfire             Blackfire installation for Linux
 geerlingguy.tomcat6               Tomcat 6 for RHEL/CentOS and Debian/Ubuntu.
 geerlingguy.php-pear              PHP PEAR library installation.

Ansible-vault

功能:管理加密解密yml文件正則表達式

ansible-vault [create|decrypt|edit|encrypt|rekey|view]
 ansible-vault encrypt hello.yml 加密
 ansible-vault decrypt hello.yml 解密
 ansible-vault view hello.yml 查看加密問題
 ansible-vault edit hello.yml 編輯加密文件
 ansible-vault rekey hello.yml 修改口令
 ansible-vault create new.yml 建立新文件

Ansible-console

可交互執行命令,支持tab補全。redis

#ansible-console
Vault password:默認是當前登陸帳號密碼

root@all (5)[f:5]$
列出全部的內置命令: ?或help

執行用戶@當前操做的主機組(all) (當前組的主機數量5)[f:併發數5]
設置併發數: forks n
root@all (5)[f:5]$ forks 10

切換組: cd 主機組
root@all (5)[f:10]$ cd db

列出當前組主機列表: list
root@all (5)[f:10]$ list
6-web-1.hunk.tech
7-web-0.hunk.tech
7-web-2.hunk.tech
6-dns-1.hunk.tech
7-db-3.hunk.tech

執行一行指令
root@web (3)[f:10]$ setup filter=ansible_distribution_version

Ansible-playbook

語法:sql

ansible-playbook <filename.yml> ... [options]
常見選項
--check 只檢測可能會發生的改變,但不真正執行操做
--list-hosts 列出運行任務的主機
--list-tasks 列出此playbook中的全部任務
--list-tags 列出此playbook中的全部的tags
--limit 主機列表 只針對主機列表中的主機執行
--step 一步一步執行腳本
--flush-cache  清除fact緩存
-C 文件名     執行前先檢查語法。
-D 顯示出執行先後的變化內容
-v 顯示過程 -vv -vvv 更詳細

第一個playbook

---

- hosts: all
  remote_user: root

  tasks:
    - name: test yml
      command: /usr/bin/wall "hello world"

語法檢查shell

image

真正執行

image

Playbook採用YAML語言編寫

Playbook工做流程

image

YAML語法簡介

這裏只涉及到playbook相關的語法,更多請參考官網http://www.yaml.org

語法很是嚴格,請仔細仔細再仔細。

在單一檔案中,可用連續三個連字號(---)區分多個檔案。另外,還有選擇性的連續三個點號( ... )用來表示檔案結尾
 次行開始正常寫Playbook的內容,通常建議寫明該Playbook的功能
 使用#號註釋代碼
 縮進必須是統一的,不能空格和tab混用,通常縮進2個空格
 縮進的級別也必須是一致的,一樣的縮進表明一樣的級別,程序判別配置的級別是經過縮進結合換行來實現的
 YAML文件內容和Linux系統大小寫判斷方式保持一致,是區別大小寫的,key/value的值均需大小寫敏感
 key/value的值能夠寫在同一行,也可換行寫。同一行使用 , 逗號分隔
 value但是個字符串,也但是另外一個列表
 一個完整的代碼塊功能需最少元素需包括 name和task
 一個name只能包括一個task
 使用| 和 > 來分隔多行,實際上這只是一行。
        include_newlines: |
            exactly as you see
            will appear these three
            lines of poetry

        ignore_newlines: >
            this is really a
            single line of text
            despite appearances
 Yaml中不容許在雙引號中出現轉義符號,因此都是以單引號來避免轉義符錯誤           
 YAML文件擴展名一般爲yml或yaml

List:列表

其全部元素均使用"-"打頭

- web
- dns
-空格web

Dictionary:字典(鍵值對)

一般由多個key與value構成

多行寫法:
name: hunk
blog: "http://https://blog.51cto.com/191226139"
name:空格hunk   > 這個冒號後面必須是一個空格

同一行寫法:
須要使用{ }
{name: hunk, blog: "http://https://blog.51cto.com/191226139"}  > 逗號後建議使用留一個空格

布爾值的表示法:
yes/no  true/false

create_key: yes
needs_agent: no
knows_oop: True
likes_emacs: TRUE
uses_cvs: false

一些特別要注意的語法

Ansible 使用 "{{ var }}" 來引用變量. 若是一個值以 "{"開頭, YAML 將認爲它是一個字典, 因此咱們必須引用它, 像這樣:

foo: "{{ variable }}"

使用引號來包裹任何包含冒號:的value值, 像這樣:

foo: "somebody said I should put a colon here: so I did"

Playbook核心元素

hosts

hosts 行的內容是一個或多個組或主機的 patterns,以逗號爲分隔符。一般是/etc/ansible/hosts定義的主機列表

remote_user 就是遠程執行任務的帳戶名:

---
- hosts: web,dns
  remote_user: root

tasks

任務集

tasks:
    - name: install httpd
      yum: name=httpd

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

    - name: check http port
      shell: ss -ntl|grep 80 > /tmp/httpd.txt

    - name: fetch
      fetch: src=/tmp/httpd.txt dest=/app

執行過程

image

執行結果
#tree /app
/app
├── 6-web-1.hunk.tech
│   └── tmp
│       └── httpd.txt
├── 7-web-0.hunk.tech
│   └── tmp
│       └── httpd.txt
├── 7-web-2.hunk.tech
│   └── tmp
│       └── httpd.txt

#cat /app/6-web-1.hunk.tech/tmp/httpd.txt 
LISTEN     0      128                      :::80                      :::*

一個yml文件裏能夠設計多個playbook,不過呢,爲了更清晰的管理,建議應該獨立存放不一樣任務需求,方便之後調用。

這裏要注意雙引號的狀況

    - name: change httpd.conf
       shell: "/bin/sed -i.bakr '/^Listen 80/cListen 8080' /etc/httpd/conf/httpd.conf"

Handlers 和 notity

由特定條件觸發的操做,知足條件方纔執行,不然不執行。

Handlers也是task列表,這些task與前述的tasks並無本質上的不一樣,用於當關注的資源發生變化時,纔會採起必定的操做

仍是拿上個例子的playbook修改下。

---
- hosts: ~^7.*web
  remote_user: root

  tasks:
    - name: install httpd
      yum: name=httpd

    - name: change httpd.conf
      copy: src=/app/httpd.conf dest=/etc/httpd/conf/ backup=yes
      notify: restart httpd             > 在 notify 中定義內容必定要和handlers中定義的 - name 內容同樣,這樣才能達到觸發的效果,不然會不生效。
    - name: start httpd
      service: name=httpd state=started

    - name: wall http status
      shell: /usr/bin/wall `ss -nltp|grep httpd`

  handlers:
    - name: restart httpd           > 只有接收到通知纔會執行這裏的任務
      service: name=httpd state=restarted
這裏準備了一個httpd2.4版本的配置文件
#grep ^Listen /app/httpd.conf
Listen 8080
這個配置文件不可用於httpd2.2版本,所以須要在執行時指定匹配的主機用正則判斷一下。
---
#ansible-playbook installhttpd.yml --limit ~^7.*web > 支持正則表達式
PLAY [web]

TASK [Gathering Facts] 

ok: [7-web-0.hunk.tech]
ok: [7-web-2.hunk.tech]

tags

指定某條任務執行,用於選擇運行playbook中的部分代碼。 ansible具備冪等性,所以會自動跳過沒有變化的部分,

即使如此,有些代碼爲測試其確實沒有發生變化的時間依然會很是地長。此時,若是確信其沒有變化,就能夠經過

tags跳過此些代碼片段。能夠爲每一個tasks設置tags,這樣方便調用。

- name: change httpd.conf
      copy: src=/app/httpd.conf dest=/etc/httpd/conf/
      tags: copyconf    > tags:後除了一個空格外,不要有其餘空格,中間可使用_下劃線
      notify: restart httpd

可使用多個tags

#ansible-playbook –t copyconf useradd.yml
#ansible-playbook –t copyconf,start_httpd useradd.yml
若是命令或腳本的退出碼不爲零,可使用以下方式替代
tasks:
- name: run this command and ignore the result
shell: /usr/bin/somecommand || /bin/true

 或者使用ignore_errors來忽略錯誤信息:
tasks:
- name: run this command and ignore the result
shell: /usr/bin/somecommand
ignore_errors: True

變量

變量命名

變量名僅能由字母、數字和下劃線組成,且只能以字母開頭

變量定義方式

1. # ansible setup facts 遠程主機的全部變量均可直接調用。setup模塊就是用來獲取遠程主機的相關信息的。通常以ansible_開頭的就是變量能夠調用

2. 在/etc/ansible/hosts中定義

普通變量:主機組中主機單獨定義,優先級高於公共變量
公共(組)變量:針對主機組中全部主機定義統一變量

[web]
6-web-1.hunk.tech hname=nginx http_prot=8080   > 主機普通變量
7-web-0.hunk.tech hname=httpd http_prot=8081   > 主機普通變量
7-web-2.hunk.tech hname=httpd24 http_prot=8082  > 主機普通變量

[web:vars]   注意:vars是關鍵字,針對web組內全部主機設置的變量
hname=web    > 主機公共(組)變量,

3. 經過命令行指定變量,優先級最高
    #ansible-playbook –e 變量名=變量值
        http_port=80

4. 在playbook中定義
vars:                 > 關鍵字
  - var1: value1
  - var2: value2

5. vars_files指定變量文件
    vars_files:
    - /app/vars.yml

6. 在role中定義

7. 經過{{ variable_name }} 調用變量,且變量名先後必須有空格,有時用"{{ variable_name }}"才生效

8. register  註冊變量
   把某一條任務執行的結果保存下來,能夠在接下的任務中調用或者作些判斷。這裏是定義告終果存到什麼名字的變量裏。常與ignore_errors配合設置成True
   整個變量可使用在template中,動做行中,或者是when語句中
   使用-v參數來查看存儲的內容或者使用debug: var=註冊名
    register變量的命名不能用 - 中橫線

各類變量優先級:
命令行 -e > vars_files指定變量文件 > 主機清單普通變量 > 主機清單公共(組)變量

一些例子:

經過playbook中使用vars: 定義調用

---
- hosts: web
  remote_user: root
  vars:                     > 關鍵字
    - username: hunk88      > 鍵值對
    - groupname: groupabc   > 鍵值對

  tasks:
    - name: add group
      group: name={{ groupname }}    > 變量調用
    - name: add user
      user: name={{ username }}      > 變量調用
...

經過playbook中使用setup中的變量調用

---
- hosts: web
  remote_user: root

  tasks:
    - name: create  file
      copy: dest=/app/ip.txt content="{{ ansible_all_ipv4_addresses }}"  > 調用了setup 模塊收集的ansible_all_ipv4_addresses變量值
...

#cat /app/ip.txt 
["192.168.5.102", "172.18.103.79", "192.168.7.201"]

經過主機清單定義普通變量並調用

[web]
6-web-1.hunk.tech hname=nginx http_prot=8080
7-web-0.hunk.tech hname=httpd http_prot=8081
7-web-2.hunk.tech hname=httpd24 http_prot=8082

---
- hosts: web
  remote_user: root

  tasks:
    - name: set hostname
      hostname: name={{ hname }}-{{ http_prot }}

結果:
#ansible web -m shell -a 'echo $HOSTNAME'
6-web-1.hunk.tech | SUCCESS | rc=0 >>
nginx-8080

7-web-0.hunk.tech | SUCCESS | rc=0 >>
httpd-8081

7-web-2.hunk.tech | SUCCESS | rc=0 >>
httpd24-8082

經過主機清單定義公共(組)變量並調用

[web]
6-web-1.hunk.tech http_prot=8080
7-web-0.hunk.tech http_prot=8081
7-web-2.hunk.tech http_prot=8082

[web:vars]
hname=web
make="-"

tasks:
    - name: change hostname
      hostname: name={{ hname }}{{ make }}{{ http_prot }}

結果:
#ansible web -m shell -a 'echo $HOSTNAME'
6-web-1.hunk.tech | SUCCESS | rc=0 >>
web-8080

7-web-0.hunk.tech | SUCCESS | rc=0 >>
web-8081

7-web-2.hunk.tech | SUCCESS | rc=0 >>
web-8082

經過獨立的變量文件調用

#vim /app/vars.yml
hname: nginx    > 注意鍵值對的格式
prot: 9527

playbook:

- hosts: web
  remote_user: root
  vars_files:
    - /app/vars.yml

  tasks:
    - name: set hostname
      hostname: name={{ hname }}-{{ prot }}

結果:

#ansible web -m shell -a 'echo $HOSTNAME'
6-web-1.hunk.tech | SUCCESS | rc=0 >>
nginx-9527

7-web-2.hunk.tech | SUCCESS | rc=0 >>
nginx-9527

7-web-0.hunk.tech | SUCCESS | rc=0 >>
nginx-9527

經過register註冊變量並調用

- hosts: web
  tasks:
  - shell: /bin/cat /etc/centos-release
    register: release               > 將上一條結果保存到release變量
  - name: show release
    debug: var=release

如下是用debug模塊查看輸出結果

ok: [7-web-0.hunk.tech] => {
    "release": {
        "changed": true,                       > 顯示是否已更改
        "cmd": "/bin/cat /etc/centos-release", > 執行的命令
        "delta": "0:00:00.006148", 
        "end": "2018-02-03 22:47:49.010194",   > 執行結束的時間
        "failed": false,
        "rc": 0,                               > 命令的返回碼
        "start": "2018-02-03 22:47:49.004046", > 執行開始的時間
        "stderr": "",                          > 若是有錯誤,則輸出錯誤的信息
        "stderr_lines": [],                    > 逐行輸出
        "stdout": "CentOS Linux release 7.4.1708 (Core) ", > 命令的輸出
        "stdout_lines": [
            "CentOS Linux release 7.4.1708 (Core) "
        ]
    }
}

調用:
- hosts: web
  tasks:
  - shell: /bin/cat /etc/centos-release
    ignore_errors: true
    register: release

  - name: show Centos 6
    command: /usr/bin/wall "Centos 6"
    when: release.stdout | match("CentOS release 6.9 (Final)")

  - name: show Centos 7
    command: /usr/bin/wall "Centos 7"
    when: release.stdout | search("release 7")  > 模糊匹配

判斷文件是否存在的實例:

- hosts: all
  tasks:
    - name: check file
      shell: ls /app/ip.txt
      ignore_errors: true
      register: release

    - name: show file not found
      command: /usr/bin/wall "file not found"
      when: release.rc != 0

    - name: show file found
      command: /usr/bin/wall "file found"
      when: release.rc == 0

when條件判斷

與shell編程中的條件判斷相似

在task後添加when子句便可使用條件測試;when語句支持Jinja2表達式語法

前面的案例使用了正則來判斷主機的系統版本號,這裏直接使用when調用系統變量來判斷

match:精確匹配
search:模糊匹配
支持正則表達式

when: release.stdout | match('.*release 6.9.*$')
when: release.stdout | match('CentOS release 6.9 \(Final\)') > 精確匹配
when: release.stdout | search("release 7")  > 模糊匹配
when: ansible_distribution_major_version == "7"

判斷變量是否認義

is defined: 變量已經定義
is undefined: 變量未定義

tasks:
    - shell: echo "I've got '{{ foo }}' and am not afraid to use it!"
      when: foo is defined

    - fail: msg="Bailing out. this play requires 'bar'"
      when: bar is undefined

with_items

當有須要重複性執行的任務時,可使用迭代機制。相似於循環

 對迭代項的引用,固定變量名爲 item"
 要在task中使用with_items給定要迭代的元素列表

列表格式:
字符串
字典

例子:

- hosts: web
  remote_user: root
  vars:               > 定義了2個變量
    - user1: hunk4    > 鍵值對
    - user2: hunk5

  tasks:
    - name: create user
      user: name={{ item }}    > 調用with_items的值,這是固定的關鍵字,不能換成其餘的。
      with_items:              > with_items:列表開始    
        - "{{ user1 }}"        > 調用vars中定義的2個變量,注意須要用雙引號引發來。
        - "{{ user2 }}"

結果:
#ansible web -a 'tail -n3 /etc/passwd'
6-web-1.hunk.tech | SUCCESS | rc=0 >>
user2:x:503:503::/home/user2:/bin/bash
hunk4:x:504:504::/home/hunk4:/bin/bash
hunk5:x:505:505::/home/hunk5:/bin/bash

7-web-0.hunk.tech | SUCCESS | rc=0 >>
user2:x:1003:1003::/home/user2:/bin/bash
hunk4:x:1004:1004::/home/hunk4:/bin/bash
hunk5:x:1005:1005::/home/hunk5:/bin/bash

7-web-2.hunk.tech | SUCCESS | rc=0 >>
user2:x:1003:1003::/home/user2:/bin/bash
hunk4:x:1004:1004::/home/hunk4:/bin/bash
hunk5:x:1005:1005::/home/hunk5:/bin/bash

固然,也能夠不像上面那樣,直接在with_items下直接給到列表內容。

另外,每一個- name 下面的with_items能夠同時存在,不相互衝突。以下面的:
- name: X1
  with_items
    - a
    - b

- name: X2
  with_items
    - c
    - d

等價的寫法:

方法1,多行:
  tasks:
    - name: with_items
      command: wall "{{ item }}"
      with_items:
        - 0
        - 2
        - 4
        - 6
        - 8
        - 10
      when: item > 5

方法2,單行:
  tasks:
    - name: with_items
      command: wall "{{ item }}"
      with_items: [ 0, 2, 4, 6, 8, 10 ]    > 使用[ ] 來存放列表
      when: item > 5

批量循環建立文件夾

本着爲了之後更好的維護變量的設計,此次把變量獨立到到個文件中
#vim /app/vars.yml
all_data:                
  - A
  - B 
  - C 
  - D

playbook:
- hosts: dns
  remote_user: root
  vars_files:
    - /app/vars.yml

  tasks:
    - name: create dir
      file: "path=/tmp/{{ item }} state=directory"
      with_items:
        - "{{ all_data }}"

#tree /tmp
/tmp
├── A
├── B
├── C
└── D

with_items嵌套子變量

此次來了個綜合一點的例子,本着爲了之後更好的維護變量的設計,此次把變量獨立到到個文件中

#cat /app/vars.yml 

user1: hunk3       > 鍵值對
user2: hunk4
group1: A
group2: B

playbook

- hosts: web
  remote_user: root
  vars_files:              > 導入變量文件
    - /app/vars.yml

  tasks:
    - name: create groups
      group: name={{ item }}   > 使用with_items建立組
      with_items:
        - "{{ group1 }}"       > with_items列表的值來自變量文件中的變量名
        - "{{ group2 }}"

    - name: create users
      user: name={{ item.username }} group={{ item.groupname }}   > 嵌套子變量,格式爲:item.with_items的列表中的鍵名
      with_items:
       - { username: "{{ user1 }}", groupname: "{{ group1 }}" }   > 別暈,最外層的{} 就是鍵值對的語法,裏面有2個鍵值對,用逗號,分隔。{{ }}是引入的變量鍵名,注意要用雙引號。
       - { username: "{{ user2 }}", groupname: "{{ group2 }}" }

結果:

image

#ansible web -m shell -a 'id hunk3;id hunk4'
6-web-1.hunk.tech | SUCCESS | rc=0 >>
uid=502(hunk3) gid=502(A) groups=502(A)
uid=503(hunk4) gid=503(B) groups=503(B)

7-web-0.hunk.tech | SUCCESS | rc=0 >>
uid=1002(hunk3) gid=1002(A) groups=1002(A)
uid=1003(hunk4) gid=1003(B) groups=1003(B)

7-web-2.hunk.tech | SUCCESS | rc=0 >>
uid=1002(hunk3) gid=1002(A) groups=1002(A)
uid=1003(hunk4) gid=1003(B) groups=1003(B)
相關文章
相關標籤/搜索