linux集群管理工具mussh和pssh

听人说mussh和pssh不错,就看了下,顺便把mussh和pssh的介绍和使用方法给大家介绍下。

先说下mussh,mussh 是shell开发的一个小工具,刚学习运维和shell的朋友可以拿来锻炼下,做个工具的二次开发。

[root@devops-ruifengyun ~ ]$ apt-get install mussh

正在读取软件包列表... 完成
正在分析软件包的依赖关系树       
正在读取状态信息... 完成       
下列软件包是自动安装的并且现在不需要了:
  kde-l10n-engb kde-l10n-zhcn libffi6:i386 libglib2.0-0:i386
  libsystemd-daemon0:i386 libudev1:i386 python-async python-git python-gitdb
  python-smmap
Use 'apt-get autoremove' to remove them.
下列【新】软件包将被安装:
  mussh
升级了 0 个软件包,新安装了 1 个软件包,要卸载 0 个软件包,有 205 个软件包未被升级。
需要下载 14.4 kB 的软件包。
解压缩后会消耗掉 71.7 kB 的额外空间。
获取:1 http://mirrors.oschina.net/ubuntu/ saucy/universe mussh all 1.0-1 [14.4 kB]
下载 14.4 kB,耗时 0秒 (30.3 kB/s)
Selecting previously unselected package mussh.
(正在读取数据库 ... 系统当前共安装有 234998 个文件和目录。)
正在解压缩 mussh (从 .../archives/mussh_1.0-1_all.deb) ...
正在处理用于 man-db 的触发器...
正在设置 mussh (1.0-1) ...
[root@devops-ruifengyun ~ ]$

wKioL1O8ngyjili3AAPxH1oSDtI506.jpg

mussh的帮助,会看到他的帮助相当的简单。

 

 
咱们直接跑一个例子,首先需要把对端的主机放到一个文件里面。然后mussh 调用-H 识别主机的list列表。

[root@devops-ruifengyun ~ ]$ 

http://rfyiamcool.blog.51cto.com/

[root@devops-ruifengyun ~ ]$ cat mu.list 

10.1.25.46

10.1.25.47

10.1.25.48

10.1.25.49

[root@devops-ruifengyun ~ ]$ 

[root@devops-ruifengyun ~ ]$ 

[root@devops-ruifengyun ~ ]$ mussh -H ./mu.list -c ‘dir’

10.154.252.46: a.py     install.log keepalived-1.2.12

10.154.252.46: epel-release-6-8.noarch.rpm  install.log.syslog  keepalived-1.2.12.tar.gz

10.154.252.47: install.log  install.log.syslog  keepalived-1.2.12  keepalived-1.2.12.tar.gz

10.154.252.48: install.log  install.log.syslog  rs.sh

10.154.252.49: install.log  install.log.syslog  rs.sh

[root@devops-ruifengyun ~ ]$ 

[root@devops-ruifengyun ~ ]$ 

wKiom1O8n8iR-Sr8AAJehoAgJNU949.jpg

测试他有没有并发的特性。

[root@devops-ruifengyun ~ ]$ time mussh -H ./mu.list -c ‘sleep 3;dir’

10.154.252.46: a.py         install.log keepalived-1.2.12

10.154.252.46: epel-release-6-8.noarch.rpm  install.log.syslog  keepalived-1.2.12.tar.gz

10.154.252.47: install.log  install.log.syslog  keepalived-1.2.12  keepalived-1.2.12.tar.gz

10.154.252.48: install.log  install.log.syslog  rs.sh

10.154.252.49: install.log  install.log.syslog  rs.sh

mussh -H ./mu.list -c ‘sleep 3;dir’  0.04s user 0.16s system 1% cpu 13.206 total

[root@devops-ruifengyun ~ ]$ 

果然没有并发执行。。。这也太不咋低了。

mussh支持发送脚本并执行的,在mussh的cli命令行  直接 -C 跟着脚本就可以了。

[root@devops-ruifengyun ~ ]$ time mussh -H ./mu.list -C c.sh

10.154.252.46: a.py         install.log keepalived-1.2.12

10.154.252.46: epel-release-6-8.noarch.rpm  install.log.syslog  keepalived-1.2.12.tar.gz

10.154.252.47: install.log  install.log.syslog  keepalived-1.2.12  keepalived-1.2.12.tar.gz

10.154.252.48: install.log  install.log.syslog  rs.sh

10.154.252.49: install.log  install.log.syslog  rs.sh

mussh -H ./mu.list -C c.sh  0.10s user 0.17s system 42% cpu 0.629 total

[root@devops-ruifengyun ~ ]$ 

[root@devops-ruifengyun ~ ]$ 

[root@devops-ruifengyun ~ ]$ 

咱们再来测试下pssh这个比mussh要高端的东西,pssh是python开发的一个用来批量管理linux主机的工具。


pssh相关参数

pssh在多个主机上并行地运行命令

-h 执行命令的远程主机列表,文件内容格式[user@]host[:port]

如 test@172.16.10.10:229

-H 执行命令主机,主机格式 user@ip:port

-l 远程机器的用户名

-p 一次最大允许多少连接

-P 执行时输出执行信息

-o 输出内容重定向到一个文件

-e 执行错误重定向到一个文件

-t 设置命令执行超时时间

-A 提示输入密码并且把密码传递给ssh(如果私钥也有密码也用这个参数)

-O 设置ssh一些选项

-x 设置ssh额外的一些参数,可以多个,不同参数间空格分开

-X 同-x,但是只能设置一个参数

-i 显示标准输出和标准错误在每台host执行完毕后

附加工具

pscp 传输文件到多个hosts,类似scp

pscp -h hosts.txt -l irb2 foo.txt /home/irb2/foo.txt

pslurp 从多台远程机器拷贝文件到本地

pnuke 并行在远程主机杀进程

pnuke -h hosts.txt -l irb2 java

prsync 使用rsync协议从本地计算机同步到远程主机

prsync -r -h hosts.txt -l irb2 foo /home/irb2/foo

[root@vm-10-154-252-82 ~]$                                                            

[root@vm-10-154-252-82 ~]$cat list                                                    

10.154.252.46                                                                         

10.154.252.47                                                                         

10.154.252.48                                                                         

10.154.252.49                                                                         

[root@vm-10-154-252-82 ~]$                                                            

[root@vm-10-154-252-82 ~]$                                                            

[root@vm-10-154-252-82 ~]$pssh -i -h list ‘uptime’                                    

[1] 10:10:14 [SUCCESS] 10.154.252.46                                                  

 10:10:14 up 62 days, 19:26,  2 users,  load average: 0.08, 0.02, 0.03                

[2] 10:10:14 [SUCCESS] 10.154.252.49                                                  

 10:10:14 up 62 days, 19:30,  1 user,  load average: 0.00, 0.00, 0.00                 

[3] 10:10:14 [SUCCESS] 10.154.252.48                                                  

 10:10:14 up 62 days, 20:49,  1 user,  load average: 0.13, 0.03, 0.01                 

[4] 10:10:14 [SUCCESS] 10.154.252.47                                                  

 10:10:14 up 62 days, 19:59,  0 users,  load average: 0.28, 0.08, 0.02                

[root@vm-10-154-252-82 ~]$                                                            

[root@vm-10-154-252-82 ~]$                                                            

pssh 是python行的,容易实现程序调度的并发。 

[root@vm-10-154-252-82 ~]$time pssh -i -h list ‘sleep 3;uptime’

http://rfyiamcool.blog.51cto.com/
[1] 10:13:10 [SUCCESS] 10.154.252.46                                      
 10:13:10 up 62 days, 19:29,  2 users,  load average: 0.00, 0.00, 0.01    
[2] 10:13:10 [SUCCESS] 10.154.252.47                                      
 10:13:10 up 62 days, 20:02,  0 users,  load average: 0.01, 0.04, 0.00    
[3] 10:13:10 [SUCCESS] 10.154.252.49                                      
 10:13:10 up 62 days, 19:33,  1 user,  load average: 0.00, 0.00, 0.00     
[4] 10:13:10 [SUCCESS] 10.154.252.48                                      
 10:13:10 up 62 days, 20:52,  1 user,  load average: 0.06, 0.04, 0.00     
real    0m3.175s                                                          
user    0m0.101s                                                          
sys     0m0.038s

 wKioL1O8qOODFWxAAAOCxI_a0x8289.jpg                                                   

pssh的源码是在 /usr/lib/python2.6/site-packages/psshlib

我们可以看看他的主调度的模块,managepy

import select    
import signal    
import sys       
import threading

里面含有这四个模块。 select用来做调度,signal用来做超时的判断,threading 用来做多任务的并发执行。  pssh 远程的ssh执行,没有调用paramiko或者是fabric这样现成的ssh库,而是直接用subprocess调用系统的ssh进程

     def clear_sigchld_handler(self):                                                    
         signal.signal(signal.SIGCHLD, signal.SIG_DFL)                                   
                                                                                         
     def set_sigchld_handler(self):                                                      
         # TODO: find out whether set_wakeup_fd still works if the default               
         # signal handler is used (I'm pretty sure it doesn't work if the                
         # signal is ignored).                                                           
         signal.signal(signal.SIGCHLD, self.handle_sigchld)                              
         # This should keep reads and writes from getting EINTR.                         
         if hasattr(signal, 'siginterrupt'):                                             
             signal.siginterrupt(signal.SIGCHLD, False)                                  
                                                                                         
     def handle_sigchld(self, number, frame):                                            
         """Apparently we need a sigchld handler to make set_wakeup_fd work."""          
         # Write to the signal pipe (only for Python <2.5, where the                     
         # set_wakeup_fd method doesn't exist).                                          
         if self.iomap.wakeup_writefd:                                                   
             os.write(self.iomap.wakeup_writefd, '\0')                                   
         for task in self.running:                                                       
             if task.proc:                                                               
                 task.proc.poll()                                                        
         # Apparently some UNIX systems automatically resent the SIGCHLD                 
         # handler to SIG_DFL.  Reset it just in case.                                   
         self.set_sigchld_handler()                                                      
     def check_timeout(self):                                                                          
         """Kills timed-out processes and returns the lowest time left."""                             
         if self.timeout <= 0:                                                                         
             return None                                                                               
                                                                                                       
         min_timeleft = None                                                                           
         for task in self.running:                                                                     
             timeleft = self.timeout - task.elapsed()                                                  
             if timeleft <= 0:                                                                         
                 task.timedout()                                                                       
                 continue                                                                              
             if min_timeleft is None or timeleft < min_timeleft:                                       
                 min_timeleft = timeleft                                                               
                                                                                                       
         if min_timeleft is None:                                                                      
             return 0                                                                                  
         else:                                                                                         
             return max(0, min_timeleft)

解析主机host文件的逻辑

def read_host_files(paths, default_user=None, default_port=None):                                     
    """Reads the given host files.                                                                    
                                                                                                      
    Returns a list of (host, port, user) triples.                                                     
    """                                                                                               
    hosts = []                                                                                        
    if paths:                                                                                         
        for path in paths:                                                                            
            hosts.extend(read_host_file(path, default_user=default_user))                             
    return hosts                                                                                      
                                                                                                      
                                                                                                      
def read_host_file(path, default_user=None, default_port=None):                                       
    """Reads the given host file.                                                                     
                                                                                                      
    Lines are of the form: host[:port] [login].                                                       
    Returns a list of (host, port, user) triples.                                                     
    """                                                                                               
    lines = []                                                                                        
    f = open(path)                                                                                    
    for line in f:                                                                                    
        lines.append(line.strip())                                                                    
    f.close()                                                                                         
                                                                                                      
    hosts = []                                                                                        
    for line in lines:                                                                                
        # Skip blank lines or lines starting with #                                                   
        line = line.strip()                                                                           
        if not line or line.startswith('#'):                                                          
            continue                                                                                  
        host, port, user = parse_host_entry(line, default_user, default_port)                         
        if host:                                                                                      
            hosts.append((host, port, user))                                                          
    return hosts

再来看看执行命令的逻辑.

    def start(self, nodenum, iomap, writer, askpass_socket=None):                      
         """Starts the process and registers files with the IOMap."""                   
         self.writer = writer                                                           
                                                                                        
         if writer:                                                                     
             self.outfile, self.errfile = writer.open_files(self.pretty_host)           
                                                                                        
         # Set up the environment.                                                      
         environ = dict(os.environ)                                                     
         environ['PSSH_NODENUM'] = str(nodenum)                                         
         environ['PSSH_HOST'] = self.host                                               
         # Disable the GNOME pop-up password dialog and allow ssh to use                
         # askpass.py to get a provided password.  If the module file is                
         # askpass.pyc, we replace the extension.                                       
         environ['SSH_ASKPASS'] = askpass_client.executable_path()                      
         if askpass_socket:                                                             
             environ['PSSH_ASKPASS_SOCKET'] = askpass_socket                            
         if self.verbose:                                                               
             environ['PSSH_ASKPASS_VERBOSE'] = '1'                                      
         # Work around a mis-feature in ssh where it won't call SSH_ASKPASS             
         # if DISPLAY is unset.                                                         
         if 'DISPLAY' not in environ:                                                   
             environ['DISPLAY'] = 'pssh-gibberish'                                      
                                                                                        
         # Create the subprocess.  Since we carefully call set_cloexec() on             
         # all open files, we specify close_fds=False.                                  
         self.proc = Popen(self.cmd, stdin=PIPE, stdout=PIPE, stderr=PIPE,              
                 close_fds=False, preexec_fn=os.setsid, env=environ)                    
         self.timestamp = time.time()                                                   
         if self.inputbuffer:                                                           
             self.stdin = self.proc.stdin                                               
             iomap.register_write(self.stdin.fileno(), self.handle_stdin)               
         else:                                                                          
             self.proc.stdin.close()                                                    
         self.stdout = self.proc.stdout                                                 
         iomap.register_read(self.stdout.fileno(), self.handle_stdout)                  
         self.stderr = self.proc.stderr                                                 
         iomap.register_read(self.stderr.fileno(), self.handle_stderr)

其实这两个工具都不太满意,还是推荐用ansible和saltstack这样的扩展性比较强的工具。

当然还是要看你的环境,怎么爽怎么来 !!!



大家觉得文章对你有些作用! 如果想赏钱,可以用微信扫描下面的二维码,感谢!
另外再次标注博客原地址  xiaorui.cc

发表评论

邮箱地址不会被公开。 必填项已用*标注