如何通过SSH远程将命令自动运行到多个服务器并行?

时间:2008-10-28 15:30:10

标签: bash ssh command sysadmin

我已经搜索了类似的问题,但除了运行一个命令或者一些命令,例如:

ssh user@host -t sudo su -

但是,如果我基本上需要同时运行一个脚本(比方说)15个服务器,该怎么办?这在bash中是可行的吗?在完美的世界中,我需要尽可能避免安装应用程序。为了论证,让我们说我需要在10个主机上执行以下操作:

  1. 部署新的Tomcat容器
  2. 在容器中部署应用程序并进行配置
  3. 配置Apache vhost
  4. 重新加载Apache
  5. 我有一个完成所有这些操作的脚本,但它依赖于我登录所有服务器,从repo中删除脚本,然后运行它。如果这在bash中不可行,你建议用什么替代方案?我是否需要更大的锤子,例如Perl(Python可能是首选,因为我可以保证在RHEL环境中的所有盒子上都有Python,这要归功于yum / up2date)?如果有人能够向我指出任何有用的信息,我将不胜感激,特别是如果它在bash中可行的话。我会满足于Perl或Python,但我只是不知道那些(继续)。谢谢!

22 个答案:

答案 0 :(得分:11)

你可以运行che和Yang所示的本地脚本,和/或你可以使用Here文档:

ssh root@server /bin/sh <<\EOF  
wget http://server/warfile    # Could use NFS here  
cp app.war /location  
command 1  
command 2  
/etc/init.d/httpd restart  
EOF 

答案 1 :(得分:9)

通常,我会使用Expect的原始Tcl版本。您只需要在本地计算机上拥有它。如果我在使用Perl的程序中,我使用Net::SSH::Expect执行此操作。其他语言也有类似的“期望”工具。

答案 2 :(得分:9)

前几天在Perl邮件列表中出现了如何在多个服务器上运行命令的问题,我将给出相同的建议I gave there,即使用gsh:< / p>

http://outflux.net/unix/software/gsh

gsh类似于“for box in box1_name box2_name box3_name”解决方案already given,但我发现gsh更方便。您在web,db,RHEL4,x86_64或其他任何组(man ghosts)中设置包含服务器的/ etc / ghosts文件,然后在调用gsh时使用该组。

[pdurbin@beamish ~]$ gsh web "cat /etc/redhat-release; uname -r"
www-2.foo.com: Red Hat Enterprise Linux AS release 4 (Nahant Update 7)
www-2.foo.com: 2.6.9-78.0.1.ELsmp
www-3.foo.com: Red Hat Enterprise Linux AS release 4 (Nahant Update 7)
www-3.foo.com: 2.6.9-78.0.1.ELsmp
www-4.foo.com: Red Hat Enterprise Linux Server release 5.2 (Tikanga)
www-4.foo.com: 2.6.18-92.1.13.el5
www-5.foo.com: Red Hat Enterprise Linux Server release 5.2 (Tikanga)
www-5.foo.com: 2.6.18-92.1.13.el5
[pdurbin@beamish ~]$

您也可以使用web + db或web-RHEL4组合或拆分重影组。

我还要提到的是,虽然我从未使用过shmux,但its website包含一个软件列表(包括gsh),它允许您同时在许多服务器上运行命令。 Capistrano已经被提及,并且(根据我的理解)也可以列在该列表中。

答案 3 :(得分:6)

看看Expect(man expect

我过去使用Expect完成了类似的任务。

答案 4 :(得分:4)

您可以将本地脚本通过管道传输到远程服务器并使用以下命令执行它:

ssh -t user@host 'sh' < path_to_script

通过使用公钥认证和脚本包装来执行并行执行,可以进一步自动化。

答案 5 :(得分:4)

您可以尝试paramiko。这是一个纯python的ssh客户端。您可以编写ssh会话。无需在远程计算机上安装任何内容。

请参阅此great article了解如何使用它。

答案 6 :(得分:3)

为您提供结构,没有实际代码。

  1. 使用scp将安装/设置脚本复制到目标框。
  2. 使用ssh在远程控制台上调用脚本。

答案 7 :(得分:2)

对于那些偶然发现这个问题的人,我将包含一个使用Fabric的答案,它完全解决了上述问题:通过ssh在多个主机上运行任意命令。

安装完Fabric后,您将创建一个fabfile.py,并实施可在远程主机上运行的任务。例如, Reload Apache 的任务可能如下所示:

from fabric.api import env, run

env.hosts = ['host1@example.com', 'host2@example.com']

def reload():
    """ Reload Apache """
    run("sudo /etc/init.d/apache2 reload")

然后,在本地计算机上运行fab reloadsudo /etc/init.d/apache2 reload命令将在env.hosts中指定的所有主机上运行。

答案 8 :(得分:2)

您是否查看了PuppetCfengine等内容。他们可以做你想做的事情,甚至更多。

答案 9 :(得分:2)

pssh可能很有趣,因为与此处提到的大多数解决方案不同,这些命令是并行运行的。

(为了我自己的用法,我写了一个更简单的小脚本,非常类似于GavinCattell的那个,它是documented here - in french)。

答案 10 :(得分:1)

您需要DSH或分布式shell,它在群集中使用很多。这是链接:dsh

你基本上有节点组(一个包含节点列表的文件),你指定了你希望运行命令的节点组,那么你就可以使用dsh,就像在ssh上运行命令一样。

dsh -a /path/to/some/command/or/script

它将同时在所有计算机上运行该命令,并返回带有主机名前缀的输出。命令或脚本必须存在于系统中,因此共享NFS目录可用于这些类型的事情。

答案 11 :(得分:1)

我发现没有安装或配置太多软件的最简单方法是使用纯旧的tmux。假设您有9台Linux服务器。选择一个盒子作为您的主要物品。开始一个tmux会话:

tmux

然后通过执行8次来创建9个拆分的tmux窗格:

ctrl-b + %

enter image description here

现在将SSH放入每个窗格的每个框中。您需要了解一些tmux快捷方式。要导航,请按:

ctrl+b <arrow-keys>

登录到每个窗格上的所有框。现在打开窗格同步,在该窗格中,您可以在每个框中键入相同的内容:

ctrl+b :setw synchronize-panes on

现在,当您按任意键时,它将显示在每个窗格中。要将其关闭,只需将其关闭即可。要循环调整窗格大小,请按ctrl + b <空格键>。

这对我来说更好,因为我需要查看每个终端的输出,因为有时在下载或升级软件时,服务器由于任何原因而崩溃或挂起。任何问题,您都可以单独隔离并解决。

答案 12 :(得分:1)

有一个名为FLATT (FLexible Automation and Troubleshooting Tool)的工具,允许您通过单击按钮在多个Unix / Linux主机上执行脚本。它是一个在Mac和Windows上运行的桌面GUI应用程序,但也有一个命令行java客户端 您可以创建批处理作业并在多个主机上重复使用 需要Java 1.6或更高版本。

答案 13 :(得分:1)

创建所有访问过的计算机的hostname ssh命令。 由Quierati http://pastebin.com/pddEQWq2

#Use in .bashrc
#Use "HashKnownHosts no" in ~/.ssh/config or /etc/ssh/ssh_config 
# If known_hosts is encrypted and delete known_hosts

[ ! -d ~/bin ] && mkdir ~/bin
for host in `cut -d, -f1 ~/.ssh/known_hosts|cut -f1 -d " "`;
  do
    [ ! -s ~/bin/$host ] && echo ssh $host '$*' > ~/bin/$host
done
[ -d ~/bin ] && chmod -R 700 ~/bin
export PATH=$PATH:~/bin 

Ex Execute:

$for i in hostname{1..10}; do $i who;done

答案 14 :(得分:1)

嗯,对于第1步和第2步,没有tomcat管理器Web界面;你可以用libl插件用curl或zsh编写脚本。

对于SSH,您需要: 1)没有提示输入密码(使用密钥) 2)在SSH的命令行上传递命令,这类似于可信网络中的rsh

其他帖子已经向您展示了该做什么,我也可能会使用sh,但我很想使用perl ssh tomcatuser@server perl -e 'do-everything-on-one-line;',或者您可以这样做:< / p>

scp the_package.tbz tomcatuser@server:the_place/.
ssh tomcatuser@server /bin/sh <<\EOF
定义 TOMCAT_WEBAPPS=/usr/local/share/tomcat/webapps之类的内容 tar xj the_package.tbz rsync rsync://repository/the_package_place
mv $TOMCAT_WEBAPPS/old_war $TOMCAT_WEBAPPS/old_war.old
mv $THE_PLACE/new_war $TOMCAT_WEBAPPS/new_war
touch $TOMCAT_WEBAPPS/new_war [你通常不必重新启动tomcat]
mv $THE_PLACE/vhost_file $APACHE_VHOST_DIR/vhost_file
$APACHECTL restart [可能需要以apache用户身份登录才能移动该文件并重启] EOF

答案 15 :(得分:1)

您可以使用cluster ssh等工具一次在多个服务器上运行相同的命令。该链接是关于当天博客的Debian软件包上的集群ssh的讨论。

答案 16 :(得分:1)

您可以像以前一样进行操作,只需编写脚本而不是手动执行。以下代码将远程命名为'loca',并在那里运行两个命令。你需要做的只是插入你想在那里运行的命令。

che@ovecka ~ $ ssh loca 'uname -a; echo something_else'
Linux loca 2.6.25.9 #1 (blahblahblah)
something_else

然后,要迭代所有机器,执行以下操作:

for box in box1_name box2_name box3_name
do
   ssh $box 'commmands_to_run_everywhere'
done

为了使这个ssh的东西在不输入密码的情况下工作,你需要设置密钥认证。您可以在IBM developerworks了解相关信息。

答案 17 :(得分:1)

虽然这是一个复杂的主题,但我强烈推荐Capistrano

答案 18 :(得分:0)

我不确定这种方法是否适用于您想要的所有内容,但您可以尝试这样的方法:

$ cat your_script.sh | ssh your_host bash

将运行远程服务器上的脚本(位于本地)。

答案 19 :(得分:0)

Multixterm这样做很酷,并且允许您轻松地将n个机器中的1个按顺序放回去。

答案 20 :(得分:0)

除了主流内核之外,只需使用blog阅读新的setsid,无需任何进一步的安装/配置。在Ubuntu14.04下测试/验证。

虽然作者有一个非常明确的解释和示例代码,但这是快速浏览的神奇部分:

#----------------------------------------------------------------------
# Create a temp script to echo the SSH password, used by SSH_ASKPASS
#----------------------------------------------------------------------
SSH_ASKPASS_SCRIPT=/tmp/ssh-askpass-script
cat > ${SSH_ASKPASS_SCRIPT} <<EOL
#!/bin/bash
echo "${PASS}"
EOL
chmod u+x ${SSH_ASKPASS_SCRIPT}

# Tell SSH to read in the output of the provided script as the password.
# We still have to use setsid to eliminate access to a terminal and thus avoid
# it ignoring this and asking for a password.
export SSH_ASKPASS=${SSH_ASKPASS_SCRIPT}
......
......
# Log in to the remote server and run the above command.
# The use of setsid is a part of the machinations to stop ssh 
# prompting for a password.
setsid ssh ${SSH_OPTIONS} ${USER}@${SERVER} "ls -rlt"

答案 21 :(得分:-2)

这是一个在多台机器上执行SSH命令的脚本,它可能有所帮助:

#!/bin/bash
MACHINES="machine1 machine2 machine3 machine4 machine5 machine6"
for m in $MACHINES
do
        cmd="ssh $m '$*'"
        eval $cmd
done

你甚至可以把它放在你的路径中,称之为sshAll,然后输入sshAll命令。