Como rsync arquivos entre dois controles remotos?


54

Gostaria de transferir arquivos entre dois hosts remotos usando no shell local, mas parece que o rsync não suporta sincronização se dois controles remotos forem especificados da seguinte maneira:

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

Que outras soluções alternativas / comandos eu poderia usar para obter resultados semelhantes?



11
Na verdade, você pode sincronizar entre 2 hosts remotos, utilizando o sshfs em um terceiro host. Basta usar sshfs para montar host1 e host2 no host 3. Em seguida, rsync entre 1 e 2.
— William Legg

A desvantagem de usar o @WilliamLegg sshfsé que ele rsyncvê os sistemas de arquivos de origem e destino como locais, de modo que desabilita seu algoritmo delta. Nesse ponto, você quase pode usar cp -p. Veja a resposta que propõe isso e seus comentários subsequentes.
— roaima

Respostas:


50

Como você descobriu, não pode usar o rsync com uma fonte remota e um destino remoto. Supondo que os dois servidores não possam conversar diretamente entre si, é possível usar o ssh para fazer um túnel através da sua máquina local.

Ao invés de

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

você pode usar isso

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

Caso você esteja se perguntando, a -Ropção configura um canal reverso da porta 50000 no host1 que mapeia (via sua máquina local) para a porta 22 no host2. Não há conexão direta do host1 para o host2.


11
Gosto da solução da @ roaima, mas não consegui fazê-la funcionar por várias razões. No final, eu costumava sshfsmontar os dois diretórios remotos localmente, depois os usava rsyncnos dois diretórios montados localmente.
— Aidan

É possível ver um exemplo em que uma chave é usada? Problemas para descobrir como usar -ipara especificar as chaves necessárias para os comandos ssh.
— Onassar 31/03

@onassar adiciona o -i key...parâmetro dentro das aspas após o sshcomando. Se isso não ajudar, por favor, sinta-se à vontade para fazer uma nova pergunta, referenciando esta resposta para contexto
— roaima 31/03/16

11
a conexão reversa não lê o ~ / .ssh / config no lado local - precisa usar algo que pode ser resolvido como se não houvesse nenhum arquivo SSH configuração
— Florenz Kley

11
'Supondo que os dois servidores não possam falar diretamente um com o outro'. Esta solução soluciona um problema de firewall ou NAT que impede uma conexão SSH direta . No entanto, ele não aborda o caso em que, por razões de segurança, o usuário de origem (no host1) não possui chave ou credenciais ou permissões de gravação insuficientes no destino. Para isso, veja a solução de Kevin Cox, ou recorra a uma conexão indireta usando um script ou scp -3.
— Cedric Knight

22

Você não disse por que não queria entrar em um host e depois copiar para o outro, para compartilhar uma das minhas razões e soluções.

Não pude fazer login em uma máquina e depois sincronizá-la com a outra porque nenhum host tinha uma chave SSH que poderia se conectar à outra. Resolvi isso usando o encaminhamento de agente SSH para permitir que o primeiro host usasse minha chave SSH enquanto estava conectado.

AVISO: O encaminhamento de SSH permite que o host use sua chave SSH durante o login. Enquanto eles não podem copiar sua chave, eles podem fazer login em outras máquinas com ela. Compreenda os riscos e não use o encaminhamento de agentes em máquinas nas quais não confia.

O comando a seguir usará o encaminhamento do agente SSH para abrir uma conexão direta de host1para host2. Isso tem a vantagem de que a máquina que executa o comando não está afunilando a transferência.

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

3
+1 para explicar um caso de uso válido (em que o usuário remoto no host1 não tem permissões no servidor de destino); pela importante advertência de segurança (use o encaminhamento de porta em -Dvez de -Acontornar a rede em vez das principais restrições); por explicar a vantagem; para o comando ser curto; e realmente funciona. Observe que você pode precisar especificar username@host1se é diferente do nome de usuário local. Além disso, o rsync executa a verificação da chave do host ao se conectar ao host2, portanto, a chave do host1 já deve estar em ~ / .ssh / known_hosts no host2 ou o comando falhará.
— Cedric Cavaleiro

Resposta fenomenal, este me ajudou a orquestrar algumas coisas em TeamCity que eu não era capaz de fazer antes (nb para outros usuários TeamCity, você deve adicionar o "Build Característica" chamado "agente SSH" para sua configuração construção antes de usar ssh -A, consulte confluência. jetbrains.com/display/TCD10/SSH+Agent ).
— precisa saber é o seguinte

12

Gosto da resposta de roaima, mas os caminhos são os mesmos nos dois exemplos, obscurecendo qual é qual. Estabelecemos que o seguinte não funciona:

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

Mas isso acontece (eu omiti o endereço bind_ex explícito do localhost da -Ropção, pois esse é o padrão):

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

Observe que você precisará ter as chaves ssh configuradas corretamente entre os dois hosts remotos, com a chave privada no host1 e a chave pública no host2.

Para depurar a conexão, divida-o em duas partes e adicione o status detalhado:

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

Se isso funcionar, você terá um shell no host1. Agora tente o comando rsync do host1. Eu recomendo fazer isso em uma janela diferente para que as informações ssh detalhadas não sejam misturadas às informações de status do rsync:

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

No meu exemplo, os caminhos são origem, destino. O rsyncé iniciado no host1 com o destino no host2. (Você poderia ter pedido esclarecimentos em um comentário.)
— roaima

11
Eu teria comentado, mas você não pode comentar na postagem de outra pessoa sem uma reputação de mais de 50 anos.
— Jaybrau

7

Reformatando a resposta por roaima na sintaxe do script bash (e adicionando caracteres de continuação de linha '\' para maior clareza), escolhi aleatoriamente a 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"

11
parece-me que tudo o que você fez foi substituir os nomes de host arbitrários por variáveis?
— Jeff Schaller

3
Sim eu fiz. Isso me esclarece qual é a máquina de origem, qual é o destino e para onde vão os caminhos de origem e destino. Levei um tempo para resolver tudo isso e não era óbvio a partir de simples nomes de host de espaços reservados.
— David I.

Da próxima vez, sinta-se à vontade para melhorar a resposta de outra pessoa diretamente, editando-a.
— roaima

Esta resposta foi a solução para mim, pois combina o encaminhamento ssh-agent (-A) com o túnel reverso (-R).
— camelthemammel

3

A maneira ideal seria executar o rsyncem um desses servidores. Mas se você não deseja executar um script no servidor remoto. Você pode executar um script em seu sistema local, executar um ssh e executar o rsync lá.

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

Além disso, como você deve saber, o rysnc faz a sincronização unidirecional. Se você quiser uma sincronização bidirecional, consulte o osync ( https://github.com/deajan/osync ). Eu o uso e achei útil.


0

Apenas como uma informação adicional:

Se você usa um host de salto para conectar as outras duas máquinas, mas elas não podem se alcançar diretamente, é possível usar o sshfs como meio entre essas duas máquinas (no host de salto):

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

O SSHFS fornece os dois caminhos no host de salto e o rsync gerencia a sincronização dos arquivos como sempre (apenas com a diferença de que ele é feito virtualmente localmente).


11
Observe que o desempenho será terrível. Isso ocorre porque, para detectar alterações, o rsync lê o arquivo do servidor de origem, transferindo tudo pela rede. Dito isto, se você não puder fazer uma transferência direta, precisará comer isso se estiver usando o rsync. Também não monte o destino, ele é desnecessário e fará com que o rsync altere alguns padrões, porque pensa que está falando com um disco local.
— Kevin Cox

0

Você pode executar um rsyncd (servidor) em um dos computadores.

Esta é a abordagem que estou adotando, já que não quero usar o ssh para permitir que a 'fonte' (no texto do rsync) acesse o 'destino' como raiz sem uma senha (como é necessário para usar o encapsulamento SSH com o rsync no um roteiro)

No meu caso, simplesmente configurei um servidor rsyncd no computador de destino com um único usuário permitido no PC de origem e usei o rsync do lado da fonte.

Funciona bem.


0

Tente usar isso. Funciona para mim.

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

0

Um script fácil de usar

Ao longo dos anos, eu fiz isso muitas vezes com mais ou menos os mesmos truques de todas as outras respostas aqui. No entanto, como é muito fácil obter alguns detalhes errados e gastar muito tempo descobrindo o problema, vim com o script abaixo:

  1. Facilita a especificação de todos os detalhes (origem, destino, opções)
  2. Testa incrementalmente cada etapa e fornece feedback se algo der errado, para que você saiba o que corrigir.
  3. Solução para os casos em que ssh -Afalha na propagação dos dados de autenticação (não sei por que isso acontece algumas vezes, pois a solução alternativa foi mais fácil do que encontrar a causa raiz)
  4. Finalmente faz o trabalho.

Como usar o script

  1. Certifique-se de poder ssh para os dois hosts do host local sem digitar uma senha.
  2. Defina as variáveis ​​nas primeiras linhas do script
  3. Execute.

Como funciona

Como eu disse, ele usa os mesmos truques que em todas as outras respostas aqui:

  • A -Ropção do ssh para ssh do host local para o host1 e, ao mesmo tempo, configura um encaminhamento de porta que permite ao host1 se conectar via host local ao host2 ( -R localhost:$FREE_PORT:$TARGET_ADDR_PORT)
  • -Aopção do ssh para permitir fácil autenticação do segundo canal ssh

Meu isso é complicado! Existe alguma maneira mais fácil?

Ao copiar todos ou a maioria dos bytes da origem para o destino, é MUITO mais fácil de usar tar:

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

O script

#!/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é ótimo quando você tem uma única transferência (não incremental) e sua transferência é concluída em uma única passagem. Por outro lado, rsynccom alças de encaminhamento reinicia e transferências incrementais.
— roaima 4/04

11
Claro que @roaima - não considero o alcatrão equivalente. Deixei essa referência de passagem para o dia em que estarei lendo isso para resolver um problema em que o rsync não será 100% necessário.
— ndemou 04/04

-1

É possível usar tarvia sshpara transferir os arquivos:

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

Altere o jparâmetro (for tar) para zem dois lugares se desejar compactar o arquivo morto em gzipvez de bzip2. Geralmente bzip2tem uma compactação mais alta que gzip, mas é mais lenta, portanto altere-a de acordo com suas necessidades (consulte: bzip2 vs gzip ).

Relacionado: Como copiar entre dois hosts remotos usando o tar canalizado no SSH do servidor remoto quando atrás de um firewall?


Como alternativa (para proteger a largura de banda, devido à compactação transparente), é possível usar sshfspara montar o sistema de arquivos remoto como local e usar rsynccomo de costume, por exemplo,

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

11
Montar o sistema de arquivos localmente não economizará largura de banda entre a máquina de origem e o local. Ele irá no entanto economizar largura de banda entre o local eo destino (como ele não está montado localmente). Usar o rsync dessa maneira só faz sentido se você estiver tentando economizar largura de banda no destino.
— Kevin Cox
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.