Ansible 之旅(九) Ansible 变量

Ansible 变量

Ansible 本身支持变量,可以在 Ansible 项目中方便的使用变量来存放数据,达到重用的目的。举个例子,通过 Ansible 部署四台机器上的 WEB 服务,但是要求每个 WEB 服务的配置文件中的某个参数不一样,如监听的 IP ,假设不使用变量的话,可能需要写 4 个 Play ,但是使用了变量,只需写一个 Play ,然后给不同的托管主机设置不同的变量即可。

所以说,变量提供了一种简便的方法来管理项目中的环境动态值,通常用于以下情形:
1. 创建用户
2. 安装软件包
3. 服务的管理
4. 文件管理
5. 从网络下载文件

变量命名

Ansible 中变量的命名和编程语言中变量命名规则是一样的,变量名称由字符串组成,字符串必须以字母开头,并且只能包含字符和下划线,如:

无效的命名 有效的命名
web server web_server
Remote.User remote_user
1st file file_1
server$1 server_1

定义变量

在 Ansible 中,变量可以定义在项目中多个地方,一般可以归纳为以下三个范围:
全局变量:变量定义在命令行(Ad Hoc)或者在 Ansible 配置文件中。
Play 变量:变量定义在 Play 中或 Ansible Playbook 相关结构中。
主机变量:变量定义在 Inventory 中有效的主机以及有效的主机组中,以及收集的 Facts 或者是通过 Task 获取。
因为变量可以存放在以上三个范围中,所以当多个地方存在同一个变量时,此时变量的值取优先级高的的范围里的变量的值。
它们之间的优先级关系是:命令行变量 > Play 变量 > inventor 变量
接下来探讨这三个范围里的变量。

在 Playbooks 中定义变量

在 Playbook 中定义变量也存在多种方法,最简单也最常见的就是在 varsvars_file 这一级中定义:

如图,在 vars 中定义了 user 和 home 这两个变量,里面有对应的值,同时也可以将变量单独写在一个文件中,然后通过 vars_file 来加载文件中的变量,在文件中的变量跟在 vars 中定义的变量语法结构是一样的。

在 Playbooks 中使用变量

一旦变量被定义,那么就可以在 Task 中使用了。使用时,需要将变量用两对花括号括起,并且变量名离花括号需要有一个空格,如果变量充当的是模块值的时候,还需要使用双引号括起

---
- hosts: all
  vars:
    user: joe
  tasks:
    - name: Create the user {{ user }}
      user:
        name: "{{ user }}"

主机和主机组变量

上面介绍的是在 Playbook 中定义的变量,这一节介绍的是在 inventory 中定义两种不同类型的变量:
主机变量:用于特定主机的变量。
主机组变量:用于特定主机组的变量。
如:

demo.example.com ansible_user=joe
demo2.example.com ansible_user=tom

[webservers]
web1.example.com
web2.example.com

[webservers:vars]
user=joe

这样在 Task 中使用变量时,不同的主机或主机组就会有不同的值。但是如果主机变量和主机组变量重复会有怎样的情况呢?如:

server1 user=tom

[web]
server1
server2

[web:vars]
user=bob

所以在上面的情形下就需要优先级来决定变量的值了,在 Ansible inventory 变量中,主机变量 > 主机组变量
另外如果 inventory 中主机和主机组比较多,在 inventory 中定义不太方便,并且如果 inventory 需要拷贝到不同的项目中的话,还面临着大量的修改,所以在定义 inventory 中的变量时,可以通过定义在与主机名和主机组名相同的文件中。需要在 inventory 所在的目录中定义存放主机变量和主机组变量的
两个目录,分别是 host_varsgroups_vars 目录,然后再把相应的变量文件保存在这两个目录下:

注意:文件名需要与主机名或主机组保持一致!
通过上面的方法就可将变量与 inventory 当中的内容独立出来,易于后期的维护。

命令行变量

通过前面介绍的变量优先级顺序,可知,首先 inventory 中的变量会覆盖 Playbook 中的变量,但是上面两种类型的变量都会在使用 ansibleansible-playbook 命令传递的变量参数所覆盖。
如:

ansible-playbook main.yml -e "package=apache"

使用 -e 来传递变量值,通过这种方法就可以覆盖 playbook 和 inventory 中的 package 变量的值。可以灵活的使用命令行变量来实现一下临时的配置。

变量与数组

假设需要创建 100 个用户,需要的信息包含:用户名、UID、GID、Shell 等。如果通过变量定义的话,可能需要定义 500 个变量,这实在是太多了,所以 Ansible 变量可以定义一组变量,这一组变量里面包括了多个属性,也称之为数组变量,如:定义一个 tom 变量,这个变量是一个数组,里面包括 tom 的信息,如 用户名、UID、GID、Shell ,这样前面举得这个例子,只需要定义 100 个变量即可。通常数组变量可以用来定义 Package 列表,Service 列表等,减少需要定义的变量。

users:
  tom:
    name: tom
    fullname: "Tom User"
    home_dir: /users/tom
    shell: /bin/bash

如上,定义了一个 users 变量,里面定义了一个 tom 变量,然后在里面又定义了几个变量,它们之间存在从属关系。如何访问变量呢?如,需要访问 tom 的 home_dir 这个变量的值:

users.tom.home_dir 或者 users['tom']['home_dir']

Registered Variables

这是一种特殊的变量,管理员可以使用 registered 语句来捕获 Task 执行的输出,然后将输出的内容赋值给一个变量。这有什么用呢?这个赋值的变量可以在后面的 Task 中用于调试或者实现其他功能,如,基于特定的输出,执行特定的任务(需要结合后面介绍的流程控制语句)。

- hosts: web_servers
  tasks:
     - shell: /usr/bin/foo
       register: foo_result
       ignore_errors: True

     - shell: /usr/bin/bar
       when: foo_result.rc == 0

上面 Playbook 的意思是在 web_servers 主机组中执行 /usr/bin/foo 这个脚本或命令,并且忽略错误(失败了也继续往下执行),然后将输出的内容赋值给变量 foo_result,在下一个 Task 中通过 when 语句来判断 foo_result 里面的 rc 的值是否等于 0 ,如果是就执行 /usr/bin/bar 这个脚本或命令。
除了上面的用法,通常还可以用作 debug ,来检测执行的 Task 的输出有无问题。

最后修改:2019 年 11 月 12 日 06 : 06 PM
如果觉得我的文章对你有用,请随意赞赏

发表评论

1 条评论

  1. […] Tasks 文件外,同样还可以引入变量,方法有多种:(具体可查看Ansible 变量这一节内容) 1、Inventory 变量定义在 inventory 文件中,或者定义到 host_vars 或 […]