如何使用 Ansible 重启 CentOS 7?

Posted

技术标签:

【中文标题】如何使用 Ansible 重启 CentOS 7?【英文标题】:How to reboot CentOS 7 with Ansible? 【发布时间】:2015-07-09 10:33:13 【问题描述】:

我正在尝试重新启动在 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

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

【问题讨论】:

根据 Marcin Skarbek 提供的答案,我准备并向 Ansible Galaxy 角色发布了使用该方法的内容。角色 Reboot-And-Wait 你可以找到here。感谢您的使用,欢迎反馈。 由于 Ansible 的快速发展,旧的答案不再适合我。请看我的回答。 【参考方案1】:

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

您可能想要做的就是从使用/sbin/reboot 切换到使用/sbin/shutdown。关闭命令可以让您消磨时间,当与-r 开关结合使用时,它将执行重新启动而不是实际关闭。所以你可能想尝试这样的任务:

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

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

【讨论】:

谢谢,这很好用!只有一个小问题:我遇到了Failed to parse time specification: +1m 错误,所以我不得不将+1m 替换为+1 注意:除非您知道自己在做什么,否则使用重启不是一个好主意。在很多 linux 发行版中它可能没问题,但在其他 unix 上它可以绕过很多系统关闭脚本,而且非常困难。这可能会导致不一致的 dbs 等,这是不好的做法。最好使用 shutdown 或 init。 这里异步和轮询的目的是什么? @Basil,see the docs here。 ;)【参考方案2】:

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


- 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

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

【讨论】:

【参考方案3】:

在重新启动时,所有 ssh 连接都将关闭。这就是 Ansible 任务失败的原因。从 Ansible 1.9.x 开始,ignore_errors: truefailed_when: false 新增功能不再起作用,因为 ssh 连接的处理方式发生了变化,现在关闭的连接是一个致命错误,在播放过程中无法捕获。

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

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

【讨论】:

感谢您的解释,但您的方法可能需要无密码 sudo(或者我错过了什么?),所以我无法在生产中使用它。【参考方案4】:

另一种解决方案:

- 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 创建“即时”新服务,该服务将在延迟 10 秒 (--on-active=10) 后启动 systemctl rebootdelay=30wait_for 中添加额外的 20 秒以确保主机实际开始重新启动。

【讨论】:

非常感谢,我认为您的解决方案是最好的,带有 wait_for。 谢谢,多等一分钟!【参考方案5】:

以上解决方案都不适合我。

发出/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 秒后服务器重启。

【讨论】:

把/sbin/reboot命令放到后台有什么帮助? @mbigras 因为没有阻塞 Ansible 的执行,所以第二个动作立即执行。没有它,它将无法工作:Ansible 将等待命令返回,但在系统关闭期间将失去连接。我相信最新的 Ansible 版本有更好的解决方案,但我没有进一步调查。 @mbigras 无论如何,不​​管是什么原因,其他答案对我来说根本不可靠。【参考方案6】:
- 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

【讨论】:

这对我很有用,尤其是async: 1。 Ansible 2.3 添加了有用的wait_for_connection delay=20 wait_for_connection 更好【参考方案7】:

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

---
- 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

【讨论】:

【参考方案8】:

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),最好的“重启并等待”如下:

- 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

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

我将此消息编辑为:

添加 krad 的可移植性建议,使用 shutdown -r now 而不是重新启动 添加延迟。如果重启很慢,需要避免 Ansible 执行下一步 增加超时时间,对于某些慢速 Bios 来说,120 秒太少了。

【讨论】:

根据我以前的 cmets 使用 reboot 真的很糟糕 在非 Linux 世界中听起来很明智。我从来没有发现一个 linux 的重启不会执行适当的有组织的重启。 另一个优点是关闭命令可以包含超时,无需使用睡眠,更干净。我喜欢您关于可移植性的建议,但我会在此处更改之前对其进行测试,以防万一。我发布的答案是最简单的,同时也可以可靠地工作。 我看过了,我不喜欢关机的一件事。延迟的最小粒度是 1 分钟,这很浪费,所以我们不能停止使用睡眠。 只需使用 'shutdown now' 并在前面休眠。世界比 linux 还大。【参考方案9】:

我正在使用 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

然后轮询让剧本尽快返回:

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

这将使 playbook 在重启后尽快返回。

【讨论】:

您好,我发现这个解决方案可能有效,但不是最佳的。我在回答的评论中指定了原因,这些原因是:-shutdown -r +1 是安全的并且将始终有效,但是 +1 会为重启增加一分钟的延迟,这可能是不可取的。 - shutdown -r now 是不安全的,因为 ssh 可能在 Ansible 得到答案之前被杀死,返回失败,因此需要 +1 或 nohup + sleep 组合。我想找一个更简单的解决方案,比如shutdown -r +1,但我不想要1分钟的延迟。 看来您的 nohup 答案只是另一种剥猫皮的方法。您已经为 shell 提供了干净退出的工作,因此您不必告诉 Ansible 忽略该错误。你说potaytoh,我说potahtoe。 嗯,避免触发错误通常比忽略错误要好。通过忽略所有可能的关闭错误,您可能会忽略另一个应该注意的错误。【参考方案10】:

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

- 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 需要几秒钟来结束连接。 关于这个问题的优秀帖子写在这里: https://www.jeffgeerling.com/blog/2018/reboot-and-wait-reboot-complete-ansible-playbook

【讨论】:

【参考方案11】:

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

reboot 模块本身的概要:

重新启动一台机器,等待它停机、恢复并响应命令。

通过一种简单的方式,您可以像这样定义一个简单的任务:

    - name: reboot server
      reboot:

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

    - name: reboot server
      reboot:
        test_command: whoami

希望这会有所帮助!

【讨论】:

以上是关于如何使用 Ansible 重启 CentOS 7?的主要内容,如果未能解决你的问题,请参考以下文章

CentOS 7安装Ansible

Ansible 服务重启失败

基于Centos6.6(7.2)源码安装Ansible

centos 7/rhel7: 如何重启/停止/启动网络服务

CentOS7使用ansible部署Ceph(Nautilus)

CentOS6.7下Ansible部署