变量的使用
1. 管理变量
1.1 Ansible变量简介
Ansible支持利用变量来存储值,并在Ansible项目的所有文件中重复使用这些值。这可以简化项目的创建和维护,并减少错误的数量。
通过变量,可以轻松地在Ansible项目中管理给定环境的动态值。例如,变量可能包含下面这些值:
- 要创建的用户
- 要安装的软件包
- 要重新启动的服务
- 要删除的文件
- 要从互联网检索的存档
1.1.1 变量的命名
变量的命名应该符合如下两个规范:
- 变量应该以字母开头
- 变量只能包含字母、数字、下划线
示例:
无效变量名 | 有效变量名 |
---|---|
web server | web_server |
remote.file | remote_file |
1st file | file_1、file1 |
remoteserver$1 | remote_server_1、remote_server1 |
1.1.2 定义变量
可以在Ansible项目中的多个位置定义变量。这些变量大致可简化为三个范围级别:
- 全局范围:从命令行或Ansible配置设置的变量
- Play范围:在play和相关结构中设置的变量
- 主机范围:由清单、事实收集或注册的任务,在主机组和个别主机上设置的变量
如果在多个xeklh定义了相同名称的变量,则采用优先级别最高的变量。窄范围优先于更广泛的范围:由清单定义的变量将被playbook定义的变量覆盖,后者将被命令行中定义的变量覆盖。
1.2 playbook中的变量
变量可以简化playbook中变量数据的管理。
1.2.1 在playbook中定义变量
Playbook变量可以通过多种方式定义。一种常见的方式是将变量放在playbook开头的vars块中:
---
- name: create user
hosts: 192.168.172.142
vars:
name: xxxxx
uid: 2021
tasks:
- name: create user
user:
name: "{{ name }}"
uid: "{{ uid }}"
state: present
另外一种方式是不在play中定义变量,而是在和这个playbook文件同级别的文件中定义变量,然后在playbook中变量指向这个路径即可。
---
- hosts: 192.168.172.142
vars_files:
- /etc/ansible/vars/file1.yml
1.2.2 在playbook中使用变量
声明了变量后,可以在任务中使用这些变量。若要引用变量,可以将变量名放在双大括号内。在任务执行时,Ansible会将变量替换为其值。
vars:
user: joe
tasks:
# This line will read: Creates the user joe
- name: Creates the user {{ user }}
user:
# This line will create the user named joe
name: "{{ user }}"
注意:当变量用作开始一个值的第一元素时,必须使用引号。这可以防止Ansible将变量引用视为YAML字典的开头。
1.3 主机变量和组变量
直接应用于主机的清单变量分为两类:
- 主机变量,应用于特定主机
- 组管理,应用于一个主机组或一组主机组中的所有主机
主机变量优先于组变量,但playbook中定义的变量的优先级比这两者更高。
若要定义主机变量和组变量,一种方法是直接在清单文件中定义。这是较旧的做法,不建议使用。
定义192.168.172.142的用户名变量
[node1]
192.168.172.142 ansible_user=root
定义整个组的用户变量
[node1]
192.168.172.142
191.168.172.143
[node1:bars]
user=root
定义servers组的user组变量,该组由两个主机组成,每个主机组有两个服务器
[server1]
node1.example.com
node2.example.com
[servers2]
node3.example.com
node4.example.com
[servers:children]
servers1
servers2
[servers:vars]
user=joe
1.3.1 使用目录填充主机和组变量
定义主机和主机组的变量的首选做法是在与清单文件或目录相同的工作目录中,创建group_vars和host_vars两个目录。这两个目录分别包含用于定义组变量和主机变量的文件。
建议的做法是使用host_vars和group_vars目录定义清单变量,而不直接在清单文件中定义它们。
为了定义用于servers组的组变量,需要创建名为group_vars/servers的YAML文件,然后该文件的内容将使用与playbook相同的语法将变量设置为值:
user: apache
例如在一个场景中,需要管理两个数据中心,并在/opt/inventory清单文件中定义数据中心主机:
[root@ansible opt]# cd /opt/playbook/
[root@ansible playbook]# cat inventory
[server1]
http
[server2]
mysql
[server:children]
server1
server2
1.4 从命令行覆盖变量
清单变量可被playbook中设置的变量覆盖,这两种变量又可通过在命令行中传递参数到ansible或ansible-playbook命令来覆盖。在命令行上设置的变量称为额外变量。
当需要覆盖一次性运行的playbook的变量的已定义值时,额外变量非常有用。例如:
[root@ansible playbook]# vim qp.yml
---
- name:
hosts: http
tasks:
- name:
user:
name: "{{ user }}"
state: present
[root@ansible playbook]# ansible-playbook -e "user=oo" qp.yml
PLAY [http] ********************************************************************
TASK [Gathering Facts] *********************************************************
ok: [192.168.172.142]
TASK [user] ********************************************************************
changed: [192.168.172.142]
PLAY RECAP *********************************************************************
192.168.172.142 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[root@localhost ~]# id oo
uid=1000(oo) gid=1000(oo) groups=1000(oo)
1.5 使用数组作为变量
除了将同一元素相关的配置数据(软件包列表、服务列表和用户列表等)分配到多个变量外,也可以使用数组。这种做法的一个好处在于,数组是可以浏览的。
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
可以使用以下变量来访问用户数据:
# Returns 'Bob'
users.bjones.first_name
# Returns '/users/acook'
users.acook.home_dir
由于变量被定义为Python字典,因此可以使用替代语法:
# Returns 'Bob'
users['bjones']['first-name']
# Returns '/users/acook'
users['acook']['home_dir']
如果键名与python方法或属性的名称(如discard、copy和add)相同,点表示法可能会造成问题。使用中括号表示法有助于避免冲突和错误。
但要声明的是,上面介绍的两种语法都有效,但为了方便故障排除,建议在任何给定Ansible项目的所有文件中一致地采用一种语法,不要混用。
1.6 使用已注册变量捕获命令输出
可以使用register语句捕获命令输出。输出保存在一个临时变量中,然后在playbook中可用于调试用途或者达成其他目的,例如基于命令输出的特定配置。
以下playbook演示了如何为调试用途捕获命令输出:
[root@ansible playbook]# vim sss.yml
---
- name:
hosts: all
tasks:
- name:
yum:
name: httpd
state: installed
register: install_result
- debug: var=install_result
运行该playbook时,debug模块用于将install_result注册变量的值转储到终端。
[root@ansible playbook]# ansible-playbook sss.yml
PLAY [all] *********************************************************************
TASK [Gathering Facts] *********************************************************
ok: [192.168.172.142]
TASK [yum] *********************************************************************
changed: [192.168.172.142]
TASK [debug] *******************************************************************
ok: [192.168.172.142] => {
"install_result": {
"changed": true,
"failed": false,
"msg": "",
"rc": 0,
"results": [
"Installed: apr-util-openssl-1.6.1-6.el8.x86_64",
"Installed: mod_http2-1.11.3-3.module+el8.2.0+4377+dc421495.x86_64",
"Installed: httpd-filesystem-2.4.37-21.module+el8.2.0+5008+cca404a3.noarch",
"Installed: mailcap-2.1.48-3.el8.noarch",
"Installed: apr-1.6.3-9.el8.x86_64",
"Installed: apr-util-1.6.1-6.el8.x86_64",
"Installed: redhat-logos-httpd-81.1-1.el8.noarch",
"Installed: apr-util-bdb-1.6.1-6.el8.x86_64",
"Installed: httpd-tools-2.4.37-21.module+el8.2.0+5008+cca404a3.x86_64",
"Installed: httpd-2.4.37-21.module+el8.2.0+5008+cca404a3.x86_64"
]
}
}
PLAY RECAP *********************************************************************
192.168.172.142 : ok=3 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0