Linux 项目上线管理 MAVEN + expect 一台机器管理所有机器的应用程序
一、目的
在一台服务器上面管理所有机器的应用程序.
设想是通过一条命令能够知道所有应用程序是否running
如果not running 查看具体项目的log 跟踪具体原因,程序问题汇报相关负责人
二.环境搭建(68部署服务器)
公司部门:业务部,数据处理部,系统运维部,数据挖掘部
/home/release/business
/home/release/datamining
/home/release/ops
/home/release/platform
ok 创建好目录我们来进行程序的上线操作
三、源码上传项目上线
1.提供相关文档(需求,设计,测试,部署,上线申请单)
2.评审ok 根据部署文档进行上线
//创建项目
mkdir /home/release/platform/dsbuffer
//打包需要在68安装maven
sh release_c_dsbuffer.sh deploy
//把打包好的lib以及conf文件部署到运行服务器上面以及启动项目
sh remoteRun.sh
//启动之后需要远程查看进程是否启动(expect )
sh remoteRunStatus
//查看远程启动日志
sh remoteRunLogs
3.好上线ok 就进入到运维阶段
前提把所有的remoteRunStatus 加入到remoteStatus.sh
这样是不是如果有100个程序我们只要运行一次就能知道程序的运行状态呢 是不是很帅气,不能在登陆到每台运行服务器上面查看进程
sh /home/release/ops/remoteStatus.sh
sh /home/release/platform/dsbuffer/remoteRunStatus
sh /home/release/platform/crawler/remoteRunStatus
4.基本的流程就是这样下面我来详细的解剖各个技术点
先来查看部署服务器上面查看
release_c_dsbuffer.sh 脚本
#编辑目录 标红地方就是项目名称打包到/home/release/platform/c_dsbuffer/
compileDir=/home/release/platform/c_dsbuffer/
svn_path=svn://portal.sina.com:3609/dataCrawl/crawlers/dsbuffer
check(){
cd ${compileDir}
echo ${compileUser}
svn checkout ${svn_path}
}
package(){
#进入到maven项目中
cd ${compileDir}/dsbuffer
mvn clean package
}
###################################
#读取脚本的第一个参数($1),进行判断
#参数取值范围:{package|check|deploy}
#如参数不在指定范围之内,则打印帮助信息
###################################
case "$1" in
'check')
check
;;
'package')
package
;;
'deploy')
check
package
;;
*)
echo "Usage: $0 {package|check|deploy}"
exit 1
esac
exit 0
~
好 打包ok
remoteRun.sh 脚本 把所有相关的lib和conf 复制到运行服务器上去 和 启动
source /home/release/platform/c_dsbuffer/constants.cfg
currentfolder=`pwd`
for ip in "${slaves[@]}";
do
#所用的常来参数到在constants.cfg里面配置
./run.sh $ip $user $pass $runDir $runShell $synShell
done
好查看一下constants.cfg文件
#常量配置文件
#运行服务器节点slaves=("192.166.32.79" "192.166.32.80") 也支持多机器的启动
slaves=("192.166.32.69")
#部署机器用户
user=crawler
#部署机器密码
pass=goodr
#部署机器的目录
runDir=/home/crawler/dsbuffer2_raw_page_hdfs_fruit/
#部署服务器同步脚本(69)
synShell=releaseSyn.sh
#部署服务器运行脚本(69)
runShell=run.sh
#监控日志地址
logPath=/home/crawler/dsbuffer2_raw_page_hdfs_fruit/nohup
~
好 下面来查看一下主要的run.sh
#!/usr/bin/expect
#同步,启动远程脚本 包括同步lib,同步conf
set ip [lindex $argv 0]
set user [lindex $argv 1]
set pass [lindex $argv 2]
set folder [lindex $argv 3]
set runShell [lindex $argv 4]
set synShell [lindex $argv 5]
//远程连接
spawn ssh $user@$ip
expect "$user@$ip's password:"
send "$pass\r"
expect "*$user*"
send "cd $folder\r"
expect "*$user*"
//复制lib到部署服务器上
send "sh $synShell lib\r"
//复制conf到部署服务器上
send "sh $synShell conf\r"
//启动部署服务器脚本
send "sh $runShell start\r"
send "exit\r"
好 最终会有日志
commons-digester-1.8.jar 100% 140KB 140.2KB/s 00:00
commons-el-1.0.jar 100% 110KB 109.7KB/s 00:00
commons-httpclient-3.0.1.jar 100% 273KB 273.2KB/s 00:00
commons-lang-2.5.jar 100% 273KB 272.7KB/s 00:00
commons-logging-1.1.1.jar 100% 59KB 59.3KB/s 00:00
commons-math-2.1.jar 100% 813KB 812.9KB/s 00:00
commons-net-1.4.1.jar 100% 177KB 176.6KB/s 00:00
core-3.1.1.jar 100% 3483KB 3.4MB/s 00:00
dsbuffer-0.0.1.jar 100% 48KB 48.3KB/s 00:00
ezmorph-1.0.6.jar 100% 84KB 84.5KB/s 00:00
hadoop-core-1.0.1.jar 100% 3818KB 3.7MB/s 00:00
hsqldb-1.8.0.10.jar 100% 690KB 690.2KB/s 00:00
imessage-0.0.3.jar 100% 138KB 138.3KB/s 00:00
jackson-core-asl-1.0.1.jar 100% 133KB 132.9KB/s 00:00
jackson-mapper-asl-1.0.1.jar 100% 264KB 264.4KB/s 00:00
jasper-compiler-5.5.12.jar 100% 396KB 395.6KB/s 00:00
jasper-runtime-5.5.12.jar 100% 75KB 74.9KB/s 00:00
jets3t-0.7.1.jar 100% 369KB 368.9KB/s 00:00
jetty-6.1.26.jar 100% 527KB 527.3KB/s 00:00
jetty-util-6.1.26.jar 100% 173KB 173.0KB/s 00:00
json-lib-2.4-jdk15.jar 100% 155KB 155.4KB/s 00:00
jsp-2.1-6.1.14.jar 100% 1001KB 1.0MB/s 00:00
jsp-api-2.1-6.1.14.jar 100% 132KB 131.8KB/s 00:00
junit-3.8.1.jar 100% 118KB 118.2KB/s 00:00
kfs-0.3.jar 100% 12KB 11.7KB/s 00:00
oro-2.0.8.jar 100% 64KB 63.7KB/s 00:00
protobuf-java-2.4.0a.jar 100% 439KB 439.3KB/s 00:00
servlet-api-2.5-20081211.jar 100% 131KB 131.0KB/s 00:00
servlet-api-2.5-6.1.14.jar 100% 129KB 129.3KB/s 00:00
slf4j-api-1.6.1.jar 100% 25KB 24.9KB/s 00:00
TCWordSeg-1.0.jar 100% 16KB 15.8KB/s 00:00
tool-1.0.4.jar 100% 247KB 246.7KB/s 00:00
xmlenc-0.52.jar 100% 15KB 14.7KB/s 00:00
[crawler@crawler02 dsbuffer2_raw_page_hdfs_fruit]$ sh releaseSyn.sh conf
/home/crawler/dsbuffer2_raw_page_hdfs_fruit exist OK...
/home/crawler/dsbuffer2_raw_page_hdfs_fruit/conf exist OK...
spawn scp server@192.168.32.68:/home/release/platform/c_dsbuffer/dsbuffer/conf/* /home/crawler/dsbuffer2_raw_page_hdfs_fruit/conf/
Address 192.168.32.68 maps to localhost, but this does not map back to the address - POSSIBLE BREAK-IN ATTEMPT!
server@192.168.32.68's password:
ds_dr_adapte.xml 100% 848 0.8KB/s 00:00
ds_dr_hdfs_weibo_noindex.xml 100% 1462 1.4KB/s 00:00
ds_dr_hdfs.xml 100% 1750 1.7KB/s 00:00
ds_raw_page_fruit.properties 100% 756 0.7KB/s 00:00
ds_raw_page_local.properties 100% 754 0.7KB/s 00:00
ds_raw_page_save.properties 100% 805 0.8KB/s 00:00
ds_user_relation.xml 100% 725 0.7KB/s 00:00
ds_weibo_repost.xml 100% 1750 1.7KB/s 00:00
libTCWordSeg.so 100% 743KB 742.6KB/s 00:00
scp: /home/release/platform/c_dsbuffer/dsbuffer/conf/tcsegdata: not a regular file
[crawler@crawler02 dsbuffer2_raw_page_hdfs_fruit]$ sh run.sh start
================================
warn: app start! (pid=859)
================================
expect eof
~
好部署服务器上面的命令看完之后 来看看运行服务器上面需要注意事项
先查看69 releaseSyn.sh 同步远程的lib 和 conf
#dir是部署机器的目录
runDir=/home/crawler/dsbuffer_raw_page_hdfs_fruit
#jarfile是源码打包后的jar包名称
jarfile=dsbuffer-0.0.1.jar
#编译机器目录
compileDir=/home/release/platform/c_dsbuffer/dsbuffer
#编译机器ip
compileIp=192.166.32.68
#编译机器登陆用户
compileUser=server1
####################################################
# 该同步脚本有以下3个功能:
# 1.conf目录
# 先清空conf,然后scp从编译机器远程传输conf
# 运行方式: ./syn.sh conf
#
# 2.同步lib目录
# 先清空lib,然后scp从编译机器远程传输lib
# 运行方式: ./syn.sh lib
#
# 3.同步源码编译后的jar
# scp从远程机器远程拷贝jar到lib下
# (一般修改了源码,这个操作即可,与同步整个lib目录相比,更为轻量级)、
# 运行方式: ./syn.sh jar
#
####################################################
#######################################################
# 将 target/lib下的源码编译好的jar,同步到部署目录下的lib里
######################################################
synjar() {
confirmDirExist ${runDir}
confirmDirExist ${runDir}/lib
echo ${compileUser}@${compileIp}:${compileDir}/target/lib/${jarfile} ${runDir}/lib/
#scp ${compileUser}@${compileIp}:${compileDir}/target/lib/${jarfile} ${runDir}/lib/
./scpSyn.sh ${compileDir}/target/lib/${jarfile} ${runDir}/lib/
}
####################################################
# 将 target下的lib目录下的所有jar,同步到部署目录下的lib里
####################################################
synlib() {
confirmDirExist ${runDir}
confirmDirExist ${runDir}/lib
rm -rf $runDir/lib/*
#scp ${compileUser}@${compileIp}:${compileDir}/target/lib/* ${runDir}/lib/
./scpSyn.sh ${compileDir}/target/lib/* ${runDir}/lib/
}
####################################################
# 同步 conf目录
####################################################
synconf() {
confirmDirExist ${runDir}
confirmDirExist ${runDir}/conf
#scp ${compileUser}@${compileIp}:${compileDir}/conf/* ${runDir}/conf
./scpSyn.sh ${compileDir}/conf/* ${runDir}/conf/
}
confirmDirExist() {
if [ -d $1 ]; then
echo $1" exist OK..."
else
mkdir $1
echo "mkdir "$1
fi
}
###################################
#读取脚本的第一个参数($1),进行判断
#参数取值范围:{jar|lib||conf}
#如参数不在指定范围之内,则打印帮助信息
###################################
case "$1" in
'jar')
synjar
;;
'lib')
synlib
;;
'conf')
synconf
;;
*)
echo "Usage: $0 {jar|lib||conf}"
exit 1
esac
exit 0
//远程复制不需要密码
#!/usr/bin/expect
# 复制操作 包括jar包 conf文件复制
set compileDir [lindex $argv 0]
set runDir [lindex $argv 1]
spawn scp server@196.166.32.68:$compileDir $runDir
expect "password:"
send "fruitr00t\r"
send "exit/r"
expect eof
~
//运行服务器环境ok 开始启动程序 关键程序就在这里 这样我们就可以 ./run.sh status 查看程序运行状态
#用户只配置Command和LogFile即可,脚本会以nohup方式运行Command,并打印日志到LogFile
#调用方式 ./run.sh start(启动) ./run.sh stop(停止) ./run.sh restart((重启) ./run.sh status(运行状态)
#原来爬虫存在进程起不来的情况,这个脚本可以重试,直到进程起来。
#Command中不能有连续多个空格,最多只能连续一个
Command="java -Xmx512m -Djava.ext.dirs=/home/crawler/dsbuffer2_raw_page_hdfs_fruit/lib com.fruit.dsbuffer.rawpage.hdfs.fruit.Boot"
LogFile="nohup"
psid=0
checkpid() {
javaps=`ps -aef | grep "$Command" | grep -v grep`
if [ -n "$javaps" ]; then
psid=`echo $javaps | awk '{print $2}'`
else
psid=0
fi
}
###################################
#(函数)启动程序
#
#说明:
#1. 首先调用checkpid函数,刷新$psid全局变量
#2. 如果程序已经启动($psid不等于0),则提示程序已启动
#3. 如果程序没有被启动,则执行启动命令行
#4. 启动命令执行后,再次调用checkpid函数
#5. 如果步骤4的结果能够确认程序的pid,则打印[OK],否则打印[Failed]
#注意:echo -n 表示打印字符后,不换行
#注意: "nohup 某命令 >/dev/null 2>&1 &" 的用法
###################################
start() {
checkpid
if [ $psid -ne 0 ]; then
echo "================================"
echo "warn: app already started! (pid=$psid)"
echo "================================"
else
echo -n "Starting $Command ..."
nohup $Command >>$LogFile&
checkpid
if [ $psid -ne 0 ]; then
echo "(pid=$psid) [OK]"
else
echo "[Failed]"
fi
fi
}
###################################
#(函数)停止程序
#
#说明:
#1. 首先调用checkpid函数,刷新$psid全局变量
#2. 如果程序已经启动($psid不等于0),则开始执行停止,否则,提示程序未运行
#3. 使用kill -9 pid命令进行强制杀死进程
#4. 执行kill命令行紧接其后,马上查看上一句命令的返回值: $?
#5. 如果步骤4的结果$?等于0,则打印[OK],否则打印[Failed]
#6. 为了防止java程序被启动多次,这里增加反复检查进程,反复杀死的处理(递归调用stop)。
#注意:echo -n 表示打印字符后,不换行
#注意: 在shell编程中,"$?" 表示上一句命令或者一个函数的返回值
###################################
stop() {
checkpid
if [ $psid -ne 0 ]; then
echo -n " ...(pid=$psid) "
kill -9 $psid
if [ $? -eq 0 ]; then
echo "[OK]"
else
echo "[Failed]"
fi
checkpid
if [ $psid -ne 0 ]; then
stop
fi
else
echo "================================"
echo "warn: app is not running"
echo "================================"
fi
}
###################################
#(函数)检查程序运行状态
#
#说明:
#1. 首先调用checkpid函数,刷新$psid全局变量
#2. 如果程序已经启动($psid不等于0),则提示正在运行并表示出pid
#3. 否则,提示程序未运行
###################################
status() {
checkpid
if [ $psid -ne 0 ]; then
echo "app is running! (pid=$psid)"
else
echo "app is not running"
fi
}
###################################
#读取脚本的第一个参数($1),进行判断
#参数取值范围:{start|stop|restart|status|info}
#如参数不在指定范围之内,则打印帮助信息
###################################
case "$1" in
'start')
start
;;
'stop')
stop
;;
'restart')
stop
start
;;
'status')
status
;;
*)
echo "Usage: $0 {start|stop|restart|status}"
exit 1
esac
exit 0
ok 程序上线完毕 下面来个流程图显示一下