SSH会话中的SSH期间有多个命令


10

我有一台本地计算机,该计算机应该与远程master计算机建立SSH会话,然后再从master到每个远程计算机进行另一个内部SSH会话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定义跳转主机的选项。
Hauleth '17

Answers:


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运行它的位置。


我明白你的观点。我感到困惑的一部分是分号,因为我认为它会同时执行多个命令,这就是为什么我不使用它的原因。
mgus

分号不会导致命令同时执行,请参见此处作为执行命令的参考。的&原因命令运行诠释他的背景,这意味着他们不会移动到下一个前等待到结束。
Centimane

10

您始终可以在Jumpbox 定义OpenSSH中的Multiplexing

多路复用是通过单条线路或连接发送多个信号的能力。通过多路复用,OpenSSH可以将现有的TCP连接重新用于多个并发的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

那很有意思!有没有一种方法可以为给定的连接显式打开和关闭它?对于这种用例来说,如此大幅度地更改所有SSH连接似乎有点过头了。可以更精确地使用它吗?要开始仅复用某个连接?
Centimane

@Centimane是的,更新了答案
Rui F Ribeiro

1
我建议将套接字放置在用户的家中,而不是放在可读写的世界中/tmp/
heemayl

@heemayl好点。在计算机上时,我将对其进行编辑。
Rui F Ribeiro

@RuiFRibeiro也像,根据man sshControlPathControlMasterControlPersist是有效选项传递一个ssh使用命令-o。可能是一个更精确的用例,ssh在脚本的第一个中设置多路复用,然后将其回收再用于其他脚本,但否则会降低性能。我想知道对于3个SSH连接来说,多路复用VS的基准不是什么,因为“打开新连接时也存在明显的延迟”
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 

或者, 如果所有文件都必须在初始计算机上,则可以执行以下操作:

脚本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

1

前一段时间,我没有机会使用控制插座像其他答案建议(这个答案基本上是使用控制插座的组合等这个答案和类似的脚本这个答案)。

用例是黑客:authorized_keys目标用户的定期被计划的任务覆盖,我想快速测试事情,而无需经过向该文件添加内容所需的繁文ta节。因此,我将设置一个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通过在运行的作业结束后立即启动新作业来在服务器上分配工作负荷。
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.