Ejecuta automáticamente comandos a través de SSH en muchos servidores


46

Hay una lista de direcciones IP en un archivo .txt, por ejemplo:

1.1.1.1
2.2.2.2
3.3.3.3

Detrás de cada dirección IP hay un servidor, y en cada servidor hay un sshd ejecutándose en el puerto 22. No todos los servidores están en la known_hostslista (en mi PC, Ubuntu 10.04 LTS / bash).

¿Cómo puedo ejecutar comandos en estos servidores y recopilar la salida?

Idealmente, me gustaría ejecutar los comandos en paralelo en todos los servidores.

Usaré la autenticación de clave pública en todos los servidores.

Aquí hay algunos peligros potenciales:

  • El ssh me pide que coloque la clave ssh de los servidores dados en mi known_hostsarchivo.
  • Los comandos dados pueden devolver un código de salida distinto de cero, lo que indica que la salida es potencialmente inválida. Necesito reconocer eso.
  • Es posible que no se pueda establecer una conexión con un servidor determinado, por ejemplo, debido a un error de red.
  • Debería haber un tiempo de espera, en caso de que el comando se ejecute por más tiempo de lo esperado o el servidor se caiga mientras se ejecuta el comando.

Los servidores son AIX / ksh (pero creo que eso realmente no importa.



1
Creo que no es un duplicado, porque el enlace que mencionas ni siquiera contiene SSH.
LanceBaynes

44
Si no lo ha hecho, debe configurar servidores ssh en todas las máquinas, hacer un par de claves privada / pública en la máquina desde la que trabaja y copiar la clave pública a las cuentas en el servidor para evitar más problemas de contraseña. Eso aplica para mi respuesta, y también para @ demure.
Anthon

Respuestas:


14

Suponiendo que no puede instalar pssh u otros, puede hacer algo similar 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
¿Qué hace exactamente esperar en este script? ty!
LanceBaynes

¿Qué sucede si una clave de servidor no está en mi archivo know_hosts?
LanceBaynes

55
poner scripts en segundo plano crea procesos secundarios. Cuando un proceso secundario finaliza, el 'espacio' del proceso y los recursos permanecen en el sistema hasta que finaliza el proceso primario o el proceso primario 'espera' al secundario. Estos procesos 'terminados por todavía presentes' se denominan procesos 'zombies'. Es un buen comportamiento limpiar después de los procesos secundarios y reclamar recursos.
Arcege

1
Si no se conoce, eso podría arruinarlo, pero puede agregarlo -o StrictHostKeyChecking=nopara evitarlo. Sin embargo, es mejor escanear todos los servidores desde una línea de comandos para poder agregar las claves del host.
Arcege

1
Como mencioné, después de que el programa ssh se pone en segundo plano y después de que se cierra, los recursos aún se mantienen. El waitcomando reclama esos recursos, incluido el código de retorno del proceso (cómo salieron los procesos). Luego, si más adelante en el programa, coloca otro proceso, digamos una compresión, en segundo plano y necesita esperar, luego sin este ciclo, la espera recuperará uno de los programas ssh completos, no la compresión, que aún puede estar corriendo Obtendría un estado de devolución en el proceso secundario incorrecto. Es bueno limpiar después de ti mismo.
Arcege

61

Existen varias herramientas que le permiten iniciar sesión y ejecutar series de comandos en varias máquinas al mismo tiempo. Aquí hay una pareja:


1
Es posible que desee agregar pdsh a la lista.
Riccardo Murri

1
Encontré clusterssh bastante intuitivo de usar. Solo mis 2 centavos ...
josinalvo

1
Yo uso pssh con frecuencia. Funciona muy bien, aunque desearía poder decirle que ciertos comandos remotos tendrán un código de salida distinto de cero, y eso no significa un error. Sin embargo, eso es puramente cosmético.
Anthony Clark

1
@AnthonyClark podría agregar algo como "|| true" a esos comandos.
exic

16

Si te gustan las secuencias de bashcomandos de Python más que las secuencias de comandos, Fabric podría ser la herramienta para ti.

Desde la página de inicio de Fabric :

Fabric es una biblioteca de Python (2.5 o superior) y una herramienta de línea de comandos para simplificar el uso de SSH para la implementación de aplicaciones o tareas de administración de sistemas.

Proporciona un conjunto básico de operaciones para ejecutar comandos de shell locales o remotos (normalmente o mediante sudo) y cargar / descargar archivos, así como funciones auxiliares, como solicitar al usuario en ejecución que ingrese o anular la ejecución.

El uso típico implica crear un módulo de Python que contenga una o más funciones y luego ejecutarlas a través de la herramienta de línea de comandos fab.


Fabric v1 fue increíble. Desafortunadamente, Fabric v2 eliminó la mayoría de las características que lo hicieron útil para este caso de uso; no lo recomendaría actualmente (junio de 2018).
Meekohi

11

Yo uso GNU paralelo para eso, más específicamente puedes usar esta receta:

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

Al your.txtser el archivo con la dirección IP / nombres del servidor.


No hay ninguna otra manera solamente usando ssh Desde que estoy usando mis servidores de la compañía no quiero instalar paquetes adicionales
Özzesh

Claro, solía hacer esto antes de que sshexistiera también, pero necesitas alguna forma de iniciar sesión en las otras computadoras y esas formas solían ser menos seguras (como rsh). No describe lo que está utilizando ahora para pasar de una máquina a otra ( telnet?, rsh?).
Anthon

1
@ Özzesh sí solo en el controlador
Anthon

1
@ Özzesh Vea si su razón para no instalar GNU Parallel está cubierta en oletange.blogspot.dk/2013/04/why-not-install-gnu-parallel.html
Ole Tange

1
@OleTange Me acabo de dar cuenta de quién comentó mi respuesta% -). Gracias por esta excelente pieza de software.
Anthon

8

Configuración muy básica:

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

Autenticar con nombre / contraseña no es realmente una buena idea. Debe configurar una clave privada para esto:

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

1
este es el que he estado buscando !!!!! Gracias michas
Özzesh

el script anterior funciona bien para mí, pero después de ejecutarlo en 10 servidores, el script no responde. ¿Cómo puedo cerrar sesión en el servidor ssh al que estoy conectado?
Özzesh

No debería necesitar cerrar sesión explícitamente. Este "script" solo se ejecutará ssh $host $commandpara cada host. Intente ejecutar esos comandos manualmente para averiguar qué está sucediendo.
michas

4

Sugiero Ansible.cc . Es un administrador de configuración y un despachador de comandos.


2

Creo que estás buscando pssh y las versiones paralelas relacionadas de los habituales scp, rsync, etc.


Esto está a un voto de ser eliminado, pero esta respuesta posterior está en +10. Tiene mucho sentido
Michael Mrozek

@MichaelMrozek Es peor de lo que sabes. El segundo de los dos VTD es mío en un accidente de clic feliz. He tenido esta pestaña abierta durante un par de días con la intención de marcarla o hacer ping para revertir mi VTD si se eliminó. Tal vez podrías voltearlo ahora para borrar los votos.
Caleb

@Caleb lo arregló
Michael Mrozek

2

He construido una herramienta de código abierto llamado Tormenta de hacer este tipo de cosas más fácil.

Primero define sus servidores:

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

Luego puede ejecutar múltiples comandos y archivos de script a través de ellos, ya sea secuencialmente o en paralelo, de la siguiente manera:

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

2

El proyecto Hypertable ha agregado recientemente una herramienta ssh de múltiples hosts. Esta herramienta está construida con libssh y establece conexiones y emite comandos de forma asíncrona y en paralelo para obtener el máximo paralelismo. Consulte Herramienta SSH de múltiples hosts para obtener la documentación completa. Para ejecutar un comando en un conjunto de hosts, debe ejecutarlo de la siguiente manera:

$ ht ssh 1.1.1.1,2.2.2.2,3.3.3.3 uptime

También puede especificar un nombre de host o un patrón de IP, por ejemplo:

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

También admite una --random-start-delay <millis>opción que retrasará el inicio del comando en cada host en un intervalo de tiempo aleatorio entre 0 y <millis>milisegundos. Esta opción se puede utilizar para evitar problemas de rebaño cuando el comando que se ejecuta accede a un recurso central.


2

He desarrollado collectnode Muy simple y efectivo para ejecutar tareas en varios servidores (ventanas incluidas)

Cómo usar CollectNode:

  1. Cree la lista de servidores para trabajar con:

    # cat hosts.file
    server1
    server2
    server3
    server4
    server5
    
  2. Ejecute CollectNode pasando la lista de servicios:

    collectnode --file servers.txt --command='cat /etc/httpd/conf/httpd.conf |grep ^User'
    
  3. Opcionalmente, es posible filtrar los resultados, por ejemplo, este comando solo muestra el servidor donde se cumple la condición.

    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
Parece que eres el desarrollador de CollectNode. En ese caso, debe revelar eso en la respuesta o esto es solo spam.
Muru

lo siento, esa no era mi intención, la respuesta modificada para ser más específica.
fvidalmolina

1

Solo un aviso para una muy buena pregunta:

La mejor solución que he encontrado es, no sorprendentemente, tmux.

Puede hacer Ctrl-B: setw sincronizar paneles en tmux para obtener un resultado sorprendente. Debe tener todas sus conexiones ssh abiertas, en diferentes paneles de 1 ventana de Tmux para esto.


0

¿Tal vez algo como esto funciona, para ejecutar comandos en varios hosts? supongamos que todos los hosts están configurados en .ssh / config para iniciar sesión sin contraseña.

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


0

Crear un archivo / etc / sxx / hosts

poblar así:

[grp_ips]
1.1.1.1
2.2.2.2
3.3.3.3

Compartir clave ssh en todas las máquinas.

Instale sxx desde el paquete:

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

Luego ejecute el comando así:

sxx username@grp_ips "whatever bash command"

¿Dónde se escribe la salida? ¿Cómo se manejan los estados de salida distintos de cero? Por favor no responda en los comentarios; edite su respuesta para que sea más clara y completa.
G-Man dice 'reinstalar a Monica' el

0

Utilice Paramiko http://www.paramiko.org/ y paralelismo basado en hilos https://docs.python.org/3/library/threading.html. ¡El código de abajo permite ejecutar múltiples comandos en cada servidor en paralelo!

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: repita las instrucciones anteriores para cada servidor.


Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.