Ansible 入門指南 - ansible-playbook 命令

上篇文章Ansible 入門指南 - 安裝及 Ad-Hoc 命令使用介紹的額是 Ad-Hoc 命令方式,本文將介紹 Playbook 方式。html

Playbook 譯爲「劇本」,以爲還挺恰當的。mysql

playbook 執行語法

Playbook 譯爲「劇本」,以爲還挺恰當的。那麼 play 那我就譯爲 「場景」吧。playbook 由一個或多個 ‘plays’ 組成.它的內容是一個以 ‘plays’ 爲元素的列表linux

playbook 基礎

能夠爲 playbook 中的每個 play,個別地選擇操做的目標機器是哪些,以哪一個用戶身份去完成要執行的步驟(called tasks)git

$ ansible-playbook  -h
Usage: ansible-playbook [options] playbook.yml [playbook2 ...]

Runs Ansible playbooks, executing the defined tasks on the targeted hosts.

palybook 小栗子

在指定的目標主機上執行定義好的 tasksgithub

playbook.yml 常包含下面幾個關鍵字:web

  • hosts:爲主機的IP,或者主機組名,或者關鍵字all
  • remote_user: 以哪一個用戶身份執行。
  • vars: 變量
  • tasks: playbook的核心,定義順序執行的動做 action。每一個action調用一個ansbile module
  • action 語法: module: module_parameter=module_value
  • 經常使用的 moduleyumcopytemplate等,module在 ansible 的做用,至關於 bash 腳本中yumcopy這樣的命令。
  • 每個 task 必須有一個名稱 name,這樣在運行 playbook 時,從其輸出的任務執行信息中能夠很好的辨別出是屬於哪個 task 的
  • handers: 是 playbook 的 event ,默認不會執行,在 action 裏觸發纔會執行。屢次觸發只執行一次。

一個簡單的示例:
deploy.yml 的功能爲 web 主機部署 apache, 其中包含如下部署步驟:sql

  • 安裝apache包;
  • 拷貝配置文件httpd,並保證拷貝文件後,apache服務會被重啓;
  • 拷貝默認的網頁文件index.html;
  • 啓動apache服務;
---
- hosts: centos
  vars:
    httpd_port: 8080
    max_clients: 200
  remote_user: root
  tasks:
  - name: ensure apache is at the latest version
    yum: name=httpd state=present

  - name: Write the configuration file
    template: src=templates/httpd.conf.j2 dest=/etc/httpd/conf/httpd.conf
    notify:
    - restart apache
    ignore_errors: False

  - name: Write the default index.html file
    template: src=templates/index.html.j2 dest=/var/www/html/index.html
    ignore_errors: False

  - name: ensure apache is running
    service: name=httpd state=started

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

運行ansible-playbook deploy.yml便可執行。shell

tasks

taks 參數實際上是有不一樣寫法的,當參數比較少時,可用key=value的方式apache

tasks:
  - name: make sure apache is running
    service: name=httpd state=running

tasks 參數比較多時,爲了美觀和不易出錯,用 yml的字典傳參比較好:編程

tasks:
  - name: make sure apache is running
    service:
      name: httpd
      state: running

task中每一個action會調用一個module,在module中會去檢查當前系統狀態是否須要從新執行。

  • 若是本次執行了,那麼 action 會獲得返回值 changed;
  • 若是不須要執行,那麼 action 獲得返回值ok

module 的執行狀態的具體判斷規則由各個 module 本身決定和實現的。例如,」copy」 module的判斷方法是比較文件的checksum,代碼以下:

ansbile-playbook 經常使用命令

查看腳本影響到的 hosts

下面這條命令,指定 inventory 文件,列出 hosts 列表,並不會去執行定義的 tasks,觀察 host 是否配置正確頗有用:

ansible-playbook -i inventory/slave_init.yml execute_slave_init.yml --list-hosts

查看輸出的細節

ansible-playbook playbook.yml  --verbose

並行執行腳本

ansible-playbook playbook.yml -f 10

輸入密碼

playbook 中使用到了 become,執行playbook時能夠加上--ask-become-pass參數:

ansible-playbook deploy.yml --ask-become-pass

yml 語法簡介

  • 大小寫敏感
  • 使用縮進表示層級關係
  • 縮進時不容許使用Tab鍵,只容許使用空格。
  • 縮進的空格數目不重要,只要相同層級的元素左側對齊便可
  • # 表示註釋,從這個字符一直到行尾,都會被解析器忽略
  • YAML 還有一個小的怪癖. 全部的 YAML 文件(不管和 Ansible 有沒有關係)開始行都應該是 ---. 這是 YAML 格式的一部分, 代表一個文件的開始.
  • 列表中的全部成員都開始於相同的縮進級別, 而且使用一個 "- " 做爲開頭(一個橫槓和一個空格)
  • 一個字典是由一個簡單的 鍵: 值 的形式組成(這個冒號後面必須是一個空格)
  • Ansible 使用 「{{ var }}」 來引用變量,foo: "{{ variable }}"

參考

Play vs Playbook

其實在一個Playbook文件中還能夠有針對兩組server進行不一樣的操做,例如給web安裝http服務器,和給lb安裝mysql放在一個文件中:

---
#安裝apache的play
- hosts: web
  remote_user: root
  tasks:
  - name: ensure apache is at the latest version
    yum: pkg=httpd state=latest

# 安裝mysql server的play
- hosts: lb
  remote_user: root
  tasks:
  - name: ensure mysqld is at the latest version
    yum: pkg=mariadb state=latest

上面例子中針對每一組 server 的全部操做就組成一個 play,通常一個 playbook 中只包含一個 play,play 的內容稱爲 tasks,即任務。

參考:

響應事件 Hanlder

handlers與tasks不一樣,tasks會默認的按定義順序執行每個task,handlers則不會,它須要在tasks中被調用,纔有可能被執行。

Handlers will only be fired for tasks which report a changed state.
只有當 task 執行狀態顯示是 changed 時,handler 動做纔會被觸發

Tasks中的任務都是有狀態的,changed或者ok。 在Ansible中,只在task的執行狀態爲 changed 的時候,纔會執行該task調用的handler。

在全部的task列表執行以後執行,若是有多個task notify同一個handler,那麼 handlers 也只執行一次。

什麼狀況下使用handlers呢?

若是你在tasks中修改了apache的配置文件。須要重起apache。此外還安裝了apache的插件。那麼還須要重起apache。像這樣的應該場景中,重起apache就能夠設計成一個handler.

當一個文件的內容被改動時,重啓兩個 services:

- name: template configuration file
  template: src=template.j2 dest=/etc/foo.conf
  notify:
     - restart memcached
     - restart apache
  • notify 下列出的便是 handlers.
  • Handlers 也是一些 task 的列表,經過名字(name)來引用。
  • Handlers 是由通知者進行 notify, 若是沒有被 notify,handlers 不會執行。
  • 無論有多少個通知者進行了 notify,等到 play 中的全部 task 執行完成以後,handlers 也只會被執行一次.
handlers:
    - name: restart memcached
      service:  name=memcached state=restarted
    - name: restart apache
      service: name=apache state=restarted

此外,還有個注意點:

  • handlers是按照在handlers中定義個順序執行的,而不是安裝notify的順序執行的。好比,handlers 定義的順序是1>2>3,notify 的順序是3>2>1,實際執行順序:1>2>3.

總結,Handlers 最佳的應用場景是用來重啓服務,或者觸發系統重啓操做.除此之外不多用到。

參考

變量

playbook 中經常使用的集中變量:

  1. 在 playbook 中,用戶自定義的變量
  2. 無需用戶定義,ansible 在執行 playbook 以前,去遠程主機上搜集的關於遠程主機的系統信息變量
  3. task 運行的結果「註冊」爲一個變量來使用,這個變量叫作「註冊變量」
  4. 容許用戶在執行的時候傳入變量的值,這時候用到的是「額外變量」

playbook 中定義的變量

在 playbook 中,經過關鍵字 vars 自定義變量,用 {{}} 引用變量。

將變量放在單獨的文件中

經過 vars_files 關鍵字指定了變量文件:

---
- hosts: centos
  vars:
    httpd_port: 80
  vars_files:
      - ./vars_servers.yml
  remote_user: root
  tasks:
  - debug:
      msg: "http_port: {{httpd_port}}"
  - debug:
      msg: "x86 passwd: {{x86.password}}"
  - debug:
      msg: "arm passwd: {{arm.password}}"
      # 也能夠用 arm['password'] 表示

專門存放變量的文件:

# vars_servers.yml
x86:
    password: 123
arm:
    password: 456

遠程節點的系統變量(facts)

ansible 經過 module setup 收集主機的系統信息,這些收集到的系統信息叫作 facts,這些facts能夠直接以變量的形式使用。

哪些 facts 變量能夠引用的?經過以下命令行調用setup module 能夠查看:

ansible all -m setup -u root

能夠看到它輸出的變量信息有不少!

複雜的facts變量的使用能夠用以下兩種形式:

  • {{ ansible_ens3["ipv4"]["address"] }}
  • {{ ansible_ens3.ipv4.address }}

好用的一些 facts 變量

  • ansible_hostname 指定的 host 名稱
  • ansible_default_ipv4.address 主機真實的 ipv4 地址,小網IP

ansible_os_family 查看系統類型的變量

---
- hosts: all
  user: root
  tasks:
  - name: echo system
    shell: echo {{ ansible_os_family }}
  - name install ntp on Debian linux
    apt: name=git state=installed
    when: ansible_os_family == "Debian"
  - name install ntp on redhat linux
    yum: name=git state=present
    when: ansible_os_family == "RedHat"

關閉 facts

在 playbook 中,若是不收集系統信息,那麼上面的變量就不能再 playbook 中使用了,可是有時候關閉會加快執行的效率:

- hosts: all
  gather_facts: no

註冊變量 register

將某個 task 執行的結果「註冊」爲一個變量。後面的 action 就可使用它

---
- hosts: centos
  tasks:
      - name: ls /tmp
        shell: ls -l /tmp
        register: result
        ignore_errors: True

      - name: echo result when rc==5
        shell: echo "{{result}}"
        when: result.rc == 5

      - name: debug show stdout
        debug:
          msg: "{{result.stdout}}"

「註冊變量」常常和debug module一塊兒使用,這樣能夠得到 action 更多的輸出信息,幫助調試。

參考

命令行傳遞變量 --extra-vars

---
- hosts: "{{hosts}}"
  remote_user: "{{user}}""

  tasks:
    - debug: msg="{{hosts}}""

命令輸入變量:

ansible-playbook extra_learn.yml --extra-vars "{'hosts':'x86','user':‘’michael'}"
# or
ansible-playbook extra_learn.yml --extra-vars "hosts=x86 user=michael"

playbook 中的邏輯控制語句

  • when:條件判斷,相似編程語言中的 if
  • loop:循環,相似編程語言中的 while
  • block:將幾個 task 組成一塊代碼,便於針對一組操做進行異常處理等

條件語句 wehn

例如,在某個特定版本的系統上裝包,或者只在磁盤空間滿了的文件系統上執行清理操做。這些操做在Playbook中用when語句實現。

主機爲Debian Linux馬上關機

tasks:
  - name: "shutdown Debian flavored systems"
    command: /sbin/shutdown -t now
    when: ansible_os_family == "Debian"

根據action的執行結果,來決定接下來執行的action。

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

遠程中的系統變量facts變量做爲when的條件,用「|int」還能夠轉換返回值的類型:

---
- hosts: web
  tasks:
    - debug: msg="only on Red Hat 7, derivatives, and later"
      when: ansible_os_family == "RedHat" and ansible_lsb.major_release|int >= 6

循環語句 loop

標準循環 with_items

爲了保持簡潔,重複的任務能夠用如下簡寫的方式:

- name: add several users
  user: name="{{ item }}" state=present groups=wheel
  with_items:
     - michael
     - qq

若是你在變量文件中或者 ‘vars’ 區域定義了一組YAML列表,你也能夠這樣作:

vars:
  userlist: ["micahel", "qq"]
tasks:
  -name: add several user
   user:
     name: "{{ item }}"
     state: present
     groups: wheel
   with_items: "{{userlist}}"

使用 with_items 用於迭代的條目類型不只僅支持簡單的字符串列表.若是你有一個哈希列表,那麼你能夠用如下方式來引用子項:

- name: add several users
  user: name="{{ item.name }}" state=present groups="{{ item.groups }}"
  with_items:
    - { name: 'michael', groups: 'wheel' }
    - { name: 'qq', groups: 'root' }

對哈希表使用循環 with_dict

這個例子不只演示了 with_dict 用法,還使用循環安裝了 RPM 包

---
- hosts: centos
  vars:
    users:
      michael:
        name: michael xiang
        phone: 123
      qq:
        name: qq huang
        phone: 456

    rpms:
        - httpd
        - lrzsz
        - vim
        - git

  tasks:
    - name: print phone records
      debug: msg="User {{item.key }} is {{ item.value.name }} {{item.value.phone}}"
      with_dict: "{{ users }}"

    - name: install rpms
      yum: name="{{item}}" state=installed
      with_items: "{{rpms}}"

對文件列表使用循環 with_filegloab

with_fileglob 能夠以非遞歸的方式來模式匹配單個目錄中的文件.以下面所示:

tasks:

    # first ensure our target directory exists
    - file: dest=/etc/fooapp state=directory

    # copy each file over that matches the given pattern
    - copy: src=\{\{ item \}\} dest=/etc/fooapp/ owner=root mode=600
      with_fileglob:
        - /playbooks/files/fooapp/*

參考

塊語句

多個action組裝成塊,能夠根據不一樣條件執行一段語句 :

tasks:
     - block:
         - yum: name=\{\{ item \}\} state=installed
           with_items:
             - httpd
             - memcached

         - template: src=templates/src.j2 dest=/etc/foo.conf

         - service: name=bar state=started enabled=True

       when: ansible_distribution == 'CentOS'
       become: true
       become_user: root

ansible 示例

參考

相關文章
相關標籤/搜索