Come sincronizzare i file tra due telecomandi?


54

Vorrei trasferire file tra due host remoti usando sulla shell locale, ma sembra che rsync non supporti la sincronizzazione se vengono specificati due telecomandi come segue:

$ rsync -vuar host1:/var/www host2:/var/www
The source and destination cannot both be remote.

Quali altre soluzioni alternative / comandi potrei usare per ottenere risultati simili?



1
In realtà puoi sincronizzare tra 2 host remoti sfruttando sshfs su un terzo host. Basta usare sshfs per montare host1 e host2 sull'host 3. Quindi rsync tra 1 e 2.
William Legg

@WilliamLegg lo svantaggio dell'uso sshfsè che rsyncvede i filesystem di origine e di destinazione entrambi come locali, quindi disabilita il suo algoritmo delta. A quel punto potresti anche solo usarlo cp -p. Vedi la risposta che propone questo e i suoi commenti successivi.
roaima,

Risposte:


50

Come hai scoperto, non puoi usare rsync con una sorgente remota e una destinazione remota. Supponendo che i due server non possano comunicare direttamente tra loro, è possibile utilizzare ssh per eseguire il tunneling tramite il computer locale.

Invece di

rsync -vuar host1:/var/www host2:/var/www

puoi usare questo

ssh -R localhost:50000:host2:22 host1 'rsync -e "ssh -p 50000" -vuar /var/www localhost:/var/www'

Nel caso ti stia chiedendo, l' -Ropzione imposta un canale inverso dalla porta 50000 sull'host1 che mappa (tramite il tuo computer locale) alla porta 22 sull'host2. Non esiste una connessione diretta da host1 a host2.


1
Mi piace la soluzione di @ roaima, ma non sono riuscita a farlo funzionare per vari motivi. Alla fine ho usato sshfsper montare entrambe le directory remote localmente, quindi ho usato rsyncle due directory montate localmente.
Aidan il

È possibile vedere un esempio in cui viene utilizzata una chiave? Problemi nel capire come utilizzare -iper specificare i tasti necessari per i comandi ssh.
onassar,

@onassar aggiunge il -i key...parametro tra virgolette dopo il sshcomando. Se ciò non ti aiuta, non esitare a fare una nuova domanda, facendo riferimento a questa risposta per contesto
roaima

1
la connessione inversa non legge ~ / .ssh / config sul lato locale - è necessario utilizzare qualcosa che può essere risolto come se non ci fosse un file di configurazione SSH
Florenz Kley

1
"Supponendo che i due server non possano parlare direttamente tra loro". Questa soluzione risolve un problema di firewall o NAT che impedisce una connessione SSH diretta . Tuttavia, non risolve il caso in cui, per motivi di sicurezza, l'utente di origine (su host1) non ha chiave o credenziali o autorizzazioni di scrittura insufficienti sulla destinazione. Per questo vedere la soluzione di Kevin Cox o ricorrere a una connessione indiretta usando uno script o scp -3.
Cedric Knight,

22

Non hai detto perché non volevi accedere a un host e quindi copiarlo sull'altro, così condividerò uno dei miei motivi e soluzioni.

Non sono stato in grado di accedere a una macchina, quindi risincronizzarmi con l'altra perché nessuno dei due host aveva una chiave SSH in grado di accedere all'altra. Ho risolto questo problema utilizzando l'inoltro dell'agente SSH per consentire al primo host di utilizzare la mia chiave SSH mentre ero connesso.

ATTENZIONE: l' inoltro SSH consente all'host di utilizzare la chiave SSH per la durata dell'accesso. Sebbene non possano copiare la chiave, possono accedere ad altre macchine con essa. Assicurati di comprendere i rischi e di non utilizzare l'inoltro dell'agente per macchine di cui non ti fidi.

Il comando seguente utilizzerà l'inoltro dell'agente SSH per aprire una connessione diretta da host1a host2. Ciò ha il vantaggio che la macchina che esegue il comando non sta strozzando il trasferimento.

ssh -A host1 rsync -vuar /var/www host2:/var/www

3
+1 per spiegare un caso d'uso valido (in cui l'utente remoto su host1 non ha autorizzazioni sul server di destinazione); per l'importante avvertimento sulla sicurezza (utilizzare il port forwarding -Dpiuttosto che -Aaggirare la rete anziché le restrizioni chiave); per spiegare il vantaggio; poiché il comando è breve; e funziona davvero. Tieni presente che potresti dover specificare username@host1se è diverso dal nome utente locale. Inoltre, rsync esegue la verifica della chiave host quando si connette a host2, quindi la chiave host1 dovrebbe essere già in ~ / .ssh / known_hosts su host2 o il comando fallirà.
Cedric Knight,

Risposta fenomenale, questo mi ha aiutato a orchestrare alcune cose in TeamCity che non ero in grado di fare prima (nb per gli altri utenti di TeamCity, è necessario aggiungere la "Funzione Build" chiamata "Agente SSH" alla configurazione della build prima di utilizzare ssh -A, vedere confluenza. jetbrains.com/display/TCD10/SSH+Agent ).
John Zwinck,

12

Mi piace la risposta di roaima, ma i percorsi sono gli stessi in entrambi gli esempi, oscurando quale è quale. Abbiamo stabilito che quanto segue non funziona:

rsync -vuar host1:/host1/path host2:/host2/path

Ma questo (ho omesso il bind_address esplicito di localhost -Rdall'opzione dal momento che è l'impostazione predefinita):

ssh -R 50000:host2:22 host1 'rsync -e "ssh -p 50000" -vuar /host1/path localhost:/host2/path'

Nota che dovrai avere le chiavi ssh impostate correttamente tra i due host remoti, con la chiave privata su host1 e la chiave pubblica su host2.

Per eseguire il debug della connessione, suddividilo in due parti e aggiungi lo stato dettagliato:

localhost$ ssh -v -R 50000:host2:22 host1

Se funziona, avrai una shell su host1. Ora prova il comando rsync da host1. Ti consiglio di farlo in una finestra diversa in modo che le informazioni dettagliate ssh non vengano mescolate con le informazioni sullo stato rsync:

host1$ rsync -e "ssh -p 50000" -vuar /host1/path localhost:/host2/path

Nel mio esempio i percorsi sono sorgente, destinazione. L' rsyncsia intentato in host1 con il target su host2. (Avresti potuto chiedere chiarimenti in un commento.)
roaima,

1
Avrei commentato, ma non puoi commentare il post di qualcun altro senza una reputazione di 50+.
Jaybrau,

7

Riformattazione della risposta di roaima nella sintassi dello script bash (e aggiunta di caratteri di continuazione della riga '\' per chiarezza) Ho scelto casualmente la porta 22000 ...

SOURCE_USER=user1
SOURCE_HOST=hostname1
SOURCE_PATH=path1

TARGET_USER=user2
TARGET_HOST=host2
TARGET_PATH=path2

ssh -l $TARGET_USER -A -R localhost:22000:$TARGET_HOST:22 \
$SOURCE_USER@$SOURCE_HOST "rsync -e 'ssh -p 22000' -vuar $SOURCE_PATH \
$TARGET_USER@localhost:$TARGET_PATH"

1
mi sembra che tutto ciò che hai fatto sia sostituire i suoi nomi host arbitrari con variabili?
Jeff Schaller

3
Si l'ho fatto. Aggiunge chiarezza per me su quale sia la macchina sorgente, che è la destinazione e dove vanno i percorsi sorgente e destinazione. Mi ci è voluto un po 'per capire tutto e non era ovvio dai semplici nomi host segnaposto.
David I.

La prossima volta sentiti libero di migliorare la risposta di qualcun altro direttamente modificandola.
roaima,

Questa risposta è stata la soluzione per me in quanto combina l'inoltro di ssh-agent (-A) con il tunnel inverso (-R).
Camelthemammel

3

Il modo ideale sarebbe quello di eseguire rsyncsu uno di quei server. Ma se non si desidera eseguire uno script sul server remoto. Potresti eseguire uno script sul tuo sistema locale ed eseguire un ssh ed eseguire il rsync lì.

ssh user@$host1 <<ENDSSH >> /tmp/rsync.out 2>&1 rsync -vuar /var/www host2:/var/www ENDSSH

Inoltre, come forse saprai, rysnc esegue la sincronizzazione in un modo. Se desideri la sincronizzazione bidirezionale, puoi consultare osync ( https://github.com/deajan/osync ). Lo uso e l'ho trovato utile.


0

Proprio come un'ulteriore informazione:

Se usi un jump host per connettere le altre due macchine ma non riescono a raggiungersi direttamente, puoi usare sshfs come mezzo tra queste due macchine in questo modo (sull'host di salto):

$ mkdir ~/sourcepath ~/destpath
$ sshfs sourcehost:/target/dir ~/sourcepath
$ sshfs desthost:/target/dir ~/destpath
$ rsync -vua ~/sourcepath ~/desthpath

SSHFS fornisce i due percorsi sull'host di salto e rsync gestisce la sincronizzazione dei file come sempre (solo con la differenza che viene praticamente eseguita localmente).


1
Nota che la performance sarà terribile. Questo perché per rilevare le modifiche rsync leggerà il file dal server di origine, trasferendo il tutto sulla rete. Detto questo, se non puoi effettuare un trasferimento diretto, dovrai mangiare questo se stai usando rsync. Inoltre non montare la destinazione, non è necessario e farà sì che rsync cambi alcuni valori predefiniti perché pensa che stia parlando con un disco locale.
Kevin Cox,

0

È possibile eseguire un rsyncd (server) su uno dei computer.

Questo è l'approccio che sto adottando, dal momento che non voglio usare ssh per consentire alla 'fonte' (in formulazione rsync) l'accesso alla 'destinazione' come root senza password (come è richiesto per usare il tunneling SSH con rsync in un copione)

Nel mio caso, ho semplicemente impostato un server rsyncd sul computer di destinazione con un singolo utente autorizzato dal PC di origine e utilizzato rsync dal lato di origine.

Funziona alla grande.


0

Prova a usare questo. Per me funziona.

ssh src_user@src_host 'rsync -av /src/dir/location/ dest_user@dest_host:/dest/dir/loc/'

0

Uno script facile da usare

Nel corso degli anni l'ho fatto molte volte con più o meno gli stessi trucchi di ogni altra risposta qui. Tuttavia, poiché è molto facile sbagliare alcuni dettagli e dedicare molto tempo a capire il problema, ho escogitato lo script seguente:

  1. Semplifica la specifica di tutti i dettagli (fonte, destinazione, opzioni)
  2. Test incrementali di ogni singolo passaggio e feedback in caso di problemi, in modo da sapere cosa risolvere.
  3. Risolve i casi in cui ssh -Anon è possibile propagare i dati di autenticazione (non so perché ciò accada a volte poiché la soluzione alternativa era più semplice della ricerca della causa principale)
  4. Finalmente fa il lavoro.

Come usare lo script

  1. Assicurati di poter ssh su entrambi gli host da localhost senza digitare una password.
  2. Imposta le variabili nelle prime righe dello script
  3. Eseguilo.

Come funziona

Come ho detto, usa gli stessi trucchi di ogni altra risposta qui:

  • L' -Ropzione di ssh per ssh da localhost a host1 mentre allo stesso tempo imposta un port forwarding che consenta a host1 di connettersi tramite localhost a host2 ( -R localhost:$FREE_PORT:$TARGET_ADDR_PORT)
  • L' -Aopzione ssh per consentire una facile autenticazione del secondo canale ssh

Questo è complicato! C'è un modo più semplice?

Quando si copiano tutti o la maggior parte dei byte dall'origine alla destinazione, è MOLTO più facile da usare tar:

ssh $SOURCE_HOST "tar czf - $SOURCE_PATH" \
    | ssh $TARGET_HOST "tar xzf - -C $TARGET_PATH/"

Il copione

#!/bin/bash
#-------------------SET EVERYTHING BELOW-------------------
# whatever you type after ssh to connect to SOURCE/TARGE host 
# (e.g. 1.2.3.4:22, user@host:22000, ssh_config_alias, etc)
# So if you use "ssh foo" to connect to SOURCE then 
# you must set SOURCE_HOST=foo
SOURCE_HOST=host1 
TARGET_HOST=host2 
# The IP address or hostname and ssh port of TARGET AS SEEN FROM LOCALHOST
# So if ssh -p 5678 someuser@1.2.3.4 will connect you to TARGET then
# you must set TARGET_ADDR_PORT=1.2.3.4:5678 and
# you must set TARGET_USER=someuser
TARGET_ADDR_PORT=1.2.3.4:5678
TARGET_USER=someuser

SOURCE_PATH=/mnt/foo  # Path to rsync FROM
TARGET_PATH=/mnt/bar  # Path to rsync TO

RSYNC_OPTS="-av --bwlimit=14M --progress" # rsync options
FREE_PORT=54321 # just a free TCP port on localhost
#---------------------------------------------------------

echo -n "Test: ssh to $TARGET_HOST: "
ssh $TARGET_HOST echo PASSED| grep PASSED || exit 2

echo -n "Test: ssh to $SOURCE_HOST: "
ssh $SOURCE_HOST echo PASSED| grep PASSED || exit 3

echo -n "Verifying path in $SOURCE_HOST "
ssh $SOURCE_HOST stat $SOURCE_PATH | grep "File:" || exit 5

echo -n "Verifying path in $TARGET_HOST "
ssh $TARGET_HOST stat $TARGET_PATH | grep "File:" || exit 5

echo "configuring ssh from $SOURCE_HOST to $TARGET_HOST via locahost"
ssh $SOURCE_HOST "echo \"Host tmpsshrs; ControlMaster auto; ControlPath /tmp/%u_%r@%h:%p; hostname localhost; port $FREE_PORT; user $TARGET_USER\" | tr ';' '\n'  > /tmp/tmpsshrs"

# The ssh options that will setup the tunnel
TUNNEL="-R localhost:$FREE_PORT:$TARGET_ADDR_PORT"

echo 
echo -n "Test: ssh to $SOURCE_HOST then to $TARGET_HOST: "
if ! ssh -A $TUNNEL $SOURCE_HOST "ssh -A -F /tmp/tmpsshrs tmpsshrs echo PASSED" | grep PASSED ; then
        echo
        echo "Direct authentication failed, will use plan #B:"
        echo "Please open another terminal, execute the following command"
        echo "and leave the session running until rsync finishes"
        echo "(if you're asked for password use the one for $TARGET_USER@$TARGET_HOST)"
        echo "   ssh -t -A $TUNNEL $SOURCE_HOST ssh -F /tmp/tmpsshrs tmpsshrs"
        read -p "Press [Enter] when done..."
fi

echo "Starting rsync"
ssh -A $TUNNEL $SOURCE_HOST "rsync -e 'ssh -F /tmp/tmpsshrs' $RSYNC_OPTS $SOURCE_PATH tmpsshrs:$TARGET_PATH"

echo
echo "Cleaning up"
ssh $SOURCE_HOST "rm /tmp/tmpsshrs"

tarè fantastico quando hai un singolo trasferimento (non incrementale) e il trasferimento viene completato in un unico passaggio. D'altra parte, rsynccon le maniglie di inoltro si riavvia e trasferimenti incrementali.
roaima,

1
Naturalmente @roaima - non considero equivalente tar. Ho lasciato questo riferimento di passaggio per il giorno in cui lo leggerò per risolvere un problema in cui rsync non sarà necessario al 100%.
ndemou,

-1

È possibile utilizzare tartramite sshper trasferire i file:

ssh -n user1@host1 'tar jcf - -C /var/www .' | ssh user2@host2 'tar jxvf - -C /var/www'

Modificare il jparametro (per tar) in zin due punti se si desidera comprimere l'archivio con gzip, anziché bzip2. Di solito bzip2ha una compressione maggiore di gzip, ma è più lenta, quindi cambiarla in base alle tue esigenze (vedi: bzip2 vs gzip ).

Correlati: Come copiare tra due host remoti utilizzando tar convogliato in SSH dal server remoto quando dietro un firewall?


In alternativa (per proteggere la larghezza di banda, a causa della compressione trasparente) è possibile utilizzare sshfsper montare il file system remoto come locale e usarlo rsynccome al solito, ad es.

$ sshfs user1@host1:/var/www /mnt
$ rsync -vuar /mnt user2@host2:/var/www

1
Il montaggio locale del filesystem non salverà alcuna larghezza di banda tra il computer di origine e quello locale. Esso sarà comunque risparmiare larghezza di banda tra il locale e di destinazione (in quanto non è montata in loco). L'uso di rsync in questo modo ha senso solo se si sta tentando di risparmiare larghezza di banda sulla destinazione.
Kevin Cox,
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.