Nhiều lệnh trong một SSH trong phiên SSH


10

Tôi có một máy cục bộ có nhiệm vụ tạo một phiên SSH cho một mastermáy từ xa và sau đó là một phiên SSH bên trong từ một masterđến một số điều khiển từ xa slaves, sau đó thực hiện 2 lệnh tức là xóa một thư mục cụ thể và tạo lại nó.

Lưu ý rằng máy cục bộ có SSH không mật khẩu cho chủ và chủ có SSH không mật khẩu cho nô lệ. Ngoài ra tất cả các tên máy chủ được biết đến trong .ssh/configcác máy cục bộ / máy chủ và tên máy chủ của nô lệ ở slaves.txtđịa phương và tôi đọc chúng từ đó.

Vì vậy, những gì tôi làm và làm việc là thế này:

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 

Cụm này nằm trên Amazon EC2 và tôi đã nhận thấy rằng có 6 phiên SSH được tạo tại mỗi lần lặp lại gây ra độ trễ đáng kể. Tôi muốn kết hợp 3 lệnh này thành 1 để có ít kết nối SSH hơn. Vì vậy, tôi đã cố gắng kết hợp 2 lệnh đầu tiên thành

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

Nhưng nó không hoạt động như mong đợi. Nó dường như thực thi cái đầu tiên ( rm -rf Input Output Partition) và sau đó thoát khỏi phiên và tiếp tục. Tôi có thể làm gì?


3
Thay vì chỉ định như vậy trong lệnh, bạn có thể sử dụng -Jtùy chọn xác định máy chủ nhảy của mình.
Hauleth

Câu trả lời:


15

Hãy coi đó &&là một toán tử logic. Nó không có nghĩa là "cũng chạy lệnh này" nó có nghĩa là "chạy lệnh này nếu lệnh kia thành công".

Điều đó có nghĩa là nếu rmlệnh thất bại (sẽ xảy ra nếu một trong ba thư mục không tồn tại) thì mkdirsẽ không được thực thi. Điều này không giống như hành vi bạn muốn; nếu các thư mục không tồn tại, có lẽ tốt để tạo chúng.

Sử dụng ;

Dấu chấm phẩy ;được sử dụng để phân tách các lệnh. Các lệnh được chạy tuần tự, chờ đợi từng cái trước khi tiếp tục tiếp theo, nhưng thành công hay thất bại của chúng không có tác động gì với nhau.

Thoát báo giá bên trong

Các trích dẫn bên trong các trích dẫn khác phải được thoát, nếu không, bạn đang tạo thêm điểm cuối và điểm bắt đầu. Lệnh của bạn:

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

Trở thành:

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

Lệnh hiện tại của bạn, vì thiếu dấu ngoặc kép nên được thực thi:

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

nếu điều đó thành công:

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

Bạn sẽ nhận thấy việc tô sáng cú pháp hiển thị toàn bộ lệnh có màu đỏ ở đây, có nghĩa là toàn bộ lệnh là chuỗi được truyền cho ssh. Kiểm tra máy cục bộ của bạn; bạn có thể có các thư mục Input OutputPartitionnơi bạn đang chạy này.


Tôi hiểu điểm của bạn. Một phần tôi đã nhầm lẫn là dấu chấm phẩy, vì tôi nghĩ rằng nó sẽ thực thi nhiều hơn 1 lệnh cùng một lúc, đó là lý do tại sao tôi không sử dụng nó.
mgus

Dấu chấm phẩy sẽ không khiến các lệnh thực thi đồng thời xem ở đây như một tài liệu tham khảo để thực hiện các lệnh. Các &lệnh nguyên nhân để chạy int ông nền, mà có nghĩa là họ sẽ không được chờ đợi đến khi kết thúc trước khi chuyển sang tiếp theo.
Centimane

10

Bạn luôn có thể xác định trong Ghép kênh của hộp nhảy trong OpenSSH

Ghép kênh là khả năng gửi nhiều tín hiệu qua một đường truyền hoặc kết nối. Với ghép kênh, OpenSSH có thể sử dụng lại kết nối TCP hiện có cho nhiều phiên SSH đồng thời thay vì tạo một kết nối mới mỗi lần.

Một lợi thế với ghép kênh SSH là chi phí tạo kết nối TCP mới bị loại bỏ. Tổng số kết nối mà máy có thể chấp nhận là tài nguyên hữu hạn và giới hạn đáng chú ý hơn trên một số máy so với các máy khác và thay đổi rất nhiều tùy thuộc vào cả tải và sử dụng. Cũng có độ trễ đáng kể khi mở một kết nối mới. Các hoạt động liên tục mở các kết nối mới có thể được tăng tốc đáng kể bằng cách sử dụng ghép kênh.

Cho rằng làm trong /etc/ssh/ssh_config:

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

Theo cách này, mọi kết nối liên tiếp được thực hiện cho cùng một máy chủ trong 30 phút sau sẽ được sử dụng lại kết nối ssh trước đó.

Bạn cũng có thể định nghĩa nó cho một máy hoặc một nhóm máy. Lấy từ liên kết được cung cấp.

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

Nó thật thú vị! Có cách nào để bật và tắt một cách rõ ràng cho một kết nối nhất định không? Có vẻ như quá mức cần thiết để thay đổi mạnh mẽ tất cả các kết nối SSH cho trường hợp sử dụng này. Nó có thể được sử dụng một cách chính xác hơn? Để bắt đầu ghép kênh chỉ một kết nối nhất định?
Centimane

@Centimane yeah, đã cập nhật câu trả lời
Rui F Ribeiro

1
Tôi sẽ đề nghị đặt ổ cắm trong nhà của người dùng chứ không phải là một thế giới có thể đọc được /tmp/.
heemayl

@heemayl Điểm tốt. Tôi sẽ chỉnh sửa nó khi ở trong máy tính.
Rui F Ribeiro

@RuiFRibeiro Cũng có vẻ như, theo man ssh, ControlPath, ControlMasterControlPersistnhững lựa chọn hợp lệ để vượt qua một sshlệnh sử dụng -o. Có thể là một trường hợp sử dụng chính xác hơn nữa, thiết lập ghép kênh trong sshtập lệnh đầu tiên và tái chế nó cho các tập lệnh khác, nhưng nếu không thì sẽ tránh bị phạt hiệu năng. Tôi tự hỏi điểm chuẩn của ghép kênh VS không dành cho 3 kết nối SSH, cho rằng "Cũng có độ trễ đáng kể khi mở kết nối mới"
Centimane

4

Bạn có thể đặt tất cả các lệnh của mình vào một tập lệnh riêng trên máy chủ "chính".

Kịch bản chính

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

Sau đó, trong tập lệnh ssh của bạn gọi nó như thế này: SSH Script

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 

HOẶC nếu tất cả các tệp phải ở trên máy ban đầu, bạn có thể làm một cái gì đó như thế này:

kịch bản1

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

kịch bản2

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

kịch bản ssh

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

1

Cách đây một thời gian, tôi có dịp sử dụng các socket điều khiển như các câu trả lời khác khuyên dùng (câu trả lời này thực chất là sự kết hợp của việc sử dụng các socket điều khiển như câu trả lời này và các đoạn script như câu trả lời này ).

Trường hợp sử dụng là một hack: Người authorized_keysdùng mục tiêu đã bị ghi đè định kỳ bởi một tác vụ theo lịch trình và tôi muốn nhanh chóng kiểm tra mọi thứ mà không cần thông qua băng đỏ để thêm một cái gì đó vào tệp đó. Vì vậy, tôi sẽ thiết lập một vòng lặp while có thêm khóa vào tệp đó khi cần, chạy thử nghiệm của tôi và hủy vòng lặp. Tuy nhiên, sẽ có một cửa sổ nhỏ nơi tác vụ theo lịch trình sẽ ghi đè lên tệp và vòng lặp của tôi vẫn sẽ được xử sleeplý. Vì vậy, thiết lập ổ cắm điều khiển khi bắt đầu sẽ cho phép tập lệnh SSH của tôi sau này không gặp sự cố:

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

Ở đâu 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"

Trình tự diễn ra như sau:

  • Các kịch bản chính (hiển thị đầu tiên) nguồn setup-ssh.sh.
  • setup-ssh.shbusy-loop các máy chủ cho đến khi tất cả chúng có thiết lập ổ cắm điều khiển. Các hoststập tin chỉ đơn giản là liệt kê tên máy chủ lưu trữ trên mỗi dòng.
  • Vì cấu hình chỉ định ổ cắm điều khiển chỉ ở trong ${CONFIG_DIR}/scripts/.ssh-config, trừ khi tôi chỉ định tệp đó bằng cách sử dụng -F, các kết nối SSH sẽ không sử dụng nó. Vì vậy, điều này cho phép tôi chỉ sử dụng ổ cắm điều khiển khi tôi cần chúng bằng Ftùy chọn.
  • Tập lệnh thiết lập cũng sao chép tập lệnh thực thi kiểm tra đến các máy chủ. Bản thân tập lệnh thực thi chứa một loạt các lệnh và vì tôi đã sao chép tập lệnh thực thi, tôi không phải lo lắng về một lớp trích dẫn bổ sung cho SSH (và chi phí nhận thức bổ sung để tìm ra những gì được mở rộng khi).
  • Sau đó, tập lệnh chính sử dụng xargsđể phân phối khối lượng công việc trên các máy chủ, bằng cách bắt đầu các công việc mới ngay khi các công việc đang chạy kết thúc.
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.