หลายคำสั่งระหว่าง SSH ภายในเซสชัน SSH


10

ฉันมีเครื่องท้องถิ่นซึ่งควรจะทำเซสชั่น SSH ไปยังmasterเครื่องระยะไกลและจากนั้นอีกเซสชั่น SSH ภายในจากmasterไปยังแต่ละระยะไกลบางส่วนslavesแล้วดำเนินการ 2 คำสั่งคือการลบไดเรกทอรีที่เฉพาะเจาะจงและสร้างมันขึ้นมาใหม่

โปรดสังเกตว่าเครื่องโลคัลมี SSH ที่ไม่มีรหัสผ่านไปที่มาสเตอร์และมาสเตอร์มี SSH ที่ไม่มีรหัสผ่านไปยังทาส นอกจากนี้ชื่อโฮสต์ทั้งหมดเป็นที่รู้จักใน.ssh/configเครื่องท้องถิ่น / เครื่องต้นแบบและชื่อโฮสต์ของทาสอยู่ในเครื่องslaves.txtและฉันอ่านจากที่นั่น

ดังนั้นสิ่งที่ฉันทำและทำงานคือ:

username="ubuntu"
masterHostname="myMaster"
while read line
do

    #Remove previous folders and create new ones.
    ssh -n $username@$masterHostname "ssh -t -t $username@$line "rm -rf Input Output Partition""
    ssh -n $username@$masterHostname "ssh -t -t $username@$line "mkdir -p EC2_WORKSPACE/$project Input Output Partition""


    #Update changed files...
    ssh -n $username@$masterHostname "ssh -t -t $username@$line "rsync --delete -avzh /EC2_NFS/$project/* EC2_WORKSPACE/$project""

done < slaves.txt 

คลัสเตอร์นี้อยู่ใน Amazon EC2 และฉันสังเกตเห็นว่ามี 6 เซสชัน SSH ที่สร้างขึ้นในแต่ละรอบซ้ำซึ่งทำให้เกิดความล่าช้าอย่างมีนัยสำคัญ ฉันต้องการรวม 3 คำสั่งเหล่านี้เป็น 1 เพื่อรับการเชื่อมต่อ SSH น้อยลง ดังนั้นฉันจึงพยายามรวมคำสั่ง 2 คำแรกเข้าด้วยกัน

ssh -n $username@$masterHostname "ssh -t -t $username@$line "rm -rf Input Output Partition && mkdir -p EC2_WORKSPACE/$project Input Output Partition""

แต่มันไม่ทำงานตามที่คาดไว้ ดูเหมือนว่าจะดำเนินการครั้งแรก ( rm -rf Input Output Partition) แล้วออกจากเซสชั่นและไป ฉันจะทำอย่างไร


3
แทนที่จะเป็นทางอ้อมในคำสั่งคุณสามารถใช้-Jตัวเลือกที่จะกำหนดโฮสต์กระโดดของคุณ
Hauleth

คำตอบ:


15

พิจารณาว่า&&เป็นตัวดำเนินการเชิงตรรกะ มันไม่ได้หมายความว่า "ยังใช้คำสั่งนี้" มันหมายถึง "ใช้คำสั่งนี้หากประสบความสำเร็จอีก"

ซึ่งหมายความว่าหากrmคำสั่งล้มเหลว (ซึ่งจะเกิดขึ้นหากหนึ่งในสามไดเรกทอรีไม่มีอยู่) ดังนั้นmkdirจะไม่ถูกดำเนินการ สิ่งนี้ไม่ได้ดูเหมือนพฤติกรรมที่คุณต้องการ หากไดเรกทอรีไม่มีอยู่อาจเป็นไปได้ที่จะสร้างมันขึ้นมา

ใช้ ;

ใช้เครื่องหมายอัฒภาค;เพื่อคั่นคำสั่ง คำสั่งจะถูกเรียกใช้ตามลำดับโดยรอก่อนที่จะดำเนินการต่อในครั้งถัดไป แต่ความสำเร็จหรือความล้มเหลวของพวกเขาจะไม่มีผลกระทบต่อกัน

หนีคำพูดภายใน

ควรใส่เครื่องหมายอัญประกาศในเครื่องหมายคำพูดอื่นไม่เช่นนั้นคุณจะสร้างจุดสิ้นสุดพิเศษและจุดเริ่มต้น คำสั่งของคุณ:

ssh -n $username@$masterHostname "ssh -t -t $username@$line "rm -rf Input Output Partition && mkdir -p EC2_WORKSPACE/$project Input Output Partition""

กลายเป็น:

ssh -n $username@$masterHostname "ssh -t -t $username@$line \"rm -rf Input Output Partition && mkdir -p EC2_WORKSPACE/$project Input OutputPartition\""

คำสั่งปัจจุบันของคุณเนื่องจากการขาดเครื่องหมายคำพูดที่หลบหนีควรจะถูกเรียกใช้งาน:

ssh -n $username@$masterHostname "ssh -t -t $username@$line "rm -rf Input Output Partition

หากประสบความสำเร็จ:

mkdir -p EC2_WORKSPACE/$project Input Output Partition"" # runs on your local machine

คุณจะสังเกตเห็นว่าการเน้นไวยากรณ์แสดงคำสั่งทั้งหมดเป็นสีแดงที่นี่ซึ่งหมายความว่าคำสั่งทั้งหมดคือสตริงที่ส่งผ่านไปยัง ssh ตรวจสอบเครื่องท้องถิ่นของคุณ คุณอาจมีไดเรกทอรีInput OutputและPartitionที่ที่คุณใช้งานอยู่


ฉันเข้าใจประเด็นของคุณ ส่วนหนึ่งที่ฉันสับสนคือเซมิโคลอนเนื่องจากฉันคิดว่ามันจะดำเนินการมากกว่า 1 คำสั่งในเวลาเดียวกันซึ่งเป็นสาเหตุที่ฉันไม่ได้ใช้มัน
mgus

อัฒภาคจะไม่ทำให้คำสั่งดำเนินการในเวลาเดียวกันดูที่นี่เป็นข้อมูลอ้างอิงสำหรับการดำเนินการคำสั่ง &คำสั่งสาเหตุที่จะเรียกใช้ int เขาพื้นหลังซึ่งหมายความว่าพวกเขาเคยชินจะรอให้เสร็จสิ้นก่อนที่จะย้ายไปยังถัดไป
Centimane

10

คุณสามารถกำหนดได้ใน jumpbox Multiplexing ใน OpenSSH

การมัลติเพล็กซ์คือความสามารถในการส่งสัญญาณมากกว่าหนึ่งสัญญาณผ่านสายเดียวหรือการเชื่อมต่อ ด้วยการทำมัลติเพล็กซ์ OpenSSH สามารถใช้การเชื่อมต่อ TCP ที่มีอยู่อีกครั้งสำหรับเซสชัน SSH พร้อมกันหลายรายการแทนที่จะสร้างใหม่ในแต่ละครั้ง

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

สำหรับสิ่งที่ต้องทำใน/etc/ssh/ssh_config:

ControlMaster auto
ControlPath ~/.ssh/controlmasters/ssh_mux_%h_%p_%r
ControlPersist 30m

ด้วยวิธีนี้การเชื่อมต่อที่ต่อเนื่องใด ๆ ที่ทำกับเซิร์ฟเวอร์เดียวกันใน 30 นาทีต่อไปนี้จะถูกนำมาใช้ซ้ำการเชื่อมต่อ ssh ก่อนหน้านี้

คุณยังสามารถกำหนดสำหรับเครื่องหรือกลุ่มของเครื่อง นำมาจากลิงก์ที่ให้ไว้

Host machine1
    HostName machine1.example.org
    ControlPath ~/.ssh/controlmasters/%r@%h:%p
    ControlMaster auto
    ControlPersist 10m

นั่นดูน่าสนใจ! มีวิธีการเปิดและปิดอย่างชัดเจนสำหรับการเชื่อมต่อที่กำหนดหรือไม่? ดูเหมือนว่า overkill เป็นอย่างมากเปลี่ยนการเชื่อมต่อ SSH ทั้งหมดสำหรับกรณีการใช้งานนี้ สามารถใช้ในลักษณะที่แม่นยำยิ่งขึ้นได้หรือไม่? ในการเริ่มต้นการมัลติเพล็กซ์เฉพาะการเชื่อมต่อที่แน่นอน
Centimane

@Centimane ใช่อัปเดตคำตอบ
Rui F Ribeiro

1
/tmp/ฉันจะแนะนำให้ใส่ซ็อกเก็ตในบ้านของผู้ใช้มากกว่าโลกอ่านเขียน
heemayl

@ heemayl จุดดี ฉันจะแก้ไขมันเมื่ออยู่ในคอมพิวเตอร์
Rui F Ribeiro

@RuiFRibeiro นอกจากนี้ยังดูเหมือนว่าตามman ssh, ControlPath, ControlMasterและControlPersistเป็นตัวเลือกที่ถูกต้องที่จะผ่านคำสั่งโดยใช้ssh -oอาจเป็นกรณีการใช้งานที่แม่นยำยิ่งขึ้นตั้งค่ามัลติเพล็กซ์ในsshสคริปต์แรกและรีไซเคิลเพื่อคนอื่น แต่หลีกเลี่ยงการปรับประสิทธิภาพ ฉันสงสัยว่าเกณฑ์มาตรฐานการทำมัลติเพล็กซิ่ง VS ไม่ใช่สำหรับการเชื่อมต่อ SSH 3 ครั้งเนื่องจาก "ยังมีความล่าช้าอย่างมากเมื่อเปิดการเชื่อมต่อใหม่"
Centimane

4

คุณสามารถใส่คำสั่งทั้งหมดลงในสคริปต์แยกต่างหากบนเซิร์ฟเวอร์ "มาสเตอร์" ของคุณ

สคริปต์ต้นแบบ

#!/bin/bash
rm -rf "Input Output Partition"
mkdir -p "EC2_WORKSPACE/$project Input Output Partition"

จากนั้นในสคริปต์ ssh ของคุณเรียกว่าดังนี้: สคริปต์ SSH

username="ubuntu"
masterHostname="myMaster"
while read line
do
ssh -n $username@$masterHostname "ssh -t -t $username@$line < /path/to/masterscript.sh"
ssh -n $username@$masterHostname "ssh -t -t $username@$line "rsync --delete -avzh /EC2_NFS/$project/* EC2_WORKSPACE/$project""
done < slaves.txt 

หรือ ถ้าไฟล์ทั้งหมดจะต้องอยู่ในเครื่องเริ่มต้นคุณสามารถทำสิ่งนี้:

script1

script2="/path/to/script2"
username="ubuntu"
while read line; do
cat $script2 | ssh -t -t $username@line
done < slaves.txt

script2

#!/bin/bash
rm -rf "Input Output Partition"
mkdir -p "EC2_WORKSPACE/$project Input Output Partition"
rsync --delete -avzh "/EC2_NFS/$project/* EC2_WORKSPACE/$project"

สคริปต์ SSH

script1="/path/to/script1"
username="ubuntu"
masterHostname="myMaster"
cat $script1 | ssh -n $username@$masterHostname

1

บางครั้งที่ผ่านมาฉันมีโอกาสใช้ซ็อกเก็ตควบคุมเหมือนคำตอบอื่น ๆ ที่แนะนำ (คำตอบนี้คือการรวมกันของการใช้ซ็อกเก็ตควบคุมเช่นคำตอบนี้และสคริปต์เช่นคำตอบนี้ )

กรณีการใช้งานเป็นแฮ็ค: authorized_keysผู้ใช้เป้าหมายถูกเขียนทับเป็นระยะโดยงานที่กำหนดไว้และฉันต้องการทดสอบสิ่งต่าง ๆ อย่างรวดเร็วโดยไม่ต้องใช้เทปสีแดงเพื่อเพิ่มบางสิ่งลงในไฟล์นั้น ดังนั้นฉันจะเซ็ต a while loop ซึ่งเพิ่มคีย์ไปยังไฟล์นั้นตามต้องการเรียกใช้การทดสอบของฉันและยกเลิกการวนซ้ำ อย่างไรก็ตามจะมีหน้าต่างเล็ก ๆ ที่จัดตารางงานจะเขียนทับไฟล์และวงของฉันจะยังคงได้รับsleepไอเอ็นจี ดังนั้นการตั้งค่าซ็อกเก็ตควบคุมเมื่อเริ่มต้นจะทำให้สคริปต์ SSH ของฉันในภายหลังโดยไม่มีปัญหา:

#! /bin/bash -xe
. "${CONFIG_DIR}/scripts/setup-ssh.sh"

# Build and test
export TEST_LABEL="${_started_by}-${BUILD_TAG%-BUILD*}"
#...
xargs --arg-file test-list \
    --no-run-if-empty \
    --process-slot-var=NUM \
    --max-procs=${#SERVERS[@]} \
    --max-args="${BATCH_SIZE:-20}" \
    "${CONFIG_DIR}/scripts/run-test.sh"

อยู่ที่ไหนsetup-ssh.sh:

export SSH_CONFIG="${CONFIG_DIR}/scripts/.ssh-config"
mapfile -t SERVERS < "${CONFIG_DIR}/scripts/hosts"

for SERVER in "${SERVERS[@]}"
do
    while ! ssh -F "${SSH_CONFIG}" "${SERVER}" -fnN; do sleep 1; done
    scp -F "${SSH_CONFIG}" "${CONFIG_DIR}/scripts/ssh-script.sh" "${SERVER}":"${TEST_LABEL}.sh"
done

และ.ssh-config:

Host test-*
  User test
  StrictHostKeyChecking no
  ControlMaster auto
  ControlPath /tmp/ssh-%h-%p-%r

และrun-test.sh:

mapfile -t TEST_SERVERS < "${CONFIG_DIR}/scripts/hosts"
ssh -F "${SSH_CONFIG}" "${TEST_SERVERS[$NUM]}" "./${TEST_LABEL}.sh"

ลำดับจะเป็นดังนี้:

  • สคริปต์หลัก (แสดงเป็นครั้งแรก) setup-ssh.shแหล่งที่มา
  • setup-ssh.shยุ่งลูปเซิร์ฟเวอร์จนกว่าพวกเขาทั้งหมดจะมีการตั้งค่าซ็อกเก็ตการควบคุม hostsไฟล์เพียงแค่แสดงหนึ่งชื่อโฮสต์เซิร์ฟเวอร์ต่อบรรทัด
  • เนื่องจากการกำหนดค่าที่ระบุซ็อกเก็ตการควบคุมอยู่ในเท่านั้น${CONFIG_DIR}/scripts/.ssh-configเว้นแต่ฉันจะระบุไฟล์ที่ใช้-Fการเชื่อมต่อ SSH จะไม่ใช้มัน ดังนั้นสิ่งนี้ช่วยให้ฉันใช้ซ็อกเก็ตควบคุมเฉพาะที่ฉันต้องการโดยใช้Fตัวเลือก
  • สคริปต์การตั้งค่ายังคัดลอกสคริปต์การดำเนินการทดสอบไปยังเซิร์ฟเวอร์ สคริปต์การดำเนินการเองมีคำสั่งมากมายและเนื่องจากฉันคัดลอกสคริปต์การเรียกใช้งานฉันไม่ต้องกังวลเกี่ยวกับเลเยอร์เพิ่มเติมของการอ้างถึง SSH (และค่าโสหุ้ยการรับรู้เพิ่มเติมสำหรับการค้นหาสิ่งที่ได้รับการขยายเมื่อ)
  • จากนั้นสคริปต์หลักใช้xargsเพื่อกระจายเวิร์กโหลดบนเซิร์ฟเวอร์โดยเริ่มงานใหม่ทันทีที่เรียกใช้งานเสร็จ
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.