美文网首页
第3章 Ansible 进阶

第3章 Ansible 进阶

作者: super_pcm | 来源:发表于2021-06-01 22:49 被阅读0次

3.1 Ansible 的配置

3.1.1 可以配置什么

安装好Ansible后,通过 /etc/ansible/ansible.cfg 文件的内容和注释可以了解到所有可以配置的选项,下面距离我们常用的配置

#可以配置主机清单文件 inventory、extra模块放置的路径 library、远程主机的临时目录 remote_tmp,以及管理节点上的临时目录 local_tmp
inventory      = /etc/ansible/hosts
library        = /usr/share/my_modules/
remote_tmp     = ~/.ansible/tmp
local_tmp      = ~/.ansible/tmp

# 可以配置连接端口号 accelerate_port、超时时间等
accelerate_port = 5099
accelerate_timeout = 30
accelerate_connect_timeout = 5.0

3.1.2 Ansible 配置文件的优先级

优先级从高到低的排序

  • ANSIBLE_CONFIG 配置的环境变量
  • 当前目录的ansible.cfg
  • 家目录下的 .ansible.cfg
  • /etc/ansible/ansible.cfg

3.2 主机清单

主机清单(Host Inventory),它告诉Ansible 需要管理哪些主机,以及这些主机的分类和分组信息的文件。可以认为这是个文件版的CMDB系统。

Inventory的默认文件为 /etc/ansible/hosts ,可以通过 /etc/ansible/ansible.cfg 配置文件进行修改。此外,我们还可以通过 -i 参数来指定主机清单配置文件

ansible-playbook -i test.ini site.yml

当然我们也可以使用 --inventory-file 参数来进行指定。

3.2.1 远程主机的分组

在inventory文件中,可以通过 "[]" 符号给主机做分组。此外,分组还支持嵌套,如下。

mail.example.com

#简单的分组
[db]
one.example.com
two.example.com

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

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

3.2.2 设置连接参数

Ansible 可以在Inventory 文件中指定主机的连接参数,包括连接的方法、用户等。在Inventory中设置链接的参数如下,用空格分割多个参数

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

其他常用的连接参数如下

连接参数的值 连接参数的含义
ansible_connection SSH的连接方式,可以指定为 smart、ssh或者paramiko
ansible_host Ansible连接的主机地址,如果你要在Ansible中给主机起了一个不同的别名,那么需要使用这个参数
ansible_port SSH端口号,默认为22
ansible_user SSH连接时默认的用户名
ansible_ssh_pass SSH连接时使用的密码,不建议用本参数存储明文密码,尽量使用values对密码进行加密存储
ansible_ssh_private_key_file 基于key的SSH连接,使用的是private key 文件
ansible_ssh_common_args 通过配置本参数指定SFTP、SCP和SSH默认的额外参数

以上的参数除了能够在Inventory文件中定义,还可以在playbook中定义或者通过变量的方式传入。

3.2.3 变量

Anible 支持在主机清单文件中指定变量,或者与主机清单文件同目录的特定子目录和文件中定义变量

  1. 主机清单文件中的变量
#为单个主机指定变量
[app]
host1 http_port=80
host2 http_port=81

#为一个组指定变量
[app:vars]
http_port=80
  1. 按目录结果存储的变量
    假设主机清单文件为 /etc/ansible/hosts,那么相关的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

这时候yaml文件存放的变量格式为 key:value 的形式,如下

---
hppt_port: 80

如果你的变量非常多,多到一个文件都存不下。那么你可以在同名目录下分开多个文件来存放变量,如下:

#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类似,是一种数据表示格式,下面介绍一些关于YAML语言的基本知识。

# 文件开始符
---

# 数组list
- element1
- element2
- element3

#字典
key: value

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

# 字典和数组的嵌套
- pangcm1:
    name: pangcm1
    job: ops
    skills: 
      - ansible
      - linux
      - python

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

需要注意的地方,变量里面如果有冒号 ":" 时需要加上引号,变量以 "{" 开头时也要加上引号

foo: "foo:bar"

foo: "{{ variable }}"

3.3.2 执行Playbook的命令

执行Playbook需要使用单独的命令: ansible-playbook,常用的使用方法如下

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

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

# 查看脚本会影响哪些主机
ansible-playbook deploy.yaml --list-hosts

# 并行执行脚本(默认的并发数量为5)
ansible-playbook deploy.yaml -f 10

3.3.3 Playbook 的基本语法

最基本的Playbok脚本分为三个部分:

  1. 在什么机器以什么身份执行
    • hosts
    • user
  2. 执行的任务都有什么
    • tasks
  3. 善后的任务都有什么
    • handlers

下面针对这上面提到的三个部分做介绍

  1. 主机和用户
key 含义
hosts 为主机的IP,或者主机组名,或者关键字all
user 在远程以哪个身份执行
become 切换成其他用户执行,值为 yes或者no
become_method 与become一起使用,值可以为 "sudo/su/pfexec/doas"
become_user 与become一起用,默认为root,也可以是其他用户名

脚本里面使用become时,执行Playbook必须加参数 --ask-become-pass,提示用户输入 "sudo" 的密码。

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

你也可以在Inventory中定义 ansible_sudo_pass 变量来避免每次都需要手工交互式地输入sudo密码。

  1. 任务列表
    • 任务(task)是从上到下顺序执行的,如果中间发生错误,那么整个Playbook会中止。
    • 每个任务都是对模块的一次调用,只是使用不用的参数和变量而已。
    • 每个任务最好有 name 属性,这是供人读的,没有实际的操作。但是有这样的输出,我们能更好地知道执行的情况以及task的用途。

下面是一个简单的示例:

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

# 上面的参数使用的是 key=value的形式,也可以使用key:value的形式。
- name: copy ansible inventory file to client
  copy:
    src: /etc/ansible/hosts
    dest: /etc/ansible/hosts
    mode: 0644

任务中Action会调用一个模块,然后在模块中检查当前系统状态是否需要重新执行。如果本次执行了,那么Action返回的值为changed。如果不需要执行,那么返回的是ok。

  1. 响应事件handler
    • 什么是handler
      每个主流的编程语言都有Event机制,而handler就是Playbook的Event。Handlers里面每一个handler都是对模块的一次调用。但是和task任务不同,handler只有在它需要在任务中被调用的时候才有可能被执行。
      前面提到,任务表中的任务都是有状态的:changed或者ok。在Ansible中,只有在任务的执行状态为changed的时候,才会执行该任务调用的handler。这也是handller和普通的Event机制不同的地方。

    • 应用场景
      什么情况下使用handler呢?如果你在任务中修改了Apache的配置文件,嘛呢需要重启Apache。如果你安装了一个Apache插件,那么也需要重启Apache。这时候,重启Apache就可以设计成一个handler。
      一个handler最多只执行一次,并且在所有任务都执行完之后再执行。如果有多个任务调用(notify)同一个handler,那么只执行一次。

下面是一个示例,第一次执行的时候会触发两个handler,第二次执行的之后只会触发第二个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的执行顺序是按照定义的顺序,而不是任务调用的顺序。就是说定义的时候顺序是 1,2,3;但是调用的时候是 3,2,1 ;但是最后执行的时候还是 1,2,3 的顺序。

3.3.4 变量

在Playbook中,常用的几种变量包括以下几种情况

  • 在Playbook中用户自定义的变量
  • 用户无须自定义,Ansible会在执行Playbook之前去远程主机搜集关于远程节点系统的信息变量
  • 在文件模版中,可以直接使用上述两种变量
  • 把任务的运行结果作为一个变量来使用,这个变量叫做注册变量
  • 为了使Playbook更灵活、通用性更强,允许用户在执行Playbook时传入变量的值,这时候需要额外变量。
  1. 在Playbook中用户自定义的变量
    用户在Playbook中使用变量时需要使用 "{{ }}" 引用起来即可。在Playbook中,我们可以使用vars关键字来定义变量,也可以使用var_files来引入变量文件。如下所示:
#使用vars来定义变量
- hosts: web
  vars:
    http_port: 80
  tasks:
  ....

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

有时候我们需要使用变量的值不是简单的字符串或者数字,而是一个对象,这时候定义的语法如下,格式为YAML的字典格式。

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

要注意有些时候YAML和Ansible Playbook的变量语法不能在一起好好地工作。这通常发生在冒号后面的值有 "{" 开头的变量时,如果不加上引号,就很有可能报语法错误。

  1. 远程主机的系统变量(Facts)
    Ansible 会通过模块 "setup" 来搜集主机的系统信息,这些收集到的系统信息叫做Facts.每个Playbook在执行前都会默认执行setup模块,所以这些Facts信息可以直接以变量的形式使用。

那么,我们怎么知道有那些Facts变量可以引用呢,我们可以使用setup模块来查看下:

ansible all -m setup -u root

在Playbook中,我们可以和使用普通变量一样来使用Facts变量。这里需要特别说明的是如何使用Facts中的复杂变量。答案是可以通过下面两种方式,如下:

#中括号
{{ ansible_ens3['ipv4']['address'] }}

#点号
{{ ansible_ens3.ipv4.address }}

收集Facts信息会消耗额外的时间,Ansible 的默认配置中要求搜集这些信息。如果要关闭,可以通过关键字 gather_facts来关闭。如下

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

template模块在Ansible中十分常用,而他在使用的时候有没有显示指定template文件中的值,所以有时候用户对template中使用的变量感到困惑,所以这里再重新强调下它的变量的使用。

template能直接使用再Playbook中定义的变量,也可以使用Facts变量,所有再Playbook中可以访问的变量,都可以再template文件中使用。通常template文件我们都是使用 j2作为后缀,因为这是使用jinja2的文件格式,里面的变量需要使用 "{{}}" 括起来。

  1. 把运行结果当作变量使用-注册变量

这时候就需要使用注册变量了,把执行的结果注册到变量中,给后面的任务使用。把执行结果注册到变量中的关键字是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 }}"

注册变量经常和debug模块一起使用,这样可以得到更多的关于执行错误的信息,以帮助用户调试。

  1. 用命令行传递参数

为了使Playbook更灵活、通用性更强,允许用户在执行的时候传入变量的值,这时候就需要用到 "额外变量"。

使用命令行传递参数可以使用 --extra-vars 也可以使用简写 -e 。如下所示:

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

#还可以使用json格式传递参数
ansible-playbook test_var.yaml -e "{'host':'web','user':'root'}"

#还可以将参数放在文件里面
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: 循环语句,类似于编程语言中的while。
  • block: 把几个任务组在一个代码块,以便针对一组操作的异常进行处理等操作。
  1. 条件判断语句when
    有时候用户很有可能需要满足特定条件才去执行特定的步骤,如在某一特定的版本的系统上安装软件包。如下:
tasks:
#远程主机如果是debian,立刻关机
- name: "shutdown Debian systems"
  command: /sbin/shutdown -t now
  when: ansible_os_family == "Debian"

#根据Action的执行结果,来决定是否执行任务
- 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 对返回值的类型做转换,如下
- name: "只有在rhel7或者更新的版本上执行任务"
  debug: "msg=hello pcm"
  when: ansible_os_family == "RedHat" and ansible_lsb.major_release | int >= 6

除了上面的用法外,我们还可以使用条件表达式

---
- hosts: localhost
  vars:
    epic: true
  tasks:
  - name: "使用布尔表达式"
    shell: echo "This is epic"
    when: epic

  - name: "布尔表达式前面可以加上not"
    shell: echo "This is epic"
    when: not epic

  - name: "还可以判断变量有没有定义"
    shell: echo "This is epic"
    when: epic is not defined

  - name: "还可以比较数值大小"
    shell: echo "This is epic"
    when: epic > 5

when除了能够用在task上,我们还会和Include或者Role一起来使用。

---
#当deploy为真时,执行deploy.yaml这个playbook。
- include: tasks/deploy.yaml
  when: deploy
--- 
- hosts: web
  #当update为真时,执行名为update的role 
  roles:
    - { role: update, when: update}
  1. 循环语句 loop
    "with_items" 可以用迭代list类型的变量,不仅支持简单的字符串列表,还可以支持哈希列表,如下:
#最简单的列表模式
- 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 }}"

#哈希列表这么用,可以使用具体的子项(字典列表)
- 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(或其他循环声明),那么when声明会为每个条目单独判断一次

Ansible的循环和编程语言的一样,也能嵌套循环
下面嵌套的是列表

---
- hosts: localhost
  tasks:
#使用with_nested,和python一样,可以使用 []来访问内层循环,也可以使用点号 "." 来访问。
  - name: debug loop
    debug: msg="username is {{ item[0] }},password is {{ item[1] }}"
    with_nested:
      - ['pcm1', 'pcm2']
      - ['passwd1', 'passwd2', 'passwd3']

上面playbook执行的结果如下:

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一样,可以使用 []来访问内层循环,也可以使用点号 "." 来访问。
  - 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 }}"

对文件,我们也可以使用循环

  tasks:
  - name: "首先确认文件是存在的"
    file: dest=/etc/fooapp state=directory
  
  - name: "复制文件到远程目录上"
    copy: "src={{ item }} dest=/etc/fooapp/ mode=600"
    with_fileglob:
      - /playbooks/files/fooapp/*
  1. 代码块 block
    多个action组成块后,可以根据不同条件执行一段语句。好比编程语言中的函数。
---
- 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支持两种重用机制,一种是重用单个静态Playbook嗯见,另外一种是重用特定功能的文件夹,类似于Python等编程语言中的包(Package)。

  • include语句: 重用单个Playbook脚本,使用起来简单、直接
  • role语句: 重用实现特定功能的Playbook文件夹,使用方法稍复杂,功能强大。role是Ansible更为推荐的重用和分享Playbook的方式。

1. include语句

include语句是基本的代码重用机制,主要重用任务,同时,include还可以将任务分割成多个文件,避免Playbook过于臃肿。

include的使用方法很简单,直接使用即可,如下:

#假设该文件名为main.yaml,下面调用deploy.yml的Playbook。
---
- hosts: localhost
  tasks:
  - include: deploy.yml

下面是deploy.yml的内容,只需要写上各个action即可。

- name: action1
  debug: msg=action1

- name: action2
  debug: msg=action2

如果我们想要引用Playbook的时候传入参数应该怎么操作呢?

#直接在行尾加上参数即可,用空格分割
- hosts: localhost
  tasks:
  - include: deploy.yml port=80

#也可以传入一个字典作为变量
  - include: deploy.yml
    vars:
      user: pangcm
      port: 80

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

如果你在Playbook中已经定义了参数,那么就不需要传入了,直接在被调用的Playbook中使用即可。

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

这里要注意 include 的位置,这是在tasks下的,也就是相当于一个大的action。如果放在和tasks同级,也就是全局include。我们不推荐这么做,因为它不支持嵌入include,而且很多的Playbook也无法使用,

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

include是场景不大的情况下还是挺好用的,但是如果引用多了这将很难管理,维护成本会变得很多。所以在使用更加灵活的重用机制时,建议使用下面的role.

2. role-Playbook 的 "Package"

Ansible好比编程语言中的include,role好比编程语言中的package。通常一个role由一组文件组成,形成一个完整的功能。如一个部署nginx的role,里面会包含若干playbook和文件。

Ansibe十分提倡在Playbook中使用role,并且提供了一个分享role的平台 ANsible Galaxy。在Galaxy上可以找到别人写好的role。

  1. role的目录结构
    在Ansible中,通过遵循特定的目录结构,就可以实现对role的定义,具体遵循的目录结构是什么样子的呢?如下:
[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

上面定义了一个名为install-nginx的role,用来安装nginx。Playbook文件中的deploy.yml调用这个role。上面的文件不要求全部拥有,看自己的实际需求。(以上目录我使用的是ansible-galaxy init install-nginx 创建的。)

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

  • defaults: 存放变量文件,存放在这里的变量优先级最低
  • files: 存放普通文件,通常给copy模块使用
  • handlers: 存放handler文件
  • meta: 存放描述依赖关系role的文件
  • tasks: 存放任务文件
  • templates: 存放模版文件
  • tests: 存放测试文件,用来测试整个role能否正常运行
  • vars: 存放变量文件,优先级比defaults的高

role的子目录里面通常有main.yml文件,这是role的入口文件。整个role的入口文件为 tasks/main.yml。

此外,我们在使用下面的几个模块的时候,调用的文件不需要路径,直接使用文件名称即可:

  • copy 或者script 使用 files 下的文件
  • template 使用templates下的文件
  • include 使用 tasks 下的文件。
  1. 在role中使用变量
    在role中使用变量非常简单,直接使用 "{{}}" 括起来就可以使用了。我们先看下默认变量怎么使用,在 install-nginx/defaults/main.yml 文件中定义一个默认变量,然后输出。
var: "I am defalut vars"

在 install-nginx/tasks/main.yml 文件,也就是我们的role的入口文件中使用这个变量,直接输出。

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

最后,我们在 role的同级目录的文件 deploy.yml 中调用这个role:

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

最后调用这个playbook,看到输出了这个默认变量。

[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 文件中定义个和defaults下同名变量,默认变量应该会被替换:

var: "I am a var vars dir"

执行结果如下,可以看到确实被替换了:

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

除此之外,我们还可以在调用role的时候传入变量参数,如下:

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

执行结果如下,可以看到这里传入的变量参数优先级高于在role里面定义的。

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

此外,role还能使用在Inventory中定义的变量,执行Playbook时传入的变量等等。更多变量优先级的介绍后面会具体说明的。

  1. role和条件when一起执行,和include一样,role也经常和when搭档使用
---
#只有在RedHat系列的主机上才会执行操作
- hosts: localhost
  roles:
    - { role: install-nginx, when: "ansible_os_family == 'RedHat'" }
  1. role和任务的执行顺序
    如果一个Playbook中同时出现role和任务,那么他们的调用顺序是怎样的呢?
    答案是: pre_tasks > role > tasks >post_tasks.

3.3.7 用标签,实现执行Playbook中的部分任务

如果Playbook文件比较大,并且在执行的时候只是想执行部分功能,那么这个时候有没有解决方案呢?答案就是使用标签(tags)了.
下面我们有个playbook,并且打上了几个tag。

---
- hosts: localhost
  tasks:
  - name: "我是标签1"
    debug: msg="first  tag"
    tags: first

  - name: "我是标签2"
    debug: msg="second  tag"
    tags: second

  - name: "可以打多个标签,和前面的有同名的也没事,符合的就执行"
    debug: msg="third  tag"
    tags:
      - first
      - second

执行的时候如果我们不加上任何参数,那么所有的标签对应的任务都会执行。如果我们要执行某个标签的任务,可以使用"-t" 参数指定:

ansible-playbook deploy.yml -t first

如果要跳过某些标签的任务,可以使用 "--skip-tags" 参数

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

标签的名字是用户自定义的,但是如果把标签的名字定义为always,那么就有点特别了。只要在执行Playbook的时候,如果没有明确指定不执行always标签,那么always标签对应的任务就始终会被执行。

在指定执行某个标签的时候,我们可以使用 "tagged" "untagged" 和 "all" 来分别标志只执行有标签的任务、只执行没有标签的任务和执行全部任务。如下:

ansible-playbook deploy.yml -t tagged

标签除了能够在action中使用外,还能在include和role中使用标签。如下:

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

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

3.4 更多的Ansible模块

3.4.1 模块的分类

在Ansible模块文档上查看单个模块的时候,每一个模块文档的底部都会表示,这是"COre Module",还是"Extra Module"。
比如,yum就是一个Core模块,而archive就是一个Extra模块。

  1. Core模块(核心模块)
  • 不需要额外下载和配置,安装Ansible后就可以直接使用的
  • 比较常用的模块
  • 经过严格测试的模块
  1. Extra模块(额外模块)
  • 需要进行下载和额外配置才能使用
  • 次常用的模块
  • 还有可能存在bug的模块

3.4.2 Extra模块的使用方法

大概流程为下载Extra模块,修改配置文件或者环境变量。具体方法自行百度。

3.4.3 命令行查看模块的用法

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

ansible-doc yum

3.5 最佳使用方法

3.5.1 写Playbook的原则

Ansible为了降低Playbook的维护成本,提高Playbook的可维护性,提倡以下两个原则:

  • 鼓励文件重用,尽量使用include和role避免重复代码。
  • 尽量把大的文件分成小的文件

3.5.2 参考别人的Playbook

官方提供了一些比较常用的、经过测试的Playbook的例子
https://github.com/ansible/ansible-examples

此外,ansible还提供了一个Playbook的分享平台,平台上的例子是Ansible用户自己上传的
https://galaxy.ansible.com/

相关文章

网友评论

      本文标题:第3章 Ansible 进阶

      本文链接:https://www.haomeiwen.com/subject/mtqmsltx.html