第3章 Ansible 進(jìn)階

3.1 Ansible 的配置

3.1.1 可以配置什么

安裝好Ansible后,通過(guò) /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ī)的分類和分組信息的文件??梢哉J(rèn)為這是個(gè)文件版的CMDB系統(tǒng)。

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

ansible-playbook -i test.ini site.yml

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

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

在inventory文件中,可以通過(guò) "[]" 符號(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 通過(guò)配置本參數(shù)指定SFTP、SCP和SSH默認(rèn)的額外參數(shù)

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

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è)文件都存不下。那么你可以在同名目錄下分開(kāi)多個(gè)文件來(lái)存放變量,如下:

#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的腳本語(yǔ)言,使用的YAML格式。YAML和JSON類似,是一種數(shù)據(jù)表示格式,下面介紹一些關(guān)于YAML語(yǔ)言的基本知識(shí)。

# 文件開(kāi)始符
---

# 數(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),變量以 "{" 開(kāi)頭時(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 的基本語(yǔ)法

最基本的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 變量來(lái)避免每次都需要手工交互式地輸入sudo密碼。

  1. 任務(wù)列表
    • 任務(wù)(task)是從上到下順序執(zhí)行的,如果中間發(fā)生錯(cuò)誤,那么整個(gè)Playbook會(huì)中止。
    • 每個(gè)任務(wù)都是對(duì)模塊的一次調(diào)用,只是使用不用的參數(shù)和變量而已。
    • 每個(gè)任務(wù)最好有 name 屬性,這是供人讀的,沒(méi)有實(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è)主流的編程語(yǔ)言都有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)用的順序。就是說(shuō)定義的時(shí)候順序是 1,2,3;但是調(diào)用的時(shí)候是 3,2,1 ;但是最后執(zhí)行的時(shí)候還是 1,2,3 的順序。

3.3.4 變量

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

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

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

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

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

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

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

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

ansible all -m setup -u root

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

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

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

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

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

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

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

  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)寫(xiě) -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 也有邏輯控制語(yǔ)句

  • when: 條件判斷語(yǔ)句,類似編程語(yǔ)言中的if。
  • loop: 循環(huán)語(yǔ)句,類似于編程語(yǔ)言中的while。
  • block: 把幾個(gè)任務(wù)組在一個(gè)代碼塊,以便針對(duì)一組操作的異常進(jìn)行處理等操作。
  1. 條件判斷語(yǔ)句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é)果,來(lái)決定是否執(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: "還可以判斷變量有沒(méi)有定義"
    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一起來(lái)使用。

---
#當(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)語(yǔ)句 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)和編程語(yǔ)言的一樣,也能嵌套循環(huán)
下面嵌套的是列表

---
- hosts: localhost
  tasks:
#使用with_nested,和python一樣,可以使用 []來(lái)訪問(wèn)內(nèi)層循環(huán),也可以使用點(diǎn)號(hào) "." 來(lái)訪問(wèn)。
  - 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一樣,可以使用 []來(lái)訪問(wèn)內(nèi)層循環(huán),也可以使用點(diǎn)號(hào) "." 來(lái)訪問(wèn)。
  - 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í)行一段語(yǔ)句。好比編程語(yǔ)言中的函數(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嗯見(jiàn),另外一種是重用特定功能的文件夾,類似于Python等編程語(yǔ)言中的包(Package)。

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

1. include語(yǔ)句

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

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

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

下面是deploy.yml的內(nèi)容,只需要寫(xiě)上各個(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

#上面的字典也可以寫(xiě)成一串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也無(wú)法使用,

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

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

2. role-Playbook 的 "Package"

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

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

  1. role的目錄結(jié)構(gòu)
    在Ansible中,通過(guò)遵循特定的目錄結(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,用來(lái)安裝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è)試文件,用來(lái)測(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)單,直接使用 "{{}}" 括起來(lái)就可以使用了。我們先看下默認(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   

接下來(lái),我們看下使用普通的變量看下,在 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ì)具體說(shuō)明的。

  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í)候有沒(méi)有解決方案呢?答案就是使用標(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)簽,和前面的有同名的也沒(méi)事,符合的就執(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

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

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

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

在指定執(zhí)行某個(gè)標(biāo)簽的時(shí)候,我們可以使用 "tagged" "untagged" 和 "all" 來(lái)分別標(biāo)志只執(zhí)行有標(biāo)簽的任務(wù)、只執(zhí)行沒(méi)有標(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)過(guò)嚴(yán)格測(cè)試的模塊
  1. Extra模塊(額外模塊)
  • 需要進(jìn)行下載和額外配置才能使用
  • 次常用的模塊
  • 還有可能存在bug的模塊

3.4.2 Extra模塊的使用方法

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

3.4.3 命令行查看模塊的用法

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

ansible-doc yum

3.5 最佳使用方法

3.5.1 寫(xiě)Playbook的原則

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

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

3.5.2 參考別人的Playbook

官方提供了一些比較常用的、經(jīng)過(guò)測(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)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容