Múltiples comandos durante un SSH dentro de una sesión SSH

10

Tengo una máquina local que se supone que debe hacer una sesión SSH en una mastermáquina remota y luego otra sesión SSH interna desde mastercada uno de algunos remotos slaves, y luego ejecutar 2 comandos, es decir, eliminar un directorio específico y recrearlo.

Tenga en cuenta que la máquina local tiene SSH sin contraseña para el maestro y el maestro tiene SSH sin contraseña para los esclavos. También todos los nombres de host son conocidos en .ssh/configlas máquinas locales / maestras y los nombres de host de los esclavos están slaves.txtlocalmente y los leo desde allí.

Entonces, lo que hago y funciona es esto:

username="ubuntu"
masterHostname="myMaster"
while read line
do

    #Remove previous folders and create new ones.
    ssh -n $username@$masterHostname "ssh -t -t $username@$line "rm -rf Input Output Partition""
    ssh -n $username@$masterHostname "ssh -t -t $username@$line "mkdir -p EC2_WORKSPACE/$project Input Output Partition""


    #Update changed files...
    ssh -n $username@$masterHostname "ssh -t -t $username@$line "rsync --delete -avzh /EC2_NFS/$project/* EC2_WORKSPACE/$project""

done < slaves.txt 

Este clúster está en Amazon EC2 y he notado que hay 6 sesiones SSH creadas en cada iteración, lo que induce un retraso significativo. Me gustaría combinar estos 3 comandos en 1 para obtener menos conexiones SSH. Así que intenté combinar los primeros 2 comandos en

ssh -n $username@$masterHostname "ssh -t -t $username@$line "rm -rf Input Output Partition && mkdir -p EC2_WORKSPACE/$project Input Output Partition""

Pero no funciona como se esperaba. Parece ejecutar el primero ( rm -rf Input Output Partition) y luego sale de la sesión y continúa. ¿Que puedo hacer?

mgus
fuente
3
En lugar de dicha indirección en el comando, puede usar la -Jopción que definiría su host de salto.
Hauleth

Respuestas:

15

Considere que &&es un operador lógico. Lo hace no media "también de este comando" que significa "ejecutar este comando si el otro tuvo éxito".

Eso significa que si el rmcomando falla (lo que sucederá si alguno de los tres directorios no existe), entonces mkdirno se ejecutará. Esto no suena como el comportamiento que desea; Si los directorios no existen, probablemente esté bien crearlos.

Utilizar ;

El punto y coma ;se usa para separar los comandos. Los comandos se ejecutan secuencialmente, esperando cada uno antes de continuar con el siguiente, pero su éxito o fracaso no tienen impacto entre ellos.

Escape de citas internas

Las comillas dentro de otras comillas deben escaparse, de lo contrario, creará un punto final y un punto de inicio adicionales. Su comando:

ssh -n $username@$masterHostname "ssh -t -t $username@$line "rm -rf Input Output Partition && mkdir -p EC2_WORKSPACE/$project Input Output Partition""

Se convierte en:

ssh -n $username@$masterHostname "ssh -t -t $username@$line \"rm -rf Input Output Partition && mkdir -p EC2_WORKSPACE/$project Input OutputPartition\""

Su comando actual, debido a la falta de comillas escapadas, debería estar ejecutándose:

ssh -n $username@$masterHostname "ssh -t -t $username@$line "rm -rf Input Output Partition

si eso tiene éxito:

mkdir -p EC2_WORKSPACE/$project Input Output Partition"" # runs on your local machine

Notará que el resaltado de sintaxis muestra el comando completo en rojo aquí, lo que significa que todo el comando es la cadena que se pasa a ssh. Verifique su máquina local; puede tener los directorios Input Outputy Partitiondónde estaba ejecutando esto.

Centimane
fuente
Entiendo tus puntos. Una parte por la que estaba confundido era el punto y coma, ya que pensé que ejecutaría más de 1 comandos al mismo tiempo, por lo que no lo usé.
mgus
El punto y coma no hará que los comandos se ejecuten al mismo tiempo, vea aquí como referencia para ejecutar comandos. Los &comandos de causas se ejecutan en el fondo, lo que significa que no se esperará a que finalicen antes de pasar al siguiente.
Centimane
10

Siempre puedes definir en tu jumpbox Multiplexación en OpenSSH

La multiplexación es la capacidad de enviar más de una señal a través de una sola línea o conexión. Con la multiplexación, OpenSSH puede reutilizar una conexión TCP existente para múltiples sesiones SSH concurrentes en lugar de crear una nueva cada vez.

Una ventaja con la multiplexación SSH es que se elimina la sobrecarga de crear nuevas conexiones TCP. El número total de conexiones que una máquina puede aceptar es un recurso finito y el límite es más notable en algunas máquinas que en otras, y varía mucho según la carga y el uso. También hay un retraso significativo al abrir una nueva conexión. Las actividades que abren nuevas conexiones repetidamente pueden acelerarse significativamente utilizando la multiplexación.

Para eso hacer en /etc/ssh/ssh_config:

ControlMaster auto
ControlPath ~/.ssh/controlmasters/ssh_mux_%h_%p_%r
ControlPersist 30m

De esta manera, cualquier conexión consecutiva realizada al mismo servidor en los siguientes 30 minutos se realizará reutilizando la conexión ssh anterior.

También puede definirlo para una máquina o grupo de máquinas. Tomado del enlace proporcionado.

Host machine1
    HostName machine1.example.org
    ControlPath ~/.ssh/controlmasters/%r@%h:%p
    ControlMaster auto
    ControlPersist 10m
Rui F Ribeiro
fuente
¡Eso es interesante! ¿Hay alguna manera de activarlo y desactivarlo explícitamente para una conexión determinada? Parece excesivo cambiar tan drásticamente todas las conexiones SSH para este caso de uso. ¿Se puede usar de manera más precisa? ¿Para comenzar a multiplexar solo una cierta conexión?
Centimane
@Centimane sí, actualizó la respuesta
Rui F Ribeiro
1
Sugeriría poner el zócalo en el hogar del usuario en lugar de un mundo de escritura relectura /tmp/.
heemayl
@heemayl Buen punto. Lo editaré cuando esté en una computadora.
Rui F Ribeiro
@RuiFRibeiro También parece que, de acuerdo con man ssh, ControlPath, ControlMastery ControlPersistson opciones válidas para pasar un sshcomando usando -o. Podría ser un caso de uso aún más preciso, configure la multiplexación en el primer sshguión y recíclela para los demás, pero evite la penalización de rendimiento. Me pregunto cuál es el punto de referencia de la multiplexación VS no para 3 conexiones SSH, dado que "También hay un retraso significativo al abrir una nueva conexión"
Centimane
4

Puede poner todos sus comandos en un script separado en su servidor "maestro".

Guión maestro

#!/bin/bash
rm -rf "Input Output Partition"
mkdir -p "EC2_WORKSPACE/$project Input Output Partition"

Luego, en su script ssh, llámelo así: SSH Script

username="ubuntu"
masterHostname="myMaster"
while read line
do
ssh -n $username@$masterHostname "ssh -t -t $username@$line < /path/to/masterscript.sh"
ssh -n $username@$masterHostname "ssh -t -t $username@$line "rsync --delete -avzh /EC2_NFS/$project/* EC2_WORKSPACE/$project""
done < slaves.txt 

O si todos los archivos deben estar en la máquina inicial, podría hacer algo como esto:

script1

script2="/path/to/script2"
username="ubuntu"
while read line; do
cat $script2 | ssh -t -t $username@line
done < slaves.txt

script2

#!/bin/bash
rm -rf "Input Output Partition"
mkdir -p "EC2_WORKSPACE/$project Input Output Partition"
rsync --delete -avzh "/EC2_NFS/$project/* EC2_WORKSPACE/$project"

ssh script

script1="/path/to/script1"
username="ubuntu"
masterHostname="myMaster"
cat $script1 | ssh -n $username@$masterHostname
jesse_b
fuente
1

Hace algún tiempo, tuve la oportunidad de usar sockets de control como recomiendan las otras respuestas (esta respuesta es esencialmente una combinación de usar sockets de control como esta respuesta y scripts como esta respuesta ).

El caso de uso fue un truco: authorized_keysuna tarea programada sobrescribía periódicamente al usuario objetivo y quería probar rápidamente las cosas sin pasar por la burocracia necesaria para agregar algo a ese archivo. Así que configuré un ciclo while que agregaba la clave a ese archivo según fuera necesario, ejecutaba mi prueba y cancelaba el ciclo. Sin embargo, habría una pequeña ventana donde la tarea programada sobrescribiría el archivo y mi bucle seguiría funcionando sleep. Entonces, configurar un socket de control al inicio permitiría que mi script SSH más tarde sin problemas:

#! /bin/bash -xe
. "${CONFIG_DIR}/scripts/setup-ssh.sh"

# Build and test
export TEST_LABEL="${_started_by}-${BUILD_TAG%-BUILD*}"
#...
xargs --arg-file test-list \
    --no-run-if-empty \
    --process-slot-var=NUM \
    --max-procs=${#SERVERS[@]} \
    --max-args="${BATCH_SIZE:-20}" \
    "${CONFIG_DIR}/scripts/run-test.sh"

Donde setup-ssh.shes:

export SSH_CONFIG="${CONFIG_DIR}/scripts/.ssh-config"
mapfile -t SERVERS < "${CONFIG_DIR}/scripts/hosts"

for SERVER in "${SERVERS[@]}"
do
    while ! ssh -F "${SSH_CONFIG}" "${SERVER}" -fnN; do sleep 1; done
    scp -F "${SSH_CONFIG}" "${CONFIG_DIR}/scripts/ssh-script.sh" "${SERVER}":"${TEST_LABEL}.sh"
done

Y .ssh-config:

Host test-*
  User test
  StrictHostKeyChecking no
  ControlMaster auto
  ControlPath /tmp/ssh-%h-%p-%r

Y run-test.sh:

mapfile -t TEST_SERVERS < "${CONFIG_DIR}/scripts/hosts"
ssh -F "${SSH_CONFIG}" "${TEST_SERVERS[$NUM]}" "./${TEST_LABEL}.sh"

La secuencia es así:

  • Las fuentes principales del script (se muestran primero) setup-ssh.sh.
  • setup-ssh.shbusy-buclea los servidores hasta que todos tengan una configuración de socket de control. El hostsarchivo simplemente enumera los nombres de host del servidor uno por línea.
  • Dado que la configuración que especifica el socket de control solo está en ${CONFIG_DIR}/scripts/.ssh-config, a menos que especifique ese archivo usando -F, las conexiones SSH no lo usarán. Entonces, esto me permite usar el zócalo de control solo donde los necesito usando la Fopción.
  • El script de configuración también copia el script de ejecución de prueba en los servidores. El script de ejecución en sí contiene un montón de comandos, y debido a que copié el script de ejecución, no tengo que preocuparme por una capa adicional de citas para SSH (y la sobrecarga cognitiva adicional para descubrir qué se expande cuando).
  • Luego, el script principal se utiliza xargspara distribuir la carga de trabajo a través de los servidores, comenzando nuevos trabajos tan pronto como finalicen los que se ejecutan.
muru
fuente