Ansible如何遍历对象列表中的嵌套数组以安装多版本PHP及对应扩展?
方案合理性评估
你当前使用dict2items+subelements遍历的实现逻辑是通顺的,完全可以正常运行,也能满足不同PHP版本对应不同扩展列表的需求,本身具备合理性,但还存在比较大的效率优化空间。
更高效的实现方案
你现有的写法每次循环仅安装1个扩展包,会反复调用apt模块,执行效率很低。Ansible的apt模块本身支持传入包名数组一次性安装多个包,我们可以基于这个特性优化,同时还能实现配置复用、避免重复写扩展列表:
第一步:重构变量结构
优先抽离公共扩展列表,不同版本的差异单独配置,完全避免重复配置:
# 所有版本通用的公共扩展列表 php_common_extensions: - common - cli - opcache - mysql - mbstring - simplexml - curl - bcmath - ldap - gd - dom - zip - xml - readline - json - fpm - imagick # 各版本PHP的扩展配置,差异部分单独增减 php_packages: 5.6: "{{ php_common_extensions }}" 7.0: "{{ php_common_extensions + ['mcrypt'] }}" # 7.0版本额外加mcrypt扩展 8.1: "{{ php_common_extensions | difference(['json']) }}" # 8.1版本内置json无需单独安装
第二步:优化安装任务
每个PHP版本仅调用1次apt模块,一次性安装该版本所有扩展,执行效率比逐个安装高几倍到几十倍:
- name: 批量安装所有PHP版本及对应扩展 apt: name: "{{ php_packages[item] | map('regex_replace', '^', 'php' ~ item ~ '-') | list }}" state: present loop: "{{ php_packages.keys() | list }}"
这个方案的优势非常明显:
- 调用apt的次数和PHP版本数量一致,和扩展数量无关,大幅减少系统包管理操作的 overhead
- 配置和逻辑完全分离,后续增减PHP版本、调整对应扩展只需要修改
php_packages变量即可,不需要动任务逻辑 - 公共扩展抽离后没有冗余配置,维护成本极低
内容的提问来源于stack exchange,提问作者Lloyd Owen
相关产品推荐
相关产品推荐

