背景:
java代码需要进行编译打包,发布到一些servlet容器中进行运行。
之前使用的方式就是本地打war包,通过ftp/sftp的方式上传到指定的目录下,然后重启容器来发布。整个流程繁杂,非常的消耗人工,也增加了出错的几率。
原来的想法是要使用一些持续发布的框架的,但是配置过程较为复杂,所以使用shell脚本来达到目的~
编写shell脚本
这是整理后的基本思路
1.安装工作区
1.1.创建CI工作区目录
1.2.下载并安装maven
1.3.安装lsof指令
1.4.通过git下载java代码
2.编译代码
2.1.清空上一次生成的工作包
2.2.通过git pull 更新代码
2.3.通过maven package打包代码
2.4.拷贝打包的代码到指定的CI工作区
3.部署代码
3.1拷贝工作包到tomcat目录下
3.2重启tomcat
Done
下面是具体的脚本代码:
进入home目录
$ cd /home
创建脚本文件
$ vi ci.sh
#! /bin/sh
#定义颜色的变量
RED_COLOR='\E[1;31m' #红
GREEN_COLOR='\E[1;32m' #绿
YELOW_COLOR='\E[1;33m' #黄
BLUE_COLOR='\E[1;34m' #蓝
PINK='\E[1;35m' #粉红
RES='\E[0m'
# >>>>>>>>>>>>>>>>>>>>设置全局变量
# >>>>>>>>>>>>>>>>>> api代码的目录
# >>>>>>>>>>>>>>>>>> ci代码库目录
# >>>>>>>>>>>>>>>>>> tomcat目录
#清屏
clear
# ci 的工作目录
CI_HOME_DIR="/home/ci/java"
CI_LIB_DIR="$CI_HOME_DIR/lib"
CI_TARGET_DIR="$CI_HOME_DIR/target"
CI_LOG_DIR="$CI_HOME_DIR/log"
CI_CONF_FILE="$CI_HOME_DIR/ci.conf"
# maven 的相关变量定义
MAVEN_VERSION="apache-maven-3.3.9"
MAVEN_TAR="$MAVEN_VERSION-bin.tar.gz"
MAVEN_DOWNLOAD_URI="http://mirrors.cnnic.cn/apache/maven/maven-3/3.3.9/binaries/$MAVEN_TAR"
MAVEN_DIR="$CI_LIB_DIR/$MAVEN_VERSION"
# tomcat的相关变量的定义
TOMCAT_HOME_DIR="/usr/local/tomcat/apache-tomcat-8.0.35"
TOMCAT_DEPLOY_DIR="$TOMCAT_HOME_DIR/webapps"
TOMCAT_PORT="8091"
# 需要读取相关的配置文件
if [ -f $CI_CONF_FILE ]; then
TOMCAT_HOME_DIR=`grep 'TOMCAT_HOME=' $CI_CONF_FILE`
TOMCAT_HOME_DIR=${TOMCAT_HOME_DIR#*=}
TOMCAT_PORT=`grep 'TOMCAT_PORT=' $CI_CONF_FILE`
TOMCAT_PORT=${TOMCAT_PORT#*=}
TOMCAT_DEPLOY_DIR="$TOMCAT_HOME_DIR/webapps"
fi
# 项目的变量定义
PROJECT_GIT="https://git.oschina.net/yfdever/BizApi.git"
PROJECT_DIR="$CI_HOME_DIR/BizApi"
PROJECT_SOURCE_DIR="$PROJECT_DIR/api"
PROJECT_TARGET_DIR="$PROJECT_SOURCE_DIR/target"
PROJECT_TARGET_VERSION_CODE=`date '+%m%d%H%M'`
# 定义相关的函数
# 返回 0 表示操作成功,小于 0 的所有返回值,均为执行错误
# 安装操作
function ciInstall {
### 创建CI工作区
echo -e "${BLUE_COLOR}[PO]>>>>>>>>>>>>>>>>> Create CI Dir >> >>>>>>>>>>>>>>>>${RES}"
#放心执行,因为已经存在的忽略掉的
mkdir -p $CI_HOME_DIR
mkdir -p $CI_LIB_DIR
mkdir -p $CI_TARGET_DIR
mkdir -p $CI_LOG_DIR
### 安装 maven
#判断是否安装过maven
if [ ! -d $MAVEN_DIR ]; then
echo -e "${BLUE_COLOR}[PO]>>>>>>>>>>>>>>>>> Install Maven >> >>>>>>>>>>>>>>>>${RES}"
cd $CI_LIB_DIR
wget $MAVEN_DOWNLOAD_URI
tar -zxvf $MAVEN_TAR
else
echo -e "${GREEN_COLOR}[OK]>>>>>>>>>>>>>>>>> Maven Installed >> >>>>>>>>>>>>>>>>${RES}"
fi
### 安装 git & lsof
echo -e "${BLUE_COLOR}[PO]>>>>>>>>>>>>>>>>> Install LSOF >> >>>>>>>>>>>>>>>>${RES}"
yum install lsof
echo -e "${GREEN_COLOR}[OK]>>>>>>>>>>>>>>>>> LSOF Installed >> >>>>>>>>>>>>>>>>${RES}"
### 下载代码
if [ ! -d $PROJECT_DIR ]; then
echo -e "${BLUE_COLOR}[PO]>>>>>>>>>>>>>>>>> Download Code From Git : >$PROJECT_GIT< ${RES}"
cd $CI_HOME_DIR
git clone $PROJECT_GIT
fi
echo -e "${GREEN_COLOR}[OK]>>>>>>>>>>>>>>>>> Code Downloaded ${RES}"
echo -e "${GREEN_COLOR}[OK]>>>>>>>>>>>>>>>>> Install Down ${RES}"
echo -e "${GREEN_COLOR}[OK]>>>>>>>>>>>>>>>>> New You Can Build The Api ${RES}"
echo -e "${GREEN_COLOR}[OK]>>>>>>>>>>>>>>>>> $ ci.sh build ${RES}"
return 0
}
# 配置设置
function ciConfig {
echo -e "${PINK}请输入tomcat的所在目录(默认:/usr/local/tomcat/apache-tomcat-8.0.35)? ${RES}"
read -p ":" _tomcatHome
if [ -z $_tomcatHome ]; then
echo -e "${PINK}确认要使用默认的安装目录: /usr/local/tomcat/apache-tomcat-8.0.35?${RES}"
read -p "[y/n]:" isYN
if [ ! $isYN = "y" ]; then
echo -e "${PINK}[ERROR]您已放弃本次配置,请在下一次部署工程前完成配置,否则将无法部署 ${RES}"
return 11
else
TOMCAT_HOME_DIR="/usr/local/tomcat/apache-tomcat-8.0.35"
fi
else
TOMCAT_HOME_DIR=$_tomcatHome
fi
echo -e "${PINK}请输入tomcat所使用的端口(默认:8091)?${RES}"
read -p ":" _tomcatPort
if [ -z $_tomcatPort ]; then
echo -e "${PINK}确认要使用默认的端口号: 8091?${RES}"
read -p "[y/n]:" isYN
if [ ! $isYN = "y" ]; then
echo -e "${PINK}[ERROR]您已放弃本次配置,请在下一次部署工程前完成配置,否则将无法部署 ${RES}"
return 12
else
TOMCAT_PORT="8091"
fi
else
TOMCAT_PORT=$_tomcatPort
fi
# 写入文件
rm -f $CI_CONF_FILE
echo "TOMCAT_HOME=$TOMCAT_HOME_DIR" > $CI_CONF_FILE
echo "TOMCAT_PORT=$TOMCAT_PORT" >> $CI_CONF_FILE
return 0
}
# 清空ci工作区的所有文件,慎用
function ciClean {
if [ ! -d $CI_HOME_DIR ]; then
#该目录已经不存在
echo -e "${PINK}目录 : $CI_HOME_DIR 已不存在,无需删除~ ${RES}"
return 22
fi
echo -e "${PINK}确认要清除CI目录么?${RES}"
read -p "[y/n]:" isYN
if [ $isYN = "y" ]; then
rm -rf $CI_HOME_DIR
else
echo "Bye"
return 21
fi
return 0
}
# 清楚ci工作区的 target & log目录
function ciClear {
echo -e "${PINK}确认要清除CI目录的日志和目标文件么?${RES}"
read -p "[y/n]:" isYN
if [ $isYN = "y" ]; then
rm -rf $CI_HOME_DIR/log/*
rm -rf $CI_HOME_DIR/target/*
else
echo "Bye"
return 31
fi
return 0
}
# 构建项目
function ciBuild {
echo -e "${BLUE_COLOR}[GO]>>>>>> CLEAN${RES}"
# 清空target目录下的文件
rm -rf $PROJECT_TARGET_DIR/*
if [ -f $CI_TARGET_DIR/api_deploy.war ]; then
rm -f $CI_TARGET_DIR/api_deploy.war
fi
echo -e "${GREEN_COLOR}[OK]>>>>>> CLEAN DONE${RES}"
#下拉代码
cd $PROJECT_DIR
echo -e "${BLUE_COLOR}[GO]>>>>>> PULL THE MASTER BRANCH CODE ${RES}"
git pull origin master
echo -e "${GREEN_COLOR}[OK]>>>>>> PULL DONE ${RES}"
echo -e "${BLUE_COLOR}[GO]>>>>>> BUILD THE SOURCE ${RES}"
#编译代码
cd $PROJECT_SOURCE_DIR
$MAVEN_DIR/bin/mvn package > $CI_LOG_DIR/MAVEN_PACKAGE_$PROJECT_TARGET_VERSION_CODE.log
echo -e "${GREEN_COLOR}[OK]>>>>>> BUILD DONE ${RES}"
#ls -l $API_TARGET_DIR
echo -e "${BLUE_COLOR}[GO]>>>>>> Copy to target dir ${RES}"
# 这里需要替换成相应的tomcat的目录
cp $PROJECT_TARGET_DIR/api.war $CI_TARGET_DIR/api_$PROJECT_TARGET_VERSION_CODE.war
cp $PROJECT_TARGET_DIR/api.war $CI_TARGET_DIR/api_deploy.war
echo -e "${GREEN_COLOR}[OK]>>>>>> Target Version : $PROJECT_TARGET_VERSION_CODE"
echo -e "${GREEN_COLOR}[OK]>>>>>> You Need TO Deploy ${RES}"
echo -e "${GREEN_COLOR}[OK]>>>>>> Like: $ ./ci.sh deploy ${RES}"
return 0
}
# 复制工程并重启tomcat
function ciRestart {
if [ -z $1 ]; then
target_war="$CI_TARGET_DIR/api_deploy.war"
fi
echo "target_war $target_war"
if [ ! -f $target_war ]; then
echo -e "${PINK}[ERROR]>>>>>> Cant Find The TargetWar File~ You Need Run The Next Command: ${RES}"
echo -e "${GREEN_COLOR}[OK]>>>>>> $ ./ci.sh build ${RES}"
return 52
fi
echo -e "${BLUE_COLOR}[GO]>>>>>> SHUTDOWN TOMCAT ${RES}"
$TOMCAT_HOME_DIR/bin/shutdown.sh
# 有时候会关闭掉,导致重启不了
# 使用lsof强制进行关闭
kill -9 `lsof -t -i:$TOMCAT_PORT`
echo -e "${GREEN_COLOR}[OK]>>>>>> Shutdown ok ${RES}"
cp $target_war $TOMCAT_DEPLOY_DIR/api.war
$TOMCAT_HOME_DIR/bin/startup.sh
if [ ! -f $TOMCAT_DEPLOY_DIR/api.war ]; then
echo -e "${PINK}[ERROR]>>>>>> API deploy failed~ plz run again ${RES}"
return 51
else
echo -e "${GREEN_COLOR}[OK]>>>>>> Success~ Deploy Finished~ ${RES}"
fi
return 0
}
# 手动部署项目
function ciDeploy {
target_war="$CI_TARGET_DIR/api_deploy.war"
if [ ! -z $1 ]; then
echo $1
target_war="$CI_TARGET_DIR/api_$1.war"
fi
echo $target_war
echo -e "${GREEN_COLOR}[GO]>>>>>> Deploy ${RES}"
echo -e "${GREEN_COLOR}[GO]>>>>>> The Tomcat Var Is: ${RES}"
echo -e "${GREEN_COLOR}[OK]>>>>>> TOMCAT_HOME_DIR At $TOMCAT_HOME_DIR ${RES}"
echo -e "${GREEN_COLOR}[OK]>>>>>> TOMCAT_PORT At $TOMCAT_PORT ${RES}"
echo -e "${GREEN_COLOR}[OK]>>>>>> TOMCAT_DEPLOY_DIR At $TOMCAT_DEPLOY_DIR ${RES}"
echo -e "${GREEN_COLOR}[OK]>>>>>> 是否使用当前环境变量进行发布?${RES}"
read -p "[y/n]:" isYN
if [ ! $isYN = "y" ]; then
echo -e "${GREEN_COLOR}[OK]>>>>>> 请输入 $ ci.sh conf 重新配置tomcat的目录${RES}"
return 41
fi
ciRestart $target_war
return $?
}
# 自动部署项目
function ciPublish {
ciRestart
return $?
}
function ciRequireCommand {
echo -e "${GREEN_COLOR}[GO]>>>>>> 您输入的参数错误,可选的参数如下: ${RES}"
echo -e "${GREEN_COLOR}[GO]>>>>>> ci install : 安装ci目录,maven,下载git代码 ${RES}"
echo -e "${GREEN_COLOR}[GO]>>>>>> ci build :编译git仓库中最新的代码 ${RES}"
echo -e "${GREEN_COLOR}[GO]>>>>>> ci deploy :将代码发布到servlet容器中并重启该容器 ${RES}"
echo -e "${GREEN_COLOR}[GO]>>>>>> ci conf :设置servlet容器的目录和端口 ${RES}"
}
echo -e "${BLUE_COLOR}[GO]>>>>>>>>>>>> Command:[$1]>>>>>>>>>>>>>>${RES}"
#没有值
if [ -z $1 ]; then
ciRequireCommand
exit
## 安装流程
elif [ $1 = "install" ]; then
ciInstall
elif [ $1 = "conf" ]; then
ciConfig
if [ $? > 0 ]; then
exit
fi
elif [ $1 = "clean" ]; then
ciClean
if [ $? > 0 ]; then
exit
fi
elif [ $1 = "clear" ]; then
ciClear
if [ $? > 0 ]; then
exit
fi
elif [ $1 = "build" ]; then
ciBuild
elif [ $1 = "deploy" ]; then
ciDeploy $2
elif [ $1 = "publish" ]; then
ciPublish
if [ $? > 0 ]; then
exit
fi
else
ciRequireCommand
exit
fi #end if
赋予可执行的权限
$ chmod +x ci.sh
执行即可
$ /home/ci.sh install && /home/ci.sh build && /home/ci.sh deploy
为了执行更加方便,可以将脚本复制到用户目录下,这样可以更加方便的执行指令
$ cp /home/ci.sh /usr/bin/ci
这样就可以直接在console中执行
$ ci build
以上便完成了一个简单的持续发布的功能
用时 : 18H
工具 : atom , xshell
脚本是在开发机的win上面写的,写好了通过xshell复制到目标机器
学到了一个关于 vi 指令 的知识:
$ vi ci.sh
$ G (是的就是大写)
$ :1,.d (这就是删除文件中所有的文本)
然后 shift+insert 粘贴本地编写好的脚本命令
[PS] 值得注意的一点就是:如果你需要用代码比如:java,node,python来执行这个sh脚本,里面用到的用户安装的程序比如:maven 需要使用完全限定的路径,即使在环境变量文件中配置了也没有用哦~,要么就安装到系统的bin目录下。
在这个shell脚本编写的过程中学到的一些东西做一个简单的汇总:
1.关于变量的使用
STR="abc" #中间是不允许出现空的的哦
#使用系统命令来定义变量
CODE="date '+%Y%m%d%H%M%S'" #这就使用了系统的date命令来生成一个时间变量
#使用变量
echo $CODE #在变量前面加上美元符号即可
#可以和任意的字符进行拼接
echo "hello$CODE" #不需要任何的拼接字符
#可以使用变量定义的目录直接运行
$MAVN_DIR/bin/mvn #直接执行mvn指令
2.关于if的使用
if_[_a_=_"foo"_];_then
#code here
fi
#这里用_表示一定要键入空格,如果没有空格,则会提示语法错误,切记不要忘记 fi来结束if语句
#关于shell的逻辑判断用到的有:
# 1. -d 判断某个目录是否已存在;
# 至于非判断就是在前面加上感叹号 ! 表示取反
#比如:
if [ -d "/home/ci" ]; then
#code here...
fi
# OR 判断目录不存在 [不要省去任何空格哦]
if [ ! -d "/home/ci" ]; then
#code here...
fi
# 2. -f 判断某个文件是否已存在,比如:
if [ -f "/home/ci.sh" ]; then
#code here...
fi
# 3. -z 判断字符串是空值
if [ -z $str ]; then
#code here..
fi
# 4. -n 判断字符串非空
if [ -n $str ]; then
#code here
fi
3.关于用户交互
#关于shell中获取用户的键盘输入,需要用到关键字 read,比如:
read -p "确认要清除CI目录的日志和目标文件么? plz type : y or n _____:" isYN
if [ $isYN = "y" ]; then
#code here...
else
echo "Bye"
fi
这里还有个比较棘手的问题还没解决,就是在 read 状态下,无法进行退格[Backspace]操作,好纠结的问题
4.脚本配合参数
#执行脚本时,可以通过传入的参数执行不同的操作,比如
#执行安装
$ ./ci.sh install
#执行编译
$ ./ci.sh build
#执行部署
$ ./ci.sh deploy
这里紧跟在脚本后面的参数如何在shell中获得呢?
这里需要用到一个神奇的变量
$1 $2 $3
这些变量是shell获得到的执行命令的参数值,比如:
如果指令是
$./ci.sh install build deploy
$1="install"
$2="build"
$3="deploy"
以此类推,当然如果没有参数,这些值就是空的。
5.函数的使用
# 定义一个函数 foo
function foo
{
echo "hello there~ $1"
return 0
# 注意一下,如果想要返回整数,只能在 [0-255]之间,范围之外的会执行失败
}
# 调用这个 foo函数
# 通过名称即可
foo "Jack"
# $ hello there~ Jack
# 但是如何获取这个函数的返回值呢?
retval=foo "Jack" #??? 千万别这么做,这是个错误的示范
# 函数的返回值会放在 $? 这个神奇的变量中
foo "Jack"
retval=$?
#这样就可以了;有点毁三观哈。