Jak synchronizować pliki między dwoma pilotami?


54

Chciałbym przesyłać pliki między dwoma zdalnymi hostami za pomocą lokalnej powłoki, ale wygląda na to, że rsync nie obsługuje synchronizacji, jeśli dwa piloty są określone w następujący sposób:

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

Jakie inne obejścia / polecenia mogę użyć, aby osiągnąć podobne wyniki?



1
W rzeczywistości możesz synchronizować między 2 zdalnymi hostami, wykorzystując sshfs na 3 hoście. Wystarczy użyć sshfs, aby zamontować host1 i host2 na hoście 3. Następnie rsync między 1 a 2.
William Legg

@WilliamLegg wadą przy użyciu sshfsjest to, że następnie rsyncwidzi źródłowy i docelowy system plików zarówno jako lokalny, więc wyłącza swój algorytm delta. W tym momencie równie dobrze możesz po prostu użyć cp -p. Zobacz odpowiedź, która proponuje to i jego dalsze komentarze.
roaima,

Odpowiedzi:


50

Jak odkryłeś, nie możesz używać rsync ze zdalnym źródłem i zdalnym miejscem docelowym. Zakładając, że dwa serwery nie mogą rozmawiać bezpośrednio ze sobą, możliwe jest użycie ssh do tunelowania za pośrednictwem komputera lokalnego.

Zamiast

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

możesz tego użyć

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

Jeśli się zastanawiasz, -Ropcja konfiguruje kanał zwrotny z portu 50000 na hoście 1, który mapuje (za pośrednictwem komputera lokalnego) na port 22 na hoście 2. Nie ma bezpośredniego połączenia z hosta 1 do hosta 2.


1
Podoba mi się rozwiązanie @ roaima, ale z różnych powodów nie mogłem go uruchomić. W końcu zwykłem sshfsmontować oba zdalne katalogi lokalnie, a następnie korzystałem rsyncz dwóch lokalnie montowanych katalogów.
aidan

Czy można zobaczyć przykład użycia klucza? Masz problem z ustaleniem, jak używać -iklawiszy do określania potrzebnych poleceń ssh.
onassar

@onassar dodaj -i key...parametr w cudzysłowie po sshpoleceniu. Jeśli to nie pomoże, możesz zadać nowe pytanie, odnosząc się do tej odpowiedzi w kontekście
roaima

1
odwrotne połączenie nie odczytuje ~ / .ssh / config po stronie lokalnej - trzeba użyć czegoś, co można rozwiązać tak, jakby nie było pliku konfiguracyjnego SSH
Florenz Kley

1
„Zakładając, że dwa serwery nie mogą ze sobą rozmawiać bezpośrednio”. To rozwiązanie działa w przypadku zapory lub problemu z NAT, który uniemożliwia bezpośrednie połączenie SSH . Nie rozwiązuje to jednak przypadku, w którym ze względów bezpieczeństwa użytkownik źródłowy (na hoście1) nie ma klucza lub poświadczeń ani niewystarczających uprawnień do zapisu w miejscu docelowym. W tym celu zobacz rozwiązanie Kevina Coxa lub skorzystaj z pośredniego połączenia za pomocą skryptu lub scp -3.
Cedric Knight

22

Nie powiedziałeś, dlaczego nie chcesz zalogować się na jednym hoście, a następnie skopiować na inny, więc podzielę się jednym z moich powodów i rozwiązań.

Nie mogłem zalogować się na jednej maszynie, a następnie rsync na drugiej, ponieważ żaden host nie miał klucza SSH, który mógłby zalogować się na drugim. Rozwiązałem to za pomocą przekazywania agenta SSH, aby umożliwić pierwszemu hostowi korzystanie z mojego klucza SSH podczas mojego logowania.

OSTRZEŻENIE: Przekazywanie SSH umożliwia hostowi używanie klucza SSH przez czas logowania. Chociaż nie mogą skopiować Twojego klucza, mogą zalogować się na innych komputerach. Upewnij się, że rozumiesz ryzyko i nie korzystaj z przekazywania agentów w przypadku maszyn, którym nie ufasz.

Następujące polecenie użyje przekierowania agenta SSH do otwarcia bezpośredniego połączenia z host1do host2. Ma to tę zaletę, że maszyna z uruchomionym poleceniem nie wączy gardła transferu.

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

3
+1 za wyjaśnienie prawidłowego przypadku użycia (gdy zdalny użytkownik na hoście 1 nie ma uprawnień na serwerze docelowym); ze względu na ważne zastrzeżenie bezpieczeństwa (użyj przekierowania portów -Dzamiast -Aominąć sieć zamiast kluczowych ograniczeń); za wyjaśnienie korzyści; za krótkie polecenie; i to faktycznie działa. Pamiętaj, że może być konieczne określenie, username@host1czy różni się ona od lokalnej nazwy użytkownika. Ponadto rsync wykonuje weryfikację klucza hosta podczas łączenia się z hostem2, więc klucz hosta1 powinien już znajdować się w ~ / .ssh / known_hosts na hoście 2, inaczej polecenie się nie powiedzie.
Cedric Knight

Zjawiskowa odpowiedź, to pomogło mi zorganizować pewne rzeczy w TeamCity, których wcześniej nie byłem w stanie zrobić (nb dla innych użytkowników TeamCity, musisz dodać „Funkcję kompilacji” o nazwie „Agent SSH” do konfiguracji kompilacji przed użyciem ssh -A, zobacz zbieżność. jetbrains.com/display/TCD10/SSH+Agent ).
John Zwinck,

12

Podoba mi się odpowiedź roaima, ale ścieżki są takie same w obu przykładach, zaciemniając, która jest która. Ustaliliśmy, że następujące elementy nie działają:

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

Ale tak się dzieje (pominąłem jawny adres bind_hosta localhost w -Ropcji, ponieważ jest to ustawienie domyślne):

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

Pamiętaj, że musisz mieć poprawnie skonfigurowane klucze ssh między dwoma zdalnymi hostami, z kluczem prywatnym na hoście 1 i kluczem publicznym na hoście 2.

Aby debugować połączenie, podziel to na dwie części i dodaj pełny status:

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

Jeśli to zadziała, będziesz mieć powłokę na hoście1. Teraz wypróbuj polecenie rsync z hosta1. Zalecam robienie tego w innym oknie, aby pełne informacje ssh nie były mieszane z informacjami o statusie rsync:

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

W moim przykładzie ścieżki są źródłowe, docelowe. rsyncInicjowane jest host1 z celem w host2. (Mogłeś poprosić o wyjaśnienie w komentarzu.)
roaima

1
Skomentowałbym, ale nie można komentować postu innej osoby bez reputacji 50+.
jaybrau

7

Reformatowanie odpowiedzi przez roaima w składni skryptu bash (i dla zachowania przejrzystości dodając znaki kontynuacji linii „\”) Losowo wybrałem port 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
wydaje mi się, że wszystko, co zrobiłeś, to zastąpić jego dowolne nazwy hostów zmiennymi?
Jeff Schaller

3
Tak. Dodaje mi jasności, na której maszynie źródłowej, która jest celem, i gdzie idą ścieżki źródłowe i docelowe. Zajęło mi to trochę czasu, aby to wszystko zrozumieć i nie było to oczywiste z prostych zastępczych nazw hostów.
David I.

Następnym razem możesz poprawić odpowiedź innej osoby bezpośrednio, edytując ją.
roaima,

Ta odpowiedź była dla mnie rozwiązaniem, ponieważ łączy przekazywanie ssh-agent (-A) z tunelem zwrotnym (-R).
camelthemammel

3

Idealnym sposobem byłoby uruchomienie rsyncna jednym z tych serwerów. Ale jeśli nie chcesz uruchamiać skryptu na zdalnym serwerze. Możesz uruchomić skrypt w systemie lokalnym, wykonać ssh i wykonać tam rsync.

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

Ponadto, jak być może wiesz, rysnc wykonuje synchronizację w jedną stronę. Jeśli chcesz synchronizacji dwukierunkowej, możesz spojrzeć na osync ( https://github.com/deajan/osync ). Używam go i uważam, że jest to pomocne.


0

Jako dodatkowe informacje:

Jeśli używasz hosta skoku do połączenia dwóch pozostałych maszyn, ale nie mogą one bezpośrednio do siebie dotrzeć, możesz użyć sshfs jako medium między tymi dwoma maszynami tak (na hoście skoku):

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

SSHFS zapewnia dwie ścieżki na hoście skoku, a rsync zarządza synchronizacją plików jak zawsze (z tą różnicą, że odbywa się to praktycznie lokalnie).


1
Pamiętaj, że wydajność będzie straszna. Wynika to z tego, że aby wykryć zmiany, rsync odczyta plik z serwera źródłowego, przesyłając całość przez sieć. Biorąc to pod uwagę, jeśli nie możesz wykonać bezpośredniego transferu, będziesz musiał to zjeść, jeśli używasz rsync. Nie instaluj także miejsca docelowego, jest to niepotrzebne i spowoduje, że rsync zmieni niektóre ustawienia domyślne, ponieważ myśli, że mówi do lokalnego dysku.
Kevin Cox

0

Możesz uruchomić rsyncd (serwer) na jednym z komputerów.

Podejmuję takie podejście, ponieważ nie chcę używać ssh, aby zezwolić „źródłowemu” (w brzmieniu rsync) dostępowi do „miejsca docelowego” jako root bez hasła (jak jest to wymagane do korzystania z tunelowania SSH z rsync w skrypt)

W moim przypadku po prostu skonfigurowałem serwer rsyncd na komputerze docelowym z jednym użytkownikiem dozwolonym ze źródłowego komputera i korzystałem z rsync od strony źródłowej.

Działa świetnie.


0

Spróbuj użyć tego. Mi to pasuje.

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

0

Łatwy w użyciu skrypt

Przez lata robiłem to wiele razy z mniej więcej tymi samymi sztuczkami, jak w każdej innej odpowiedzi tutaj. Ponieważ jednak bardzo łatwo jest pomylić niektóre szczegóły i poświęcić dużo czasu na rozwiązywanie problemu, wymyśliłem poniższy skrypt:

  1. Ułatwia określenie wszystkich szczegółów (źródło, miejsce docelowe, opcje)
  2. Stopniowo testuje każdy krok i przekazuje informację zwrotną, jeśli coś pójdzie nie tak, abyś wiedział, co naprawić.
  3. Działa w przypadkach, gdy ssh -Anie można propagować danych uwierzytelniających (nie wiem, dlaczego tak się dzieje czasami, ponieważ obejście było łatwiejsze niż znalezienie głównej przyczyny)
  4. Wreszcie robi robotę.

Jak korzystać ze skryptu

  1. Upewnij się, że możesz ssh do obu hostów z localhost bez wpisywania hasła.
  2. Ustaw zmienne w pierwszych kilku wierszach skryptu
  3. Wykonaj to.

Jak to działa

Jak powiedziałem, używa tych samych sztuczek, co w każdej innej odpowiedzi tutaj:

  • SSH jest -Ropcja ssh z localhost do host1 podczas gdy w tym samym czasie konfigurowania przekierowania portów, które następnie pozwala host1 łączyć się za pośrednictwem localhost do host2 ( -R localhost:$FREE_PORT:$TARGET_ADDR_PORT)
  • -AOpcja ssh umożliwiająca łatwą autoryzację drugiego kanału ssh

Moje to jest skomplikowane! Czy jest jakiś łatwiejszy sposób?

Podczas kopiowania wszystkich lub większości bajtów ze źródła do miejsca docelowego jest OSTATNIE łatwiejsze w użyciu tar:

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

Scenariusz

#!/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"

tarjest świetny, gdy masz pojedynczy (nie przyrostowy) transfer, a transfer kończy się w jednym przejściu. Z drugiej strony, rsyncz uchwytami do przekazywania, restartuje się i przelewy przyrostowe.
roaima

1
Oczywiście @roaima - nie uważam, że jest to odpowiednik tar. Zostawiłem tę mijającą informację na dzień, w którym będę ją czytał, aby rozwiązać problem, w którym rsync nie będzie w 100% potrzebny.
ndemou

-1

Można użyć tarza pomocą sshdo przesłania plików:

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

Zmień jparametr (for tar) na zw dwóch miejscach, jeśli chcesz skompresować archiwum gzipzamiast bzip2. Zwykle bzip2ma wyższą kompresję niż gzip, ale jest wolniejsza, więc zmieniaj ją w zależności od potrzeb (patrz: bzip2 vs gzip ).

Powiązane: Jak kopiować między dwoma zdalnymi hostami za pomocą tar przesyłanych strumieniowo do SSH ze zdalnego serwera, gdy znajduje się za zaporą?


Alternatywnie (aby zabezpieczyć przepustowość, ze względu na przezroczystą kompresję) można użyć sshfsdo zamontowania zdalnego systemu plików jako lokalnego i używać rsyncjak zwykle, np.

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

1
Lokalne podłączenie systemu plików nie pozwoli zaoszczędzić przepustowości między maszyną źródłową a lokalną. To będzie jednak zaoszczędzić przepustowość pomiędzy lokalnym i przeznaczenia (ponieważ nie jest montowany na miejscu). Używanie rsync w ten sposób ma sens tylko wtedy, gdy próbujesz zaoszczędzić przepustowość w miejscu docelowym.
Kevin Cox,
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.