Как перезагрузить CentOS 7 с помощью Ansible?
Я пытаюсь перезагрузить сервер под управлением CentOS 7 на VirtualBox. Я использую эту задачу:
- 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
Что я делаю не так? Как я могу это исправить?
10 ответов:
Вы, вероятно, не делаете ничего по-настоящему плохого, просто /sbin/reboot закрывает сервер так быстро, что сервер разрывает SSH-соединение, используемое Ansible, прежде чем Ansible сам может закрыть его. В результате 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-соединение будет прервано, а вместе с ним и 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/
- 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: 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создает "на лету" новую службу, которая запуститсяsystemctl rebootчерез 10 секунд задержки (--on-active=10).delay=30вwait_forдобавить дополнительные 20 секунд, чтобы убедиться, что хост действительно начал перезагрузку.
Ни одно из вышеперечисленных решений не работало для меня надежно.
Выдача
/sbin/rebootзавершает игру (SSH-соединение закрывается до того, как ansible завершит задачу, оно завершается даже сignore_errors: true) и/usr/bin/systemd-run --on-active=2 /usr/bin/systemctl rebootне перезагрузится через 2 секунды, но через случайное количество времени между 20 секундами и одной минутой, поэтому задержка иногда не достаточна, и это не предсказуемо.Также я не хочу ждать несколько минут, пока облачный сервер может перезагрузиться за несколько секунд.
Итак, вот мой решение:
- 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 & ), которая делает трюк.С помощью скрипта
( command & )в оболочке запускает программу в фоновом режиме и отсоединяет ее: команда выполняется немедленно, но сохраняется после разрушения оболочки.Ansible получает свой ответ немедленно, и сервер перезагружается через 3 секунды.
Ансибль развивается быстро, и старые ответы не работали для меня.
Я нашел две проблемы:
- рекомендуемый способ перезагрузки может убить SSH-соединение до того, как Ansible завершит задачу.
Лучше запустить:
nohup bash -c "sleep 2s && shutdown -r now" &Это запустит оболочку с
sleep&&shutdown, но не будет ждать окончания оболочки из-за последнего&. Сон даст некоторое время для завершения задачи Ansible до перезагрузки, иnohupбудет гарантирую, что Баша не убьют, когда задание закончится.
- модуль
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Я получил команду nohup от: https://github.com/keithchambers/microservices-playground/blob/master/playbooks/upgrade-packages.yml
Я отредактировал это сообщение следующим образом:
- добавьте предложение по переносимости krad, используя shutdown-r теперь вместо перезагрузки
- добавьте задержку. Это необходимо, чтобы избежать Ansible для выполнения следующего шага, если перезагрузка медленная
- увеличьте время ожидания, 120s было слишком мало для некоторых медленных BIOS.
Еще одна (объединенная из других ответов) версия:
--- - 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
Во время перезагрузки все ssh-соединения закрываются. Вот почему задача Ансибля терпит неудачу. Дополнения
ignore_errors: trueилиfailed_when: falseбольше не работают по состоянию на Ansible 1.9.x потому что обработка ssh-соединений изменилась, и закрытое соединение теперь является фатальной ошибкой, которую нельзя поймать во время игры.Единственный способ, которым я понял, как это сделать, - это запустить локальную задачу оболочки, которая затем запускает отдельное ssh-соединение, которое затем может завершиться неудачей.
- name: Rebooting delegate_to: localhost shell: ssh -S "none" {{ inventory_hostname }} sudo /usr/sbin/reboot" failed_when: false changed_when: true
Я использую 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Затем опрос, чтобы сделать playbook вернуться как можно скорее:
- name: Wait for the server to finish rebooting wait_for_connection: delay: 15 sleep: 15 timeout: 300Это позволит вернуть playbook как можно скорее после перезагрузки.
Следующее решение работает для меня идеально:
- 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
Comments