Exécuter automatiquement des commandes via SSH sur de nombreux serveurs

46

Il y a une liste d'adresses IP dans un fichier .txt, ex .:

1.1.1.1
2.2.2.2
3.3.3.3

Derrière chaque adresse IP, il y a un serveur et sur chaque serveur, il y a un sshd fonctionnant sur le port 22. Tous les serveurs ne figurent pas dans la known_hostsliste (sur mon PC, Ubuntu 10.04 LTS / bash).

Comment puis-je exécuter des commandes sur ces serveurs et collecter la sortie?

Idéalement, j'aimerais exécuter les commandes en parallèle sur tous les serveurs.

Je vais utiliser l'authentification par clé publique sur tous les serveurs.

Voici quelques pièges potentiels:

  • Le SSH m'invite à mettre la clé SSH des serveurs donnés à mon known_hostsfichier.
  • Les commandes données peuvent renvoyer un code de sortie différent de zéro, indiquant que la sortie est potentiellement non valide. J'ai besoin de le reconnaître.
  • Une connexion peut ne pas être établie avec un serveur donné, par exemple à cause d’une erreur de réseau.
  • Il devrait y avoir un délai d'expiration, au cas où la commande serait exécutée plus longtemps que prévu ou si le serveur ne fonctionnait pas pendant l'exécution de la commande.

Les serveurs sont AIX / ksh (mais je pense que cela n'a pas vraiment d'importance.

LanceBaynes
la source
1
Je pense que ce n'est pas un doublon, car le lien que vous mentionnez ne contient même pas SSH.
LanceBaynes
4
Si vous ne l'avez pas encore fait, vous devez configurer les serveurs ssh sur toutes les machines, créer une paire de clés privée / publique sur la machine à partir de laquelle vous travaillez et copier la clé publique sur les comptes du serveur pour éviter toute usure supplémentaire au niveau des mots de passe. Cela vaut pour ma réponse, ainsi que pour @ sage.
Anthon

Réponses:

14

En supposant que vous ne puissiez pas installer pssh ou d’autres personnes, vous pourriez faire quelque chose comme:

tmpdir=${TMPDIR:-/tmp}/pssh.$$
mkdir -p $tmpdir
count=0
while IFS= read -r userhost; do
    ssh -n -o BatchMode=yes ${userhost} 'uname -a' > ${tmpdir}/${userhost} 2>&1 &
    count=`expr $count + 1`
done < userhost.lst
while [ $count -gt 0 ]; do
    wait $pids
    count=`expr $count - 1`
done
echo "Output for hosts are in $tmpdir"
Arcege
la source
1
qu'est-ce que l'attente fait exactement dans ce script ?? ty!
LanceBaynes
que se passe-t-il si une clé de serveur ne se trouve pas dans mon fichier know_hosts?
LanceBaynes
5
mettre des scripts en arrière-plan crée des processus enfants. Lorsqu'un processus enfant se termine, le "logement" et les ressources du processus restent dans le système jusqu'à la fin du processus parent ou jusqu'à ce que le processus parent "attende" pour l'enfant. Ces processus "terminés par toujours présent" sont appelés processus "zombie". C'est un bon comportement de nettoyer après les processus enfants et de récupérer les ressources.
Arcege
1
Si vous ne le connaissez pas, vous risquez de vous -o StrictHostKeyChecking=notromper , mais vous pouvez ajouter pour éviter cela. Cependant, il est préférable d'analyser d'abord tous les serveurs à partir d'une ligne de commande afin que les clés de l'hôte puissent être ajoutées.
Arcege
1
Comme je l'ai mentionné, une fois que le programme ssh est mis en arrière-plan et après sa fermeture, les ressources sont toujours conservées. La waitcommande récupère ces ressources, y compris le code de retour du processus (comment les processus se sont terminés). Ensuite, si plus tard dans le programme, vous mettez un autre processus, disons une compression, en arrière-plan et vous devez l’attendre, puis sans cette boucle, l’attente récupérera l’un des programmes ssh terminés, pas la compression - ce qui peut encore être en cours d'exécution. Vous obtiendrez un statut de retour sur le mauvais processus enfant. Il est bon de nettoyer après vous-même.
Arcege
61

Il existe plusieurs outils vous permettant de vous connecter à et d'exécuter des séries de commandes sur plusieurs ordinateurs à la fois. Voici un couple:

Caleb
la source
1
Vous voudrez peut-être ajouter pdsh à la liste.
Riccardo Murri
1
J'ai trouvé clusterssh assez intuitif à utiliser. Juste mes 2 cents ...
josinalvo
1
J'utilise pssh fréquemment. Cela fonctionne très bien, bien que j'aimerais pouvoir lui dire que certaines commandes à distance auront un code de sortie non nul, ce qui ne signifie pas une erreur. C'est purement cosmétique cependant.
Anthony Clark
1
@AnthonyClark vous pouvez ajouter quelque chose comme "|| true" à ces commandes.
exic
16

Si vous utilisez plus les scripts Python que les bashscripts, alors Fabric est peut-être l'outil idéal.

Depuis la page d'accueil de Fabric :

Fabric est une bibliothèque Python (2.5 ou supérieure) et un outil de ligne de commande permettant de rationaliser l'utilisation de SSH pour le déploiement d'applications ou les tâches d'administration système.

Il fournit une suite d'opérations de base pour exécuter des commandes de shell locales ou distantes (normalement ou via sudo) et pour charger / télécharger des fichiers, ainsi que des fonctionnalités auxiliaires telles que l'invite de l'utilisateur en cours de saisie ou l'abandon de l'exécution.

Son utilisation typique consiste à créer un module Python contenant une ou plusieurs fonctions, puis à les exécuter via l’outil de ligne de commande fab.

Riccardo Murri
la source
Fabric v1 était incroyable. Malheureusement, Fabric v2 a supprimé la plupart des fonctionnalités qui le rendaient utile pour ce cas d'utilisation - ce que je ne recommanderais pas actuellement (juin 2018).
Meekohi
11

J'utilise GNU parallèle pour cela, plus précisément vous pouvez utiliser cette recette:

parallel --tag --nonall --slf your.txt command

Avec your.txtêtre le fichier avec l'adresse IP / les noms du serveur.

Anthon
la source
N'existe
Bien sûr, j’avais l'habitude de faire cela auparavant ssh, mais vous avez besoin d'un moyen de vous connecter aux autres ordinateurs et ces moyens étaient moins sécurisés (comme rsh). Vous ne décrivez pas ce que vous utilisez maintenant pour aller de machine en machine ( telnet?, rsh?).
Anthon
1
@ Özzesh oui seulement sur le contrôleur
Anthon
1
@ Özzesh Voyez si votre raison de ne pas installer GNU Parallel est couverte sur oletange.blogspot.dk/2013/04/why-not-install-gnu-parallel.html
Ole Tange
1
@OleTange Je viens de réaliser qui a commenté ma réponse% -). Merci pour cet excellent logiciel.
Anthon
8

Configuration très basique:

for host in $(cat hosts.txt); do ssh "$host" "$command" >"output.$host"; done

Authentifier avec nom / mot de passe n'est vraiment pas une bonne idée. Vous devez configurer une clé privée pour cela:

ssh-keygen && for host in $(cat hosts.txt); do ssh-copy-id $host; done
michas
la source
1
c'est celui que je cherchais !!!!! Merci michas
Özzesh
le script ci-dessus fonctionne bien pour moi, mais après exécution sur 10 serveurs, le script ne répond pas. Comment puis-je me déconnecter du serveur ssh auquel je suis connecté?
Özzesh
Vous ne devriez pas avoir besoin de vous déconnecter explicitement. Ce "script" sera exécuté ssh $host $commandpour chaque hôte. Essayez d’exécuter ces commandes manuellement pour savoir ce qui se passe.
michas
4

Je suggère Ansible.cc . C'est un gestionnaire de configuration et un répartiteur de commandes.

À M
la source
2

Je pense que vous êtes à la recherche de pssh et des versions parallèles des scp, rsync, etc.

onclejamil
la source
Ceci est à un vote de la suppression, mais cette réponse est à +10. Cela a du sens
Michael Mrozek
@ MichaelMrozek C'est pire que vous ne le savez. Le deuxième des deux VTD est le mien sur un clic-heureux-accident. Cet onglet est ouvert depuis quelques jours dans l'intention de vous signaler ou de vous envoyer une requête ping afin de rétablir mon VTD s'il était supprimé. Peut-être pourriez-vous simplement le retourner maintenant pour effacer les votes.
Caleb
@Caleb Fixe le problème
Michael Mrozek
2

J'ai construit un outil open-source appelé Overcast pour faciliter ce genre de choses.

D'abord, vous définissez vos serveurs:

overcast import vm.01 --ip 1.1.1.1 --ssh-key /path/to/key
overcast import vm.02 --ip 2.2.2.2 --ssh-key /path/to/key

Ensuite, vous pouvez exécuter plusieurs commandes et fichiers de script, séquentiellement ou parallèlement, comme suit:

overcast run vm.* uptime "free -m" /path/to/script --parallel
Andrew Childs
la source
2

Le projet Hypertable a récemment ajouté un outil ssh multi-hôtes. Cet outil est construit avec libssh et établit des connexions et émet des commandes de manière asynchrone et en parallèle pour un parallélisme maximal. Voir Outil SSH multi-hôtes pour une documentation complète. Pour exécuter une commande sur un ensemble d'hôtes, vous devez l'exécuter comme suit:

$ ht ssh 1.1.1.1,2.2.2.2,3.3.3.3 uptime

Vous pouvez également spécifier un nom d'hôte ou un modèle IP, par exemple:

$ ht ssh 1.1.1.[1-99] uptime
$ ht ssh host[00-99] uptime

Il prend également en charge une --random-start-delay <millis>option qui retardera le début de la commande sur chaque hôte d’un intervalle de temps aléatoire compris entre 0 et <millis>millisecondes. Cette option peut être utilisée pour éviter des problèmes de tonnerre lorsque la commande en cours d'exécution accède à une ressource centrale.

Doug Judd
la source
2

J'ai développé collectnode Très simple et efficace pour exécuter des tâches sur plusieurs serveurs (Windows inclus)

Comment utiliser CollectNode:

  1. Créez la liste du serveur, avec laquelle travailler:

    # cat hosts.file
    server1
    server2
    server3
    server4
    server5
    
  2. Exécutez CollectNode en passant la liste des services:

    collectnode --file servers.txt --command='cat /etc/httpd/conf/httpd.conf |grep ^User'
    
  3. En option, il est possible de filtrer les résultats. Par exemple, cette commande n’affiche que le serveur sur lequel la condition est remplie.

    collectnode --file servers.txt --command='cat /etc/httpd/conf/httpd.conf |grep ^User' --where="command contain User"
    

https://collectnode.com/5-tasks-collectnode-can-help-managing-servers/

fvidalmolina
la source
1
Il semble que vous soyez le développeur de CollectNode. Dans ce cas, vous devez l'indiquer dans la réponse ou il ne s'agit que de spam.
Muru
désolé, ce n'était pas mon intention, modifiez votre réponse pour qu'elle soit plus précise.
fvidalmolina
1

Juste un heads-up pour une très bonne question:

La meilleure solution que j'ai trouvée est, sans surprise, tmux.

Vous pouvez faire Ctrl-B: setw synchronize-panes dans tmux pour des résultats étonnants. Pour cela, vous devez avoir toutes vos connexions ssh ouvertes, dans des sous-fenêtres différentes d'une fenêtre de Tmux.

Mikhail Krutov
la source
0

Peut-être que quelque chose comme ceci fonctionne, pour exécuter la commande sur plusieurs hôtes? Supposons que tous les hôtes sont configurés dans .ssh / config pour une connexion sans mot de passe.

$ < hosts.txt xargs -I {} ssh {} command

Y0NG
la source
0

Créez un fichier / etc / sxx / hosts

peupler comme ça:

[grp_ips]
1.1.1.1
2.2.2.2
3.3.3.3

partage la clé SSH sur toutes les machines.

Installez sxx à partir du paquet:

https://github.com/ericcurtin/sxx/releases

Puis lancez la commande comme ceci:

sxx username@grp_ips "whatever bash command"
Ericcurtin
la source
Où est la sortie écrite? Comment sont gérés les statuts de sortie non nuls? S'il vous plaît ne répondez pas dans les commentaires; éditez votre réponse pour la rendre plus claire et plus complète.
G-Man dit 'Réintégrez Monica'
0

Utilisez Paramiko http://www.paramiko.org/ et le parallélisme basé sur les threads https://docs.python.org/3/library/threading.html . Le code .below permet d'exécuter plusieurs commandes sur chaque serveur en parallèle!

ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.load_system_host_keys()
ssh.connect(hostname, port, username, password)
t = threading.Thread(target=tasks[index], args=(ssh, box_ip,))
t.start()

Remarque: répétez les instructions ci-dessus pour chaque serveur.

Sharma
la source
0

Je pense "attendre" est ce dont vous avez besoin.
Beaucoup de gens ne savent même pas qu'il existe. C'est un programme basé sur tcl qui posera des questions et des réponses possibles en votre nom. Jetez un coup d'œil à https://wiki.tcl-lang.org/page/Expect

Clément
la source