为何要用到Rex,由于目前线上业务量愈来愈多,服务器数量也愈来愈多,维护的项目也愈来愈多,不管是安装软件,修改配置,优化,管理,升级等操做经过写一堆脚原本集中操做已经很难达到个人要求。这时候就须要将全部不一样业务类型不一样项目所对应的集群环境都统一块儿来,集中进行管理。java
经常使用的集中管理软件有puppet salt ansible Rex等。在进行综合比对后,我选择了Rex。缘由是Rex是基于SSH来进行集成管理的,不须要再各个服务节点安装客户端,简洁,轻量,是我选择Rex的一部分缘由,固然其它的集成管理软件没有怎么研究过,不过Rex已经能知足个人全部要求了,模块Rex既能够作为一个库来调用,也能够做为一个集中管理平台来使用,经过rex命令来进行一切操做。我对perl很是熟练,对于一些特殊的应用场景我会结合把Rex当作一个普通的模块,经过在本身的脚本中调用Rex模块提供的一些方法来进行远程操做,灵活性,可用性都比较强。这也是我选择Rex的一个主要缘由。linux
介绍一下我线上的环境:nginx
我要管理7个项目,每一个项目都有一个集群环境(平均都是4个节点左右),每一个节点上的web服务都是用tomcat7.0+jdk1.7的环境;session共享使用的是两台memcache组成的集群环境,数据库采用的是二台高性能的物理机+一个iscsi的盘柜组成的RAC环境。四台代理服务器(都是采用的nginx),图片存储采用的drbd+heartbeat+nfs的形式,由于是商城网站图片量如今愈来愈多,访问量愈来愈多,nfs图片服务器很容易由于I/O问题变的很是不稳定,目前测试用Moosefs和fastDFS,准备将图片存储迁移到分布式存储。web
我接手以后就是这么个环境,固然总体的网络结构设计的很糟糕,不好劲。不管是从安全性,稳定性,高可用性方面去看都存在缺陷。可是上头不肯意让我对架构进行改动,只好对现有的环境进行集中管理。(哎,作运维很难!!)shell
废话很少说,由于实验环境有限,我只能为7个项目准备7个节点,也就是一个项目对应的集群就是一个节点也就是它本身!(公司穷,没办法,内部测试用两台pc机加一个组装的盘柜搞了一个集群虚拟化,为了节约资源只能这样玩) 数据库
1,由于是内部测试,为了方便,每一个节点对应的域名都在hosts文件中解析;json
[root@localhost ~]# cat /etc/hosts 127.0.0.1 mail.weike.com mx localhost localhost.localdomain localhost4 localhost4.localdomain4 ::1 localhost localhost.localdomain localhost6 localhost6.localdomain6 #192.168.0.128 test1 #192.168.0.129 test2 192.168.0.164 shopwap 192.168.0.193 gerenwap 192.168.0.196 appwap 192.168.0.224 geren 192.168.0.226 chaoshi 192.168.0.228 quanguo 192.168.0.215 boss
则七个节点对应的域名为 shopwap gerenwap appwap geren chaoshi quanguo boss(实际上线上的项目远比这多,有的是单个tomcat节点跑多个实例)vim
2,安装Rex,在安装以前须要肯定你已经安装了perl环境(若是没有就经过yum install perl cpan进行安装)缓存
[root@localhost src]# perl -v This is perl 5, version 16, subversion 3 (v5.16.3) built for x86_64-linux-thread-multi (with 28 registered patches, see perl -V for more detail) Copyright 1987-2012, Larry Wall
3,对于全部的perl模块安装咱们都用cpanm命令来安装,到cpan或者metacpan 上去找一个叫App-cpanminus 的源码包,而后下载下来进行解压编译安装tomcat
[root@StorageServer1 src]# ls -l |grep -i app -rw-r--r-- 1 root root 316814 Sep 16 09:52 App-cpanminus-1.7039.tar.gz [root@StorageServer1 src]# tar zxvf App-cpanminus-1.7039.tar.gz App-cpanminus-1.7039/ App-cpanminus-1.7039/bin/ App-cpanminus-1.7039/Changes App-cpanminus-1.7039/cpanfile App-cpanminus-1.7039/lib/ App-cpanminus-1.7039/LICENSE App-cpanminus-1.7039/Makefile.PL App-cpanminus-1.7039/MANIFEST App-cpanminus-1.7039/MANIFEST.SKIP App-cpanminus-1.7039/META.json App-cpanminus-1.7039/META.yml App-cpanminus-1.7039/README App-cpanminus-1.7039/t/ App-cpanminus-1.7039/t/happy_cpantesters.t App-cpanminus-1.7039/lib/App/ App-cpanminus-1.7039/lib/App/cpanminus/ App-cpanminus-1.7039/lib/App/cpanminus.pm App-cpanminus-1.7039/lib/App/cpanminus/fatscript.pm App-cpanminus-1.7039/bin/cpanm [root@StorageServer1 src]# cd App-cpanminus-1.7039 [root@StorageServer1 App-cpanminus-1.7039]# perl Makefile.PL && make && make install Checking if your kit is complete... Looks good Warning: prerequisite Test::More 0 not found. Writing Makefile for App::cpanminus cp lib/App/cpanminus/fatscript.pm blib/lib/App/cpanminus/fatscript.pm cp lib/App/cpanminus.pm blib/lib/App/cpanminus.pm cp bin/cpanm blib/script/cpanm /usr/bin/perl -MExtUtils::MY -e 'MY->fixin(shift)' -- blib/script/cpanm Manifying blib/man1/cpanm.1 Manifying blib/man3/App::cpanminus::fatscript.3pm Manifying blib/man3/App::cpanminus.3pm Installing /usr/local/share/perl5/App/cpanminus.pm Installing /usr/local/share/perl5/App/cpanminus/fatscript.pm Installing /usr/local/share/man/man1/cpanm.1 Installing /usr/local/share/man/man3/App::cpanminus::fatscript.3pm Installing /usr/local/share/man/man3/App::cpanminus.3pm Installing /usr/local/bin/cpanm Appending installation info to /usr/lib64/perl5/perllocal.pod [root@StorageServer1 App-cpanminus-1.7039]#
3,安装完成如今可使用cpanm来安装Rex了(由于源地址默认都是国外的一些站点,有可能会被屏蔽,因此用163提供的源地址),设置下环境变量:
[root@StorageServer1 ~]# cat .bashrc # .bashrc # User specific aliases and functions alias vi='vim' alias rm='rm -i' alias cp='cp -i' alias mv='mv -i' alias cpanm='cpanm --mirror http://mirrors.163.com/cpan --mirror-only' # Source global definitions if [ -f /etc/bashrc ]; then . /etc/bashrc fi [root@StorageServer1 ~]#
4安装rex
root@StorageServer1 ~]# cpanm Rex --> Working on Rex Fetching http://www.cpan.org/authors/id/F/FE/FERKI/Rex-1.3.3.tar.gz ... OK ==> Found dependencies: ExtUtils::MakeMaker
安装过程当中它本身会解决模块相关的依赖关系,可能会有一些底层的库须要手动去安装,好比我在安装过程当中就失败了
! Installing the dependencies failed: Module 'XML::LibXML' is not installed, Module 'XML::Simple' is not installed
! Bailing out the installation for Rex-1.3.3.
提示有个XML::LibXML相关的模块安装不成功,这个和它依赖的相关的底层xml库有关系,因此我将libxml相关的底层库都安装一下就好了。
[root@StorageServer1 ~]# yum install libxml*
而后再安装rex
root@StorageServer1 ~]# cpanm Rex --> Working on Rex Fetching http://www.cpan.org/authors/id/F/FE/FERKI/Rex-1.3.3.tar.gz ... OK ==> Found dependencies: ExtUtils::MakeMaker
5,安装完成后如今就开始进行管理。
用户:管理用户我用tomcat(由于root权限不能给测试人员使用);
模块:创建7个模块,每一个模块对应一个不一样的项目;
模板:创建两个模板模块,将对全部项目节点的统一操做都写进模板里,好比批量更新软件,设置时间,删除软件等等。
主机名配置文件:以ini形式保存全部项目的主机名。七个项目创建七个组,每一个组中包含的主机名就是属于该项目集群环境中的几点服务器的主机名(由于集群就一个节点因此只有一个主机名)
Rexfile:配置文件,rex命令全部的操做都是读取该文件,全部相似于全局设置的选项都保存在该文件里。
第一步:创建模板:两个模板对应的名称为:
Template::Service :该模板主要存放服务等相关的操做好比操做tomcat,启动 关闭 等
Template::File: 该模块主要发布项目和一些文件,包括文件内容同步等相关工做
创建tomcat用户并切换到tomcat目录下,而后建立rex目录,进入rex目录在建立两个模板;以下:
[
tomcat@StorageServer1 ~]$ pwd /home/tomcat [tomcat@StorageServer1 ~]$ mkdir rex [tomcat@StorageServer1 ~]$ cd rex [tomcat@StorageServer1 rex]$ rexify Template::Service --create-module Creating module Template::Service... mkdir Template/Service Creating template file: __module__.pm Creating template file: meta.yml Your module has been created in Template/Service. [tomcat@StorageServer1 rex]$ rexify Template::File --create-module Creating module Template::File... mkdir Template/File Creating template file: __module__.pm Creating template file: meta.yml Your module has been created in Template/File. [tomcat@StorageServer1 rex]$ ls Template [tomcat@StorageServer1 rex]$ ls -ld Template/* drwxr-xr-x 2 tomcat tomcat 4096 Sep 16 12:18 Template/File drwxr-xr-x 2 tomcat tomcat 4096 Sep 16 12:18 Template/Service
第二步:在rex目录下创建file.ini文件 里面存放的主要是操做的主机组以下
[tomcat@StorageServer1 rex]$ ls file.ini Template [tomcat@StorageServer1 rex]$ cat file.ini [quanguo_servers] quanguo [chaoshi_servers] chaoshi [geren_servers] geren [boss_servers] boss [shopwap_servers] shopwap [appwap_servers] appwap [gerenwap_servers] gerenwap [all_servers] @quanguo_servers @chaoshi_servers @geren_servers @boss_servers @shopwap_servers @appwap_servers @gerenwap_servers [tomcat@StorageServer1 rex]$
主机名所对应的ip能够查看hosts文件
第三步:在rex目录下创建模块,总共七个项目,我须要创建七个模块;
[tomcat@StorageServer1 rex]$ rexify Servers::Appwap --create-module Creating module Servers::Appwap... mkdir Servers/Appwap Creating template file: __module__.pm Creating template file: meta.yml Your module has been created in Servers/Appwap. [tomcat@StorageServer1 rex]$ rexify Servers::Boss --create-module Creating module Servers::Boss... mkdir Servers/Boss Creating template file: __module__.pm Creating template file: meta.yml Your module has been created in Servers/Boss. [tomcat@StorageServer1 rex]$ rexify Servers::Chaoshi --create-module Creating module Servers::Chaoshi... mkdir Servers/Chaoshi Creating template file: __module__.pm Creating template file: meta.yml Your module has been created in Servers/Chaoshi. [tomcat@StorageServer1 rex]$ rexify Servers::Geren --create-module Creating module Servers::Geren... mkdir Servers/Geren Creating template file: __module__.pm Creating template file: meta.yml Your module has been created in Servers/Geren. [tomcat@StorageServer1 rex]$ rexify Servers::Gerenwap --create-module Creating module Servers::Gerenwap... mkdir Servers/Gerenwap Creating template file: __module__.pm Creating template file: meta.yml Your module has been created in Servers/Gerenwap. [tomcat@StorageServer1 rex]$ rexify Servers::Quanguo --create-module Creating module Servers::Quanguo... mkdir Servers/Quanguo Creating template file: __module__.pm Creating template file: meta.yml Your module has been created in Servers/Quanguo. [tomcat@StorageServer1 rex]$ rexify Servers::Shopwap --create-module Creating module Servers::Shopwap... mkdir Servers/Shopwap Creating template file: __module__.pm Creating template file: meta.yml Your module has been created in Servers/Shopwap. [tomcat@StorageServer1 rex]$
查看建立的七个模块
[tomcat@StorageServer1 rex]$ ls Servers/ -l total 28 drwxr-xr-x 2 tomcat tomcat 4096 Sep 16 12:27 Appwap drwxr-xr-x 2 tomcat tomcat 4096 Sep 16 12:27 Boss drwxr-xr-x 2 tomcat tomcat 4096 Sep 16 12:27 Chaoshi drwxr-xr-x 2 tomcat tomcat 4096 Sep 16 12:27 Geren drwxr-xr-x 2 tomcat tomcat 4096 Sep 16 12:28 Gerenwap drwxr-xr-x 2 tomcat tomcat 4096 Sep 16 12:28 Quanguo drwxr-xr-x 2 tomcat tomcat 4096 Sep 16 12:28 Shopwap [tomcat@StorageServer1 rex]$ ls file.ini Servers Template [tomcat@StorageServer1 rex]$
第五步:在rex目录下建立Rexfile主配置文件
[tomcat@StorageServer1 rex]$ ls file.ini Rexfile Servers Template
稍后会讲Rexfile中的内容是什么意思(如今能够忽略Rexfie中的内容只须要建立个Rexfile文件就行);
由于我全部项目都是部署的tomcat7.0+jdk1.7 因此我能够将重启 关闭 启动等服务操做写到Template::Sevice模块中以下:
[tomcat@StorageServer1 rex]$ cat Template/Service/__module__.pm package Template::Service; use v5.10; use warnings; use Rex -base; task "shutdown_tomcat",group=>"all_servers",sub { my $server = Rex::get_current_connection()->{server}; for my $proc(ps()){ if($proc->{"command"}=~/java.*?tomcat/i){ run "./shutdown.sh", cwd =>"/usr/local/tomcat/bin", only_if =>"pgrep java"; say "[$server]: tomcat服务关闭完成"; last; }else{ next; } } given($server){ when(/\bchaoshi\b/i){ file "/usr/local/tomcat/webapps/osms",ensure=>"absent"; file "/usr/local/tomcat/work/Catalina",ensure=>"absent"; file "/usr/local/tomcat/webapps/ROOT",ensure=>"absent"; say "[$server:缓存清理完成]"; break;} when(/\bquanguo\b/i){ file "/usr/local/tomcat/webapps/olsm",ensure=>"absent"; file "/usr/local/tomcat/work/Catalina",ensure=>"absent"; file "/usr/local/tomcat/webapps/ROOT",ensure=>"absent"; say "[$server:缓存清理完成]"; break;} when(/\bgeren\b/i){ file "/usr/local/tomcat/webapps/imss",ensure=>"absent"; file "/usr/local/tomcat/work/Catalina",ensure=>"absent"; file "/usr/local/tomcat/webapps/ROOT",ensure=>"absent"; say "[$server:缓存清理完成]"; break;} when(/\bboss\b/i){ file "/usr/local/tomcat/webapps/boss",ensure=>"absent"; file "/usr/local/tomcat/work/Catalina",ensure=>"absent"; file "/usr/local/tomcat/webapps/ROOT",ensure=>"absent"; say "[$server:缓存清理完成]"; break;} when(/\bshopwap\b/i){ file "/usr/local/tomcat/webapps/shopwap",ensure=>"absent"; file "/usr/local/tomcat/work/Catalina",ensure=>"absent"; file "/usr/local/tomcat/webapps/ROOT",ensure=>"absent"; say "[$server:缓存清理完成]"; break;} when(/\bappwap\b/i){ file "/usr/local/tomcat/webapps/moser",ensure=>"absent"; file "/usr/local/tomcat/work/Catalina",ensure=>"absent"; file "/usr/local/tomcat/webapps/ROOT",ensure=>"absent"; say "[$server:缓存清理完成]"; break;} when(/\bgerenwap\b/i){ file "/usr/local/tomcat/webapps/imsswap",ensure=>"absent"; file "/usr/local/tomcat/work/Catalina",ensure=>"absent"; file "/usr/local/tomcat/webapps/ROOT",ensure=>"absent"; say "[$server:缓存清理完成]"; break;} default{ say "没有该服务";} } say "[$server]: 服务已经关闭"; }; task "start_tomcat",group=>"all_servers",sub { my $server = Rex::get_current_connection()->{server}; if(is_file("/usr/local/tomcat/bin/startup.sh")){ run "./startup.sh",sub { my($stdout,$stderr)=@_; say "[$server]: $stdout"; }, cwd =>"/usr/local/tomcat/bin", unless =>"pgrep java"; }else{ say "[$server]:没有正确安装tomcat,请认真检查服务状态"; exit 0; } for my $proc(ps()){ if($proc->{"command"}=~/java.*tomcat/i){ say "[$server]: tomcat已经启动,进程pid:".$proc->{"pid"}; last; }else{ next; } } }; task "restart_tomcat",group=>"all_servers",sub { my $server = Rex::get_current_connection()->{server}; needs 'shutdown_tomcat'; sleep 5; needs 'start_tomcat'; say "[$server]: 服务重启完成"; }; task "show_time",group=>"all_servers",sub { say run "date"; }; 1;
里面定义了四个任务,分别为tomcat的启动,关闭,重启,和系统当前时间
第四步:调用该模板,查看当前任务,咱们讲过全部的操做都是经过rex命令来完成的,rex必需要在有Rexfile的目录下执行而且读取Rexfile中的代码;所以我要经过在Rexfile写代码调用这个模板。以下所示
[tomcat@StorageServer1 rex]$ cat Rexfile use Rex -feature => ['1.3']; use strict; use warnings; use Rex::Group::Lookup::INI; #use Data::Dumper; #加载模版 require Template::Service; require Template::File; #设置并发链接数,默认是1 parallelism 'max'; #将服务器分组并以文件的形式来保存主机名 groups_file "file.ini"; #将定义好的方法,属性,以及变量都保存在改模版中(此模板也是一个模块) auth for =>"all_servers"=> user=>"tomcat", private_key=>"/home/tomcat/.ssh/id_rsa", public_key=> "/home/tomcat/.ssh/id_rsa.pub"; desc "启动全部web服务"; task "web_start",group=>"all_servers",sub { Template::start_tomcat(); }; desc "关闭全部web服务"; task "web_stop",group=>"all_servers",sub { Template::shutdown_tomcat(); }; desc "重启全部web服务"; task "web_restart",group=>"all_servers",sub { Template::Service::restart_tomcat(); }; desc "查看全部服务器节点时间"; task "show_times",group=>"all_servers",sub { Template::show_time(); };
经过rex -T来查看当前的任务 以下
[tomcat@StorageServer1 rex]$ rex -T Tasks show_times 查看全部服务器节点时间 web_restart 重启全部web服务 web_start 启动全部web服务 web_stop 关闭全部web服务 Server Groups all_servers appwap, boss, chaoshi, geren, gerenwap, quanguo, shopwap appwap_servers appwap boss_servers boss chaoshi_servers chaoshi geren_servers geren gerenwap_servers gerenwap quanguo_servers quanguo shopwap_servers shopwap [tomcat@StorageServer1 rex]$
好比我如今要重启全部项目的web服务 我只须要经过rex+任务名就好了,
在执行以前我要说明下:由于rex是经过ssh来进行集成管理的,因此我须要用到帐户和密码,ssh登录能够经过口令登录
也能够经过公钥认证的方式,我这里使用的是公钥认证的方式,须要将本地生成的公钥传输到各个节点上,否则登录的话会提示让你输入密码等交互操做
为了解决这个问题,我写了个脚本名为login.pl执行如下就好了 操做以下
首先生成key
[tomcat@StorageServer1 rex]$ ssh-keygen -t rsa Generating public/private rsa key pair. Enter file in which to save the key (/home/tomcat/.ssh/id_rsa): Created directory '/home/tomcat/.ssh'. Enter passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved in /home/tomcat/.ssh/id_rsa. Your public key has been saved in /home/tomcat/.ssh/id_rsa.pub. The key fingerprint is: 2b:15:90:70:0a:06:99:a6:2d:e1:5f:28:99:11:31:a9 tomcat@StorageServer1 The key's randomart image is: +--[ RSA 2048]----+ |.B* ..o. | |+=.. o.. | |=o+ o . | |E=.. . . | | .o . S | | . . . | | . . | | . | | | +-----------------+
而后在写个login.pl脚本 赋予执行权限 在执行(由于用到了Expect模块若是没安装的话用cpanm安装下就好了)
[tomcat@StorageServer1 rex]$ vi login.pl #!/usr/bin/perl use v5.16; use warnings; use Expect; my @serversqw(quanguo chaoshi geren boss shopwap appwap imsswap); for my $host(@servers){ my $exp=Expect->new(); $exp->spawn("ssh-copy-id -i /home/tomcat/.ssh/id_rsa.pub $host"); $exp->exp_internal(1); $exp->log_stdout(0); $exp->debug(3); $exp->expect(2,[ qr/connecting \(yes\/no\)\?/i,sub { my $self=shift; $self->send("yes\n"); exp_continue; }], [ qr/password: /i,sub { my $self=shift; $self->send("tomcat12300.\n"); exp_continue; }] ); [tomcat@StorageServer1 rex]$ chmod a+x login.pl [tomcat@StorageServer1 rex]$ ./login.pl
重启全部tomcat服务