Esegui automaticamente comandi su SSH su molti server


46

C'è un elenco di indirizzi IP in un file .txt, ad es .:

1.1.1.1
2.2.2.2
3.3.3.3

Dietro ogni indirizzo IP c'è un server, e su ogni server c'è un SSH in esecuzione sulla porta 22. Non tutti i server sono known_hostsnell'elenco (sul mio PC, Ubuntu 10.04 LTS / bash).

Come posso eseguire comandi su questi server e raccogliere l'output?

Idealmente, vorrei eseguire i comandi in parallelo su tutti i server.

Userò l'autenticazione con chiave pubblica su tutti i server.

Ecco alcune potenziali insidie:

  • Lo ssh mi chiede di inserire la chiave ssh del mio server nel mio known_hostsfile.
  • I comandi forniti potrebbero restituire un codice di uscita diverso da zero, indicando che l'output è potenzialmente non valido. Devo riconoscerlo.
  • Potrebbe non essere possibile stabilire una connessione a un determinato server, ad esempio a causa di un errore di rete.
  • Dovrebbe esserci un timeout, nel caso in cui il comando venga eseguito più a lungo del previsto o il server si arresti durante l'esecuzione del comando.

I server sono AIX / ksh (ma penso che non contano davvero.



1
Penso che non sia un duplicato, perché il link che menzioni non contiene nemmeno SSH.
LanceBaynes,

4
Se non lo hai ancora fatto, dovresti impostare server ssh su tutte le macchine, creare una coppia di chiavi privata / pubblica sulla macchina da cui lavori e copiare la chiave pubblica negli account sul server per evitare ulteriori problemi con la password. Questo vale per la mia risposta, e anche per @ demure.
Anthon,

Risposte:


14

Supponendo che non sei in grado di installare pssh o altri, potresti fare qualcosa di simile a:

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"

1
cosa aspetta esattamente fare in questo script ?? ty!
LanceBaynes,

cosa succede se una chiave del server non si trova nel mio file know_hosts?
LanceBaynes,

5
mettere gli script in background crea processi figlio. Quando viene chiuso un processo figlio, il processo "slot" e le risorse rimangono nel sistema fino a quando il processo padre non viene chiuso o il processo padre "attende" il figlio. Questi processi "terminati da ancora presenti" sono chiamati processi "zombi". È un buon comportamento ripulire dopo le procure dei figli e recuperare le risorse.
Arcege,

1
Se non noto, ciò potrebbe rovinare tutto, ma è possibile aggiungere -o StrictHostKeyChecking=noper evitarlo. Tuttavia, è consigliabile eseguire prima la scansione di tutti i server da una riga di comando in modo da poter aggiungere le chiavi dell'host.
Arcege,

1
Come ho già detto, dopo che il programma ssh è stato messo in secondo piano e dopo la sua uscita, le risorse sono ancora mantenute. Il waitcomando recupera tali risorse, incluso il codice di ritorno del processo (come sono usciti i processi). Quindi se più avanti nel programma, metti un altro processo, diciamo una compressione, in background e devi aspettare, quindi senza questo ciclo, l'attesa recupererà uno dei programmi ssh completati, non la compressione - che potrebbe ancora essere in esecuzione. Otterresti uno stato di ritorno sul processo figlio errato. È bene ripulire dopo te stesso.
Arcege,

61

Esistono diversi strumenti che ti consentono di accedere ed eseguire serie di comandi su più macchine contemporaneamente. Eccone un paio:


1
Potresti voler aggiungere pdsh all'elenco.
Riccardo Murri,

1
Ho trovato i cluster abbastanza intuitivi da usare. Solo i miei 2 centesimi ...
josinalvo

1
Uso spesso pssh. Funziona molto bene, anche se vorrei poter dire che alcuni comandi remoti avranno un codice di uscita diverso da zero e ciò non significa un errore. Questo è puramente cosmetico però.
Anthony Clark,

1
@AnthonyClark potresti aggiungere qualcosa come "|| true" a quei comandi.
exic

16

Se ti piacciono gli script Python più che gli bashscript, Fabric potrebbe essere lo strumento che fa per te.

Dalla home page di Fabric :

Fabric è una libreria Python (2.5 o successiva) e uno strumento da riga di comando per semplificare l'uso di SSH per le attività di distribuzione dell'applicazione o di amministrazione dei sistemi.

Fornisce una suite di operazioni di base per l'esecuzione di comandi shell locali o remoti (normalmente o tramite sudo) e il caricamento / download di file, nonché funzionalità ausiliarie come la richiesta di input all'utente o l'interruzione dell'esecuzione.

L'uso tipico prevede la creazione di un modulo Python contenente una o più funzioni, quindi la loro esecuzione tramite lo strumento da riga di comando fab.


Fabric v1 è stato fantastico. Sfortunatamente, Fabric v2 ha rimosso la maggior parte delle funzionalità che lo hanno reso utile per questo caso d'uso - non lo consiglierei attualmente (giugno 2018).
Meekohi,

11

Per questo uso GNU parallelo , in particolare puoi usare questa ricetta:

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

Con l' your.txtessere il file con l'indirizzo / i nomi IP del server.


non c'è altro modo di usare solo ssh Dal momento che sto usando i server della mia azienda non voglio installare pacchetti aggiuntivi
Özzesh

Certo, prima facevo anche questo ssh, ma hai bisogno di un modo per accedere agli altri computer e quei modi erano meno sicuri (come rsh). Non descrivi ciò che stai usando ora per passare da una macchina all'altra ( telnet?, rsh?).
Anthon,

1
@ Özzesh sì, solo sul controller
Anthon,

1
@ Özzesh Verifica se il motivo della mancata installazione di GNU Parallel è coperto su oletange.blogspot.dk/2013/04/why-not-install-gnu-parallel.html
Ole Tange,

1
@OleTange Ho appena capito chi ha commentato la mia risposta% -). Grazie per questo eccellente software.
Anthon,

8

Configurazione molto semplice:

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

L'autenticazione con nome / password non è davvero una buona idea. È necessario impostare una chiave privata per questo:

ssh-keygen && for host in $(cat hosts.txt); do ssh-copy-id $host; done

1
questo è quello che stavo cercando !!!!! Grazie michas
Özzesh,

lo script sopra funziona bene per me ma dopo l'esecuzione in 10 server lo script non risponde. Come posso disconnettermi dal server SSH a cui sono connesso?
Özzesh,

Non è necessario disconnettersi in modo esplicito. Questo "script" verrà eseguito solo ssh $host $commandper ciascun host. Prova a eseguire quei comandi manualmente per scoprire cosa sta succedendo.
Michas,


2

Penso che tu stia cercando pssh e le relative versioni parallele del solito scp, rsync, ecc.


Questo è un voto lontano dall'eliminazione, ma questa risposta successiva è a +10. Ha perfettamente senso
Michael Mrozek

@MichaelMrozek È peggio di quanto tu sappia. Il secondo dei due VTD è il mio per un clic-felice-incidente. Ho aperto questa scheda per un paio di giorni con l'intenzione di contrassegnare o eseguire il ping per ripristinare il mio VTD se è stato eliminato. Forse potresti semplicemente capovolgerlo ora per cancellare i voti.
Caleb,

@Caleb Risolto
Michael Mrozek

2

Ho creato uno strumento open source chiamato Overcast per semplificare questo genere di cose.

Per prima cosa definisci i tuoi server:

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

Quindi è possibile eseguire più comandi e file di script su di essi, in sequenza o in parallelo, in questo modo:

overcast run vm.* uptime "free -m" /path/to/script --parallel

2

Il progetto Hypertable ha recentemente aggiunto uno strumento ssh multi-host. Questo strumento è costruito con libssh e stabilisce connessioni ed emette comandi in modo asincrono e in parallelo per il massimo parallelismo. Vedere lo strumento SSH multi-host per la documentazione completa. Per eseguire un comando su un set di host, eseguirlo come segue:

$ ht ssh 1.1.1.1,2.2.2.2,3.3.3.3 uptime

È inoltre possibile specificare un nome host o un modello IP, ad esempio:

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

Supporta anche --random-start-delay <millis>un'opzione che ritarderà l'inizio del comando su ciascun host di un intervallo di tempo casuale tra 0 e <millis>millisecondi. Questa opzione può essere utilizzata per evitare tuoni fragorosi quando il comando in esecuzione accede a una risorsa centrale.


2

Ho sviluppato collectnode Molto semplice ed efficace per eseguire le attività in diversi server (finestre incluse)

Come usare CollectNode:

  1. Crea l'elenco di server, per lavorare con:

    # cat hosts.file
    server1
    server2
    server3
    server4
    server5
    
  2. Esegui CollectNode passando l'elenco dei servizi:

    collectnode --file servers.txt --command='cat /etc/httpd/conf/httpd.conf |grep ^User'
    
  3. Opzionalmente, è possibile filtrare i risultati, ad esempio questo comando visualizza solo il server in cui viene soddisfatta la condizione.

    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/


1
Sembra che tu sia lo sviluppatore di CollectNode. In tal caso, è necessario rivelare che nella risposta o questo è solo spam.
muru

scusa, non era mia intenzione, risposta modificata per essere più specifica.
fvidalmolina,

1

Solo un avvertimento per una domanda davvero bella:

La migliore soluzione che ho trovato è, non così sorprendentemente, tmux.

Puoi fare Ctrl-B: setwynize-panes in tmux per un incredibile resut. Per questo è necessario avere tutte le connessioni ssh aperte, in diversi riquadri di 1 finestra di Tmux.


0

Forse qualcosa del genere funziona, per eseguire il comando su più host? supponiamo che tutti gli host siano configurati in .ssh / config per l'accesso senza password.

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


0

Crea un file / etc / sxx / hosts

popolare così:

[grp_ips]
1.1.1.1
2.2.2.2
3.3.3.3

condividi chiave ssh su tutte le macchine.

Installa sxx dal pacchetto:

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

Quindi eseguire il comando in questo modo:

sxx username@grp_ips "whatever bash command"

Dove viene scritto l'output? Come vengono gestiti gli stati di uscita diversi da zero? Si prega di non rispondere nei commenti; modifica la tua risposta per renderla più chiara e completa.
G-Man dice "Ripristina Monica" il

0

Usa Paramiko http://www.paramiko.org/ e il parallelismo basato su thread https://docs.python.org/3/library/threading.html Il codice .below consente di eseguire più comandi su ciascun server in parallelo!

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()

Nota: ripetere le istruzioni precedenti per ciascun server.


Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.