如何在两个遥控器之间同步文件?


54

我想在本地外壳上使用两个远程主机之间传输文件,但是如果按如下所示指定两个远程,则rsync似乎不支持同步:

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

我还可以使用其他哪些解决方法/命令来获得相似的结果?



1
实际上,您可以利用第3个主机上的sshfs在2个远程主机之间进行同步。只需使用sshfs的安装在主机3. host1和host2然后1 2的rsync之间
威廉·莱格

@WilliamLegg使用using的缺点sshfs是然后rsync将源文件系统和目标文件系统都视为本地文件系统,因此它禁用了增量算法。到那时,您几乎不妨使用cp -p。请参阅提出此问题的答案及其后续意见。
roaima

Answers:


50

如发现的那样,您无法将rsync与远程源和远程目标一起使用。假设两个服务器不能直接相互通信,则可以使用ssh通过本地计算机建立隧道。

代替

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

你可以用这个

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

如果您想知道,该-R选项设置了从host1上的端口50000反向通道,该通道映射(通过本地计算机)到host2上的端口22。从host1到host2没有直接连接。


1
我喜欢@roaima的解决方案,但由于种种原因,我无法使其正常运行。最后,我曾经sshfs在本地安装两个远程目录,然后rsync在两个本地安装的目录中使用。
艾丹,2015年

可以看到使用钥匙的示例吗?无法弄清楚如何用于-i指定ssh命令所需的键。
onassar,2016年

@onassar -i key...ssh命令后的引号内添加参数。如果那不能解决您的问题,请随时提出一个新问题,并参考上下文的答案
roaima

1
反向连接不会读取本地端的〜/ .ssh / config-需要使用可以解决的内容,就好像没有SSH配置文件一样
Florenz Kley

1
“假设这两个服务器不能直接相互通信”。此解决方案确实可以解决阻止直接SSH 连接的防火墙或NAT问题。但是,它不能解决出于安全原因源用户(在host1上)对目标没有密钥或凭据或写入权限不足的情况。为此,请参见Kevin Cox的解决方案,或诉诸使用脚本或的间接连接scp -3
Cedric Knight

22

您没有说为什么不想登录到一台主机然后复制到另一台主机,所以我将分享我的一个原因和解决方案。

我无法登录到一台计算机,然后无法同步到另一台计算机,因为两台主机都没有可以登录另一台计算机的SSH密钥。我通过使用SSH代理转发来解决此问题,从而允许第一台主机在登录时使用我的SSH密钥。

警告: SSH转发允许主机在您登录期间使用SSH密钥。尽管他们无法复制您的密钥,但他们可以使用它登录其他计算机。确保您了解风险,并且不要对不信任的计算机使用代理转发。

以下命令将使用SSH代理转发打开从host1到的直接连接host2。这样做的好处是,运行命令的计算机不会阻塞传输。

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

3
+1用于解释有效的用例(其中host1上的远程用户对目标服务器没有权限);对于重要的安全警告(使用端口转发-D而不是-A绕过网络而不是密钥限制);用于解释优势;因为命令很短;它实际上有效。请注意,您可能需要指定username@host1它是否与本地用户名不同。同样,rsync在连接到host2时会执行主机密钥验证,因此host1的密钥应该已经在host2上的〜/ .ssh / known_hosts中,否则命令将失败。
Cedric Knight

现象的答案,这帮助我整理了TeamCity中一些以前无法完成的工作(对于其他TeamCity用户,请注意ssh -A,在使用之前,必须在构建配置中添加名为“ SSH代理”的“ Build Feature” ,请参见融合)。 jetbrains.com/display/TCD10/SSH+Agent)。
John Zwinck

12

我喜欢roaima的答案,但是两个示例中的路径都相同,但不清楚是哪个。我们确定以下内容不起作用:

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

但这确实是(我从-R选项中省略了localhost的显式bind_address,因为这是默认设置):

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

请注意,必须在两个远程主机之间正确设置ssh密钥,其中host1上的私钥和host2上的公钥。

要调试连接,请将其分为两部分并添加详细状态:

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

如果可行,您将在host1上安装一个shell。现在,尝试从host1执行rsync命令。我建议在其他窗口中执行此操作,以免将冗长的ssh信息与rsync状态信息混合在一起:

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

在我的示例中,路径是源,目标。该rsync是在与主机2目标主机1启动。(您可能已在评论中要求澄清。)
roaima

1
我会发表评论,但如果您的声誉不超过50 ,您就无法发表评论
jaybrau

7

我用bash脚本语法重新格式化了roaima的答案(为清楚起见,并添加了行继续符'\'),我随机选择了端口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
在我看来,您所做的全部就是用变量替换他的任意主机名?
杰夫·谢勒

3
是的,我做到了。它使我更清楚地知道源机器,目标机器以及源路径和目标路径的位置。我花了一些时间来解决所有这些问题,从简单的占位符主机名来看这并不明显。
David I.

下次,请随时通过编辑直接改善别人的答案。
roaima

这个答案是我的解决方案,因为它结合了ssh-agent转发(-A)和反向隧道(-R)。
camelthemammel

3

理想的方法是rsync在其中一台服务器上运行。但是,如果您不想在远程服务器上运行脚本。您可以在本地系统上运行脚本并执行ssh并在那里执行rsync。

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

另外,您可能已经知道rysnc进行单向同步。如果您想要双向同步,可以查看osync(https://github.com/deajan/osync)。我使用它,发现它很有帮助。


0

作为附加信息:

如果您使用跳转主机连接其他两台计算机,但它们不能直接相互连接,则可以在这两台计算机之间使用sshfs作为介质,就像这样(在跳转主机上):

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

SSHFS在跳转主机上提供了两条路径,rsync像往常一样管理文件的同步(只是区别在于它实际上是在本地完成的)。


1
请注意,性能会很糟糕。这是因为要检测更改,rsync将从源服务器读取文件,从而通过网络传输整个内容。话虽这么说,如果您不能进行直接传输,那么在使用rsync的情况下就必须吃掉它。也不要挂载目标,这是不必要的,并且会导致rsync更改一些默认值,因为它认为它正在与本地磁盘通信。
凯文·考克斯

0

您可以在一台计算机上运行rsyncd(服务器)。

这是我采用的方法,因为我不想使用ssh来允许“源”(以rsync的方式)以root身份访问“目的地”而无需输入密码(这是在SSH隧道中使用rsync所必需的)一个脚本)

就我而言,我只是在目标计算机上设置了一个rsyncd服务器,而源计算机允许一个用户,并在源端使用了rsync。

效果很好。



0

易于使用的脚本

多年来,我用与这里其他所有答案差不多的技巧做了很多次。但是,由于很容易弄错一些细节并花费大量时间来解决问题,因此我在下面提供了以下脚本:

  1. 轻松指定所有详细信息(源,目标,选项)
  2. 逐步测试每个步骤,并在出现问题时提供反馈,以便您知道要解决的问题。
  3. 解决ssh -A无法传播身份验证数据的情况(不知道为什么有时会发生这种情况,因为解决方法比查找根本原因更容易)
  4. 最后完成工作。

如何使用脚本

  1. 确保无需输入密码即可从本地主机SSH到这两个主机。
  2. 在脚本的前几行中设置变量
  3. 执行它。

这个怎么运作

正如我所说的,它使用与此处其他所有答案相同的技巧:

  • ssh -R从localhost到host1的ssh 选项,同时设置端口转发,然后允许host1通过localhost连接到host2(-R localhost:$FREE_PORT:$TARGET_ADDR_PORT
  • ssh的-A选项,可以轻松验证第二个ssh chanel

我的这很复杂!有没有更简单的方法?

将所有或大部分字节从源复制到目标时,FAR易于使用tar

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

剧本

#!/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当您进行单次(非增量)转移并且一次转移完成转移时,该功能非常有用。另一方面,rsync带有转发句柄的重新启动和增量传输。
roaima

1
当然@roaima-我不认为tar等效。我将在阅读本文的那一天留下这个通过的参考,以解决rsync不需要100%必要的问题。
ndemou

-1

可以使用tarvia ssh来传输文件:

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

如果您想使用而不是压缩档案,请将j(for tar)参数z在两个位置更改。通常压缩率要高于,但速度较慢,因此请根据需要进行更改(请参阅:bzip2 vs gzip)。gzipbzip2bzip2gzip

相关:在防火墙后面时,如何使用从远程服务器通过SSH连接到SSH的tar在两个远程主机之间进行复制?


另外(为了保证带宽,由于透明压缩),可以sshfs将远程文件系统挂载为本地文件,并rsync像往常一样使用,例如

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

1
在本地安装文件系统不会节省源计算机和本地计算机之间的任何带宽。但是,它将节省本地和目标之间的带宽(因为它不是本地安装的)。仅当您尝试在目标上节省带宽时,以这种方式使用rsync才有意义。
凯文·考克斯
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.