ansible, host在不同group中,变量覆盖问题

问题背景

在ansible中,inventory的组织方式可如下

1
2
3
4
5
6
7
8
9
10
11
somedomain
[cluster01]
domain01
[cluster02]
domain02
[tomcat:children]
cluster01
cluster02

这样我们可以使用子分组来区分不同分组主机的变量,但是生产环境中,有可能cluster01和02在同一台主机上
此时,在切换子分组的时候,每个子分组的变量会互相干涉吗?

以下所有实验的目录结构

1
2
3
4
5
6
7
8
tree .
.
├── group_vars
│   ├── group
│   ├── group01
│   └── group02
├── hosts
└── main.yml

group_vars同一层级之间会竞争,无法共存

场景1、子分组变量会覆盖父分组变量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
# inventory文件
****************************
[group:children]
group01
[group01]
47.90.80.156
****************************
# 父group变量文件:group_vars/group
****************************
---
test: test_group
****************************
# 子group变量文件:group_vars/group
****************************
---
test: test_group_01
****************************
# 测试yaml文件:main.yml
****************************
---
- hosts: "{{ host }}"
remote_user: root
tasks:
- debug: msg="{{ test }}"
****************************
# 测试结果
ansible-playbook -i hosts main.yml -e '{"host":"group"}'
PLAY [group] *******************************************************************
TASK [setup] *******************************************************************
ok: [47.90.80.156]
TASK [debug] *******************************************************************
ok: [47.90.80.156] => {
"msg": "test_group_01"
}
PLAY RECAP *********************************************************************
47.90.80.156 : ok=2 changed=0 unreachable=0 failed=0
# 结论
子分组的变量会覆盖父分组

场景2、host变量会覆盖组变量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# 与场景1唯一的改变是在inventory文件中增加host变量
****************************
[group:children]
group01
[group01]
47.90.80.156 test=test_host
****************************
# 测试结果
ansible-playbook -i hosts main.yml -e '{"host":"group"}'
PLAY [group] *******************************************************************
TASK [setup] *******************************************************************
ok: [47.90.80.156]
TASK [debug] *******************************************************************
ok: [47.90.80.156] => {
"msg": "test_host"
}
PLAY RECAP *********************************************************************
47.90.80.156 : ok=2 changed=0 unreachable=0 failed=0
# 结论
host变量会覆盖组变量

场景3、同一层级的组变量,不确定哪一方会胜出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# 与场景1(注意是场景1)的区别1是修改了inventory内容
****************************
[group:children]
group01
group02
[group01]
47.90.80.156
[group02]
47.90.80.156
****************************
# 与场景1(注意是场景1)的区别2是增加了group_vars/group02的内容
****************************
---
test: test_group_02
****************************
# 测试结果
ansible-playbook -i hosts main.yml -e '{"host":"group"}'
PLAY [group] *******************************************************************
TASK [setup] *******************************************************************
ok: [47.90.80.156]
TASK [debug] *******************************************************************
ok: [47.90.80.156] => {
"msg": "test_group_01"
}
PLAY RECAP *********************************************************************
47.90.80.156 : ok=2 changed=0 unreachable=0 failed=0
# 结论
当同层级(group01和group02)同时存在针对同一host的组变量时,不确定哪一个会生效

当然,实验3也是主要的问题所在,因为假设在同一台host上我们部署了两个tomcat,一主一备,
当我们希望去分别指定两个tomcat时,同一变量的情况下,我们无法准确的知道该变量会指定谁。

如何解决主机同时处在不同分组时变量传递的问题

从上面的实验中,我们得出一个结论,ansible对于变量的层级分为三种,all、group、host(暂不考虑role)

  • 不同类别中变量优先级为host>group>all
  • 同类别中,子层级>父层级
    也就是说,对于主机的指定越精确的变量,优先级越大。

这里思考解决办法:
办法1,可以通过使用不同的role,来达到隔离分组变量互相干扰的问题(个人不是太喜欢这种方法,未测试)
办法2,上面的变量覆盖和冲突,根源在于ansible对同一变量名的优先级逻辑,那我们可以在变量名称逻辑上下功夫

解决办法测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
# inventory内容
****************************
[group:children]
group01
group02
[group01]
47.90.80.156
[group02]
47.90.80.156
****************************
# group变量文件:group_vars/group
****************************
---
test:
- '{{ test_01 | d({}) }}'
- '{{ test_02 | d({}) }}'
****************************
# 含义为当test_01变量不存在时,返回{}
# test_02亦同
# group01变量文件:group_vars/group01
****************************
---
test_01: test_group_01
****************************
# group02变量文件:group_vars/group02
****************************
---
test_02: test_group_02
****************************
# 测试yaml文件内容
****************************
---
- hosts: "{{ host }}"
remote_user: root
tasks:
- debug: msg="{{ test }}"
****************************
# 测试结果
ansible-playbook -i hosts main.yml -e '{"host":"group"}'
PLAY [group] *******************************************************************
TASK [setup] *******************************************************************
ok: [47.90.80.156]
TASK [debug] *******************************************************************
ok: [47.90.80.156] => {
"msg": [
"test_group_01",
"test_group_02"
]
}
PLAY RECAP *********************************************************************
47.90.80.156 : ok=2 changed=0 unreachable=0 failed=0
# 此时我们发现返回的结果是一个list,包含了两个变量的值。但我们希望它返回两次,而不是一个list
# 因为若返回结果是list,我们在很多模块中调用它会因为类型问题报错
# 我们仅对yaml文件进行修改
****************************
---
- hosts: "{{ host }}"
remote_user: root
tasks:
- debug: msg="{{ item }}"
with_items: "{{ test }}"
****************************
# 再次测试
ansible-playbook -i hosts main.yml -e '{"host":"group"}'
PLAY [group] *******************************************************************
TASK [setup] *******************************************************************
ok: [47.90.80.156]
TASK [debug] *******************************************************************
ok: [47.90.80.156] => (item=test_group_01) => {
"item": "test_group_01",
"msg": "test_group_01"
}
ok: [47.90.80.156] => (item=test_group_02) => {
"item": "test_group_02",
"msg": "test_group_02"
}
PLAY RECAP *********************************************************************
47.90.80.156 : ok=2 changed=0 unreachable=0 failed=0
# 此时结果完全符合我们的预期