4.1 管理变量
4.1.1 目标
学完这一章节,学生能去创建和查阅playbook中的变量影响特定的主机或主机组,play,或者全局环境变量,并且去描述变量如何优先工作。
4.2.1 介绍ANSIBLE的变量
Ansible支持使用变量去存储数值,变量可以被反复使用在整改Ansible项目中。这可以简化Ansible项目的创建和维护,并减少错误的数量。
变量提供了一个方便的方式去管理动态的数值对于一个给定的环境在你的Ansible项目中,变量的数值可能包含:
- 用户需要去创建
- 包需要去安装
- 服务需要去重启
- 文件需要去移除
- 文档需要去检索从互联网上
4.2.1.1 变量的命名
变量的名字必须已字母开头,它们可以包含字母,数字和下划线。下表展示了有效和无效的变量名。
INVALID VARIABLE NAMES | ALID VARIABLE NAMES |
---|
web server | web_server | remote.file | remote_file | 1st file | file1 file_1 | remoteserver$1 | remote_server_1 remote_server1 |
4.2.1.2 变量的定义
在ansible项目中,变量可以定义在不同的地方。这可以简化为三个基本的范围级别。
- 全局范围: 变量设置在命令行中或Ansible配置文件中
- play范围: 变量设置在play或者相关结构中
- 主机范围: 变量设置在清单文件中的主机组或者独立的主机上,事实收集或者注册任务
如果相同的变量名被定义在多个级别中,优先选中最高优先级的。窄作用域优先于宽作用域,变量定义在清单文件中被覆盖变量定义在playbook中,变量定义在playbook中的被覆盖变量定义在命令行中。
变量优先级的详细讨论可以在Ansible的文档中查阅,链接被提供在本章节后面的参考文献中。
变量扮演了非常重要的角色在playbook中,因为他们减少了playbook中变量数据的管理。
4.2.2 playbook中定义变量
当写playbook时,你可以定义你的自有变量并且调用这些变量在任务中。例如,一个名为web_package的变量可以用HTTPD的值来定义,一个任务能调用变量使用yum模块去安装httpd包。
playbook变量能被定义安装多种方式,一种最通用的方式是去放置一个变量在vars快在playbook的开头。
- hosts: all
vars:
user: joe
home: /home/joe
也可以定义playbook变量在外部文件中。下面的案例中,代替使用playbook中的vars快,vars_files指令可以被使用,后面是相对于playbook位置的外部变量文件的名称列表
- hosts: all
vars_files:
- vars/users.yml
playbook变量被定义在独立的文件中使用YAML文件格式:
user: joe
home: /home/joe
4.2.3 playbook使用变量
变量被声明后,管理员可以使用这些变量在任务中。变量被重新引用通过放置变量在双花括号中({{}})。Ansible替代变量用它的当任务被执行。
vars:
user: joe
tasks:
# this line will read: Create the user joe
- name: Creates the user {{ user }}
user:
# This line will create the user named Joe
name: "{{ user }}"
当一个变量被用作一个值的第一个元素时,必须使用引号。 这可以防止ansible将变量引用解释为启动一个YAML字典。
4.2.4 主机变量和组变量
直接应用于主机的清单文件变量可分为两大类:主机变量被指向一个指定的主机。组变量指向主机组中所有的主机或一组主机组。主机变量优先级高于组变量,由playbook定义的变量优先于两者。
- 定义ansible_user主机变量为demo.example.com主机
[server]
demo.example.com ansible_user=joe
[servers]
demo1.example.com
demo2.example.com
[servers:vars]
user=joe
- 定义用户组变量为servers组,servers组包含了2个主机组,每个主机组包含了2个servers。
[servers1]
demo1.example.com
demo2.example.com
[servers2]
demo3.example.com
demo4.example.com
[servers:children]
servers1
servers2
[servers:vars]
user=joe
这种方法的一些缺点是它使inventory清单文件更难去管理。它把主机信息和变量信息混在了同一个文件中,使用了一种老式的语法。
4.2.5 使用group_vars和host_vars目录
优先使用的方式去定义主机变量和主机组变量是去创建两个目录,group_vars和host_vars,和inventory放在相同目录中。这些目录分别包含了主机变量文件和组变量文件。
最佳实践是去定义主机变量和组变量使用host_vars和group_vars目录,不直接在inventory文件中定义。
定义组变量为servers组,你应该创建一个YAML文件命名为group_vars/servers,文件的内容将使用与playbook中相同的语法将变量设置为值。
user: joe
同样地,定义主机变量为一个指定的主机,在host_vars目录中创建一个与inventory中主机相同名称的文件,文件包含主机变量。
如下两个例子详细阐述了这一方法,考虑这样一个场景,有两个数据中心要管理,数据中心主机被定义在~/project/inventory清单文件中:
[admin@station project]$ cat ~/project/inventory
[datacenter1]
demo1.example.com
demo2.example.com
[datacenter2]
demo3.example.com
demo4.example.com
[datacenters:children]
datacenter1
datacenter2
- 如果你需要去定义一个通用的值为所有的主机在2个数据中心,设置一个组变量为datacenters主机组
[admin@station project]$ cat ~/project/group_vars/datacenters
package: httpd
- 如果定义变量为每一个数据中心,设置一个变量为每个数据中心主机组
[admin@station project]$ cat ~/project/group_vars/datacenter1
package: httpd
[admin@station project]$ cat ~/project/group_vars/datacenter2
package: apache
- 如果为每个数据中心主机定义变量,在单独的主机变量文件中定义变量
[admin@station project]$ cat ~/project/host_vars/demo1.example.com
package: httpd
[admin@station project]$ cat ~/project/host_vars/demo2.example.com
package: apache
[admin@station project]$ cat ~/project/host_vars/demo3.example.com
package: mariadb-server
[admin@station project]$ cat ~/project/host_vars/demo4.example.com
package: mysql-server
4.2.6 覆盖变量从命令行
清单文件中的变量被设置在playbook中的变量覆盖,这两种形式的变量被覆盖通过传递给ansible或ansible-playbook命令的参数,设置在命令行中的变量称为外部变量。
外部变量是非常有用的当你需要去覆盖定义的为playbook的一次性运行重写变量时,如下例:
[admin@station project]$ ansible-playbook main.yml -e "package=apache"
4.2.7 变量和数组
代替指定配置文件,配置文件关联到相同的元素(一个安装包列表,一个服务清单列表,一个用户列表等),对于读个变量,管理员可以使用数组,这样做的一个结果是可以浏览数组。
user1_first_name: Bob
user1_last_name: Jones
user1_home_dir: /users/bjones
user2_first_name: Anne
user2_last_name: Cook
user2_home_dir: /users/acook
这能被写成一个users数组
users:
bjones:
first_name: Bob
last_name: Jones
home_dir: /users/bjones
acook:
first_name: Anne
last_name: Cook
home_dir: /users/acook
你能用下面的变量接入用户的数据
# Return 'Bob'
users.bjones.first_name
# Return '/users/accook'
users.acook.home_dir
因为变量被定义在python字典,另一种可用的语法是
# Return 'Bob'
users['bjones']['first_name']
# Return '/users/accook'
users['acook']['home_dir']
句号符号可能引起一些问题,如果keyname与python的方法或属性相同,如discard,copy,add等。使用方括号能避免这些问题。上述两种方法都是有效的,为了更容易排错。红帽推荐持续使用一种语法在所有的Ansible项目文件中。
4.2.8 注册变量
管理员可以使用register语句去捕获命令行的输出,这个输出被保存到一个变量中能被使用在后面,为了debug目的或者实现一些目的。比如命令行输出一个特定的配置文件。下例的playbook示范了怎样去捕获命令的输出为debug目的。
---
- name: Install a package and prints the result
hosts: all
tasks:
- name: Install the package
yum:
name: httpd
state: installed
register: install_result
- debug: var=install_result
当你执行playbook时,debug模块被用来转储install_result注册变量到终端。
[admin@station project]$ ansible-playbook playbook.yml
PLAY[Install a package and prints the result]
TASK[setup]
ok: [demo.example.com]
TASK[Install the package]
ok: [demo.example.com]
TASK[debug]
ok:[demo.example.com] => {
"install_result": {
"changed": false,
"msg": "",
"rc": 0,
"results": [
"httpd-2.4.6 is already installed"
]
}
}
PLAY RECAP******************************
demo.example.com : ok=3 changed=0 unreachable=0 failed=0
|