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 中定义变量也存在多种方法,最简单也最常见的就是在 vars 和 vars_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_vars 和 groups_vars 目录,然后再把相应的变量文件保存在这两个目录下:
注意:文件名需要与主机名或主机组保持一致!
通过上面的方法就可将变量与 inventory 当中的内容独立出来,易于后期的维护。
命令行变量
通过前面介绍的变量优先级顺序,可知,首先 inventory 中的变量会覆盖 Playbook 中的变量,但是上面两种类型的变量都会在使用 ansible 和 ansible-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 的输出有无问题。
[…] Tasks 文件外,同样还可以引入变量,方法有多种:(具体可查看Ansible 变量这一节内容) 1、Inventory 变量定义在 inventory 文件中,或者定义到 host_vars 或 […]