三個層面學playbook(核心)

三個層面學playbook(核心)

ansible-playbook是ansible工具中的核心,對比ad-hoc(ansible)命令,能夠把playbook理解爲一系列動做的組成,結果傳遞、判斷等等,這些是ansible命令沒法完成的。
ansible中如何使用yaml編寫playbook,這對於不少人來講不容易搞懂,特別是層級縮進關係方面。
我打算從三個層面講playbook編寫,正如4.7所說,按照playbook、play、tasks三個層面理解
playbook關鍵字
附上官網關關鍵字連接,本文對其中一部分舉例,注意只是一部分介紹,我也不懂所有,介紹這些只爲了理解playbook書寫規則,規則掌握了,後續學習基本不會迷路html

# 先附上一部分綜合例子,便於後面理解
---
- hosts: lzcx
  # gather_facts: False
  connection: local
  become: yes
  remote_user: root
  vars:
    var1: value1
    var2: value2
  tasks:
    - debug: msg="{{var2}} {{var3}}"
      vars:
        var2: value3
        var3: value4
      when: ansible_distribution_major_version == "7"
    - name: print something
      shell: echo {{item}}
      with_items:
        - zhangsan
        - lisi
        - wangwu
      register: hi
      ignore_errors: True
    - debug: msg="{% for i in hi.results %} {{i.stdout}} {% endfor %}"

5.一、playbook層面

playbook層面,由於一個playbook通常一個play,便於維護,這裏不做詳細介紹。mysql

5.二、play層面(重要)

play層面,對應元素hosts, tasks, 變量vars, connection, remote_user, become、name, 等等,這裏介紹常見的元素。web

5.2.一、hosts指定主機

指定inventory中的主機或主機組,一個play對應一個hosts,通常yaml文件裏面就一個hosts,定義在開頭
取值方面,多個值按逗號","分割,支持2.5節裏面的匹配,具體查看2.5節sql

5.2.二、gether_facts

獲取遠程主機信息,關閉時能加快playbook執行速度,前提是不須要獲取主機信息,當須要調用主機信息相關變量,能夠用setup模塊查看,例如"ansible_all_ipv4_addresses",不能關閉該選項
本章開始的gether_facts註釋打開,則when語句行須要註釋shell

5.2.三、connection

說明文檔原文"connection type to use (default=smart)",默認會根據環境自動設置,通常不用本身設置apache

5.2.四、become

是否切換爲其餘用戶,值爲yes|no編程

5.2.五、become_user

切換的用戶json

5.2.六、vars定義變量

須要注意的是vars是能夠存在了play層面和tasks層面的元素,同時tasks層面的vars變量會覆蓋play層面的同名變量,這一點比較特殊,參考 5.3.1.四、 vars定義變量centos

5.三、tasks層面(重要)

5.3.一、變量

ansible中定義變量的⽅式有不少種,⼤致有:(1)將模塊的執⾏結果註冊爲變量;(2)直接定義字典類型的變量;(3)role中⽂件內定義變量;(4)命令⾏傳遞變量;(5)藉助with_items迭代將多個task的結果賦值給⼀個變量;(6)inventory中的主機或主機組變量;(7)內置變量數組

5.3.1.二、register註冊變量

使⽤register選項,能夠將當前task的輸出結果賦值給⼀個變量,注意,模塊的輸出結果是json格式的,因此,引⽤變量時要指定引⽤的對象

---
    - hosts: lzcx
      tasks:
        - shell: echo 'hahaha'
          register: temp
        - debug: var=temp.stdout

5.3.1.三、 set_fact定義變量

set_fact和register的功能很類似,也是將值賦值給變量。它更像shell中變量的賦值⽅式,能夠將某個變量的值賦值給另⼀個變量,也能夠將字符串賦值給變量

---
    - hosts: lzcx
      tasks:
        - shell: echo haha
          register: say_ha
        - set_fact: var1="{{say_ha.stdout}}"
        - set_fact: var2="your name is"
        - debug: msg="{{var2}} {{var1}}"

5.3.1.四、 vars定義變量

能夠在play或task層次使⽤vars定義字典型變量。若是同名,則task層次的變量覆蓋play層次的變量

---
    - hosts: lzcx
      vars:
        var1: value1
        var2: value2
      tasks:
        - debug: msg="{{var1}} {{var2}}"
          vars:
            var2: value2.2          # tasks層次的變量會覆蓋play層次的同名變量

5.3.1.五、 roles中的變量

因爲role是整合playbook的,它有默認的⽂件組織結構。其中有⼀個⽬錄vars,其內的main.yml⽤於定義變量。還有defaults⽬錄內的main.yml則是定義role默認變量的,默認變量的優先級最低

5.3.1.六、 命令行傳遞變量

ansible和ansible-playbook命令的"-e"選項均可以傳遞變量,傳遞的⽅式有兩種: -e key=value 和 -e @var_file 。注意,當key=value⽅式傳遞變量時,若是變量中包含特殊字符,必須防⽌其被shell解析

ansible localhost -m shell -a "echo {{say_hi}}" -e 'say_hi="hello world"'
ansible localhost -m shell -a "echo {{say_hi}}" -e @/tmp/var_file1.yml
# /tmp/var_file1.yml 內容
---
    say_hi: zhangsan lisi

5.3.1.七、 藉助with_items疊加變量

ansible中能夠藉助with_items實現列表迭代的功能,做⽤於變量註冊的⾏爲上,就能夠實現將多個結果賦值給同⼀個變量
例以下⾯的playbook中,給出了3個item列表,並在shell模塊中經過固定變量"{{item}}"分別迭代,第⼀次迭代的是haha,第⼆次迭代的是heihei,第三次迭代的是hehe,也就實現了3次循環。最後,將結果註冊爲變量hi_var。還可使⽤f or循環遍歷列表

#
---
    - hosts: lzcx
      connection: local
      remote_user: root
      become: yes
      tasks:
        - name: test with items
          shell: echo "{{item}}"
          with_items:
            - haha
            - heihei
            - hehe
          register: hi_var
        - debug: var=hi_var.results[0].stdout
        - debug: var=hi_var.results[1].stdout
        - debug: var=hi_var.results[2].stdout
        - debug: msg="{% for i in hi_var.results %} {{i.stdout}} {% endfor %}"

每次迭代的過程當中,調⽤item的模塊都會將結果保存在⼀個key爲results的數組中。所以,引⽤迭代後註冊的變量時,須要在變量名中加上results,並指定數組名。例如上⾯的 hi_var.results[N].stdout
建議使用循環輸出格式

5.3.1.八、 inventory中的主機變量和組變量

在inventory⽂件中能夠爲主機和主機組定義變量,不只包括內置變量賦值,還包括⾃定義變量賦值。
主機變量優先級⾼於主機組變量,給定的主機組變量優先級⾼於all特殊組

# 自定義臨時清單
cat /tmp/hosts
192.168.1.214 ansible_ssh_port=22 var1=1   # 主機內置變量,這類變量不能調用
[centos7]
192.168.1.214 var1=2    # 主機變量,優先級最高
[centos7:vars]
var1=2.2                    # 主機組變量,優先級次之
var2=3
[all:vars]
var2=4                      # 全部組變量,優先級最低
# 執行查看變量優先級
ansible 192.168.1.214 -i /tmp/hosts -m shell -a 'echo "{{var1}} {{var2}}"'
# 結果
192.168.1.214 | CHANGED | rc=0 >>
2 3

5.3.1.九、內置變量

ansible除了inventory中內置的⼀堆不可被引⽤的設置類變量,還有⼏個全局均可以引⽤的內置變量,主要有如下⼏個:
inventory_hostname、inventory_hostname_short、groups、groups_names、hostvars、play_hosts、inventory_dir、ansible_version

  1. inventory_hostname和inventory_hostname_short
    分表表明的是inventory中被控節點的主機名和主機名的第⼀部分,若是定義的是主機別名,則變量的值也是別名
  2. groups和group_names
    group_names返回的是主機所屬主機組,若是該主機在多個組中,則返回多個組,若是它不在組中,則返回
    ungrouped這個特殊組
    groups變量則是返回其所在inventory⽂件中全部組和其內主機名。注意,該變量對每一個控制節點都返回⼀次,因此返回的內容可能⾮常多
  3. hostvars
    該變量⽤於引⽤其餘主機上收集的facts中的數據,或者引⽤其餘主機的主機變量、主機組變量。其key爲主機名或主機組名。但注意,在引⽤其餘主機facts中數據時,要求被引⽤主機進⾏了facts收集動做,或者有facts緩存。不然都沒收集,固然⽆法引⽤其facts數據。也就是說,當被引⽤主機沒有facts緩存時,ansible的控制節點中必須同時包含引⽤主機和被引⽤主機。
    除了引⽤其餘主機的facts數據,還能夠引⽤其餘主機的主機變量和主機組變量,且不要求被引⽤主機有facts數據,由於主機變量和主機組變量是在ansible執⾏任務前加載的
  4. play_hosts和inventory_dir
    play_hosts表明的是當前play所涉及inventory內的全部主機名列表
    inventory_dir是所使⽤inventory所在的⽬錄
  5. ansible_version

5.3.二、循環

ansible中的循環都是藉助迭代來實現的。基本都是以"with_"開頭。如下是常見的⼏種循環

5.3.2.一、with_items迭代列表(重要)

參考 5.3.1.7,

5.3.2.二、with_dict迭代字典項

使⽤"with_dict"能夠迭代字典項。迭代時,使⽤"item.key"表⽰字典的key,"item.value"表⽰字典的值
另⼀種狀況,字典是已存儲好的。例如ansible f acts中的ansible_eth0.ipv4,這種狀況下,with_dict處能夠直接指定該字典的key

5.3.2.三、with_fileglob迭代⽂件

例如,拷貝⼀堆⽤通配符匹配出來的⽂件到各遠程主機上,注意,通配符⽆法匹配"/",所以⽆法遞歸到⼦⽬錄中,也就⽆法迭代⼦⽬錄中的⽂件

5.3.2.四、with_lines迭代⾏(重要)

能夠將命令⾏的輸出結果按⾏迭代。例如,find⼀堆⽂件出來,copy⾛

---
    - hosts: localhost
      tasks:
        - copy: src="{{item}}" dest=/tmp/yaml
          with_lines:
            - find /tmp -type -f -name "*.yml"

5.3.2.四、 with_nested嵌套迭代

嵌套迭代是指屢次迭代列表項

---
- hosts: localhost
  tasks:
    - debug: msg="{{item[0]}} & {{item[1]}}"
      with_nested:
        - [a, b]
        - [1, 2, 3]

5.3.三、 條件判斷when

在ansible中,只有when語句能夠實現條件判斷。when判斷的對象是task,因此和task在同⼀列表層次。它的判斷結果決定它所在task是否執⾏,⽽不是它下⾯的task是否執⾏。when中引⽤變量的時候不須要加{{ }}符號。

tasks: 
 - name: config the yum repo for centos 6
   yum_repository:
     name: epel
     description: epel
     baseurl: http://mirrors.aliyun.com/epel/6/$basearch/
     gpgcheck: no
   when: ansible_distribution_major_version == "6"

when語句支持邏輯操做,或(or)、與(and)也能夠分行寫、非(not)
支持直接引用定義了布爾值的變量
可使⽤jinja2的 defined 來測試變量是否已定義,使⽤ 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

5.3.四、報錯處理failed_when

該選項相似編程語言中的try語句,可以抓取報錯信息,讓playbook執行完成

---
- hosts: lzcx
  tasks:
    - name: this command prints FAILED when it fails
      command: /usr/bin/example-command -x -y -z
      register: command_result
      failed_when: "FAILED in command_result.stdout"

很明顯,例子中的命令不存在,即執行失敗,failed_when經過調用註冊變量打印錯誤信息,此時會生成yaml文件同名的retry後綴格式文件

5.3.五、命名name

用於給模塊自定義命名,若是沒有設置,默認輸出模塊名

5.3.六、ignore_errors

忽略報錯信息

---
- hosts: lzcx
  tasks:
    - name: this command prints FAILED when it fails
      command: /usr/bin/example-command -x -y -z
      register: command_result
      ignore_errors: True
      failed_when: "FAILED in command_result.stdout"

此時不會生成yaml文件同名的retry後綴格式文件

5.3.七、tag標籤

能夠爲playbook中的每一個任務都打上標籤,標籤的主要做⽤是能夠在ansible-playbook中設置只執⾏哪些被打上tag的任務或忽略被打上tag的任務,如下是ansible-playbook中關於tag的選項

--list-tags # list all available tags
t TAGS, --tags=TAGS # only run plays and tasks tagged with these values
--skip-tags=SKIP_TAGS # only run plays and tasks whose tags do not match these values

tasks:
  - name: make sure apache is running
    service: name=httpd state=started
    tags: apache
  - name: make sure mysql is runnig
    service: name=mysqld state=started
    tags: mysql

5.3.八、include

include的設計是爲了讓playbook模塊化,將任務中的playbook分拆,細化各個部分,便宜維護和複用
能夠將task列表和handlers獨⽴寫在其餘的⽂件中,而後在某個playbook⽂件中使⽤include來包含它們。除此以外,還能夠寫獨⽴的playbook⽂件,使⽤include來包含這個⽂件。也便是說,include能夠導⼊兩種⽂件:導⼊task、導⼊playbook。除此以外還能夠傳入變量給include
注意:nsible2.4以前,引入外部task或play只有include方法,在2.4以後,新增了includes和imports方法,具體查看官網說明includes和imports
用法一

# 引入task列表文件,a.yml
---
- name: execute ntpdate
  shell: /usr/sbin/ntpdate ntp1.aliyun.com
- name: execute the variables
  debug: msg="{{hi}} {{haha}}"

同級目錄下調用a.yml

---
- hosts: localhost
  tasks:
    - include: a.yml hi="Hello world"    # 傳入參數
      vars:
        haha: "ni hao ya"                    # 用vars傳遞參數

用法二

# 引入整個playbook,因爲是引入整個playbook,加載裏面的play,須要注意層級關係
- name: this is a play at the top level of a file
  hosts: localhost
  become: yes
  remote_user: root
  tasks:
    - name: say hi
      tags: foo
      shell: echo "hahaha"
- include: webserver.yml   # 注意層級關係
- include: dbserver.yml

從上面兩個例子能夠看出,include和vars元素同樣,是能夠跨層級出現的,二者跨的層級不一樣,vars是跨play和tasks;include是跨tasks和playbook

5.3.九、notify和handlers

notify:ansible中⼏乎全部的模塊都具備冪等性,這意味着被控主機的狀態是否發⽣改變是能被捕捉的,即每一個任務的changed=true或changed=false
ansible在捕捉到changed=true時,能夠觸發notify組件,notify是⼀個組件,並⾮⼀個模塊,它能夠直接定義action,其主要⽬的是調⽤handler
notify這個action可用於在每一個play的最後被觸發,這樣能夠避免屢次有改變發生時每次都執行指定的操做,取而代之,僅在全部的變化發生完成後一次性地執行指定操做
handlers:handlers是一些 task 的列表,經過名字來引用,它們和通常的 task 並無什麼區別,handlers裏面的name必需要和notify一致,最佳的應用場景是用來重啓服務,或者觸發系統重啓操做

tasks:
  - name: template configuration file
    template: src=template.j2 dest=/etc/foo.conf
    notify:
      - restart memcached
      - restart apache
    handlers:
      - name: restart memcached
        service: name=memcached state=restarted
      - name: restart apache
        service: name=apache state=restarted

5.3.十、總結

ansible中的playbook到此介紹,基礎部分相信可以搞懂了,至少版本新特性,進階高級用法等等,對於掌握規則來講不難,規則掌握以後,跟着官網例子學習就能夠了

相關文章
相關標籤/搜索