如何使用 Ansible 重启 CentOS 7?

How to reboot CentOS 7 with Ansible?

我正在尝试在 VirtualBox 上重启服务器 运行 CentOS 7。我使用这个任务:

- name: Restart server
  command: /sbin/reboot
  async: 0
  poll: 0
  ignore_errors: true

服务器已重新启动,但出现此错误:

TASK: [common | Restart server] ***********************************************
fatal: [rolcabox] => SSH Error: Shared connection to 127.0.0.1 closed.
It is sometimes useful to re-run the command using -vvvv, which prints SSH debug output to help diagnose the issue.

FATAL: all hosts have already failed -- aborting

我做错了什么?我该如何解决这个问题?

您可能并没有做错任何事情,只是 /sbin/reboot 关闭服务器的速度如此之快,以至于服务器在 Ansible 本身可以关闭它之前就断开了 Ansible 使用的 SSH 连接。结果 Ansible 报告错误,因为它发现 SSH 连接因意外原因而失败。

要解决此问题,您可能想做的是从使用 /sbin/reboot 切换为使用 /sbin/shutdown。 shutdown 命令可让您传递一个时间,当与 -r 开关结合使用时,它将执行重新启动而不是实际关闭。所以你可能想尝试这样的任务:

- name: Restart server
  command: /sbin/shutdown -r +1
  async: 0
  poll: 0
  ignore_errors: true

这会将服务器重启延迟 1 分钟,但这样做应该给 Ansible 足够的时间来关闭 SSH 连接本身,从而避免您当前遇到的错误。

重启任务后,你应该有一个local_action等待远程主机完成重启的任务,否则,ssh连接将被终止,剧本也会被终止。


- name: Reboot server
  command: /sbin/reboot

- name: Wait for the server to finish rebooting
  sudo: no
  local_action: wait_for host="{{ inventory_hostname }}" search_regex=OpenSSH port=22 timeout=300

我还写了一篇关于实现类似解决方案的博客post:https://oguya.github.io/linux/2015/02/22/ansible-reboot-servers/

在重新启动时,所有 ssh 连接都将关闭。这就是 Ansible 任务失败的原因。 ignore_errors: truefailed_when: false 添加项从 Ansible 1 开始不再起作用。9.x 因为 ssh 连接的处理方式已经改变,关闭的连接现在是一个致命错误,在游戏过程中无法捕获.

我想出的唯一方法是 运行 一个本地 shell 任务,然后启动一个单独的 ssh 连接,然后可能会失败。

- name: Rebooting
  delegate_to: localhost
  shell: ssh -S "none" {{ inventory_hostname }} sudo /usr/sbin/reboot"
  failed_when: false
  changed_when: true

另一个解决方案:

- name: reboot host
  command: /usr/bin/systemd-run --on-active=10 /usr/bin/systemctl reboot
  async: 0
  poll: 0

- name: wait for host sshd
  local_action: wait_for host="{{ inventory_hostname }}" search_regex=OpenSSH port=22 timeout=300 delay=30

systemd-run 创建 "on the fly" 新服务,它将在 systemctl reboot 延迟 10 秒 (--on-active=10) 后启动。 delay=30wait_for 中添加额外的 20 秒以确保主机真正开始重新启动。

None 以上解决方案对我来说很可靠。

发出 /sbin/reboot 会使播放崩溃(SSH 连接在 ansible 完成任务之前关闭,即使使用 ignore_errors: true 也会崩溃)并且 /usr/bin/systemd-run --on-active=2 /usr/bin/systemctl reboot 不会在 2 秒后重新启动,但是在 20 秒到 1 分钟之间的随机时间之后,所以延迟有时是不够的,这是不可预测的。

我也不想等待几分钟,而云服务器可以在几秒钟内重新启动。

所以这是我的解决方案:

- name: Reboot the server for kernel update
  shell: ( sleep 3 && /sbin/reboot & )
  async: 0
  poll: 0 

- name: Wait for the server to reboot
  local_action: wait_for host="{{ansible_host}}" delay=15 state=started port="{{ansible_port}}" connect_timeout=10 timeout=180

那是行得通的 shell: ( sleep 3 && /sbin/reboot & ) 行。

在 shell 脚本中使用 ( command & ) 在后台运行程序并将其分离:命令立即成功,但在 shell 被销毁后仍然存在。

Ansible 立即得到响应,服务器在 3 秒后重启。

- name: restart server
  shell: sleep 2 && shutdown -r now "Ansible updates triggered"
  async: 1
  poll: 0
  become: true
  ignore_errors: true


- name: waiting for the server to come back
  local_action: wait_for host=testcentos state=started delay=30 timeout=300
  sudo: false

另一个(结合其他答案)版本:

---
- name: restart server
  command: /usr/bin/systemd-run --on-active=5 --timer-property=AccuracySec=100ms /usr/bin/systemctl reboot
  async: 0
  poll: 0
  ignore_errors: true
  become: yes

- name: wait for server {{ ansible_ssh_host | default(inventory_hostname) }} to come back online
  wait_for:
    port: 22
    state: started
    host: '{{ ansible_ssh_host | default(inventory_hostname) }}'
    delay: 30
  delegate_to: localhost

Ansible 正在快速发展,旧的答案对我不起作用。

我发现了两个问题:

  • 推荐的重启方式可能会在 Ansible 完成任务之前终止 SSH 连接。

不如运行:nohup bash -c "sleep 2s && shutdown -r now" &

这将启动带有 sleep && shutdown 的 shell,但由于最后一个 & 而不会等待 shell 结束.睡眠将为 Ansible 任务在重启前结束提供一些时间,并且 nohup 将保证 bash 在任务结束时不会被杀死。

  • wait_for 模块无法可靠地等待 SSH 服务。

它检测到端口打开,可能是systemd打开的,但是当下一个任务是运行时,SSH仍然没有准备好。

如果您使用的是 Ansible 2.3+,wait_for_connection 工作可靠。

根据我的经验(我使用的是 Ansible 2.4),最好的 'reboot and wait' 如下:

- name: Reboot the machine
  shell: nohup bash -c "sleep 2s && shutdown -r now" &

- name: Wait for machine to come back
  wait_for_connection:
    timeout: 240
    delay: 20

我从以下位置获得了 nohup 命令:https://github.com/keithchambers/microservices-playground/blob/master/playbooks/upgrade-packages.yml

我将此消息编辑为:

  • 添加 krad 的可移植性建议,现在使用 shutdown -r 而不是 reboot
  • 添加延迟。需要避免Ansible在重启慢的情况下执行下一步
  • 增加超时时间,120 秒对于一些慢速 BIOS 来说太短了。

我正在使用 Ansible 2.5.3。 下面的代码可以轻松工作,

- name: Rebooting host
  shell: 'shutdown -r +1 "Reboot triggered by Ansible"'

- wait_for_connection:
    delay: 90
    timeout: 300

您可以立即重新启动,如果您的机器需要一段时间才能关闭,则插入延迟:

    - name: Rebooting host
      shell: 'shutdown -r now "Reboot triggered by Ansible"'
      async: 1
      poll: 1
      ignore_errors: true

# Wait 120 seconds to make sure the machine won't connect immediately in the next section.
    - name: Delay for the host to go down
      local_action: shell /bin/sleep 120

然后尽快投票制作剧本return:

    - name: Wait for the server to finish rebooting
      wait_for_connection:
        delay: 15
        sleep: 15
        timeout: 300

这将使 playbook 在重启后尽快 return。

以下解决方案非常适合我:

- name: Restart machine
  shell: "sleep 5 && sudo shutdown -r now"
  async: 1
  poll: 0

- name: wait for ssh again available.
  wait_for_connection:
    connect_timeout: 20
    sleep: 5
    delay: 5
    timeout: 300

需要睡眠,因为 ansible 需要几秒钟的时间来结束连接。 关于这个问题的优秀 post 写在这里: https://www.jeffgeerling.com/blog/2018/reboot-and-wait-reboot-complete-ansible-playbook

如果您使用的 Ansible 版本 >=2.7,您可以使用 reboot 模块,如 here

所述

reboot模块本身的概要:

Reboot a machine, wait for it to go down, come back up, and respond to commands.

简单来说,你可以这样定义一个简单的任务:

    - name: reboot server
      reboot:

但是你可以添加一些参数,比如 test_command 来测试你的服务器是否准备好接受进一步的任务

    - name: reboot server
      reboot:
        test_command: whoami

希望对您有所帮助!