SSH 세션 중 여러 명령

SSH 세션 중 여러 명령

master원격 컴퓨터와 SSH 세션을 설정한 다음 master각 원격 컴퓨터에서 또 다른 내부 SSH 세션을 설정한 다음 2개의 명령을 실행하는 로컬 컴퓨터가 있습니다. slaves즉, 특정 디렉터리를 삭제하고 다시 생성합니다.

로컬 머신에는 마스터에 대한 비밀번호 없는 SSH가 있고, 마스터에는 슬레이브에 대한 비밀번호 없는 SSH가 있습니다. 또한 .ssh/configlocal/master의 모든 호스트 이름이 알려져 있고 슬레이브의 호스트 이름은 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 세션이 생성되어 상당한 지연 시간이 발생한다는 것을 확인했습니다. SSH 연결을 줄이기 위해 이 3개의 명령을 1로 결합하고 싶습니다. 그래서 처음 두 명령을 결합해 보았습니다.

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)을 실행한 다음 세션을 종료하고 계속 진행합니다. 어떻게 해야 합니까?

답변1

이걸 고려하세요&& 논리 연산자라고 생각하십시오. 물론아니요"이 명령도 실행", "다른 명령이 성공하면 이 명령을 실행"을 의미합니다.

즉, 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 OutputPartition이를 실행할 위치가 있을 것입니다.

답변2

Jumpbox에서 언제든지 정의할 수 있습니다.OpenSSH의 멀티플렉싱

멀티플렉싱은 단일 회선이나 연결을 통해 여러 신호를 보내는 기능입니다. 멀티플렉싱을 사용하면 OpenSSH가 매번 새 연결을 생성하는 대신 여러 동시 SSH 세션에 대해 기존 TCP 연결을 재사용할 수 있습니다.

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

답변3

모든 명령을 "마스터" 서버의 별도 스크립트에 넣을 수 있습니다.

메인 스크립트

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

또는 모든 파일이 초기 컴퓨터에 있어야 하는 경우 다음을 수행할 수 있습니다.

스크립트 1

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

스크립트 2

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

답변4

얼마 전 다른 답변에서 권장하는 대로 제어 소켓을 사용할 기회가 있었습니다(이 답변은 본질적으로 제어 소켓 사용의 조합입니다.이 답변그리고 이런 스크립트이 답변).

사용 사례는 해킹입니다. authorized_keys대상 사용자의 파일은 예약된 작업에 의해 정기적으로 덮어쓰기되며 해당 파일에 항목을 추가하는 데 필요한 절차를 거치지 않고 신속하게 무언가를 테스트하고 싶습니다. 그래서 while 루프를 설정하고 필요에 따라 파일에 키를 추가하고 테스트를 실행한 다음 루프를 취소했습니다. 그러나 예약된 작업이 파일을 덮어쓰고 루프가 계속 실행되는 작은 창이 있습니다 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해당 파일을 지정하지 않으면 -FSSH 연결은 이를 사용하지 않습니다 . 따라서 F해당 옵션을 사용해야 하는 경우에만 제어 소켓을 사용할 수 있습니다.
  • 또한 설정 스크립트는 테스트 실행 스크립트를 서버에 복사합니다. 실행 스크립트 자체에는 여러 명령이 포함되어 있으며 실행 스크립트를 복사했기 때문에 SSH에 대한 추가 참조 계층(및 언제 무엇을 확장할지 파악하는 추가 인지 오버헤드)에 대해 걱정할 필요가 없었습니다.
  • 그런 다음 기본 스크립트는 xargs실행 중인 작업이 끝나자마자 새 작업을 시작하여 서버 전체에 작업 부하를 분산합니다.

관련 정보