关于Ansible批量关机及主机离线验证的技术问询
首先先看你用的这个批量关机playbook:
- hosts: my_hosts become: yes remote_user: my_user tasks: - name: Confirm shutdown pause: prompt: >- Do you really want to shutdown machine(s) "{{play_hosts}}"? Press Enter to continue or Ctrl+C, then A, then Enter to abort - name: Cancel existing shutdown calls command: /sbin/shutdown -c ignore_errors: yes - name: Shutdown machine command: /sbin/shutdown -h now
针对你提出的两个问题,我来逐一解答:
1. 是否存在更优雅的模块替代这两个自定义命令来处理关机操作?
当然有!Ansible自带的ansible.builtin.shutdown模块就是专门为关机/重启场景设计的,比直接用command调用系统命令要优雅得多:
- 它会自动适配不同操作系统的关机命令,不用硬编码
/sbin/shutdown这种路径; - 支持设置延迟时间、关机提示消息等参数;
- 返回的状态信息更标准化,便于后续任务判断。
不过要注意,取消已发起的关机操作目前还没有专门的模块,还是需要用command: /sbin/shutdown -c来处理(毕竟不同系统的取消方式差异不大,Ubuntu下这个命令是有效的)。但关机操作可以完全替换成shutdown模块,修改后的任务如下:
- name: Cancel existing shutdown calls command: /sbin/shutdown -c ignore_errors: yes - name: Shutdown machine using dedicated module ansible.builtin.shutdown: state: halted # 对应关机(halt),如果是重启用reboot delay: 0 # 立即执行
2. 能否验证这些主机是否真的已离线?在同一playbook中执行该验证是否属于反模式?
先解决你用net_ping失败的问题
net_ping模块是给网络设备(比如交换机、路由器)设计的,根本不适合用来检测普通服务器是否离线,而且它要求连接方式为local,你用默认的ssh连接自然会报错。
正确的离线验证方式
当然可以验证主机是否离线,但不能在同一个play里直接执行——因为原来的play是针对目标主机的,主机关机后Ansible会尝试通过ssh连接执行任务,必然失败。
正确的做法是:把验证部分放到一个独立的play中,将连接方式改为local,在控制节点上执行检测。这样就不会依赖目标主机的ssh连接了,而且整个流程还能放在同一个playbook里,完全不属于反模式,反而很合理。
给你两种常用的验证方案:
方案一:检测SSH端口是否关闭(推荐)
用ansible.builtin.wait_for模块检测目标主机的22端口是否停止监听,这是判断服务器离线的可靠方式:
- name: Verify hosts are offline hosts: my_hosts connection: local # 在控制节点本地执行 gather_facts: no # 不需要收集主机信息,加快速度 tasks: - name: Wait for SSH port to close (host offline) ansible.builtin.wait_for: host: "{{ ansible_host }}" port: 22 state: stopped timeout: 300 # 最多等待5分钟,可根据实际情况调整 connect_timeout: 5
方案二:用ping命令验证
如果更习惯用ping检测,可以在控制节点上执行系统ping命令,判断主机是否不可达:
- name: Verify hosts are offline hosts: my_hosts connection: local gather_facts: no tasks: - name: Check if host is unreachable via ping ansible.builtin.command: ping -c 5 "{{ ansible_host }}" register: ping_result failed_when: ping_result.rc == 0 # 如果ping通(返回码0)则判定失败,因为期望主机离线
关于同一playbook执行验证的说明
把关机和验证放在同一个playbook里是完全合理的,只要把验证部分拆成独立的play并设置connection: local,就不会有问题——这样整个工作流可以一次性完成,不用手动切换脚本或命令。
内容的提问来源于stack exchange,提问作者Dirk

