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.