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

如何用Ansible对比两台RedHat服务器的运行中服务差异?

问题

我需要通过Ansible对比两台RedHat服务器的运行中服务列表,仅输出server1独有的运行服务(例如:server1运行服务为a,b,c,d,server2为c,d,e,f时,仅输出a,b)。我编写了如下Playbook,但执行后却输出了server1的所有服务,怀疑difference过滤器未生效,请问该如何解决?

- hosts: server1:server2
  gather_facts: true
  tasks:
    - name: Run command to get running services on server1
      shell: systemctl list-units --type=service --state=running --no-pager | grep '\.service' | awk '{print $1}'
      register: result_server1
      when: "'server1' in inventory_hostname"

    - name: Run command to get running services on server2
      shell: systemctl list-units --type=service --state=running --no-pager | grep '\.service' | awk '{print $1}'
      register: result_server2
      when: "'server2' in inventory_hostname"

    - name: Set facts for server1 services
      set_fact:
        server1_services: "{{ result_server1.stdout_lines }}"
      when: "'server1' in inventory_hostname"

    - name: Set facts for server2 services
      set_fact:
        server2_services: "{{ result_server2.stdout_lines }}"
      when: "'server2' in inventory_hostname"

    - name: Find the difference between services
      set_fact:
        service_difference: "{{ server1_services | difference(server2_services) }}"
      when: "'server1' in inventory_hostname"

    - name: Print the difference for server2
      debug:
        msg: "Service difference for server1: {{ service_difference }}"
      when: "'server1' in inventory_hostname"

执行结果:

TASK [Print differences] **********************************************************************************************************************************************************************
task path: /home/jenkins/workspace/custom-playbooks/2getservicelist.yaml:49
ok: [server1] => {
    "msg": "Service difference for server1: [u'auditd.service', u'crond.service', u'dbus.service', u'getty@tty1.service', u'httpd.service', u'irqbalance.service', u'lvm2-lvmetad.service', u'NetworkManager.service', u'polkit.service', u'postfix.service', u'rhnsd.service', u'rhsmcertd.service', u'rsyslog.service', u'sshd.service', u'systemd-journald.service', u'systemd-logind.service', u'systemd-udevd.service', u'tuned.service', u'vgauthd.service', u'vmtoolsd.service']"

skipping: [server2] => {}
META: ran handlers
META: ran handlers
问题分析与解决

核心问题

原Playbook的逻辑错误在于:Ansible的任务是在每个目标主机上独立执行的。当server1执行计算差异的任务时,server2_services变量根本不存在——因为设置该变量的任务仅在server2上运行,server1无法获取到这个值。此时difference过滤器相当于接收了一个未定义的参数,直接返回server1_services的完整列表,导致输出所有服务。

修正方案

方案一:将两台主机的服务列表汇聚到控制节点计算差异

这种方式把服务收集和差异计算分离,逻辑更清晰:

- hosts: server1:server2
  gather_facts: true
  tasks:
    - name: 获取运行中服务列表
      shell: systemctl list-units --type=service --state=running --no-pager --plain --no-legend | awk '{print $1}'
      register: running_services

    - name: 将服务列表同步到控制节点
      set_fact:
        "{{ inventory_hostname }}_services": "{{ running_services.stdout_lines }}"
      delegate_to: localhost
      run_once: false

- hosts: localhost
  tasks:
    - name: 计算server1独有的服务
      set_fact:
        server1_unique_services: "{{ server1_services | difference(server2_services) }}"

    - name: 输出结果
      debug:
        msg: "server1独有的运行中服务: {{ server1_unique_services }}"

方案二:在server1上直接获取server2的服务信息

通过delegate_to让server1的任务去server2上执行命令,直接拿到server2的服务列表:

- hosts: server1
  gather_facts: true
  tasks:
    - name: 获取server1运行中服务
      shell: systemctl list-units --type=service --state=running --no-pager --plain --no-legend | awk '{print $1}'
      register: server1_services_result

    - name: 获取server2运行中服务(委托执行)
      shell: systemctl list-units --type=service --state=running --no-pager --plain --no-legend | awk '{print $1}'
      register: server2_services_result
      delegate_to: server2

    - name: 计算server1独有的服务
      set_fact:
        server1_unique_services: "{{ server1_services_result.stdout_lines | difference(server2_services_result.stdout_lines) }}"

    - name: 输出结果
      debug:
        msg: "server1独有的运行中服务: {{ server1_unique_services }}"

额外优化

原命令中的grep '\.service'可以去掉,通过systemctl的--plain --no-legend参数直接输出纯净的服务名列表,避免grep可能带来的匹配问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 08:30:27