寻求Ansible高效定位备份目录并生成格式化清单的最佳实践
优化Ansible备份清单生成Playbook的最佳实践
当前实现
我有一个Ansible Playbook,通过SSH访问远程主机,生成可插入邮件正文的远程主机文件系统备份清单文本文件。当前用于生成备份清单的任务如下:
- name: Create backup log from Remote Host shell: | cd /mnt/bntestmnt; echo -e "Backup server: [ipv4 address goes here] Backup directory: /export /Backups/ESG Confluence Backups:" > BackupStatus.txt ls -td Confluence/daily/* | xargs du -sh >> BackupStatus.txt; echo " " >> BackupStatus.txt; ls -td Confluence/weekly/* | xargs du -sh >> BackupStatus.txt; echo -e " Gitlab Backups:" >> BackupStatus.txt ls -td GitLab/daily/* | xargs du -sh >> BackupStatus.txt; echo " " >> BackupStatus.txt ls -td GitLab/weekly/* | xargs du -sh >> BackupStatus.txt; echo -e " Jira Backups:" >> BackupStatus.txt ls -td Jira/daily/* | xargs du -sh >> BackupStatus.txt; echo " " >> BackupStatus.txt ls -td Jira/weekly/* | xargs du -sh >> BackupStatus.txt; cat BackupStatus.txt register: Backup_Status delegate_to: [remote host name goes here]
由于使用>>重定向输出到文件,Ansible无法直接获取结果,所以最后用cat读取文件内容并注册为变量,用于后续插入邮件正文。
预期输出
Backup server: [ipv4 address goes here] Backup directory: /export/Backups/ESG Confluence Backups: 4.1G Confluence/daily/Thu-23Mar23 4.0G Confluence/daily/Wed-22Mar23 4.0G Confluence/daily/Tue-21Mar23 4.0G Confluence/daily/Mon-20Mar23 4.0G Confluence/daily/Sun-19Mar23 3.9G Confluence/daily/Sat-18Mar23 3.9G Confluence/daily/Fri-17Mar23 3.7G Confluence/weekly/Fri-10Mar23 3.5G Confluence/weekly/Fri-03Mar23 3.4G Confluence/weekly/Fri-24Feb23 3.3G Confluence/weekly/Sat-18Feb23 Gitlab Backups: 2.5G GitLab/daily/Thu-23Mar23 2.5G GitLab/daily/Wed-22Mar23 2.4G GitLab/daily/Tue-21Mar23 2.4G GitLab/daily/Mon-20Mar23 2.4G GitLab/daily/Sun-19Mar23 2.3G GitLab/daily/Sat-18Mar23 2.3G GitLab/daily/Fri-17Mar23 2.2G GitLab/weekly/Fri-10Mar23 2.1G GitLab/weekly/Fri-03Mar23 2.2G GitLab/weekly/Fri-24Feb23 Jira Backups: 2.6G Jira/daily/Thu-23Mar23 2.6G Jira/daily/Wed-22Mar23 2.6G Jira/daily/Tue-21Mar23 2.6G Jira/daily/Mon-20Mar23 2.6G Jira/daily/Sun-19Mar23 2.6G Jira/daily/Sat-18Mar23 2.6G Jira/daily/Fri-17Mar23 2.6G Jira/weekly/Fri-10Mar23 2.6G Jira/weekly/Fri-03Mar23 2.6G Jira/weekly/Fri-24Feb23 2.6G Jira/weekly/Fri-17Feb23
每个应用的清单中,最后一个daily备份与第一个weekly备份之间有换行。
尝试过的替代方案
试过以下命令,但无法实现预期输出:
ls -td Confluence/{daily,weekly}/* | xargs du -sh
或者:
find Confluence -mindepth 2 -type d -exec du -sh {} \;
这个版本排序有问题,大小和日期顺序混乱。
也尝试过用Jinja2模板,但不太熟悉,任务格式如下:
- name: Create backup log from Remote Host template: src: backup_report.j2 dest: /mnt/bntestmnt/BackupStatus.txt vars: confluence_backups: [variable goes here] gitlab_backups: [variable goes here] jira_backups: [variable goes here]
目前模板backup_report.j2内容:
Backup server: [ipv4 address] Backup directory: /export/Backups/ESG Confluence Backups: {% for backup in confluence_backups %} {{ backup }} {% endfor %} Gitlab Backups: {% for backup in gitlab_backups %} {{ backup }} {% endfor %} Jira Backups: {% for backup in jira_backups %} {{ backup }} {% endfor %}
优化方案与最佳实践
1. 用Ansible原生逻辑替代Shell临时文件
直接在远程主机上执行命令并收集结果,不需要生成临时文件后再cat。可以用循环简化重复代码,直接组装报告内容:
- name: Collect backup server info set_fact: backup_server_ip: "{{ ansible_default_ipv4.address }}" backup_dir: "/export/Backups/ESG" delegate_to: [remote host name goes here] - name: Define backup applications set_fact: backup_apps: - name: "Confluence" path: "Confluence" - name: "GitLab" path: "GitLab" - name: "Jira" path: "Jira" - name: Collect backup details for each app shell: | echo -e "{{ app.name }} Backups:" ls -td {{ app.path }}/daily/* | xargs du -sh echo " " ls -td {{ app.path }}/weekly/* | xargs du -sh register: app_backups loop: "{{ backup_apps }}" delegate_to: [remote host name goes here] - name: Assemble final backup report content set_fact: backup_report_content: | Backup server: {{ backup_server_ip }} Backup directory: {{ backup_dir }} {% for result in app_backups.results %} {{ result.stdout }} {% endfor %}
后续直接用{{ backup_report_content }}插入邮件正文即可,无需临时文件。
2. 完善Jinja2模板实现
如果倾向用模板,先分模块收集备份数据,再传入模板生成报告:
数据收集任务
- name: Collect Confluence daily backups shell: ls -td Confluence/daily/* | xargs du -sh register: confluence_daily_backups delegate_to: [remote host name goes here] - name: Collect Confluence weekly backups shell: ls -td Confluence/weekly/* | xargs du -sh register: confluence_weekly_backups delegate_to: [remote host name goes here] # 同理收集GitLab和Jira的备份数据... - name: Generate backup report via template template: src: backup_report.j2 dest: /mnt/bntestmnt/BackupStatus.txt vars: backup_server_ip: "{{ ansible_default_ipv4.address }}" backup_dir: "/export/Backups/ESG" confluence_daily: "{{ confluence_daily_backups.stdout_lines }}" confluence_weekly: "{{ confluence_weekly_backups.stdout_lines }}" gitlab_daily: "{{ gitlab_daily_backups.stdout_lines }}" gitlab_weekly: "{{ gitlab_weekly_backups.stdout_lines }}" jira_daily: "{{ jira_daily_backups.stdout_lines }}" jira_weekly: "{{ jira_weekly_backups.stdout_lines }}" delegate_to: [remote host name goes here]
完善后的backup_report.j2模板
Backup server: {{ backup_server_ip }} Backup directory: {{ backup_dir }} Confluence Backups: {% for item in confluence_daily %} {{ item }} {% endfor %} {% for item in confluence_weekly %} {{ item }} {% endfor %} GitLab Backups: {% for item in gitlab_daily %} {{ item }} {% endfor %} {% for item in gitlab_weekly %} {{ item }} {% endfor %} Jira Backups: {% for item in jira_daily %} {{ item }} {% endfor %} {% for item in jira_weekly %} {{ item }} {% endfor %}
3. 简化Shell命令,避免重复
可以在Shell中定义函数减少重复代码,让逻辑更清晰:
generate_backup_list() { app_name=$1 app_path=$2 echo -e "\n${app_name} Backups:" ls -td ${app_path}/daily/* | xargs du -sh echo " " ls -td ${app_path}/weekly/* | xargs du -sh } echo -e "Backup server: $(hostname -i) Backup directory: /export/Backups/ESG" generate_backup_list "Confluence" "Confluence" generate_backup_list "GitLab" "GitLab" generate_backup_list "Jira" "Jira"
将这段代码放入Ansible的shell任务中执行,即可生成符合要求的输出。
4. 处理特殊目录名,避免xargs问题
如果备份目录名称包含空格,xargs会出错,改用循环读取目录:
ls -td Confluence/daily/* | while read dir; do du -sh "$dir"; done
或者用find保证排序正确性:
find Confluence/daily -mindepth 1 -maxdepth 1 -type d -printf "%T@ %p\n" | sort -nr | cut -d' ' -f2- | while read dir; do du -sh "$dir"; done
这个写法既支持带空格的目录名,又能保证按修改时间倒序排序,和ls -td效果一致。
内容的提问来源于stack exchange,提问作者Eridith
相关产品推荐
相关产品推荐

