Ansible最佳实践之Playbook高级循环任务如何操作
admin
2024-03-14 11:22:19
0

写在前面


  • 今天和小伙伴分享一些ansible剧本中数据迭代的笔记
  • 博文内容比较简单
  • 主要介绍的常见的迭代对比
  • 使用过滤器和查找插件在复杂数据结构上实施迭代循环
  • 食用方式:了解Ansible基础语法
  • 理解不足小伙伴帮忙指正

傍晚时分,你坐在屋檐下,看着天慢慢地黑下去,心里寂寞而凄凉,感到自己的生命被剥夺了。当时我是个年轻人,但我害怕这样生活下去,衰老下去。在我看来,这是比死亡更可怕的事。--------王小波


循环和查找插件

Ansible 在 2.5 中引入了loop关键字。以前任务迭代通过使用with_开头并以查找的名称结尾的关键字的方法。与 loop 等效的是 with_list,设计用于在简单的扁平列表中进行迭代,对于简单的列表来讲,loop 是最佳语法。

以下三种语法具有相同的结果,其中第一个使用的loop是首选:

$ cat loop_demo.yaml
---
- name: loop Playhosts: serveragather_facts: novars:- mylist:- li- rui- longtasks:- name: using loopdebug: msg={{ item }}loop: "{{ mylist }}"- name: using with_listdebug: msg={{ item }}with_list: "{{ mylist }}"- name: using lookup plugindebug: msg={{ item }}loop: "{{ lookup('list',mylist) }}"
$

运行剧本是一样的效果,这里第三种方式通过,lookup插件的的方式实现的,lookup 插件是 Jinja2 模板引擎的 Ansible 扩展。通过插件使 Ansible 能够使用外部来源的数据,我们这里使用lookup来将一个数据转化为list

$ ansible-playbook  loop_demo.yamlPLAY [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: testBremote_user: rootgather_facts: novars:users:alice: femalebob: maletasks:- debug:msg: "{{item.key}} is {{item.value}}"loop: "{{ lookup('dict',users) }}"

在2.6版本的官网手册中,官方开始推荐使用 loop加filter 的方式来替代"loop加lookup"的方式,

---
- hosts: testBremote_user: rootgather_facts: novars:users:alice: femalebob: maletasks:- debug:msg: "{{item.key}} is {{item.value}}"loop: "{{ users | dict2items }}"

loop 方式还提供了 loop_control属性

可以用于控制循环的行为,添加索引之类,比如,使用loop_control的index_var选项,就能在遍历列表时,将元素对应的索引写入到指定的变量中,除了index_var选项,loop_control还有一些其他的选项可用,此处我们就来总结一下这些选项。

pause选项能够让我们设置每次循环之后的暂停时间,以秒为单位,换句话说就是设置每次循环之间的间隔时间,示例如下

迭代场景示例

在列表的列表上迭代

对于需要多级迭代的嵌套数据,使用传统的循环方式,往往获取不到子数据,即不能实现数据的扁平化处理。

---
- name: loop Playhosts: serveragather_facts: novars:- mylist:- ['l','i']- rui- longtasks:- name: using loopdebug: msg={{ item }}loop: "{{ mylist }}"- name: using with_listdebug: msg={{ item }}with_list: "{{ mylist }}"- name: using lookup plugindebug: msg={{ item }}loop: "{{ lookup('list',mylist) }}"

上面迭代的数据为一个嵌套的list,使用前面所讲的迭代方式不能对嵌套的子数组进行迭代。

三种不同方式的测试,都不能做的扁平化的迭代

$ ansible-playbook  loop_demo.yamlPLAY [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 Playhosts: serveragather_facts: notasks:- name: using with_listdebug:msg: "{{ item }}"with_items:- [ 1,2,4 ]- [ r,u ]
$ ansible-playbook  loop_demos.yamlPLAY [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 demohosts: serveragather_facts: ntasks:- name: test whit_sequencedebug: msg={{ item }}with_sequence:start=1end=5stride=1
$ ansible-playbook  loop_demo_sq.yamlPLAY [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 Playhosts: serveragather_facts: notasks:- name: using with_listdebug:msg: "{{ item }}"#with_items:loop:- [ 1,2,4,[3,4,5,[6]] ]- [ r,u ]
$ ansible-playbook loop_demos.yamlPLAY [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 Playhosts: serveragather_facts: notasks:- name: using with_listdebug:msg: "{{ item }}"loop: "{{ numList | flatten(levels=3) }}"vars:numList:- [ 1,2,4,[3,4,5,[6]] ]- [ r,u ]$

执行测试

$ ansible-playbook loop_demos.yamlPLAY [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 demohosts: serveravars:names:- liruilong:- key: li- liruilong:- key: rui- liruilong:- key: longtasks:- name: loop demodebug: msg={{ item }}loop: "{{ names | subelements('liruilong') }}"

执行测试

$ ansible-playbook subelements.yaml -bPLAY [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": [{"liruilong": [{"key": "long"}]},{"key": "long"}]
}PLAY RECAP ***************************************************************************************************
servera                    : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
  • 第一个元素包含对每个用户的引用。
  • 第二个元素包含该用户的 liruilong 字典中的单个条目的引用。

迭代字典

在 Ansible 2.5 之前,必须使用 with_dict 关键字来迭代字典中的键值对。

item 变量具有两个属性:key 和 value。

key 属性包含一个字典键的值,而 value 属性则包含与字典关联的数据

$ cat dist_demo.yaml
---
- name: 字典 demohosts: serveravars:users:xiaoming:name: xiaomingxiaoli:name: xiaolitasks:- name: dist demodebug: msg={{ item.value.name }}loop: "{{ users | dict2items }}"- name: dist demo1debug: msg={{ item.key }}with_dict : "{{ users  }}"
$

这里使用 dict2item 可以实现相同的功能

$ ansible-playbook dist_demo.yamlPLAY [字典 demo] *************************************************************************************************************TASK [Gathering Facts] *****************************************************************************************************
ok: [servera]TASK [dist demo] ***********************************************************************************************************
ok: [servera] => (item={'key': 'xiaoming', 'value': {'name': 'xiaoming'}}) => {"msg": "xiaoming"
}
ok: [servera] => (item={'key': 'xiaoli', 'value': {'name': 'xiaoli'}}) => {"msg": "xiaoli"
}TASK [dist demo1] **********************************************************************************************************
ok: [servera] => (item={'key': 'xiaoming', 'value': {'name': 'xiaoming'}}) => {"msg": "xiaoming"
}
ok: [servera] => (item={'key': 'xiaoli', 'value': {'name': 'xiaoli'}}) => {"msg": "xiaoli"
}PLAY RECAP *****************************************************************************************************************
servera                    : ok=3    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0$

迭代文件通配模式

通过fileglob查找插件构建循环,以迭代与所提供的文件通配模式的文件列表:

$ cat file_loop.yaml
---
- name: demohosts: serverctasks:- name: file demodebug: msg={{lookup('fileglob','~/.bash*')}}

执行测试

$ ansible-playbook  file_loop.yamlPLAY [demo] ****************************************************************************************************************TASK [Gathering Facts] *****************************************************************************************************
ok: [serverc]TASK [file demo] ***********************************************************************************************************
ok: [serverc] => {"msg": "/home/student/.bash_logout,/home/student/.bash_profile,/home/student/.bashrc,/home/student/.bash_history"
}PLAY RECAP *****************************************************************************************************************
serverc                    : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

可以使用 query 代替 lookup, 以列表的形式展示

$ sed 's/lookup/query/' file_loop.yaml -i
$ ansible-playbook  file_loop.yamlPLAY [demo] ****************************************************************************************************************TASK [Gathering Facts] *****************************************************************************************************
ok: [serverc]TASK [file demo] ***********************************************************************************************************
ok: [serverc] => {"msg": ["/home/student/.bash_logout","/home/student/.bash_profile","/home/student/.bashrc","/home/student/.bash_history"]
}PLAY RECAP *****************************************************************************************************************
serverc                    : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0$

博文参考


《Red Hat Ansible Engine 2.8 DO447》

相关内容

热门资讯

珠海华润银行正式更名为广东华润... 2月26日,大型央企华润集团旗下珠海华润银行完成工商登记变更,正式更名为广东华润银行,截至发稿,该行...
2026马年春节品牌营销图鉴-... 今天分享的是:2026马年春节品牌营销图鉴-艺恩 报告共计:27页 2026马年春节品牌营销围绕Z世...
锂电行业现V型反转!杉杉、天齐... 来源:证券市场周刊 2025年锂电产业链迎来V型反转,中游材料企业靠降本增效复苏,而上游锂矿双雄则展...
奥雅股份:公司近日与芜湖市江北... 证券日报网讯 2月27日,奥雅股份在互动平台回答投资者提问时表示,基于奥雅城市文旅大模型的核心能力,...
成交飙回2.56万亿!周期强势... 本周A股在节后情绪修复基础上放量上行,成交规模跃升,市场风格出现显著切换,周期资源品成为新主线,中小...
金融监管总局系统查处吊销注销6... 【金融监管总局系统查处吊销注销60家保险专业中介法人牌照】财联社2月27日电,为深入贯彻中央金融工作...
白癜风医生祃开芬:白癜风患者如... 脚踝是白癜风的高发部位,此处长期承受身体重量、易受鞋子挤压摩擦,且夏季易出汗、冬季易干燥,皮肤屏障脆...
萨洛蒙大增始祖鸟放缓,亚玛芬靠... “第四季度为亚玛芬体育具有突破性意义的一年画上了圆满句号。2025全年,所有业务板块、地区以及渠道均...
亚马逊CEO发出警告:未来许多... 【CNMO科技消息】近日,亚马逊CEO安迪·贾西(Andy Jassy)在采访中表示:过去二三十年靠...
出大事了!中东开战,A股这4个... 文 | 付一夫 周末“黑天鹅”来袭! 就在刚刚,美国和以色列对伊朗发动突袭,中东地缘局势骤然升级。作...
原创 访... 白宫率先宣布,特朗普将于3月31日到4月2日访问中国,行程比原计划提前了40天。但是不到一天时间,美...
河南省股权投资基金首批子基金管... 投资界2月28日消息,近日,河南省股权投资基金首批子基金管理机构公开遴选名单,基金名称为:河南资产产...
人民币汇率三日急涨600点!央... 2月27日,中国人民银行果断亮出政策工具箱,宣布自2026年3月2日起将远期售汇业务外汇风险准备金率...
GDP差距缩至3495亿,江苏... 记者 刘亚宁 近日,广东在“新春第一会”上提出了“永争第一、不为人后”的目标,明确未来10年,经济总...
遂宁:青春小店已成为彰显青春气... 人民网记者 王波 2月27日上午,遂宁市第八届人民代表大会第七次会议开幕。市长王忠诚代表遂宁市人民政...
【银行业展望系列】中间业务:优... 在净息差持续收窄的背景下,中间业务正在重塑银行业的盈利模式,从2025年上市银行披露的数据显示,上市...
近6000万播放!富国基金20... 出品|中访网 审核|李晓燕 岁序更替,华章日新。近日,富国基金发布2025年度投资者教育年鉴,全面回...
突发!以色列对伊朗发动先发制人... 每经编辑|杜宇 据央视新闻2月28日消息,以色列方面称,以色列已对伊朗发起打击,以色列多地响起防空...
原创 5... “谁能做到任正非这样,谁就永远不会缺忠心耿耿的下属。” 老周是济南的一个老板,白手起家创业几十年,现...
22.4万亿私募基金监管升级!... 农历马年伊始,私募基金行业迎来监管升级。 2月27日晚间,证监会发布《私募投资基金信息披露监督管理办...