第3章 Ansible 進(jìn)階

3.1 Ansible 的配置

3.1.1 可以配置什么

安裝好Ansible后,通過 /etc/ansible/ansible.cfg 文件的內(nèi)容和注釋可以了解到所有可以配置的選項(xiàng)顶捷,下面距離我們常用的配置

#可以配置主機(jī)清單文件 inventory达椰、extra模塊放置的路徑 library翰蠢、遠(yuǎn)程主機(jī)的臨時(shí)目錄 remote_tmp,以及管理節(jié)點(diǎn)上的臨時(shí)目錄 local_tmp
inventory      = /etc/ansible/hosts
library        = /usr/share/my_modules/
remote_tmp     = ~/.ansible/tmp
local_tmp      = ~/.ansible/tmp

# 可以配置連接端口號(hào) accelerate_port啰劲、超時(shí)時(shí)間等
accelerate_port = 5099
accelerate_timeout = 30
accelerate_connect_timeout = 5.0

3.1.2 Ansible 配置文件的優(yōu)先級(jí)

優(yōu)先級(jí)從高到低的排序

  • ANSIBLE_CONFIG 配置的環(huán)境變量
  • 當(dāng)前目錄的ansible.cfg
  • 家目錄下的 .ansible.cfg
  • /etc/ansible/ansible.cfg

3.2 主機(jī)清單

主機(jī)清單(Host Inventory)梁沧,它告訴Ansible 需要管理哪些主機(jī),以及這些主機(jī)的分類和分組信息的文件蝇裤⊥⒅В可以認(rèn)為這是個(gè)文件版的CMDB系統(tǒng)。

Inventory的默認(rèn)文件為 /etc/ansible/hosts 栓辜,可以通過 /etc/ansible/ansible.cfg 配置文件進(jìn)行修改恋拍。此外,我們還可以通過 -i 參數(shù)來指定主機(jī)清單配置文件

ansible-playbook -i test.ini site.yml

當(dāng)然我們也可以使用 --inventory-file 參數(shù)來進(jìn)行指定藕甩。

3.2.1 遠(yuǎn)程主機(jī)的分組

在inventory文件中施敢,可以通過 "[]" 符號(hào)給主機(jī)做分組。此外狭莱,分組還支持嵌套僵娃,如下。

mail.example.com

#簡(jiǎn)單的分組
[db]
one.example.com
two.example.com

[web]
www[01:50].example.com

#嵌套分組
[linuxserver:children]
db
web

3.2.2 設(shè)置連接參數(shù)

Ansible 可以在Inventory 文件中指定主機(jī)的連接參數(shù)腋妙,包括連接的方法默怨、用戶等。在Inventory中設(shè)置鏈接的參數(shù)如下辉阶,用空格分割多個(gè)參數(shù)

[targets]
localhost ansible_connect=local
other1.example.com ansible_connect=ssh ansible_user=root 
other1.example.com ansible_connect=ssh ansible_user=pangcm

其他常用的連接參數(shù)如下

連接參數(shù)的值 連接參數(shù)的含義
ansible_connection SSH的連接方式先壕,可以指定為 smart、ssh或者paramiko
ansible_host Ansible連接的主機(jī)地址谆甜,如果你要在Ansible中給主機(jī)起了一個(gè)不同的別名垃僚,那么需要使用這個(gè)參數(shù)
ansible_port SSH端口號(hào),默認(rèn)為22
ansible_user SSH連接時(shí)默認(rèn)的用戶名
ansible_ssh_pass SSH連接時(shí)使用的密碼规辱,不建議用本參數(shù)存儲(chǔ)明文密碼谆棺,盡量使用values對(duì)密碼進(jìn)行加密存儲(chǔ)
ansible_ssh_private_key_file 基于key的SSH連接,使用的是private key 文件
ansible_ssh_common_args 通過配置本參數(shù)指定SFTP、SCP和SSH默認(rèn)的額外參數(shù)

以上的參數(shù)除了能夠在Inventory文件中定義改淑,還可以在playbook中定義或者通過變量的方式傳入碍岔。

3.2.3 變量

Anible 支持在主機(jī)清單文件中指定變量,或者與主機(jī)清單文件同目錄的特定子目錄和文件中定義變量

  1. 主機(jī)清單文件中的變量
#為單個(gè)主機(jī)指定變量
[app]
host1 http_port=80
host2 http_port=81

#為一個(gè)組指定變量
[app:vars]
http_port=80
  1. 按目錄結(jié)果存儲(chǔ)的變量
    假設(shè)主機(jī)清單文件為 /etc/ansible/hosts朵夏,那么相關(guān)的Host和Group變量可以放在 /etc/ansible/host_vars 和 /etc/ansible/group_vars 下同名目錄中的文件蔼啦,通常使用 yaml 文件。如下:
#host1的變量
/etc/ansible/host_vars/host1.yml

#app組的變量
/etc/ansible/group_vars/app.yml

這時(shí)候yaml文件存放的變量格式為 key:value 的形式仰猖,如下

---
hppt_port: 80

如果你的變量非常多捏肢,多到一個(gè)文件都存不下。那么你可以在同名目錄下分開多個(gè)文件來存放變量饥侵,如下:

#host1的變量
/etc/ansible/host_vars/host/vars1.yml
/etc/ansible/host_vars/host/vars2.yml

3.3 Ansible 的腳本Playbook

3.3.1 Playbook的文件格式 YAML

Playbook是ANsible的腳本語言鸵赫,使用的YAML格式。YAML和JSON類似躏升,是一種數(shù)據(jù)表示格式辩棒,下面介紹一些關(guān)于YAML語言的基本知識(shí)。

# 文件開始符
---

# 數(shù)組list
- element1
- element2
- element3

#字典
key: value

#字典的嵌套
pangcm:
  name: pangcm
  job: ops
  skill: ansible

# 字典和數(shù)組的嵌套
- pangcm1:
    name: pangcm1
    job: ops
    skills: 
      - ansible
      - linux
      - python

- pangcm2:
    name: pangcm2
    job: ops
    skills: 
      - ansible
      - linux
      - python

需要注意的地方膨疏,變量里面如果有冒號(hào) ":" 時(shí)需要加上引號(hào)一睁,變量以 "{" 開頭時(shí)也要加上引號(hào)

foo: "foo:bar"

foo: "{{ variable }}"

3.3.2 執(zhí)行Playbook的命令

執(zhí)行Playbook需要使用單獨(dú)的命令: ansible-playbook,常用的使用方法如下

# 基本使用方法
ansible-playbook deploy.yaml

# 查看輸出西街
ansible-playbook deploy.yaml -v

# 查看腳本會(huì)影響哪些主機(jī)
ansible-playbook deploy.yaml --list-hosts

# 并行執(zhí)行腳本(默認(rèn)的并發(fā)數(shù)量為5)
ansible-playbook deploy.yaml -f 10

3.3.3 Playbook 的基本語法

最基本的Playbok腳本分為三個(gè)部分:

  1. 在什么機(jī)器以什么身份執(zhí)行
    • hosts
    • user
  2. 執(zhí)行的任務(wù)都有什么
    • tasks
  3. 善后的任務(wù)都有什么
    • handlers

下面針對(duì)這上面提到的三個(gè)部分做介紹

  1. 主機(jī)和用戶
key 含義
hosts 為主機(jī)的IP成肘,或者主機(jī)組名卖局,或者關(guān)鍵字all
user 在遠(yuǎn)程以哪個(gè)身份執(zhí)行
become 切換成其他用戶執(zhí)行斧蜕,值為 yes或者no
become_method 與become一起使用双霍,值可以為 "sudo/su/pfexec/doas"
become_user 與become一起用,默認(rèn)為root批销,也可以是其他用戶名

腳本里面使用become時(shí)洒闸,執(zhí)行Playbook必須加參數(shù) --ask-become-pass,提示用戶輸入 "sudo" 的密碼。

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

你也可以在Inventory中定義 ansible_sudo_pass 變量來避免每次都需要手工交互式地輸入sudo密碼均芽。

  1. 任務(wù)列表
    • 任務(wù)(task)是從上到下順序執(zhí)行的丘逸,如果中間發(fā)生錯(cuò)誤,那么整個(gè)Playbook會(huì)中止掀宋。
    • 每個(gè)任務(wù)都是對(duì)模塊的一次調(diào)用深纲,只是使用不用的參數(shù)和變量而已。
    • 每個(gè)任務(wù)最好有 name 屬性劲妙,這是供人讀的湃鹊,沒有實(shí)際的操作。但是有這樣的輸出镣奋,我們能更好地知道執(zhí)行的情況以及task的用途币呵。

下面是一個(gè)簡(jiǎn)單的示例:

tasks:
# name 是可選的,建議使用
- name: make sure apache is running
  service: name=httpd state=running

# 上面的參數(shù)使用的是 key=value的形式侨颈,也可以使用key:value的形式余赢。
- name: copy ansible inventory file to client
  copy:
    src: /etc/ansible/hosts
    dest: /etc/ansible/hosts
    mode: 0644

任務(wù)中Action會(huì)調(diào)用一個(gè)模塊芯义,然后在模塊中檢查當(dāng)前系統(tǒng)狀態(tài)是否需要重新執(zhí)行。如果本次執(zhí)行了妻柒,那么Action返回的值為changed扛拨。如果不需要執(zhí)行,那么返回的是ok举塔。

  1. 響應(yīng)事件handler
    • 什么是handler
      每個(gè)主流的編程語言都有Event機(jī)制鬼癣,而handler就是Playbook的Event。Handlers里面每一個(gè)handler都是對(duì)模塊的一次調(diào)用啤贩。但是和task任務(wù)不同待秃,handler只有在它需要在任務(wù)中被調(diào)用的時(shí)候才有可能被執(zhí)行。
      前面提到痹屹,任務(wù)表中的任務(wù)都是有狀態(tài)的:changed或者ok章郁。在Ansible中,只有在任務(wù)的執(zhí)行狀態(tài)為changed的時(shí)候志衍,才會(huì)執(zhí)行該任務(wù)調(diào)用的handler暖庄。這也是handller和普通的Event機(jī)制不同的地方。

    • 應(yīng)用場(chǎng)景
      什么情況下使用handler呢?如果你在任務(wù)中修改了Apache的配置文件楼肪,嘛呢需要重啟Apache培廓。如果你安裝了一個(gè)Apache插件,那么也需要重啟Apache春叫。這時(shí)候肩钠,重啟Apache就可以設(shè)計(jì)成一個(gè)handler。
      一個(gè)handler最多只執(zhí)行一次暂殖,并且在所有任務(wù)都執(zhí)行完之后再執(zhí)行价匠。如果有多個(gè)任務(wù)調(diào)用(notify)同一個(gè)handler,那么只執(zhí)行一次呛每。

下面是一個(gè)示例,第一次執(zhí)行的時(shí)候會(huì)觸發(fā)兩個(gè)handler踩窖,第二次執(zhí)行的之后只會(huì)觸發(fā)第二個(gè)handler。

---
- hosts: lb
  remote_user: root
  vars:
    random_number: "{{ 10000 |random }}"
  tasks:
  - name: Copy the /etc/hosts to /tmp/hosts
    copy: src=/etc/hosts dest=/tmp/hosts
    notify:
      - call by /tmp/hosts

  - name: Copy the /etc/hosts to /tmp/hosts.{{ random_number }}
    copy:  src=/etc/hosts dest=/tmp/hosts.{{ random_number }}
    notify:
      - call by /tmp/hosts.{{ random_number }} 
  handlers:
  - name: call by /tmp/hosts.{{ random_number }} 
    debug: msg="call by /tmp/hosts.{{ random_number }} " 

  - name: call by /tmp/hosts
    debug: msg="call first time" 

這里需要注意的是handler的執(zhí)行順序是按照定義的順序晨横,而不是任務(wù)調(diào)用的順序洋腮。就是說定義的時(shí)候順序是 1,2,3;但是調(diào)用的時(shí)候是 3,2,1 手形;但是最后執(zhí)行的時(shí)候還是 1,2,3 的順序啥供。

3.3.4 變量

在Playbook中,常用的幾種變量包括以下幾種情況

  • 在Playbook中用戶自定義的變量
  • 用戶無須自定義叁幢,Ansible會(huì)在執(zhí)行Playbook之前去遠(yuǎn)程主機(jī)搜集關(guān)于遠(yuǎn)程節(jié)點(diǎn)系統(tǒng)的信息變量
  • 在文件模版中滤灯,可以直接使用上述兩種變量
  • 把任務(wù)的運(yùn)行結(jié)果作為一個(gè)變量來使用,這個(gè)變量叫做注冊(cè)變量
  • 為了使Playbook更靈活、通用性更強(qiáng)鳞骤,允許用戶在執(zhí)行Playbook時(shí)傳入變量的值窒百,這時(shí)候需要額外變量。
  1. 在Playbook中用戶自定義的變量
    用戶在Playbook中使用變量時(shí)需要使用 "{{ }}" 引用起來即可豫尽。在Playbook中篙梢,我們可以使用vars關(guān)鍵字來定義變量,也可以使用var_files來引入變量文件美旧。如下所示:
#使用vars來定義變量
- hosts: web
  vars:
    http_port: 80
  tasks:
  ....

#使用var_files來引入變量文件
- hosts: web
  var_files:
    - vars/server_vars.yaml
  tasks:
  ....

有時(shí)候我們需要使用變量的值不是簡(jiǎn)單的字符串或者數(shù)字渤滞,而是一個(gè)對(duì)象,這時(shí)候定義的語法如下榴嗅,格式為YAML的字典格式妄呕。

---
- hosts: localhost
  vars:
    foo:
      field1: one
      field2: two
  tasks:
  - name: use vars
    debug:
      var=foo['field1'] #也可以foo.field1

要注意有些時(shí)候YAML和Ansible Playbook的變量語法不能在一起好好地工作。這通常發(fā)生在冒號(hào)后面的值有 "{" 開頭的變量時(shí)嗽测,如果不加上引號(hào)绪励,就很有可能報(bào)語法錯(cuò)誤。

  1. 遠(yuǎn)程主機(jī)的系統(tǒng)變量(Facts)
    Ansible 會(huì)通過模塊 "setup" 來搜集主機(jī)的系統(tǒng)信息唠粥,這些收集到的系統(tǒng)信息叫做Facts.每個(gè)Playbook在執(zhí)行前都會(huì)默認(rèn)執(zhí)行setup模塊疏魏,所以這些Facts信息可以直接以變量的形式使用。

那么晤愧,我們?cè)趺粗烙心切〧acts變量可以引用呢大莫,我們可以使用setup模塊來查看下:

ansible all -m setup -u root

在Playbook中,我們可以和使用普通變量一樣來使用Facts變量官份。這里需要特別說明的是如何使用Facts中的復(fù)雜變量只厘。答案是可以通過下面兩種方式,如下:

#中括號(hào)
{{ ansible_ens3['ipv4']['address'] }}

#點(diǎn)號(hào)
{{ ansible_ens3.ipv4.address }}

收集Facts信息會(huì)消耗額外的時(shí)間,Ansible 的默認(rèn)配置中要求搜集這些信息贯吓。如果要關(guān)閉懈凹,可以通過關(guān)鍵字 gather_facts來關(guān)閉蜀变。如下

- hosts: db
  gather_facts: no
  1. 文件模版中使用的變量

template模塊在Ansible中十分常用悄谐,而他在使用的時(shí)候有沒有顯示指定template文件中的值,所以有時(shí)候用戶對(duì)template中使用的變量感到困惑库北,所以這里再重新強(qiáng)調(diào)下它的變量的使用爬舰。

template能直接使用再Playbook中定義的變量,也可以使用Facts變量寒瓦,所有再Playbook中可以訪問的變量情屹,都可以再template文件中使用。通常template文件我們都是使用 j2作為后綴杂腰,因?yàn)檫@是使用jinja2的文件格式垃你,里面的變量需要使用 "{{}}" 括起來。

  1. 把運(yùn)行結(jié)果當(dāng)作變量使用-注冊(cè)變量

這時(shí)候就需要使用注冊(cè)變量了,把執(zhí)行的結(jié)果注冊(cè)到變量中惜颇,給后面的任務(wù)使用皆刺。把執(zhí)行結(jié)果注冊(cè)到變量中的關(guān)鍵字是register,使用方法如下:

---
- hosts: web
  tasks:
  - name: exec shell
    shell: ls
    register: result
    ignore_errors: True

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

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

注冊(cè)變量經(jīng)常和debug模塊一起使用凌摄,這樣可以得到更多的關(guān)于執(zhí)行錯(cuò)誤的信息羡蛾,以幫助用戶調(diào)試。

  1. 用命令行傳遞參數(shù)

為了使Playbook更靈活锨亏、通用性更強(qiáng)痴怨,允許用戶在執(zhí)行的時(shí)候傳入變量的值,這時(shí)候就需要用到 "額外變量"器予。

使用命令行傳遞參數(shù)可以使用 --extra-vars 也可以使用簡(jiǎn)寫 -e 浪藻。如下所示:

#在命令行中傳值的方法
ansible-playbook test_var.yaml -e "host=web user=root"

#還可以使用json格式傳遞參數(shù)
ansible-playbook test_var.yaml -e "{'host':'web','user':'root'}"

#還可以將參數(shù)放在文件里面
ansible-playbook test_var.yaml -e "@vars.json"

上面的例子可以下面的playbook。

---
- hosts: localhost
  tasks:
  - name: show vars
    debug: msg="host is {{ host }}, user is {{ user }}"

3.3.5 Playbook 也有邏輯控制語句

  • when: 條件判斷語句乾翔,類似編程語言中的if珠移。
  • loop: 循環(huán)語句,類似于編程語言中的while末融。
  • block: 把幾個(gè)任務(wù)組在一個(gè)代碼塊钧惧,以便針對(duì)一組操作的異常進(jìn)行處理等操作。
  1. 條件判斷語句when
    有時(shí)候用戶很有可能需要滿足特定條件才去執(zhí)行特定的步驟勾习,如在某一特定的版本的系統(tǒng)上安裝軟件包浓瞪。如下:
tasks:
#遠(yuǎn)程主機(jī)如果是debian,立刻關(guān)機(jī)
- name: "shutdown Debian systems"
  command: /sbin/shutdown -t now
  when: ansible_os_family == "Debian"

#根據(jù)Action的執(zhí)行結(jié)果巧婶,來決定是否執(zhí)行任務(wù)
- name: result is false
  command: /bin/false
  register: result
  ignore_errors: True
- name: exec shell
  shell: /bin/something
  when: result | failed
- name: exec other shell
  shell: /bin/something_else
  when: result | success

#還可以使用 |int 對(duì)返回值的類型做轉(zhuǎn)換,如下
- name: "只有在rhel7或者更新的版本上執(zhí)行任務(wù)"
  debug: "msg=hello pcm"
  when: ansible_os_family == "RedHat" and ansible_lsb.major_release | int >= 6

除了上面的用法外乾颁,我們還可以使用條件表達(dá)式

---
- hosts: localhost
  vars:
    epic: true
  tasks:
  - name: "使用布爾表達(dá)式"
    shell: echo "This is epic"
    when: epic

  - name: "布爾表達(dá)式前面可以加上not"
    shell: echo "This is epic"
    when: not epic

  - name: "還可以判斷變量有沒有定義"
    shell: echo "This is epic"
    when: epic is not defined

  - name: "還可以比較數(shù)值大小"
    shell: echo "This is epic"
    when: epic > 5

when除了能夠用在task上,我們還會(huì)和Include或者Role一起來使用艺栈。

---
#當(dāng)deploy為真時(shí)英岭,執(zhí)行deploy.yaml這個(gè)playbook。
- include: tasks/deploy.yaml
  when: deploy
--- 
- hosts: web
  #當(dāng)update為真時(shí)湿右,執(zhí)行名為update的role 
  roles:
    - { role: update, when: update}
  1. 循環(huán)語句 loop
    "with_items" 可以用迭代list類型的變量诅妹,不僅支持簡(jiǎn)單的字符串列表,還可以支持哈希列表毅人,如下:
#最簡(jiǎn)單的列表模式
- name: add serveral user
  user: name={{ item }} state=present groups=wheel
  with_items:
    - testuser1
    - testuser2

#如果在vars中定義了列表變量吭狡,還能這么操作
vars:
  users: ['user1','user2']
tasks:
- name: add serveral user
  user: name={{ item }} state=present groups=wheel
  with_items: "{{ users }}"

#哈希列表這么用,可以使用具體的子項(xiàng)(字典列表)
- name: add serveral user
  user: name={{ item.user }} state=present groups={{ item.group }}
  with_items:
    - {user: 'user1', group:'group1'}
    - {user: 'user2', group:'group2'}

如果同事使用when和with_items(或其他循環(huán)聲明),那么when聲明會(huì)為每個(gè)條目單獨(dú)判斷一次

Ansible的循環(huán)和編程語言的一樣丈莺,也能嵌套循環(huán)
下面嵌套的是列表

---
- hosts: localhost
  tasks:
#使用with_nested,和python一樣划煮,可以使用 []來訪問內(nèi)層循環(huán),也可以使用點(diǎn)號(hào) "." 來訪問缔俄。
  - name: debug loop
    debug: msg="username is {{ item[0] }},password is {{ item[1] }}"
    with_nested:
      - ['pcm1', 'pcm2']
      - ['passwd1', 'passwd2', 'passwd3']

上面playbook執(zhí)行的結(jié)果如下:

TASK [debug loop] ***************************************************************************************************************************************************************************
ok: [localhost] => (item=[u'pcm1', u'passwd1']) => {
    "msg": "username is pcm1,password is passwd1"
}
ok: [localhost] => (item=[u'pcm1', u'passwd2']) => {
    "msg": "username is pcm1,password is passwd2"
}
ok: [localhost] => (item=[u'pcm1', u'passwd3']) => {
    "msg": "username is pcm1,password is passwd3"
}
ok: [localhost] => (item=[u'pcm2', u'passwd1']) => {
    "msg": "username is pcm2,password is passwd1"
}
ok: [localhost] => (item=[u'pcm2', u'passwd2']) => {
    "msg": "username is pcm2,password is passwd2"
}
ok: [localhost] => (item=[u'pcm2', u'passwd3']) => {
    "msg": "username is pcm2,password is passwd3"
}
---
- hosts: localhost
  tasks:
#使用with_dict,和python一樣弛秋,可以使用 []來訪問內(nèi)層循環(huán)器躏,也可以使用點(diǎn)號(hào) "." 來訪問。
  - name: debug loop
    debug: msg="username is {{ item[0] }},password is {{ item[1] }}"
    with_nested:
      - ['pcm1', 'pcm2']
      - ['passwd1', 'passwd2', 'passwd3']

下面嵌套的是哈希表

---
- hosts: localhost
  vars:
    user:
      - user1:
          name: pcm1
          age: 18
      - user2:
          name: pcm2
          age: 20
  tasks:
  - name: print mans
    debug: msg="User {{ item.key }} is {{ item.value.name }},age is {{ item.value.age }}"
    with_dict: "{{ users }}"

對(duì)文件蟹略,我們也可以使用循環(huán)

  tasks:
  - name: "首先確認(rèn)文件是存在的"
    file: dest=/etc/fooapp state=directory
  
  - name: "復(fù)制文件到遠(yuǎn)程目錄上"
    copy: "src={{ item }} dest=/etc/fooapp/ mode=600"
    with_fileglob:
      - /playbooks/files/fooapp/*
  1. 代碼塊 block
    多個(gè)action組成塊后邀桑,可以根據(jù)不同條件執(zhí)行一段語句。好比編程語言中的函數(shù)科乎。
---
- hosts: localhost
  vars:
    flag: true
  tasks:
  - block:
    - name: action1
      debug: msg="hello world"

    - name: action2
      debug: msg="hello ansible"
    when: flag

block除了能和when組合在一起之外壁畸,還可以和rescue和always一起組合。效果可以類比python中的 try茅茂、except捏萍、finally 。如下:

---
- hosts: localhost
  tasks:
  - block:
      - debug:
          msg: 'I execute normally'
      - command: /bin/false
      - debug:
          msg: 'I never execute, due to the above task failing'
    rescue:
      - debug:
          msg: 'I caught an error'
      - command: /bin/false
      - debug:
          msg: 'I also never execute'
    always:
      - debug:
          msg: "This always executes"

3.3.6 重用 Playbook

Playbook支持兩種重用機(jī)制空闲,一種是重用單個(gè)靜態(tài)Playbook嗯見令杈,另外一種是重用特定功能的文件夾,類似于Python等編程語言中的包(Package)碴倾。

  • include語句: 重用單個(gè)Playbook腳本逗噩,使用起來簡(jiǎn)單、直接
  • role語句: 重用實(shí)現(xiàn)特定功能的Playbook文件夾跌榔,使用方法稍復(fù)雜异雁,功能強(qiáng)大。role是Ansible更為推薦的重用和分享Playbook的方式僧须。

1. include語句

include語句是基本的代碼重用機(jī)制纲刀,主要重用任務(wù),同時(shí)担平,include還可以將任務(wù)分割成多個(gè)文件示绊,避免Playbook過于臃腫。

include的使用方法很簡(jiǎn)單暂论,直接使用即可面褐,如下:

#假設(shè)該文件名為main.yaml,下面調(diào)用deploy.yml的Playbook。
---
- hosts: localhost
  tasks:
  - include: deploy.yml

下面是deploy.yml的內(nèi)容取胎,只需要寫上各個(gè)action即可展哭。

- name: action1
  debug: msg=action1

- name: action2
  debug: msg=action2

如果我們想要引用Playbook的時(shí)候傳入?yún)?shù)應(yīng)該怎么操作呢?

#直接在行尾加上參數(shù)即可扼菠,用空格分割
- hosts: localhost
  tasks:
  - include: deploy.yml port=80

#也可以傳入一個(gè)字典作為變量
  - include: deploy.yml
    vars:
      user: pangcm
      port: 80

#上面的字典也可以寫成一串json
  - { include: deploy.yml,user:pangcm,port=80 }

如果你在Playbook中已經(jīng)定義了參數(shù)摄杂,那么就不需要傳入了,直接在被調(diào)用的Playbook中使用即可循榆。

---
- hosts: localhost
  vars:
    port: 80
  tasks:
  - include: deploy.yml

這里要注意 include 的位置,這是在tasks下的墨坚,也就是相當(dāng)于一個(gè)大的action秧饮。如果放在和tasks同級(jí)映挂,也就是全局include。我們不推薦這么做盗尸,因?yàn)樗恢С智度雐nclude柑船,而且很多的Playbook也無法使用,

---
- hosts: localhost
  tasks:
  ...
- include: deploy.yml  

include是場(chǎng)景不大的情況下還是挺好用的泼各,但是如果引用多了這將很難管理鞍时,維護(hù)成本會(huì)變得很多。所以在使用更加靈活的重用機(jī)制時(shí)扣蜻,建議使用下面的role.

2. role-Playbook 的 "Package"

Ansible好比編程語言中的include逆巍,role好比編程語言中的package。通常一個(gè)role由一組文件組成莽使,形成一個(gè)完整的功能锐极。如一個(gè)部署nginx的role,里面會(huì)包含若干playbook和文件芳肌。

Ansibe十分提倡在Playbook中使用role灵再,并且提供了一個(gè)分享role的平臺(tái) ANsible Galaxy。在Galaxy上可以找到別人寫好的role亿笤。

  1. role的目錄結(jié)構(gòu)
    在Ansible中翎迁,通過遵循特定的目錄結(jié)構(gòu),就可以實(shí)現(xiàn)對(duì)role的定義净薛,具體遵循的目錄結(jié)構(gòu)是什么樣子的呢鸳兽?如下:
[root@xxx-test roles]# tree 
.
├── deploy.yml
└── install-nginx
    ├── defaults
    │   └── main.yml
    ├── files
    ├── handlers
    │   └── main.yml
    ├── meta
    │   └── main.yml
    ├── README.md
    ├── tasks
    │   └── main.yml
    ├── templates
    ├── tests
    │   ├── inventory
    │   └── test.yml
    └── vars
        └── main.yml

上面定義了一個(gè)名為install-nginx的role,用來安裝nginx罕拂。Playbook文件中的deploy.yml調(diào)用這個(gè)role揍异。上面的文件不要求全部擁有,看自己的實(shí)際需求爆班。(以上目錄我使用的是ansible-galaxy init install-nginx 創(chuàng)建的衷掷。)

下面解析下role目錄的功能:

  • defaults: 存放變量文件,存放在這里的變量?jī)?yōu)先級(jí)最低
  • files: 存放普通文件柿菩,通常給copy模塊使用
  • handlers: 存放handler文件
  • meta: 存放描述依賴關(guān)系role的文件
  • tasks: 存放任務(wù)文件
  • templates: 存放模版文件
  • tests: 存放測(cè)試文件戚嗅,用來測(cè)試整個(gè)role能否正常運(yùn)行
  • vars: 存放變量文件,優(yōu)先級(jí)比defaults的高

role的子目錄里面通常有main.yml文件枢舶,這是role的入口文件懦胞。整個(gè)role的入口文件為 tasks/main.yml。

此外凉泄,我們?cè)谑褂孟旅娴膸讉€(gè)模塊的時(shí)候躏尉,調(diào)用的文件不需要路徑,直接使用文件名稱即可:

  • copy 或者script 使用 files 下的文件
  • template 使用templates下的文件
  • include 使用 tasks 下的文件。
  1. 在role中使用變量
    在role中使用變量非常簡(jiǎn)單扮饶,直接使用 "{{}}" 括起來就可以使用了诚卸。我們先看下默認(rèn)變量怎么使用避咆,在 install-nginx/defaults/main.yml 文件中定義一個(gè)默認(rèn)變量哩罪,然后輸出滩愁。
var: "I am defalut vars"

在 install-nginx/tasks/main.yml 文件抖仅,也就是我們的role的入口文件中使用這個(gè)變量匾寝,直接輸出括堤。

---
- name: use var
  debug: msg="{{ var }}"

最后碌秸,我們?cè)?role的同級(jí)目錄的文件 deploy.yml 中調(diào)用這個(gè)role:

---
- hosts: localhost
  roles:
    - install-nginx

最后調(diào)用這個(gè)playbook,看到輸出了這個(gè)默認(rèn)變量悄窃。

[root@xxx-test roles]# ansible-playbook deploy.yml 

PLAY [localhost] ****************************************************************************************************************************************************************************

TASK [Gathering Facts] **********************************************************************************************************************************************************************
ok: [localhost]

TASK [install-nginx : use var] **************************************************************************************************************************************************************
ok: [localhost] => {
    "msg": "I am defalut vars"
}

PLAY RECAP **********************************************************************************************************************************************************************************
localhost                  : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

接下來讥电,我們看下使用普通的變量看下,在 install-nginx/vars/main.yml 文件中定義個(gè)和defaults下同名變量广匙,默認(rèn)變量應(yīng)該會(huì)被替換:

var: "I am a var vars dir"

執(zhí)行結(jié)果如下,可以看到確實(shí)被替換了:

TASK [install-nginx : use var] *************************************************************************************************************************************************************
ok: [localhost] => {
    "msg": "I am a var vars dir"
}

除此之外允趟,我們還可以在調(diào)用role的時(shí)候傳入變量參數(shù),如下:

---
- hosts: localhost
  roles:
    - { role: install-nginx,var: "I am a var in role" }

執(zhí)行結(jié)果如下,可以看到這里傳入的變量參數(shù)優(yōu)先級(jí)高于在role里面定義的鸦致。

TASK [install-nginx : use var] *************************************************************************************************************************************************************
ok: [localhost] => {
    "msg": "I am a var in role"
}

此外潮剪,role還能使用在Inventory中定義的變量,執(zhí)行Playbook時(shí)傳入的變量等等分唾。更多變量?jī)?yōu)先級(jí)的介紹后面會(huì)具體說明的抗碰。

  1. role和條件when一起執(zhí)行,和include一樣,role也經(jīng)常和when搭檔使用
---
#只有在RedHat系列的主機(jī)上才會(huì)執(zhí)行操作
- hosts: localhost
  roles:
    - { role: install-nginx, when: "ansible_os_family == 'RedHat'" }
  1. role和任務(wù)的執(zhí)行順序
    如果一個(gè)Playbook中同時(shí)出現(xiàn)role和任務(wù)绽乔,那么他們的調(diào)用順序是怎樣的呢弧蝇?
    答案是: pre_tasks > role > tasks >post_tasks.

3.3.7 用標(biāo)簽,實(shí)現(xiàn)執(zhí)行Playbook中的部分任務(wù)

如果Playbook文件比較大折砸,并且在執(zhí)行的時(shí)候只是想執(zhí)行部分功能看疗,那么這個(gè)時(shí)候有沒有解決方案呢?答案就是使用標(biāo)簽(tags)了.
下面我們有個(gè)playbook睦授,并且打上了幾個(gè)tag两芳。

---
- hosts: localhost
  tasks:
  - name: "我是標(biāo)簽1"
    debug: msg="first  tag"
    tags: first

  - name: "我是標(biāo)簽2"
    debug: msg="second  tag"
    tags: second

  - name: "可以打多個(gè)標(biāo)簽,和前面的有同名的也沒事去枷,符合的就執(zhí)行"
    debug: msg="third  tag"
    tags:
      - first
      - second

執(zhí)行的時(shí)候如果我們不加上任何參數(shù)怖辆,那么所有的標(biāo)簽對(duì)應(yīng)的任務(wù)都會(huì)執(zhí)行。如果我們要執(zhí)行某個(gè)標(biāo)簽的任務(wù)删顶,可以使用"-t" 參數(shù)指定:

ansible-playbook deploy.yml -t first

如果要跳過某些標(biāo)簽的任務(wù)竖螃,可以使用 "--skip-tags" 參數(shù)

ansible-playbook deploy.yml --skip-tags first

標(biāo)簽的名字是用戶自定義的,但是如果把標(biāo)簽的名字定義為always逗余,那么就有點(diǎn)特別了特咆。只要在執(zhí)行Playbook的時(shí)候,如果沒有明確指定不執(zhí)行always標(biāo)簽猎荠,那么always標(biāo)簽對(duì)應(yīng)的任務(wù)就始終會(huì)被執(zhí)行坚弱。

在指定執(zhí)行某個(gè)標(biāo)簽的時(shí)候蜀备,我們可以使用 "tagged" "untagged" 和 "all" 來分別標(biāo)志只執(zhí)行有標(biāo)簽的任務(wù)关摇、只執(zhí)行沒有標(biāo)簽的任務(wù)和執(zhí)行全部任務(wù)荒叶。如下:

ansible-playbook deploy.yml -t tagged

標(biāo)簽除了能夠在action中使用外,還能在include和role中使用標(biāo)簽输虱。如下:

---
#include中使用
- include: foo.yml
  tags: [web,foo]

#role中使用
roles:
  - {role: webserver, port: 5000, tags: [web,foo]}

3.4 更多的Ansible模塊

3.4.1 模塊的分類

在Ansible模塊文檔上查看單個(gè)模塊的時(shí)候些楣,每一個(gè)模塊文檔的底部都會(huì)表示,這是"COre Module",還是"Extra Module"宪睹。
比如愁茁,yum就是一個(gè)Core模塊,而archive就是一個(gè)Extra模塊亭病。

  1. Core模塊(核心模塊)
  • 不需要額外下載和配置鹅很,安裝Ansible后就可以直接使用的
  • 比較常用的模塊
  • 經(jīng)過嚴(yán)格測(cè)試的模塊
  1. Extra模塊(額外模塊)
  • 需要進(jìn)行下載和額外配置才能使用
  • 次常用的模塊
  • 還有可能存在bug的模塊

3.4.2 Extra模塊的使用方法

大概流程為下載Extra模塊,修改配置文件或者環(huán)境變量罪帖。具體方法自行百度促煮。

3.4.3 命令行查看模塊的用法

通過命令 ansible-doc,可以查看模塊的用法,如下:

ansible-doc yum

3.5 最佳使用方法

3.5.1 寫Playbook的原則

Ansible為了降低Playbook的維護(hù)成本整袁,提高Playbook的可維護(hù)性菠齿,提倡以下兩個(gè)原則:

  • 鼓勵(lì)文件重用,盡量使用include和role避免重復(fù)代碼坐昙。
  • 盡量把大的文件分成小的文件

3.5.2 參考別人的Playbook

官方提供了一些比較常用的绳匀、經(jīng)過測(cè)試的Playbook的例子
https://github.com/ansible/ansible-examples

此外,ansible還提供了一個(gè)Playbook的分享平臺(tái)炸客,平臺(tái)上的例子是Ansible用戶自己上傳的
https://galaxy.ansible.com/

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末疾棵,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子痹仙,更是在濱河造成了極大的恐慌是尔,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,496評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蝶溶,死亡現(xiàn)場(chǎng)離奇詭異嗜历,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)抖所,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,407評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門梨州,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人田轧,你說我怎么就攤上這事暴匠。” “怎么了傻粘?”我有些...
    開封第一講書人閱讀 162,632評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵每窖,是天一觀的道長(zhǎng)帮掉。 經(jīng)常有香客問我,道長(zhǎng)窒典,這世上最難降的妖魔是什么蟆炊? 我笑而不...
    開封第一講書人閱讀 58,180評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮瀑志,結(jié)果婚禮上涩搓,老公的妹妹穿的比我還像新娘。我一直安慰自己劈猪,他們只是感情好昧甘,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,198評(píng)論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著战得,像睡著了一般充边。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上常侦,一...
    開封第一講書人閱讀 51,165評(píng)論 1 299
  • 那天浇冰,我揣著相機(jī)與錄音,去河邊找鬼刮吧。 笑死湖饱,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的杀捻。 我是一名探鬼主播井厌,決...
    沈念sama閱讀 40,052評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼致讥!你這毒婦竟也來了仅仆?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,910評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤垢袱,失蹤者是張志新(化名)和其女友劉穎墓拜,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體请契,經(jīng)...
    沈念sama閱讀 45,324評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡咳榜,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,542評(píng)論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了爽锥。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片涌韩。...
    茶點(diǎn)故事閱讀 39,711評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖氯夷,靈堂內(nèi)的尸體忽然破棺而出臣樱,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 35,424評(píng)論 5 343
  • 正文 年R本政府宣布雇毫,位于F島的核電站玄捕,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏棚放。R本人自食惡果不足惜枚粘,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,017評(píng)論 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望席吴。 院中可真熱鬧赌结,春花似錦捞蛋、人聲如沸孝冒。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,668評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽庄涡。三九已至,卻和暖如春搬设,著一層夾襖步出監(jiān)牢的瞬間穴店,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,823評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工拿穴, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留泣洞,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,722評(píng)論 2 368
  • 正文 我出身青樓默色,卻偏偏與公主長(zhǎng)得像球凰,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子腿宰,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,611評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容