Ansible最佳实践之Playbook高级循环任务如何操作
Posted 山河已无恙
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Ansible最佳实践之Playbook高级循环任务如何操作相关的知识,希望对你有一定的参考价值。
写在前面
- 今天和小伙伴分享一些ansible剧本中数据迭代的笔记
- 博文内容比较简单
- 主要介绍的常见的迭代对比
- 使用过滤器和查找插件在复杂数据结构上实施迭代循环
- 食用方式:了解Ansible基础语法
- 理解不足小伙伴帮忙指正
傍晚时分,你坐在屋檐下,看着天慢慢地黑下去,心里寂寞而凄凉,感到自己的生命被剥夺了。当时我是个年轻人,但我害怕这样生活下去,衰老下去。在我看来,这是比死亡更可怕的事。--------王小波
循环和查找插件
Ansible 在 2.5 中引入了loop
关键字。以前任务迭代通过使用with_
开头并以查找的名称结尾的关键字的方法。与 loop 等效的是 with_list
,设计用于在简单的扁平列表中进行迭代,对于简单的列表来讲,loop 是最佳语法。
以下三种语法具有相同的结果,其中第一个使用的loop
是首选:
$ cat loop_demo.yaml
---
- name: loop Play
hosts: servera
gather_facts: no
vars:
- mylist:
- li
- rui
- long
tasks:
- name: using loop
debug: msg= item
loop: " mylist "
- name: using with_list
debug: msg= item
with_list: " mylist "
- name: using lookup plugin
debug: msg= item
loop: " lookup('list',mylist) "
$
运行剧本是一样的效果,这里第三种方式通过,lookup插件的的方式实现的,lookup 插件是 Jinja2 模板引擎的 Ansible 扩展。通过插件使 Ansible 能够使用外部来源的数据,我们这里使用lookup来将一个数据转化为list
$ ansible-playbook loop_demo.yaml
PLAY [loop Play] *********************************************************************************************
TASK [using loop] ********************************************************************************************
ok: [servera] => (item=li) =>
"msg": "li"
ok: [servera] => (item=rui) =>
"msg": "rui"
ok: [servera] => (item=long) =>
"msg": "long"
TASK [using with_list] ***************************************************************************************
ok: [servera] => (item=li) =>
"msg": "li"
ok: [servera] => (item=rui) =>
"msg": "rui"
ok: [servera] => (item=long) =>
"msg": "long"
TASK [using lookup plugin] ***********************************************************************************
ok: [servera] => (item=li) =>
"msg": "li"
ok: [servera] => (item=rui) =>
"msg": "rui"
ok: [servera] => (item=long) =>
"msg": "long"
PLAY RECAP ***************************************************************************************************
servera : ok=3 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
$
使用 loop 关键字替代 with_* 样式的循环具有以下优点:
- 无需记住或查找 with_* 样式关键字来满足当前迭代场景。
- 专注于学习 Ansible 中提供的插件和过滤器,适用性比单纯的迭代更广泛。
- 可以通过
ansible-doc -t lookup
命令访问查找插件文档,结合插件文档实现复杂遍历
使用loop关键字和dict插件替换"with_dict"关键字
---
- hosts: testB
remote_user: root
gather_facts: no
vars:
users:
alice: female
bob: male
tasks:
- debug:
msg: "item.key is item.value"
loop: " lookup('dict',users) "
在2.6版本的官网手册中,官方开始推荐使用 loop加filter
的方式来替代"loop加lookup"的方式,
---
- hosts: testB
remote_user: root
gather_facts: no
vars:
users:
alice: female
bob: male
tasks:
- debug:
msg: "item.key is item.value"
loop: " users | dict2items "
loop 方式还提供了 loop_control
属性
可以用于控制循环的行为,添加索引之类,比如,使用loop_control的index_var选项,就能在遍历列表时,将元素对应的索引写入到指定的变量中,除了index_var选项,loop_control还有一些其他的选项可用,此处我们就来总结一下这些选项。
pause选项能够让我们设置每次循环之后的暂停时间,以秒为单位,换句话说就是设置每次循环之间的间隔时间,示例如下
迭代场景示例
在列表的列表上迭代
对于需要多级迭代的嵌套数据,使用传统的循环方式,往往获取不到子数据,即不能实现数据的扁平化处理。
---
- name: loop Play
hosts: servera
gather_facts: no
vars:
- mylist:
- ['l','i']
- rui
- long
tasks:
- name: using loop
debug: msg= item
loop: " mylist "
- name: using with_list
debug: msg= item
with_list: " mylist "
- name: using lookup plugin
debug: msg= item
loop: " lookup('list',mylist) "
上面迭代的数据为一个嵌套的list,使用前面所讲的迭代方式不能对嵌套的子数组进行迭代。
三种不同方式的测试,都不能做的扁平化的迭代
$ ansible-playbook loop_demo.yaml
PLAY [loop Play] *********************************************************************************************
TASK [using loop] ********************************************************************************************
ok: [servera] => (item=['l', 'i']) =>
"msg": [
"l",
"i"
]
ok: [servera] => (item=rui) =>
"msg": "rui"
ok: [servera] => (item=long) =>
"msg": "long"
TASK [using with_list] ***************************************************************************************
ok: [servera] => (item=['l', 'i']) =>
"msg": [
"l",
"i"
]
ok: [servera] => (item=rui) =>
"msg": "rui"
ok: [servera] => (item=long) =>
"msg": "long"
TASK [using lookup plugin] ***********************************************************************************
ok: [servera] => (item=['l', 'i']) =>
"msg": [
"l",
"i"
]
ok: [servera] => (item=rui) =>
"msg": "rui"
ok: [servera] => (item=long) =>
"msg": "long"
PLAY RECAP ***************************************************************************************************
servera : ok=3 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
这个时候,我们可以使用 with_items
关键字来迭代复杂的列表,实现列表数据的扁平化处理
$ cat loop_demos.yaml
---
- name: loop Play
hosts: servera
gather_facts: no
tasks:
- name: using with_list
debug:
msg: " item "
with_items:
- [ 1,2,4 ]
- [ r,u ]
$ ansible-playbook loop_demos.yaml
PLAY [loop Play] *********************************************************************************************
TASK [using with_list] ***************************************************************************************
ok: [servera] => (item=1) =>
"msg": 1
ok: [servera] => (item=2) =>
"msg": 2
ok: [servera] => (item=4) =>
"msg": 4
ok: [servera] => (item=r) =>
"msg": "r"
ok: [servera] => (item=u) =>
"msg": "u"
PLAY RECAP ***************************************************************************************************
servera : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
获取序列
有时候希望在剧本里获取一些序列,可以通过 whit_sequence
关键字实现
$ cat loop_demo_sq.yaml
---
- name: liruilong demo
hosts: servera
gather_facts: n
tasks:
- name: test whit_sequence
debug: msg= item
with_sequence:
start=1
end=5
stride=1
$ ansible-playbook loop_demo_sq.yaml
PLAY [liruilong demo] ****************************************************************************************
TASK [test whit_sequence] ************************************************************************************
ok: [servera] => (item=1) =>
"msg": "1"
ok: [servera] => (item=2) =>
"msg": "2"
ok: [servera] => (item=3) =>
"msg": "3"
ok: [servera] => (item=4) =>
"msg": "4"
ok: [servera] => (item=5) =>
"msg": "5"
PLAY RECAP ***************************************************************************************************
servera : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
flatten 代替 with_items
若希望重构旧的剧本里的 with_items
任务以使用 loop
关键字,可使用 flatten 过滤器。
$ cat loop_demos.yaml
---
- name: loop Play
hosts: servera
gather_facts: no
tasks:
- name: using with_list
debug:
msg: " item "
#with_items:
loop:
- [ 1,2,4,[3,4,5,[6]] ]
- [ r,u ]
$ ansible-playbook loop_demos.yaml
PLAY [loop Play] *********************************************************************************************
TASK [using with_list] ***************************************************************************************
ok: [servera] => (item=[1, 2, 4, [3, 4, 5, [6]]]) =>
"msg": [
1,
2,
4,
[
3,
4,
5,
[
6
]
]
]
ok: [servera] => (item=['r', 'u']) =>
"msg": [
"r",
"u"
]
PLAY RECAP ***************************************************************************************************
servera : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
$
-
flatten 过滤器将以递归方式搜索嵌入式列表,并从发现的值创建一个列表。
-
flatten 过滤器接受 levels 参数,用于指定搜索嵌入式列表的整数的级别数,levels = 1 与 with_items 隐式进行的相同的一级扁平化。
$ cat loop_demos.yaml
---
- name: loop Play
hosts: servera
gather_facts: no
tasks:
- name: using with_list
debug:
msg: " item "
loop: " numList | flatten(levels=3) "
vars:
numList:
- [ 1,2,4,[3,4,5,[6]] ]
- [ r,u ]
$
执行测试
$ ansible-playbook loop_demos.yaml
PLAY [loop Play] *********************************************************************************************
TASK [using with_list] ***************************************************************************************
ok: [servera] => (item=1) =>
"msg": 1
ok: [servera] => (item=2) =>
"msg": 2
ok: [servera] => (item=4) =>
"msg": 4
ok: [servera] => (item=3) =>
"msg": 3
ok: [servera] => (item=4) =>
"msg": 4
ok: [servera] => (item=5) =>
"msg": 5
ok: [servera] => (item=6) =>
"msg": 6
ok: [servera] => (item=r) =>
"msg": "r"
ok: [servera] => (item=u) =>
"msg": "u"
PLAY RECAP ***************************************************************************************************
servera : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
迭代嵌套列表
subelements 过滤器从 names
变量数据中创建一个新列表。列表中的每一项本身是一个两元素列表。
$ cat subelements.yaml
---
- name: liruilong demo
hosts: servera
vars:
names:
- liruilong:
- key: li
- liruilong:
- key: rui
- liruilong:
- key: long
tasks:
- name: loop demo
debug: msg= item
loop: " names | subelements('liruilong') "
执行测试
$ ansible-playbook subelements.yaml -b
PLAY [liruilong demo] ****************************************************************************************
TASK [Gathering Facts] ***************************************************************************************
ok: [servera]
TASK [loop demo] *********************************************************************************************
ok: [servera] => (item=['liruilong': ['key': 'li'], 'key': 'li']) =>
"msg": [
"liruilong": [
"key": "li"
]
,
"key": "li"
]
ok: [servera] => (item=['liruilong': ['key': 'rui'], 'key': 'rui']) =>
"msg": [
"liruilong": [
"key": "rui"
]
,
"key": "rui"
]
ok: [servera] => (item=['liruilong': ['key': 'long'], 'key': 'long']) =>
"msg&以上是关于Ansible最佳实践之Playbook高级循环任务如何操作的主要内容,如果未能解决你的问题,请参考以下文章
Ansible最佳实践之Playbook不同上下文提权Demo