如何编写Ansible Copy任务实现多文件批量复制到多JVM目录?
问题背景
每台RHEL服务器的/etc/rc.d/init.d/目录下,有一个名为JVMNAMES的文件,文件内每行记录一个JVM名称,内容示例如下:
abc-def01 bcd-efg02 cde-fgh01
需求是循环将四个.sh文件复制到每个JVM的bin目录中。此前通过Shell脚本实现该需求,脚本内容如下:
LIST=/etc/rc.d/init.d/JVMNAMES for i in `cat $LIST` do echo "Updating the needed .sh files for JVM: '$i'..." cp /usr/apache/tomcat/tomcat-current/bin/catalina.sh /usr/apache/tomcat/$i/bin/ cp /usr/apache/tomcat/tomcat-current/bin/version.sh /usr/apache/tomcat/$i/bin/ cp /usr/apache/tomcat/tomcat-current/bin/startup.sh /usr/apache/tomcat/$i/bin/ cp /usr/apache/tomcat/tomcat-current/bin/shutdown.sh /usr/apache/tomcat/$i/bin/ done
目前编写了如下Ansible Playbook,但尚未运行,希望得到优化建议:
- name: Copy the needed .sh files to the bin directory of each JVM ansible.builtin.copy: src: "/usr/apache/tomcat/tomcat-current/bin/{{ item }}" dest: "/usr/apache/tomcat/{{ jvm_idx }}/bin/" owner: mwuser group: mwadmin mode: "u+rwx,g+rx,o=rx" with-items: - catalina.sh - version.sh - startup.sh - shutdown.sh loop: "{{ lookup('file', '/etc/rc.d/init.d/JVMNAMES') }}" loop_control: index_var: jvm_idx
优化建议
你的Playbook存在语法冲突和逻辑问题,以下是更合理的实现方案:
核心问题修正
原Playbook同时混用了旧语法with-items和新语法loop,这会导致循环逻辑混乱;且直接读取文件内容未处理换行符,可能出现无效的JVM名称。
优化后Playbook
- name: 定义JVM列表和目标文件列表 set_fact: jvm_list: "{{ lookup('file', '/etc/rc.d/init.d/JVMNAMES').splitlines() }}" target_sh_files: - catalina.sh - version.sh - startup.sh - shutdown.sh - name: 复制sh文件到每个JVM的bin目录 ansible.builtin.copy: src: "/usr/apache/tomcat/tomcat-current/bin/{{ sh_file }}" dest: "/usr/apache/tomcat/{{ jvm_name }}/bin/" owner: mwuser group: mwadmin mode: "u+rwx,g+rx,o=rx" loop: "{{ jvm_list | product(target_sh_files) | list }}" loop_control: loop_var: jvm_sh_pair label: "Copying {{ jvm_sh_pair.1 }} to JVM {{ jvm_sh_pair.0 }}" vars: jvm_name: "{{ jvm_sh_pair.0 }}" sh_file: "{{ jvm_sh_pair.1 }}"
优化点说明
- 使用
product过滤器实现两个列表的笛卡尔积,完美对应“每个JVM复制所有sh文件”的嵌套循环逻辑 splitlines()将读取的文件内容拆分为每行一个元素的列表,避免换行符干扰loop_control的label参数让执行日志更简洁,只显示关键操作信息- 将列表定义为变量,后续修改JVM或文件列表时无需改动核心任务代码
- 统一使用Ansible推荐的
loop语法,弃用已过时的with-items
可选增强优化
- 添加JVM目录存在性校验,防止复制到不存在的路径报错:
pre_tasks: - name: 检查JVM的bin目录是否存在 ansible.builtin.stat: path: "/usr/apache/tomcat/{{ item }}/bin" register: jvm_bin_check loop: "{{ jvm_list }}" - name: 复制sh文件到每个JVM的bin目录 ansible.builtin.copy: ... when: (jvm_bin_check.results | selectattr('item', 'equalto', jvm_name) | first).stat.exists
内容的提问来源于stack exchange,提问作者Jason Skeel
相关产品推荐
相关产品推荐

