Bagaimana cara me-rsync file di antara dua remote?


54

Saya ingin mentransfer file antara dua host jarak jauh yang menggunakan shell lokal, tetapi sepertinya rsync tidak mendukung sinkronisasi jika dua remote ditentukan sebagai berikut:

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

Solusi / perintah lain apa yang bisa saya gunakan untuk mencapai hasil yang serupa?



1
Sebenarnya Anda dapat rsync antara 2 host jarak jauh dengan memanfaatkan sshfs pada host ketiga. Cukup gunakan sshfs untuk me-mount host1 dan host2 pada host 3. Kemudian rsync antara 1 dan 2.
William Legg

@ WillillLegg kelemahan dengan menggunakan sshfsadalah bahwa kemudian rsyncmelihat sumber dan sistem file tujuan keduanya lokal, sehingga menonaktifkan algoritma delta-nya. Pada titik itu Anda hampir bisa juga menggunakannya cp -p. Lihat jawaban yang mengusulkan ini dan komentar selanjutnya.
roaima

Jawaban:


50

Seperti yang telah Anda temukan, Anda tidak dapat menggunakan rsync dengan sumber jarak jauh dan tujuan jarak jauh. Dengan asumsi kedua server tidak dapat berbicara langsung satu sama lain, dimungkinkan untuk menggunakan ssh to tunnel melalui mesin lokal Anda.

Dari pada

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

Anda bisa menggunakan ini

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

Jika Anda bertanya-tanya, -Ropsi mengatur saluran balik dari port 50000 di host1 yang memetakan (melalui mesin lokal Anda) ke port 22 di host2. Tidak ada koneksi langsung dari host1 ke host2.


1
Saya suka solusi @ roaima, tetapi saya tidak bisa membuatnya bekerja karena berbagai alasan. Pada akhirnya saya digunakan sshfsuntuk me-mount kedua direktori remote secara lokal, kemudian digunakan rsyncdi dua direktori yang dipasang secara lokal.
Aidan

Kemungkinan untuk melihat contoh di mana kunci digunakan? Mengalami kesulitan mencari tahu cara menggunakan -iuntuk menentukan kunci yang diperlukan untuk perintah ssh.
onassar

@ Makassar menambahkan -i key...parameter di dalam tanda kutip setelah sshperintah. Jika itu tidak membantu Anda, jangan ragu untuk mengajukan Pertanyaan Baru, merujuk jawaban ini untuk konteks
roaima

1
koneksi balik tidak membaca ~ / .ssh / config di sisi lokal - perlu menggunakan sesuatu yang dapat diselesaikan seolah-olah tidak ada file konfigurasi SSH
Florenz Kley

1
'Dengan asumsi kedua server tidak dapat berbicara langsung satu sama lain'. Solusi ini berfungsi di sekitar masalah firewall atau NAT yang mencegah koneksi SSH langsung . Namun, itu tidak membahas kasus di mana karena alasan keamanan pengguna sumber (pada host1) tidak memiliki kunci atau kredensial atau izin menulis tidak mencukupi di tujuan. Untuk itu lihat solusi Kevin Cox, atau gunakan koneksi tidak langsung menggunakan skrip atau scp -3.
Cedric Knight

22

Anda tidak mengatakan mengapa Anda tidak ingin masuk ke satu host dan kemudian menyalin ke host lain sehingga saya akan membagikan salah satu alasan dan solusi saya.

Saya tidak bisa masuk ke satu mesin kemudian rsync ke yang lain karena tidak ada host yang memiliki kunci SSH yang bisa masuk ke yang lain. Saya memecahkan masalah ini dengan menggunakan penerusan agen SSH untuk memungkinkan host pertama menggunakan kunci SSH saya saat saya masuk.

PERINGATAN: Penerusan SSH memungkinkan host untuk menggunakan kunci SSH Anda selama login Anda. Meskipun mereka tidak dapat menyalin kunci Anda, mereka dapat masuk ke mesin lain dengan itu. Pastikan Anda memahami risikonya dan jangan gunakan forwarding agen untuk mesin yang tidak Anda percayai.

Perintah berikut akan menggunakan penerusan agen SSH untuk membuka koneksi langsung dari host1ke host2. Ini memiliki keuntungan bahwa mesin yang menjalankan perintah tidak menghambat transfer.

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

3
+1 untuk menjelaskan kasus penggunaan yang valid (di mana pengguna jarak jauh di host1 tidak memiliki izin di server tujuan); untuk peringatan keamanan penting (gunakan port forwarding -Ddaripada -Aberkeliling jaringan daripada pembatasan kunci); untuk menjelaskan keuntungan; karena perintahnya singkat; dan itu benar-benar berfungsi. Perhatikan bahwa Anda mungkin perlu menentukan username@host1apakah itu berbeda dengan nama pengguna lokal. Juga bahwa rsync melakukan verifikasi kunci host ketika menghubungkan ke host2, jadi kunci host1 harus sudah ada di ~ / .ssh / known_hosts pada host2 atau perintah akan gagal.
Cedric Knight

Jawaban fenomenal, ini membantu saya mengatur beberapa hal di TeamCity yang tidak dapat saya lakukan sebelumnya (nb untuk pengguna TeamCity lainnya, Anda harus menambahkan "Build Fitur" yang disebut "agen SSH" ke konfigurasi build Anda sebelum menggunakan ssh -A, lihat pertemuan. jetbrains.com/display/TCD10/SSH+Agent ).
John Zwinck

12

Saya suka jawaban roaima, tapi jalannya sama di kedua contoh, mengaburkan mana. Kami telah menetapkan bahwa yang berikut ini tidak berfungsi:

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

Tapi ini tidak (saya menghilangkan bind_address eksplisit localhost dari -Ropsi karena itu defaultnya):

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

Perhatikan bahwa Anda harus mengatur kunci ssh dengan benar antara dua host jarak jauh, dengan kunci pribadi di host1 dan kunci publik di host2.

Untuk men-debug koneksi, pecah ini menjadi dua bagian dan tambahkan status verbose:

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

Jika ini berhasil, Anda akan memiliki shell di host1. Sekarang coba perintah rsync dari host1. Saya sarankan melakukan ini di jendela yang berbeda sehingga info ssh verbose tidak tercampur dengan info status rsync:

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

Dalam contoh saya path adalah sumber, tujuan. Ini rsyncdimulai pada host1 dengan target pada host2. (Anda bisa meminta klarifikasi dalam komentar.)
roaima

1
Saya akan berkomentar, tetapi Anda tidak dapat mengomentari pos orang lain tanpa reputasi 50+.
jaybrau

7

Memformat ulang jawaban oleh roaima dalam sintaks skrip bash (dan menambahkan karakter kelanjutan garis '\' untuk kejelasan) Saya secara acak memilih 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
menurut saya semua yang Anda lakukan adalah mengganti nama host sewenang-wenang dengan variabel?
Jeff Schaller

3
Ya saya lakukan. Ini menambah kejelasan bagi saya yang merupakan mesin sumber, yang merupakan target, dan di mana jalur sumber dan target pergi. Butuh beberapa saat untuk menyelesaikan semua itu dan tidak jelas dari nama host placeholder yang sederhana.
David I.

Lain kali jangan ragu untuk meningkatkan jawaban orang lain secara langsung dengan mengeditnya.
roaima

Jawaban ini adalah solusi bagi saya karena menggabungkan ssh-agent forwarding (-A) dengan reverse tunnel (-R).
camelthemammel

3

Cara yang ideal adalah menjalankannya rsyncdi salah satu server itu. Tetapi jika Anda tidak ingin menjalankan skrip di server jauh. Anda dapat menjalankan skrip pada sistem lokal Anda dan melakukan ssh dan menjalankan rsync di sana.

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

Juga, karena Anda mungkin menyadari rysnc melakukan sinkronisasi satu arah. Jika Anda ingin sinkronisasi dua arah, Anda dapat melihat osync ( https://github.com/deajan/osync ). Saya menggunakannya dan ternyata bermanfaat.


0

Sama seperti info tambahan:

Jika Anda menggunakan host melompat untuk menghubungkan dua mesin lain tetapi mereka tidak dapat menjangkau satu sama lain secara langsung, Anda dapat menggunakan sshfs sebagai media antara dua mesin ini seperti itu (pada host melompat):

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

SSHFS menyediakan dua jalur pada host melompat dan rsync mengelola sinkronisasi file seperti biasa (hanya dengan perbedaan yang sebenarnya dilakukan secara lokal).


1
Perhatikan bahwa kinerjanya akan mengerikan. Ini karena untuk mendeteksi perubahan, rsync akan membaca file dari server sumber, mentransfer semuanya melalui jaringan. Itu dikatakan jika Anda tidak dapat melakukan transfer langsung Anda harus makan ini jika Anda menggunakan rsync. Juga jangan me-mount tujuan, itu tidak perlu dan akan menyebabkan rsync untuk mengubah beberapa default karena menganggap itu berbicara ke disk lokal.
Kevin Cox

0

Anda dapat menjalankan rsyncd (server) di salah satu komputer.

Ini adalah pendekatan yang saya ambil, karena saya tidak ingin menggunakan ssh untuk mengizinkan 'sumber' (dalam kata-kata rsync) akses ke 'tujuan' sebagai root tanpa kata sandi (seperti yang diperlukan untuk menggunakan tunneling SSH dengan rsync di sebuah skrip)

Dalam kasus saya, saya cukup mengatur server rsyncd di komputer tujuan dengan satu pengguna diizinkan dari PC sumber dan menggunakan rsync dari sisi sumber.

Bagus sekali.


0

Coba gunakan ini. Ini bekerja untuk saya.

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

0

Script yang mudah digunakan

Selama bertahun-tahun saya telah melakukan ini berkali-kali dengan trik yang kurang lebih sama seperti dalam setiap jawaban lainnya di sini. Namun karena sangat mudah untuk mendapatkan detail yang salah dan menghabiskan banyak waktu untuk mencari tahu masalah saya telah membuat skrip di bawah ini:

  1. Memudahkan untuk menentukan semua detail (sumber, tujuan, opsi)
  2. Secara bertahap menguji setiap langkah dan memberikan umpan balik jika ada yang salah, sehingga Anda tahu apa yang harus diperbaiki.
  3. Bekerja di sekitar kasus di mana ssh -Agagal menyebarkan data otentikasi (tidak tahu mengapa ini terjadi kadang-kadang karena solusinya lebih mudah daripada menemukan akar penyebabnya)
  4. Akhirnya berhasil.

Cara menggunakan skrip

  1. Pastikan Anda dapat ssh ke kedua host dari localhost tanpa mengetik kata sandi.
  2. Atur variabel dalam beberapa baris pertama skrip
  3. Jalankan itu.

Bagaimana itu bekerja

Seperti yang saya katakan itu menggunakan trik yang sama seperti pada setiap jawaban lainnya di sini:

  • ssh ini -Rpilihan untuk ssh dari localhost ke host1 sementara pada saat yang sama menyiapkan port forwarding yang kemudian memungkinkan host1 untuk terhubung melalui localhost ke host2 ( -R localhost:$FREE_PORT:$TARGET_ADDR_PORT)
  • -AOpsi ssh untuk memungkinkan otentikasi mudah dari ssh chanel kedua

Ini rumit! Apakah ada cara yang lebih mudah?

Saat menyalin semua atau sebagian besar byte dari sumber ke tujuan, JAUH lebih mudah digunakan tar:

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

Naskah

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

tarluar biasa ketika Anda mendapat satu transfer (non-incremental) dan transfer Anda selesai dalam satu pass tunggal. Di sisi lain, rsyncdengan pegangan penerusan mulai ulang dan transfer tambahan.
roaima

1
Tentu saja @roaima - Saya tidak menganggap setara tar. Saya meninggalkan referensi lewat ini untuk hari ketika saya akan membaca ini untuk memecahkan masalah di mana rsync tidak akan 100% diperlukan.
ndemou

-1

Dimungkinkan untuk menggunakan tarvia sshuntuk mentransfer file:

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

Ubah jparameter (untuk tar) menjadi zdi dua tempat jika Anda ingin mengompres arsip dengan gzip, alih-alih bzip2. Biasanya bzip2memiliki kompresi yang lebih tinggi daripada gzip, tetapi lebih lambat, jadi ubah tergantung pada kebutuhan Anda (lihat: bzip2 vs gzip ).

Terkait: Bagaimana cara menyalin antara dua host jarak jauh menggunakan tar yang disalurkan ke SSH dari server jauh ketika di belakang firewall?


Atau (untuk mengamankan bandwidth, karena kompresi transparan) dimungkinkan sshfsuntuk me-mount sistem file jarak jauh sebagai lokal dan menggunakan rsyncseperti biasa, misalnya

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

1
Memasang sistem file secara lokal tidak akan menghemat bandwidth antara sumber dan mesin lokal. Namun itu akan menghemat bandwidth antara lokal dan tujuan (karena tidak dipasang secara lokal). Menggunakan rsync dengan cara ini hanya masuk akal jika Anda mencoba untuk menghemat bandwidth di tujuan.
Kevin Cox
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.