Как rsync файлы между двумя пультами?


54

Я хотел бы передавать файлы между двумя удаленными узлами, используя локальную оболочку, но кажется, что rsync не поддерживает синхронизацию, если два удаленных узла указаны следующим образом:

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

Какие другие обходные пути / команды я мог бы использовать для достижения аналогичных результатов?



1
На самом деле вы можете rsync между двумя удаленными хостами, используя sshfs на третьем хосте. Просто используйте sshfs для монтирования host1 и host2 на хосте 3. Затем выполните rsync между 1 и 2.
William Legg

Недостаток @WilliamLegg в использовании sshfsзаключается в том, rsyncчто исходная и целевая файловые системы рассматриваются как локальные, поэтому он отключает свой дельта-алгоритм. На этом этапе вы почти могли бы просто использовать cp -p. Смотрите ответ, который предлагает это и его последующие комментарии.
Ройма

Ответы:


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опция устанавливает обратный канал от порта 50000 на хосте 1, который отображается (через локальный компьютер) на порт 22 на хосте 2. Прямого соединения между host1 и host2 нет.


1
Мне нравится решение @ roaima, но я не смог заставить его работать по разным причинам. В конце я использовал sshfsдля локального монтирования обоих удаленных каталогов, а затем использовал их rsyncдля двух локально монтируемых каталогов.
aidan

Можно увидеть пример, где используется ключ? Возникают проблемы с выяснением того, как использовать -iдля указания ключей, необходимых для команд ssh.
Онассар

@onassar добавить -i key...параметр в кавычки после sshкоманды. Если это не помогает, пожалуйста, не стесняйтесь задавать новый вопрос, ссылаясь на этот ответ для контекста
roaima

1
обратное соединение не читает ~ / .ssh / config на локальной стороне - нужно использовать что-то, что может быть решено, как если бы не было файла конфигурации SSH
Florenz Kley

1
«Предполагая, что два сервера не могут общаться напрямую друг с другом». Это решение решает проблему брандмауэра или NAT, препятствующую прямому соединению SSH . Однако это не относится к случаю, когда из соображений безопасности исходный пользователь (на хосте 1) не имеет ни ключа, ни учетных данных, ни недостаточных разрешений на запись в место назначения. Для этого смотрите решение Кевина Кокса или прибегайте к косвенному соединению с помощью скрипта или scp -3.
Седрик Найт

22

Вы не сказали, почему не хотите войти на один хост, а затем скопировать на другой, поэтому я поделюсь одной из моих причин и решений.

Я не мог войти на одну машину, а затем выполнить rsync для другой, потому что ни у одного хоста не было ключа 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 уже должен находиться в ~ / .ssh / known_hosts на host2, иначе команда не будет выполнена.
Седрик Найт

Феноменальный ответ, это помогло мне организовать некоторые вещи в TeamCity, которые я не мог сделать раньше (для других пользователей TeamCity, вы должны добавить «Build Feature» под названием «SSH agent» в конфигурацию сборки перед использованием ssh -A, см. Слияние). jetbrains.com/display/TCD10/SSH+Agent ).
Джон Цвинк

12

Мне нравится ответ Роаймы, но пути в обоих примерах одинаковы, скрывая что есть что. Мы установили, что следующее не работает:

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

Но это так (я опускал явный bind_address localhost из -Rопции, так как это по умолчанию):

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. Теперь попробуйте команду rsync с host1. Я рекомендую делать это в другом окне, чтобы подробная ssh-информация не смешивалась с информацией о состоянии rsync:

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

В моем примере пути являются источником, местом назначения. rsyncИнициируется на host1 с мишенью на host2. (Вы могли бы попросить разъяснения в комментарии.)
roaima

1
Я бы прокомментировал, но вы не можете комментировать чужой пост без репутации 50+.
Jaybrau

7

Переформатирование ответа roaima в синтаксисе bash-скрипта (и добавление символов продолжения строки '\' для ясности) Я случайно выбрал порт 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
Да. Это добавляет мне ясности в отношении того, какая машина-источник является целью, и куда идут пути источника и цели. Мне потребовалось некоторое время, чтобы разобраться со всем этим, и это не было очевидно из простых имен хостов-заполнителей.
Дэвид И.

В следующий раз, пожалуйста, не стесняйтесь улучшать чей-либо ответ, редактируя его.
Роайма

Этот ответ был для меня решением, поскольку он сочетает в себе пересылку 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

Попробуйте использовать это. Меня устраивает.

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

0

Простой в использовании скрипт

За эти годы я делал это много раз с более или менее теми же хитростями, что и в любом другом ответе здесь. Однако, потому что очень легко ошибиться в деталях и потратить много времени на выяснение проблемы, с которой я столкнулся, сценарий ниже:

  1. Позволяет легко указать все детали (источник, пункт назначения, параметры)
  2. Поэтапно проверяет каждый шаг и дает обратную связь, если что-то пойдет не так, чтобы вы знали, что исправить.
  3. Обходит случаи, когда ssh -Aне удается распространить данные аутентификации (не знаю, почему это иногда случается, поскольку обходной путь был легче, чем поиск основной причины)
  4. Наконец делает работу.

Как использовать скрипт

  1. Убедитесь, что вы можете использовать ssh для обоих хостов с локального хоста без ввода пароля.
  2. Установите переменные в первых нескольких строках скрипта
  3. Выполните это.

Как это устроено

Как я уже сказал, он использует те же приемы, что и в любом другом ответе:

  • SSH в -Rвозможность SSH с локального хоста на host1 и в то же время создание переадресацию порта , который затем позволяет host1 подключиться через локальный к host2 ( -R localhost:$FREE_PORT:$TARGET_ADDR_PORT)
  • -AОпция ssh для простой аутентификации второго канала ssh

Это сложно! Есть ли более простой способ?

При копировании всех или большей части байтов из источника в место назначения, это гораздо проще использовать 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с переадресацией ручки перезапускаются и инкрементно переводятся.
Роайма

1
Конечно @roaima - я не считаю смолу эквивалентной. Я оставил эту мимолетную ссылку на день, когда буду читать это, чтобы решить проблему, когда rsync не будет на 100% необходим.
ndemou

-1

Можно использовать tarчерез sshдля передачи файлов:

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

Измените jпараметр (для tar) на zдва, если вы хотите сжать архив gzip, а не bzip2. Обычно bzip2имеет более высокое сжатие, чем gzip, но оно медленнее, поэтому меняйте его в зависимости от ваших потребностей (см. Bzip2 vs gzip ).

Связанный: Как скопировать между двумя удаленными узлами, используя tar, переданный по SSH с удаленного сервера, когда он находится за брандмауэром


В качестве альтернативы (для обеспечения безопасности полосы пропускания из-за прозрачного сжатия) можно использовать sshfsдля монтирования удаленной файловой системы как локальную и использовать rsyncкак обычно, например

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

1
Монтирование файловой системы локально не сохранит пропускную способность между источником и локальной машиной. Это будет , однако сохранить полосу пропускания между локальным и назначением ( так как он не установлен локально). Использование rsync таким способом имеет смысл, только если вы пытаетесь сохранить пропускную способность в месте назначения.
Кевин Кокс
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.