You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Ansible playbook中lineinfile模块写入日志内容丢失问题

问题产生原因
  • Ansible默认启用多主机并行执行(默认并发数为5),你的两个受控主机会同时执行delegate到localhost的lineinfile写文件任务,触发竞态条件。
  • lineinfile模块的工作逻辑是:先将目标文件完整读取到内存中,完成内容修改后再整体覆盖写入原文件。当多个进程同时操作同一个文件时,进程A读取文件后,进程B写入了新内容,进程A后续写入自己的修改结果时会直接覆盖进程B的写入内容,最终表现为随机丢失条目、写入结果不稳定。
解决方案

提供三种可选方案,按推荐优先级排序:

方案1:统一收集结果后单次写入(最优,无并发问题、性能最好)

先在所有受控主机上采集命令结果,最后仅在控制端执行一次写入任务,一次性把所有主机的结果写入日志文件,完全避免并发冲突:

---
- name: 采集主机信息
  hosts: all
  tasks:
    - name: 采集date命令结果
      command: date
      register: date_output

    - name: 采集hostname命令结果
      command: hostname
      register: hostname_output

- name: 统一写入日志到控制端
  hosts: localhost
  tasks:
    - name: 生成所有主机的日志内容
      set_fact:
        log_content: |
          {% for host in groups['all'] %}
          {{ hostvars[host].inventory_hostname }} date
          ======================
          {{ hostvars[host].date_output.stdout }}
          {{ hostvars[host].inventory_hostname }} hostname
          ======================
          {{ hostvars[host].hostname_output.stdout }}

          {% endfor %}

    - name: 写入到日志文件
      copy:
        content: "{{ log_content }}"
        path: /home/ubuntu/list.log
        create: yes

方案2:调整play并发数为1(最简单,改动最小)

在play配置中添加serial: 1参数,强制同一时间只有一个主机执行任务,避免并发写冲突:

---
- name: 采集主机信息并写入日志
  hosts: all
  serial: 1 # 核心改动,关闭并行执行
  tasks:
    - command: date
      register: date_output
    - command: hostname
      register: hostname_output
    - lineinfile:
        line: "{{inventory_hostname}} {{ item.cmd | join(' ') }}\n======================\n{{ item.stdout }}"
        path: /home/ubuntu/list.log
        create: yes
      with_items: 
        - "{{ date_output }}" 
        - "{{ hostname_output }}"
      delegate_to: localhost

额外优化:添加item.cmd | join(' ')可以把命令列表转为字符串,避免输出['date']这种格式。

方案3:分临时文件写入后合并

如果需要保持多主机并行执行性能,可以先让每个主机写入自己的临时文件,所有任务完成后再合并临时文件到最终日志:

---
- name: 采集主机信息并写入临时文件
  hosts: all
  tasks:
    - command: date
      register: date_output
    - command: hostname
      register: hostname_output
    - lineinfile:
        line: "{{inventory_hostname}} {{ item.cmd | join(' ') }}\n======================\n{{ item.stdout }}"
        path: "/tmp/{{ inventory_hostname }}_tmp.log"
        create: yes
      with_items: 
        - "{{ date_output }}" 
        - "{{ hostname_output }}"
      delegate_to: localhost

- name: 合并临时文件到最终日志
  hosts: localhost
  tasks:
    - name: 合并所有临时日志
      shell: cat /tmp/*_tmp.log > /home/ubuntu/list.log && rm -f /tmp/*_tmp.log

内容的提问来源于stack exchange,提问作者Bindu G

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.13 09:21:02