如何使用 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: true
或 failed_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 reboot
。
delay=30
在 wait_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/rhel7: 如何重启/停止/启动网络服务