วิธีการ rsync ไฟล์ระหว่างรีโมทสองรีโมท?


54

ฉันต้องการถ่ายโอนไฟล์ระหว่างสองรีโมตโฮสต์โดยใช้บนโลคัลเชลล์ แต่ดูเหมือนว่า rsync ไม่สนับสนุนการซิงโครไนซ์หากมีการระบุรีโมตสองรายการดังนี้:

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

วิธีแก้ปัญหา / คำสั่งอื่นใดที่ฉันสามารถใช้เพื่อให้ได้ผลลัพธ์ที่คล้ายกัน



1
ที่จริงคุณสามารถ rsync ระหว่าง 2 รีโมตโฮสต์โดยการใช้ประโยชน์จาก sshfs บนโฮสต์ที่ 3 เพียงใช้ sshfs เพื่อ mount host1 และ host2 บนโฮสต์ 3 จากนั้น rsync ระหว่าง 1 และ 2
William Legg

@WilliamLegg ข้อเสียของการใช้sshfsคือrsyncเห็นระบบแฟ้มต้นทางและปลายทางทั้งคู่เป็นแบบโลคัลดังนั้นจึงปิดใช้งานอัลกอริทึมของเดลต้า ณ cp -pจุดที่คุณเกือบเช่นกันอาจจะเพียงแค่ใช้ ดูคำตอบที่เสนอนี้และความคิดเห็นที่ตามมา
roaima

คำตอบ:


50

ในขณะที่คุณค้นพบว่าคุณไม่สามารถใช้ rsync กับแหล่งข้อมูลระยะไกลและปลายทางระยะไกล สมมติว่าเซิร์ฟเวอร์ทั้งสองไม่สามารถพูดคุยกันได้โดยตรงคุณสามารถใช้ ssh to tunnel ผ่านเครื่องท้องถิ่นของคุณได้

แทน

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

@onassar เพิ่ม-i key...พารามิเตอร์ภายในเครื่องหมายคำพูดหลังsshคำสั่ง หากวิธีนี้ไม่ได้ช่วยให้คุณรู้สึกอิสระที่จะถามคำถามใหม่ให้อ้างอิงคำตอบสำหรับบริบทนี้
roaima

1
การเชื่อมต่อย้อนกลับไม่ได้อ่าน ~ / .ssh / config ที่ด้านโลคัล - จำเป็นต้องใช้บางสิ่งที่สามารถแก้ไขได้ราวกับว่าไม่มีไฟล์ปรับแต่ง SSH
Florenz Kley

1
'สมมติว่าเซิร์ฟเวอร์ทั้งสองไม่สามารถพูดคุยกันได้โดยตรง' การแก้ปัญหานี้ไม่หลีกเลี่ยงไฟร์วอลล์หรือ NAT ปัญหาที่ป้องกันไม่ให้ SSH โดยตรงการเชื่อมต่อ อย่างไรก็ตามไม่ได้ระบุถึงกรณีที่ผู้ใช้แหล่งข้อมูล (บนโฮสต์ 1) ไม่มีเหตุผลหรือความปลอดภัยในการใช้งานสำหรับปลายทาง scp -3สำหรับวิธีการแก้ปัญหาที่เห็นว่าเควินคอคส์หรือรีสอร์ทเพื่อการเชื่อมต่อทางอ้อมโดยใช้สคริปต์หรือ
Cedric Knight

22

คุณไม่ได้พูดว่าทำไมคุณไม่ต้องการเข้าสู่โฮสต์หนึ่งแล้วคัดลอกไปที่อื่นดังนั้นฉันจะแบ่งปันหนึ่งในเหตุผลและวิธีแก้ปัญหาของฉัน

ฉันไม่สามารถเข้าสู่เครื่องหนึ่งแล้ว rsync ไปที่อื่นเพราะไม่มีโฮสต์ที่มีคีย์ SSH ที่สามารถเข้าสู่ระบบอื่น ๆ ฉันแก้ไขได้โดยใช้การส่งต่อตัวแทน SSH เพื่อให้โฮสต์แรกใช้คีย์ SSH ของฉันในขณะที่ฉันเข้าสู่ระบบ

คำเตือน:การส่งต่อ SSH อนุญาตให้โฮสต์ใช้คีย์ SSH ของคุณในช่วงเวลาของการเข้าสู่ระบบของคุณ ในขณะที่พวกเขาไม่สามารถคัดลอกคีย์ของคุณพวกเขาสามารถเข้าสู่เครื่องอื่น ๆ ด้วย ตรวจสอบให้แน่ใจว่าคุณเข้าใจความเสี่ยงและไม่ใช้ตัวแทนส่งต่อสำหรับเครื่องที่คุณไม่ไว้วางใจ

คำสั่งต่อไปนี้จะใช้การส่งต่อตัวแทน SSH เปิดการเชื่อมต่อโดยตรงไปยังhost1 host2นี่เป็นข้อได้เปรียบที่เครื่องที่รันคำสั่งไม่ได้เป็นคอขวดในการโอน

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

3
+1 สำหรับการอธิบายกรณีการใช้ที่ถูกต้อง (ที่ผู้ใช้รีโมตบนโฮสต์ 1 ไม่มีสิทธิ์บนเซิร์ฟเวอร์ปลายทาง); สำหรับข้อควรระวังด้านความปลอดภัยที่สำคัญ (ใช้การส่งต่อพอร์ต-Dแทนที่จะ-Aไปที่เครือข่ายแทนที่จะใช้ข้อ จำกัด ที่สำคัญ) เพื่ออธิบายข้อดี; สำหรับคำสั่งที่สั้น และมันใช้งานได้จริง โปรดทราบว่าคุณอาจจำเป็นต้องระบุusername@host1ว่าชื่อนั้นแตกต่างจากชื่อผู้ใช้ท้องถิ่นหรือไม่ นอกจากนี้ rsync จะทำการตรวจสอบคีย์โฮสต์เมื่อเชื่อมต่อกับ host2 ดังนั้นคีย์ของ host1 ควรอยู่ใน ~ / .ssh / known_hosts บน host2 มิฉะนั้นคำสั่งจะล้มเหลว
Cedric Knight

คำตอบที่เป็นปรากฎการณ์นี้ช่วยให้ฉันแต่งบางสิ่งบางอย่างใน TeamCity ว่าผมไม่สามารถที่จะทำก่อน (nb สำหรับผู้ใช้ TeamCity อื่น ๆ ที่คุณต้องเพิ่ม "สร้างคุณลักษณะ" เรียกว่า "ตัวแทน SSH" เพื่อสร้างปรับแต่งของคุณก่อนที่จะใช้ssh -Aดูบรรจบกัน jetbrains.com/display/TCD10/SSH+Agent )
John Zwinck

12

ฉันชอบคำตอบของ roaima แต่เส้นทางนั้นเหมือนกันในทั้งสองตัวอย่างซึ่งคลุมเครือ เราได้พิสูจน์แล้วว่าสิ่งต่อไปนี้ใช้ไม่ได้:

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 และพับลิกคีย์บนโฮสต์ 2

หากต้องการดีบักการเชื่อมต่อให้แบ่งส่วนนี้ออกเป็นสองส่วนและเพิ่มสถานะ verbose:

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

หากใช้งานได้คุณจะมีเชลล์บน host1 ตอนนี้ลองใช้คำสั่ง rsync จาก host1 ฉันแนะนำให้ทำในหน้าต่างอื่นเพื่อให้ข้อมูล verbose ssh ไม่ได้ปะปนกันกับข้อมูลสถานะ rsync:

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

ในตัวอย่างของฉันเส้นทางคือต้นทางปลายทาง rsyncจะเริ่มใน host1 กับเป้าหมายใน host2 (คุณสามารถขอให้มีการชี้แจงในความคิดเห็น.)
roaima

1
ฉันจะแสดงความคิดเห็น แต่คุณไม่สามารถแสดงความคิดเห็นในโพสต์ของคนอื่นโดยไม่ต้องชื่อเสียง 50+
jaybrau

7

การจัดรูปแบบคำตอบใหม่โดย 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
ดูเหมือนว่าสิ่งที่คุณทำทั้งหมดจะถูกแทนที่ชื่อโฮสต์ตามอำเภอใจของเขาด้วยตัวแปรหรือไม่?
Jeff Schaller

3
ใช่ฉันทำ. มันเพิ่มความชัดเจนให้ฉันซึ่งเป็นเครื่องต้นทางซึ่งเป็นเป้าหมายและเส้นทางที่ต้นทางและปลายทางไป ฉันใช้เวลาพอสมควรที่จะทำงานทั้งหมดและมันไม่ชัดเจนจากชื่อโฮสต์ตัวยึดตำแหน่งที่เรียบง่าย
David I.

ครั้งต่อไปโปรดปรับปรุงคำตอบของคนอื่นโดยตรงโดยแก้ไข
roaima

คำตอบนี้เป็นคำตอบสำหรับฉันเนื่องจากรวมการส่งต่อ ssh-agent (-A) เข้ากับ reverse tunnel (-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 เปลี่ยนค่าเริ่มต้นเพราะคิดว่ามันกำลังพูดกับดิสก์ในเครื่อง
Kevin Cox

0

คุณสามารถเรียกใช้ rsyncd (เซิร์ฟเวอร์) บนคอมพิวเตอร์เครื่องใดเครื่องหนึ่ง

นี่เป็นวิธีการที่ฉันใช้เนื่องจากฉันไม่ต้องการใช้ ssh เพื่ออนุญาตให้ 'source' (ในถ้อยคำ rsync) เข้าถึง 'ปลายทาง' ในฐานะรูทโดยไม่มีรหัสผ่าน (ตามที่จำเป็นต้องใช้ SSH tunneling กับ 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 ไปยังโฮสต์ทั้งสองจาก localhost โดยไม่ต้องพิมพ์รหัสผ่าน
  2. ตั้งค่าตัวแปรในสองสามบรรทัดแรกของสคริปต์
  3. ดำเนินการ

มันทำงานอย่างไร

อย่างที่ฉันบอกว่ามันใช้อุบายแบบเดียวกันกับคำตอบอื่น ๆ ที่นี่:

  • -Rตัวเลือกของ ssh เพื่อ ssh จาก localhost ไปยัง host1 ในขณะเดียวกันการตั้งค่าการส่งต่อพอร์ตที่อนุญาตให้ host1 เชื่อมต่อผ่าน localhost ไปยัง host2 ( -R localhost:$FREE_PORT:$TARGET_ADDR_PORT)
  • -Aตัวเลือกของ ssh เพื่อให้ง่ายในการตรวจสอบความถูกต้องของ ssh chelel ที่สอง

นี่มันซับซ้อน! มีวิธีง่ายกว่านี้ไหม?

เมื่อคัดลอกทั้งหมดหรือไบต์มากที่สุดจากต้นทางไปยังปลายทางที่มันไกลง่ายต่อการใช้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

เป็นไปได้ที่จะใช้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 piped ใน SSH จากเซิร์ฟเวอร์ระยะไกลเมื่ออยู่หลังไฟร์วอลล์ได้อย่างไร


อีกทางหนึ่ง (เพื่อความปลอดภัยของแบนด์วิดท์เนื่องจากการบีบอัดแบบโปร่งใส) เป็นไปได้ที่จะใช้sshfsเพื่อเมาท์ระบบไฟล์ระยะไกลเป็นแบบโลคัลและใช้rsyncตามปกติเช่น

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

1
การติดตั้งระบบไฟล์แบบโลคัลจะไม่บันทึกแบนด์วิดท์ใด ๆ ระหว่างต้นทางและเครื่องโลคัล มันจะอย่างไรก็ตามบันทึกแบนด์วิธระหว่างท้องถิ่นและปลายทาง (ที่ยังไม่ได้ติดตั้งในประเทศ) การใช้ rsync ด้วยวิธีนี้จะสมเหตุสมผลถ้าคุณพยายามประหยัดแบนด์วิดท์ในปลายทาง
Kevin Cox
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.