Несколько команд во время 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. Поэтому я попытался объединить первые две команды в

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опцию, которая будет определять ваш прыжковый хост.
Хаулет

Ответы:


15

Считайте, что &&это логический оператор. Это не означает «также выполнить эту команду», это означает «выполнить эту команду, если другая преуспела».

Это означает, что если rmкоманда не выполнена (что произойдет, если какой-либо из трех каталогов не существует), то команда mkdirне будет выполнена. Это не похоже на поведение, которое вы хотите; если каталоги не существуют, вероятно, их можно создать.

использование ;

Точка с запятой ;используется для разделения команд. Команды выполняются последовательно, ожидая каждой, прежде чем перейти к следующей, но их успех или неудача не влияют друг на друга.

Escape внутренние кавычки

Кавычки внутри других кавычек следует избегать, в противном случае вы создаете дополнительную конечную точку и начальную точку. Ваша команда:

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 он фона, а это значит , они не будут дождались до конца , прежде чем перейти на следующий.
Сентиман

10

Вы всегда можете определить в своем Jumpbox мультиплексирование в 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

Это интересно! Есть ли способ явно включить его и выключить для данного соединения? Похоже, излишне сильно менять все соединения SSH для этого одного варианта использования. Можно ли использовать его более точно? Чтобы начать мультиплексирование только определенного соединения?
Сентиман

@Centimane да, обновил ответ
Rui F Ribeiro

1
Я бы посоветовал поставить сокет в доме пользователя, а не в мире, доступном для чтения /tmp/.
Heemayl

@heemayl Хороший вопрос. Я буду редактировать его, когда на компьютере.
Руи Ф Рибейро

@RuiFRibeiro также выглядит, по man ssh, ControlPath, ControlMasterи ControlPersistявляются действительными варианты , чтобы передать sshкоманду , используя -o. Может быть, даже более точный вариант использования, настройте мультиплексирование в первом sshсценарии и перезапустите его для других, но в противном случае избегайте снижения производительности. Интересно, что эталон мультиплексирования VS не для 3 SSH-соединений, учитывая, что «Существует также значительная задержка при открытии нового соединения»
Centimane

4

Вы можете поместить все свои команды в отдельный скрипт на своем «главном» сервере.

Мастер сценарий

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

Тогда в вашем скрипте ssh назовите это так: 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 

ИЛИ, если все файлы должны быть на исходной машине, вы можете сделать что-то вроде этого:

script1

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

1

Некоторое время назад у меня была возможность использовать контрольные сокеты, как рекомендуют другие ответы (этот ответ по сути представляет собой комбинацию использования контрольных сокетов, таких как этот ответ, и сценариев, подобных этому ответу ).

Вариант использования был взломом: 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указан управляющий сокет, присутствует только в том случае , если я не укажу этот файл с помощью -F, соединения SSH не будут его использовать. Так что это позволяет мне использовать контрольный сокет только там, где он мне нужен, используя Fопцию.
  • Сценарий установки также копирует сценарий выполнения теста на серверы. Сам сценарий выполнения содержит набор команд, и, поскольку я скопировал сценарий выполнения, мне не нужно беспокоиться о дополнительном уровне цитирования для SSH (и дополнительных когнитивных издержках для выяснения того, что расширяется, когда).
  • Затем основной сценарий используется xargsдля распределения рабочей нагрузки по серверам, начиная новые задания, как только выполняются выполняемые.
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.