ansible 变量
文章目录
- ansible 变量
- 一、Ansible 变量介绍
- 二、变量命名规则
- 三、变量类型
- 1.全局变量
- 2.剧本变量
- 3.资产变量
- 4.Facts 变量
- 5.注册变量
- 6.变量优先级
一、Ansible 变量介绍
在 PlayBook 一节中,将 PlayBook 类比成了 linux 中的shell。那么它作为一门 ansible 特殊的语言,肯定要涉及到变量定义、控制结构的使用等特性。
二、变量命名规则
- 变量的名字由 字母、下划线和数字组成,必须以字母开头
- 保留关键字不能作为变量名称
三、变量类型
根据变量的作用范围大体的将变量分为:
- 全局变量
- 剧本变量
- 资产变量
这只是比较粗糙的划分,不能囊括 ansible 中的所有变量,下面将分别介绍者者三种变量的使用。
1.全局变量
全局变量,是我们使用ansible 或使用 ansible-playbook 时,手动通过 -e 参数传递给 ansible 的变量。
通过 ansible 或者 ansible-playbook 的 help 帮助,可以获取具体格式使用方式:
#ansible -h |grep var -e EXTRA_VARS,--extra-vars=EXTRA_VARS set additional variables as key=value or YAML/JSON
#ansible-playbook -h |grep var -e EXTRA_VARS,--extra-vars=EXTRA_VARS set additional variables as key=value or YAML/JSON
栗子
#ansible all -i localhost, -m debug -a "msg='my key is {{key}}'" -e "key=value"
传递一个YAML/JSON 的形式(注意不管YAML 还是 JSON,它们的最终格式一定要是一个字典)
```bash
#cat test.json
{"name": "guan", "type": "people"}
[root@master1 ~]# ansible all -i localhost, -m debug -a "msg='name is {{name}},type is {{type}}'" -e @test.json
[WARNING]: Found variable using reserved name: name
localhost | SUCCESS => {
"msg": "name is guan,type is people"
}
[root@master1 ~]# cat abc.yml
---
name: guan
type: student
...
[root@master1 ~]# ansible all -i localhost, -m debug -a "msg='name is {{name}},type is {{type}}'" -e @
abc.yml
[WARNING]: Found variable using reserved name: name
localhost | SUCCESS => {
"msg": "name is guan,type is student"
}
[root@master1 ~]#
2.剧本变量
这种变量和playbook 有关,定义在 playbook 中的,它的定义方式有多种。这里介绍两种最常见的定义方式。
通过 Playbook 属性 vars 定义
---
- name: test play vars
hosts: all
vars:
user: zhangsan
home: /home/zhangsan
...
通过 Play 属性 vars_files 定义
#当通过vars属性定义的变量很多时,这个 Play 就会感觉特别臃肿,此时我们可将变量单独从play中抽离出来
#形成单独的 yaml 文件
---
- name: test play vars
hosts: all
vars:
- vars/users.yml
...
#cat vars/users.yml
---
user: zhangsan
home: /home/zhangsan
如何在 playbook 中使用这些变量
在playbook中使用变量时,使用 {{ 变量名 }} 来使用变量
---
- name: test play vars
hosts: all
vars:
user: zhangsan
home: /home/zhangsan
tasks:
- name: create the user {{ user}}
user:
name: "{{ user }}"
home: "{{ home }}"
...
[root@master1 ~]# vim test_play_vars.yml
[root@master1 ~]# ansible-playbook -i localhost, test_play_vars.yml -C
PLAY [test play vars] *********************************************************************************
TASK [Gathering Facts] ********************************************************************************
The authenticity of host 'localhost (::1)' can't be established.
ECDSA key fingerprint is SHA256:ygT6h9ejxNmaemQtyIzVYHEbRko0BaG4PstS2LTavDM.
ECDSA key fingerprint is MD5:88:1f:c4:d2:fe:73:b9:1f:7f:26:cd:2c:ba:ad:5c:b5.
Are you sure you want to continue connecting (yes/no)? yes
fatal: [localhost]: UNREACHABLE! => {"changed": false, "msg": "Failed to connect to the host via ssh: Warning: Permanently added 'localhost' (ECDSA) to the list of known hosts.\r\nPermission denied (publickey,gssapi-keyex,gssapi-with-mic,password).", "unreachable": true}
PLAY RECAP ********************************************************************************************
localhost : ok=0 changed=0 unreachable=1 failed=0 skipped=0 rescued=0 ignored=0
[root@master1 ~]# ssh-copy-id root@192.168.200.181
/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/root/.ssh/id_rsa.pub"
The authenticity of host '192.168.200.181 (192.168.200.181)' can't be established.
ECDSA key fingerprint is SHA256:ygT6h9ejxNmaemQtyIzVYHEbRko0BaG4PstS2LTavDM.
ECDSA key fingerprint is MD5:88:1f:c4:d2:fe:73:b9:1f:7f:26:cd:2c:ba:ad:5c:b5.
Are you sure you want to continue connecting (yes/no)? yes
/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys
root@192.168.200.181's password:
Number of key(s) added: 1
Now try logging into the machine, with: "ssh 'root@192.168.200.181'"
and check to make sure that only the key(s) you wanted were added.
[root@master1 ~]# ansible-playbook -i localhost, test_play_vars.yml -C
PLAY [test play vars] *********************************************************************************
TASK [Gathering Facts] ********************************************************************************
ok: [localhost]
TASK [create the user zhangsan] ***********************************************************************
changed: [localhost]
PLAY RECAP ********************************************************************************************
localhost : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[root@master1 ~]# cat test_play_vars.yml
---
- name: test play vars
hosts: all
vars:
user: zhangsan
home: /home/zhangsan
tasks:
- name: create the user {{ user}}
user:
name: "{{ user }}"
home: "{{ home }}"
...
[root@master1 ~]#
- 执行出现以下错误的原因是 {{ user }} 两端没有加双引号
[root@master1 ~]# ansible-playbook -i localhost, test_play_vars.yml -C
ERROR! We were unable to read either as JSON nor YAML, these are the errors we got from each:
JSON: No JSON object could be decoded
Syntax Error while loading YAML.
found unacceptable key (unhashable type: 'AnsibleMapping')
The error appears to be in '/root/test_play_vars.yml': line 10, column 16, but may
be elsewhere in the file depending on the exact syntax problem.
The offending line appears to be:
user:
name: {{ user }}
^ here
We could be wrong, but this one looks like it might be an issue with
missing quotes. Always quote template expression brackets when they
start a value. For instance:
with_items:
- {{ foo }}
Should be written as:
with_items:
- "{{ foo }}"
[root@master1 ~]#
这样错误的主要原因是playbook 是yaml的格式文件,当 ansible 分析 yaml 文件时,有可能会误认为是字典。
name: {{ user }} 是一个字典的开始。因此,加针对变量的使用,加上了双引号,避免 ansible 错误解析。
3.资产变量
资产变量分为主机变量和主机组变量,分别针对资产中的单个主机和主机组。
主机变量
以下资产中,定义了一个主机变量 lisi ,此变量只针对 192.168.200.183 这台服务器有效。
[root@master1 ~]# vim hosts_vars
[root@master1 ~]# cat hosts_vars
[web_servers]
192.168.200.183 user=lisi port=3309
192.168.200.182
[root@master1 ~]#
验证
[root@master1 ~]# ansible 192.168.200.183 -i hosts_vars -m debug -a "msg='{{user}} {{port}}'"
192.168.200.183 | SUCCESS => {
"msg": "lisi 3309"
}
[root@master1 ~]#
//未获取到定义的变量值,因为 user 这个变量针对 192.168.200.182 主机无效
[root@master1 ~]# ansible 192.168.200.182 -i hosts_vars -m debug -a "var=user"
192.168.200.182 | SUCCESS => {
"user": "VARIABLE IS NOT DEFINED!"
}
主机组变量
以下资产中,定义了一个组变量home,此变量将针对 web_servers 这个主机组中的所有服务器有效
[root@master1 ~]# cat hosts_groupvars
[web_servers]
192.168.200.183 user=lisi port=3309
192.168.200.182
[web_servers:vars]
home="/home/lisi"
验证
[root@master1 ~]# ansible web_servers -i hosts_groupvars -m debug -a "var=home"
192.168.200.182 | SUCCESS => {
"home": "/home/lisi"
}
192.168.200.183 | SUCCESS => {
"home": "/home/lisi"
}
[root@master1 ~]#
主机变量 vs 主机组变量
当主机变量和组变量在同一个资产中发生重名的情况,会有什么效果
[root@master1 ~]# vim hosts_vs
[root@master1 ~]# cat hosts_vs
[web_servers]
192.168.200.183 user=lisi
192.168.200.182
[web_servers:vars]
user=tongtong
验证
//在资产中定义了主机变量和组变量 user,此时发现 192.168.200.183 这台服务器的主机变量 user 的优先级 高于 组变量user 使用。
[root@master1 ~]# ansible web_servers -i hosts_vs -m debug -a "var=user"
192.168.200.183 | SUCCESS => {
"user": "lisi"
}
192.168.200.182 | SUCCESS => {
"user": "tongtong"
}
[root@master1 ~]#
变量的继承
[root@master1 ~]# cat hosts_v1
[web3_servers]
192.168.200.183
[web2_servers]
192.168.200.182
[allservers]
[allservers:children]
web2_servers
web3_servers
[allservers:vars]
user=lisi
//在资产继承的同时,对应的变量也发生了继承
[root@master1 ~]# ansible allservers -i hosts_v1 -m debug -a "var=user"
192.168.200.183 | SUCCESS => {
"user": "lisi"
}
192.168.200.182 | SUCCESS => {
"user": "lisi"
}
[root@master1 ~]#
[root@master1 ~]# ansible web2_servers -i hosts_v1 -m debug -a "var=user"
192.168.200.182 | SUCCESS => {
"user": "lisi"
}
[root@master1 ~]# ansible web3_servers -i hosts_v1 -m debug -a "var=user"
192.168.200.183 | SUCCESS => {
"user": "lisi"
}
[root@master1 ~]#
4.Facts 变量
facts 变量不包含在之前介绍的全局变量、剧本变量及资产变量之内。
facts 变量不需要我们人为去声明变量名及赋值。它的声明和赋值完全有 ansible 中的 setup 模块帮助我们完成。
它收集了有关被管理服务器的操作系统版本、服务器IP地址、主机名,磁盘的使用情况、cpu个数、内存条大小等等有关被管理服务器的私有信息。
在每次playbook运行的时候都会发现在 Playbook 执行一个 Gathering Facts的过程。这个过程就是收集被管理服务器的facts信息过程。
手动收集 Facts 变量
[root@master1 ~]# ansible all -i localhost, -c local -m setup
localhost | SUCCESS => {
"ansible_facts": {
"ansible_all_ipv4_addresses": [
"192.168.200.181",
"192.168.122.1"
],
"ansible_all_ipv6_addresses": [
"fe80::8054:e8a7:a00d:e7f5",
"fe80::2e53:1e73:716d:c608",
"fe80::5d99:b781:21b8:139b"
],
"ansible_apparmor": {
"status": "disabled"
},
"ansible_architecture": "x86_64",
"ansible_bios_date": "07/22/2020",
"ansible_bios_version": "6.00",
"ansible_cmdline": {
"BOOT_IMAGE": "/vmlinuz-3.10.0-957.el7.x86_64",
"LANG": "zh_CN.UTF-8",
"crashkernel": "auto",
"quiet": true,
"rd.lvm.lv": "centos/swap",
"rhgb": true,
"ro": true,
"root": "/dev/mapper/centos-root"
},
...
...
...
过滤 Facts
通过刚刚的手动收集 Facts,我们发现facts 信息量很大。因此,可以有针对性的显示我们想要的信息。
可以通过使用facts 模块中filter 参数去过滤我们想要的信息。
- 仅获取服务器的内存信息情况
[root@master1 ~]# ansible all -i localhost, -c local -m setup -a "filter=*memory*"
localhost | SUCCESS => {
"ansible_facts": {
"ansible_memory_mb": {
"nocache": {
"free": 1826,
"used": 1001
},
"real": {
"free": 189,
"total": 2827,
"used": 2638
},
"swap": {
"cached": 94,
"free": 1567,
"total": 2047,
"used": 480
}
},
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false
}
- 仅获取服务器的磁盘挂在情况
[root@master1 ~]# ansible all -i localhost, -c local -m setup -a "filter=*mount*"
localhost | SUCCESS => {
"ansible_facts": {
"ansible_mounts": [
{
"block_available": 213906,
"block_size": 4096,
"block_total": 259584,
"block_used": 45678,
"device": "/dev/sda1",
"fstype": "xfs",
"inode_available": 523947,
"inode_total": 524288,
"inode_used": 341,
"mount": "/boot",
"options": "rw,relatime,attr2,inode64,noquota",
"size_available": 876158976,
"size_total": 1063256064,
"uuid": "1bb90732-6784-4a0f-b4f7-71c74e55e7b5"
},
{
"block_available": 0,
"block_size": 0,
"block_total": 0,
"block_used": 0,
"device": "/dev/fuse",
"fstype": "fuse",
"inode_available": 0,
"inode_total": 0,
"inode_used": 0,
"mount": "/run/user/1001/doc",
"options": "rw,nosuid,nodev,relatime,user_id=1001,group_id=1008",
"size_available": 0,
"size_total": 0,
"uuid": "N/A"
},
{
"block_available": 2042537,
"block_size": 4096,
"block_total": 4452864,
"block_used": 2410327,
"device": "/dev/mapper/centos-root",
"fstype": "xfs",
"inode_available": 8670224,
"inode_total": 8910848,
"inode_used": 240624,
"mount": "/",
"options": "rw,relatime,attr2,inode64,noquota",
"size_available": 8366231552,
"size_total": 18238930944,
"uuid": "c26721c5-0deb-42fe-949d-3779b2bd4276"
}
],
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false
}
[root@master1 ~]#
在 Playbook 中去使用Facts 变量
默认情况下,在执行Playbook的时候,它会去自动的获取每台被管理服务器的facts信息。
[root@master1 ~]# vim facts.yml
[root@master1 ~]# ansible-playbook -i localhost, facts.yml
PLAY [print facts variable] ***************************************************************************
TASK [Gathering Facts] ********************************************************************************
ok: [localhost]
TASK [print facts variable] ***************************************************************************
ok: [localhost] => {
"msg": "The default IPV4 address is [u'0', u'AuthenticAMD', u'AMD Ryzen 7 5700U with Radeon Graphics', u'1', u'AuthenticAMD', u'AMD Ryzen 7 5700U with Radeon Graphics']"
}
PLAY RECAP ********************************************************************************************
localhost : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[root@master1 ~]# cat facts.yml
---
- name: print facts variable
hosts: all
tasks:
- name: print facts variable
debug:
msg: "The default IPV4 address is {{ ansible_processor }}"
...
[root@master1 ~]#
[root@master1 ~]# ansible-playbook -i localhost, facts.yml
PLAY [print facts variable] ***************************************************************************
TASK [Gathering Facts] ********************************************************************************
ok: [localhost]
TASK [print facts variable] ***************************************************************************
ok: [localhost] => {
"msg": "/usr/bin/python"
}
PLAY RECAP ********************************************************************************************
localhost : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[root@master1 ~]# cat facts.yml
---
- name: print facts variable
hosts: all
tasks:
- name: print facts variable
debug:
msg: "{{ ansible_python.executable }}" //如果是字典就通过键获取对应的值
...
[root@master1 ~]#
在Playbook 中去关闭 Facts 变量的获取
若在整个 Playbook 的执行过程中,完全未使用过 Facts 变量,此时我们可以将其关闭,以加速 playbook 的执行速度。
---
- name: the first play example
hosts: web_servers
gather_facts: no //关闭 facts 变量收集功能
remote_user: root
tasks:
- name: install nginx package
yum: name=nginx state=present
- name: copy nginx.conf to remote server
copy: src=nginx.conf dest=/etc/nginx/nginx.conf
- name: start nginx server
service:
name: nginx
enabled:true
state: started
...
执行
[root@master1 ~]# ansible-playbook -i hosts my_playbook01.yml
5.注册变量
用于保存一个 task 任务的执行结果,以便于 debug 时使用,或者将此次 task 任务的结果作为条件,去判断是否执行其他 task 任务。
注册变量在playbook中通过 register
关键字 去实现。
[root@master1 ~]# vim my_playbook02.yml
[root@master1 ~]# cat my_playbook02.yml
---
- name: install a package and print the result
hosts: web_servers
remote_user: root
tasks:
- name: install nginx package
yum: name=nginx state=present
register: install_result
- name: print result
debug: var=install_result
...
执行
[root@master1 ~]# ansible-playbook -i hosts my_playbook02.yml
PLAY [install a package and print the result] *********************************************************
TASK [Gathering Facts] ********************************************************************************
ok: [192.168.200.183]
TASK [install nginx package] **************************************************************************
ok: [192.168.200.183]
TASK [print result] ***********************************************************************************
ok: [192.168.200.183] => {
"install_result": {
"changed": false,
"failed": false,
"msg": "",
"rc": 0,
"results": [
"1:nginx-1.20.1-10.el7.x86_64 providing nginx is already installed"
]
}
}
PLAY RECAP ********************************************************************************************
192.168.200.183 : ok=3 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[root@master1 ~]#
6.变量优先级
前面介绍了全局变量、剧本变量、资产变量、Facts 变量及注册变量,其中 facts 变量不需要人为去声明、赋值;注册变量只需通过关键字 register
去声明,而不需要赋值,而全局变量、剧本变量及资产变量则完全需要人为的去声明、赋值。
变量的优先权讨论,也将从这三类变量去分析。
假设在使用过程中,我们同时在全局变量、剧本变量及资产变量声明了同一个变量名,那么哪一个优先级最高呢?
下面通过实验去验证变量的优先级
环境准备
- 定义一份资产、且定义了资产变量 user
[root@master1 ~]# vim hosts_v1
[root@master1 ~]# cat hosts_v1
[web3_servers]
192.168.200.183
[web2_servers]
192.168.200.182
[allservers]
[allservers:children]
web2_servers
web3_servers
[allservers:vars]
user=tomcat
[root@master1 ~]#
2、编写一份 playbook 、同样定义剧本变量 user
[root@master1 ~]# vim user_playbook.yml
[root@master1 ~]# cat user_playbook.yml
---
- name: test variable priority
hosts: all
remote_user: root
vars:
user: mysql
tasks:
- name: print the user value
debug: msg='the user value is {{ user }}'
...
[root@master1 ~]#
验证测试
[root@master1 ~]# ansible-playbook -i hosts priority.yml
PLAY [test variable priority] *************************************************************************
TASK [Gathering Facts] ********************************************************************************
ok: [192.168.200.183]
ok: [192.168.200.182]
TASK [print the user value] ***************************************************************************
ok: [192.168.200.183] => {
"msg": "the user value is mysql"
}
ok: [192.168.200.182] => {
"msg": "the user value is mysql"
}
PLAY RECAP ********************************************************************************************
192.168.200.182 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
192.168.200.183 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[root@master1 ~]# ansible-playbook -i hosts priority.yml -e "user=xiaobai"
PLAY [test variable priority] *************************************************************************
TASK [Gathering Facts] ********************************************************************************
ok: [192.168.200.183]
ok: [192.168.200.182]
TASK [print the user value] ***************************************************************************
ok: [192.168.200.183] => {
"msg": "the user value is xiaobai"
}
ok: [192.168.200.182] => {
"msg": "the user value is xiaobai"
}
PLAY RECAP ********************************************************************************************
192.168.200.182 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
192.168.200.183 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[root@master1 ~]#
变量优先级结论
当一个变量同时在全局变量、剧本变量 和 资产变量中定义时,优先级最高的是全局变量;其次是剧本变量;最后才是资产变量。