Ansible 入門指南 - ansible-playbook 命令


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

Playbook 譯為「劇本」,覺得還挺恰當的。

playbook 執行語法

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

playbook 基礎

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

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

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

palybook 小栗子

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

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

  • 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, 其中包含以下部署步驟:

  • 安裝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即可執行。

tasks

taks 參數其實是有不同寫法的,當參數比較少時,可用key=value的方式

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 示例

參考


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM