如何使用Ansible等待服务器重启?

时间:2014-05-26 21:11:18

标签: linux deployment ssh ansible ansible-playbook

我试图重新启动服务器,然后等待,使用:

- name: Restart server
  shell: reboot

- name: Wait for server to restart
  wait_for:
    port=22
    delay=1
    timeout=300

但是我收到了这个错误:

TASK: [iptables | Wait for server to restart] ********************************* 
fatal: [example.com] => failed to transfer file to /root/.ansible/tmp/ansible-tmp-1401138291.69-222045017562709/wait_for:
sftp> put /tmp/tmpApPR8k /root/.ansible/tmp/ansible-tmp-1401138291.69-222045017562709/wait_for

Connected to example.com.
Connection closed

11 个答案:

答案 0 :(得分:52)

Ansible> = 2.7(2018年10月发布)

使用新的reboot模块。

Ansible< 2.7

作为任务重新启动

- name: restart server
  shell: 'sleep 1 && shutdown -r now "Reboot triggered by Ansible" && sleep 1'
  async: 1
  poll: 0
  become: true

这将shell命令作为asynchronous task运行,因此Ansible不会等待命令的结束。通常async param为任务提供了最长的时间,但是当poll设置为0时,Ansible将永远不会轮询该命令是否已完成 - 它将使该命令成为"触发并忘记&#34 ;。在shutdown之前和之后休眠是为了防止在Ansible仍然连接到远程主机时重启期间断开SSH连接。

等待任务

你可以使用:

- name: Wait for server to restart
  local_action:
    module: wait_for
      host={{ inventory_hostname }}
      port=22
      delay=10
    become: false

..但如果使用以下条目,您可能更喜欢使用{{ ansible_ssh_host }}变量作为主机名和/或{{ ansible_ssh_port }}作为SSH主机和端口:

hostname         ansible_ssh_host=some.other.name.com ansible_ssh_port=2222 

..在您的广告资源中(Ansible hosts文件)。

这将运行wait_for任务on the machine running Ansible。此任务将等待端口22在远程主机上打开,延迟10秒后开始。

重新启动并等待处理程序

但我建议将这两者用作处理程序,而不是任务。

这有两个主要原因:

  • 代码重用 - 您可以为许多任务使用处理程序。 示例:触发服务器重启after changing the timezone并在更改内核后

  • 只触发一次 - 如果您为一些任务使用处理程序,并且其中超过1个将进行一些更改=>触发处理程序,然后处理程序执行的操作只会发生一次。 示例:如果你有一个httpd重启处理程序附加到httpd配置更改和SSL证书更新,那么如果配置和SSL证书更改httpd将只重启一次。

详细了解处理程序here

重新启动并等待重新启动作为处理程序:

  handlers:

    - name: Restart server
      command: 'sleep 1 && shutdown -r now "Reboot triggered by Ansible" && sleep 1'
      async: 1
      poll: 0
      ignore_errors: true
      become: true

    - name: Wait for server to restart
      local_action:
        module: wait_for
          host={{ inventory_hostname }}
          port=22
          delay=10
        become: false

..并按顺序在你的任务中使用它,就像这样,这里配合重启服务器处理程序:

  tasks:
    - name: Set hostname
        hostname: name=somename
        notify:
          - Restart server
          - Wait for server to restart

请注意 handlers are run in the order they are defined, not the order they are listed in notify

答案 1 :(得分:33)

您应该将wait_for任务更改为local_action,并指定您正在等待的主机。例如:

- name: Wait for server to restart
  local_action:
    module: wait_for
      host=192.168.50.4
      port=22
      delay=1
      timeout=300

答案 2 :(得分:10)

我最可靠的是1.9.4得到了(这是更新的,原始版本在底部):

- name: Example ansible play that requires reboot
  sudo: yes
  gather_facts: no
  hosts:
    - myhosts
  tasks:
    - name: example task that requires reboot
      yum: name=* state=latest
      notify: reboot sequence
  handlers:
    - name: reboot sequence
      changed_when: "true"
      debug: msg='trigger machine reboot sequence'
      notify:
        - get current time
        - reboot system
        - waiting for server to come back
        - verify a reboot was actually initiated
    - name: get current time
      command: /bin/date +%s
      register: before_reboot
      sudo: false
    - name: reboot system
      shell: sleep 2 && shutdown -r now "Ansible package updates triggered"
      async: 1
      poll: 0
      ignore_errors: true
    - name: waiting for server to come back
      local_action: wait_for host={{ inventory_hostname }} state=started delay=30 timeout=220
      sudo: false
    - name: verify a reboot was actually initiated
      # machine should have started after it has been rebooted
      shell: (( `date +%s` - `awk -F . '{print $1}' /proc/uptime` > {{ before_reboot.stdout }} ))
      sudo: false

请注意async选项。 1.8和2.0可能与0一起生效,但1.9想要它1。以上还检查机器是否实际重启。这很好,因为一旦我输入错误导致重启失败并且没有失败的迹象。

最大的问题是等待机器升级。这个版本只是在那里坐了330秒,从来没有尝试过早点访问主机。其他一些答案建议使用端口22.如果这两个都是真的,这很好:

  • 您可以直接访问这些机器
  • 在端口22打开后立即可以访问您的计算机

这些并非总是如此,所以我决定浪费5分钟的计算时间。我希望ansible扩展wait_for模块以实际检查主机状态以避免浪费时间。

顺便提一下,建议使用处理程序的答案很好。来自我的处理程序+1(我更新了使用处理程序的答案)。

这是原始版本,但它不太好,不太可靠:

- name: Reboot
  sudo: yes
  gather_facts: no
  hosts:
    - OSEv3:children
  tasks:
    - name: get current uptime
      shell: cat /proc/uptime | awk -F . '{print $1}'
      register: uptime
      sudo: false
    - name: reboot system
      shell: sleep 2 && shutdown -r now "Ansible package updates triggered"
      async: 1
      poll: 0
      ignore_errors: true
    - name: waiting for server to come back
      local_action: wait_for host={{ inventory_hostname }} state=started delay=30 timeout=300
      sudo: false
    - name: verify a reboot was actually initiated
      # uptime after reboot should be smaller than before reboot
      shell: (( `cat /proc/uptime | awk -F . '{print $1}'` < {{ uptime.stdout }} ))
      sudo: false

答案 3 :(得分:8)

2018年更新

从2.3开始,Ansible现在附带wait_for_connection模块,可用于此目的。

#
## Reboot
#

- name: (reboot) Reboot triggered
  command: /sbin/shutdown -r +1 "Ansible-triggered Reboot"
  async: 0
  poll: 0

- name: (reboot) Wait for server to restart
  wait_for_connection:
    delay: 75

shutdown -r +1可以防止返回1的返回码,并且ansible使任务失败。关闭作为异步任务运行,因此我们必须将wait_for_connection任务延迟至少60秒。 75为我们提供了雪花盒的缓冲区。

wait_for_connection - Waits until remote system is reachable/usable

答案 4 :(得分:6)

我想评论Shahar帖子,他使用硬编码的主机地址更好的是让它变量来引用当前主机ansible正在配置{{inventory_hostname}},所以他的代码将是这样的:

- name: Wait for server to restart
  local_action:
    module: wait_for
     host={{ inventory_hostname }}
     port=22
     delay=1
     timeout=300

答案 5 :(得分:5)

对于较新版本的Ansible(在我的情况下为1.9.1),轮询和异步参数设置为0有时是不够的(可能取决于设置的分布是什么?)。正如https://github.com/ansible/ansible/issues/10616中所解释的,一个解决方法是:

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

然后,等待重新启动完成,如本页的许多答案中所述。

答案 6 :(得分:4)

通过反复试验+大量阅读这是最终使用2.0版Ansible的工作方式:

$ ansible --version
ansible 2.0.0 (devel 974b69d236) last updated 2015/09/01 13:37:26 (GMT -400)
  lib/ansible/modules/core: (detached HEAD bbcfb1092a) last updated 2015/09/01 13:37:29 (GMT -400)
  lib/ansible/modules/extras: (detached HEAD b8803306d1) last updated 2015/09/01 13:37:29 (GMT -400)
  config file = /Users/sammingolelli/projects/git_repos/devops/ansible/playbooks/test-2/ansible.cfg
  configured module search path = None

我的解决方案是禁用SELinux并在需要时重新启动节点:

---
- name: disable SELinux
  selinux: state=disabled
  register: st

- name: reboot if SELinux changed
  shell: shutdown -r now "Ansible updates triggered"
  async: 0
  poll: 0
  ignore_errors: true
  when: st.changed

- name: waiting for server to reboot
  wait_for: host="{{ ansible_ssh_host | default(inventory_hostname) }}" port={{ ansible_ssh_port | default(22) }} search_regex=OpenSSH delay=30 timeout=120
  connection: local
  sudo: false
  when: st.changed

# vim:ft=ansible:

答案 7 :(得分:0)

- wait_for:
    port: 22
    host: "{{ inventory_hostname }}"
  delegate_to: 127.0.0.1

答案 8 :(得分:0)

如果您还没有远程服务器的DNS设置,您可以传递IP地址而不是变量主机名:

- name: Restart server
  command: shutdown -r now

- name: Wait for server to restart successfully
  local_action:
    module: wait_for
      host={{ ansible_default_ipv4.address }}
      port=22
      delay=1
      timeout=120

这是我添加到ansible-swap playbook末尾的两项任务(在新的Digital Ocean水滴上安装4GB交换。

答案 9 :(得分:0)

我创建了一个reboot_server ansible角色,该角色可以通过以下方式从其他角色中动态调用:

- name: Reboot server if needed
  include_role:
    name: reboot_server
  vars:
    reboot_force: false

角色内容为:

- name: Check if server restart is necessary
  stat:
    path: /var/run/reboot-required
  register: reboot_required

- name: Debug reboot_required
  debug: var=reboot_required

- name: Restart if it is needed
  shell: |
    sleep 2 && /sbin/shutdown -r now "Reboot triggered by Ansible"
  async: 1
  poll: 0
  ignore_errors: true
  when: reboot_required.stat.exists == true
  register: reboot
  become: true

- name: Force Restart
  shell: |
    sleep 2 && /sbin/shutdown -r now "Reboot triggered by Ansible"
  async: 1
  poll: 0
  ignore_errors: true
  when: reboot_force|default(false)|bool
  register: forced_reboot
  become: true

# # Debug reboot execution
# - name: Debug reboot var
#   debug: var=reboot

# - name: Debug forced_reboot var
#   debug: var=forced_reboot

# Don't assume the inventory_hostname is resolvable and delay 10 seconds at start
- name: Wait 300 seconds for port 22 to become open and contain "OpenSSH"
  wait_for:
    port: 22
    host: '{{ (ansible_ssh_host|default(ansible_host))|default(inventory_hostname) }}'
    search_regex: OpenSSH
    delay: 10
  connection: local
  when: reboot.changed or forced_reboot.changed

这最初是设计用于Ubuntu OS的。

答案 10 :(得分:0)

关于此,我没有看到太多可见性,但是最近的更改(https://github.com/ansible/ansible/pull/43857)添加了“ ignore_unreachable”关键字。这使您可以执行以下操作:

- name: restart server
  shell: reboot
  ignore_unreachable: true

- name: wait for server to come back
  wait_for_connection: 
      timeout: 120

- name: the next action
  ...