J'essaie de redémarrer le serveur exécutant CentOS 7
sur VirtualBox. J'utilise cette tâche:
- name: Restart server
command: /sbin/reboot
async: 0
poll: 0
ignore_errors: true
Le serveur est redémarré, mais j'obtiens cette erreur:
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
Qu'est-ce que je fais mal? Comment puis-je réparer cela?
Vous ne faites probablement rien de vraiment faux, c'est simplement que/sbin/reboot arrête le serveur si rapidement que le serveur supprime la connexion SSH utilisée par Ansible avant qu'Ansible puisse le fermer. En conséquence, Ansible signale une erreur car il voit la connexion SSH échouer pour une raison inattendue.
Ce que vous voudrez peut-être faire pour contourner ce problème est de passer de /sbin/reboot
à /sbin/shutdown
à la place. La commande shutdown vous laisse passer un temps et, lorsqu'elle est combinée avec le commutateur -r
, elle effectuera un redémarrage plutôt que de s'éteindre réellement. Donc, vous voudrez peut-être essayer une tâche comme celle-ci:
- name: Restart server
command: /sbin/shutdown -r +1
async: 0
poll: 0
ignore_errors: true
Cela retardera le redémarrage du serveur pendant une minute, mais vous devrez ainsi laisser à Ansible le temps de fermer la connexion SSH elle-même, évitant ainsi l'erreur que vous obtenez actuellement.
Après la tâche de redémarrage, vous devriez avoir une tâche local_action
qui attend que l'hôte distant ait fini de redémarrer, sinon la connexion ssh sera terminée, de même que le livre de lecture.
- 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
J'ai également écrit un article de blog sur la réalisation d'une solution similaire: 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
Une autre solution:
- 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
crée un nouveau service "à la volée" qui démarrera systemctl reboot
après 10 secondes de retard (--on-active=10
) .delay=30
dans wait_for
afin d'ajouter 20 secondes supplémentaires pour être sûr que l'hôte a réellement commencé à redémarrer.
Aucune des solutions ci-dessus n'a fonctionné de manière fiable pour moi.
L’émission de /sbin/reboot
bloque la lecture (la connexion SSH est fermée avant qu ’ansible ait terminé la tâche, elle se bloque même avec ignore_errors: true
) et /usr/bin/systemd-run --on-active=2 /usr/bin/systemctl reboot
ne redémarre pas après 2 secondes, mais après un délai aléatoire entre 20 secondes et une minute est parfois insuffisant et ce n’est pas prévisible.
De plus, je ne veux pas attendre des minutes pendant lesquelles un serveur cloud peut redémarrer en quelques secondes.
Alors voici ma solution:
- 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
C'est la ligne Shell: ( sleep 3 && /sbin/reboot & )
qui fait l'affaire.
L'utilisation de ( command & )
dans le script Shell exécute un programme en arrière-plan et le détache: la commande aboutit immédiatement mais persiste après la destruction du shell.
Ansible obtient sa réponse immédiatement et le serveur redémarre 3 secondes plus tard.
Ansible se développe rapidement et les réponses plus anciennes ne fonctionnaient pas pour moi.
J'ai trouvé deux problèmes:
Il vaut mieux exécuter: Nohup bash -c "sleep 2s && shutdown -r now" &
Ceci lancera un Shell avec les sleep
&& shutdown
, mais n'attendra pas la fin du Shell en raison du dernier &
. La mise en veille laissera un peu de temps pour que la tâche Ansible se termine avant le redémarrage et la variable Nohup
garantira que bash ne sera pas tué à la fin de la tâche.
wait_for
n'attend pas de manière fiable le service SSH. Il détecte le port ouvert, probablement ouvert par systemd, mais lors de l'exécution de la tâche suivante, SSH n'est toujours pas prêt.
Si vous utilisez Ansible 2.3+, wait_for_connection fonctionne de manière fiable.
Le meilleur «redémarrage et attente» de mon expérience (j'utilise Ansible 2.4) est le suivant:
- 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
J'ai la commande Nohup de: https://github.com/keithchambers/microservices-playground/blob/master/playbooks/upgrade-packages.yml
J'ai édité ce message pour:
Encore une autre version (combinée d’autres réponses):
---
- 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
J'utilise Ansible 2.5.3 . Le code ci-dessous fonctionne avec facilité,
- name: Rebooting Host
Shell: 'shutdown -r +1 "Reboot triggered by Ansible"'
- wait_for_connection:
delay: 90
timeout: 300
Vous pouvez redémarrer immédiatement, puis insérer un délai si votre machine met un certain temps à s’éteindre:
- 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
Ensuite, faites un sondage pour que le livre de jeu revienne le plus rapidement possible:
- name: Wait for the server to finish rebooting
wait_for_connection:
delay: 15
sleep: 15
timeout: 300
Cela rendra le livre de jeu le plus tôt possible après le redémarrage.
si vous utilisez la version Ansible> = 2.7, vous pouvez utiliser le module reboot
comme décrit ici
Le synopsis du module reboot
lui-même:
Redémarrez une machine, attendez qu’elle s’effondre, revenez en arrière et répondez aux commandes.
De manière simple, vous pouvez définir une tâche simple comme celle-ci:
- name: reboot server
reboot:
Mais vous pouvez ajouter des paramètres comme test_command
pour vérifier si votre serveur est prêt à exécuter d'autres tâches.
- name: reboot server
reboot:
test_command: whoami
J'espère que cela t'aides!
Au moment du redémarrage, toutes les connexions SSH sont fermées. C'est pourquoi la tâche Ansible échoue. Les ajouts ignore_errors: true
ou failed_when: false
ne fonctionnent plus à partir de Ansible 1.9.x car la gestion des connexions ssh a changé et une connexion fermée est maintenant une erreur fatale qui ne peut pas être interceptée pendant la lecture.
La seule façon pour moi de le faire est d'exécuter une tâche Shell locale qui démarre ensuite une connexion ssh distincte, qui peut ensuite échouer.
- name: Rebooting
delegate_to: localhost
Shell: ssh -S "none" {{ inventory_hostname }} Sudo /usr/sbin/reboot"
failed_when: false
changed_when: true