背景:
java代碼需要進(jìn)行編譯打包,發(fā)布到一些servlet容器中進(jìn)行運行。
之前使用的方式就是本地打war包,通過ftp/sftp的方式上傳到指定的目錄下,然后重啟容器來發(fā)布。整個流程繁雜,非常的消耗人工,也增加了出錯的幾率。
原來的想法是要使用一些持續(xù)發(fā)布的框架的,但是配置過程較為復(fù)雜,所以使用shell腳本來達(dá)到目的~
編寫shell腳本
這是整理后的基本思路
1.安裝工作區(qū)
1.1.創(chuàng)建CI工作區(qū)目錄
1.2.下載并安裝maven
1.3.安裝lsof指令
1.4.通過git下載java代碼
2.編譯代碼
2.1.清空上一次生成的工作包
2.2.通過git pull 更新代碼
2.3.通過maven package打包代碼
2.4.拷貝打包的代碼到指定的CI工作區(qū)
3.部署代碼
3.1拷貝工作包到tomcat目錄下
3.2重啟tomcat
Done
下面是具體的腳本代碼:
進(jìn)入home目錄
$ cd /home
創(chuàng)建腳本文件
$ 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' #藍(lán)
PINK='\E[1;35m' #粉紅
RES='\E[0m'
# >>>>>>>>>>>>>>>>>>>>設(shè)置全局變量
# >>>>>>>>>>>>>>>>>> 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 的相關(guān)變量定義
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的相關(guān)變量的定義
TOMCAT_HOME_DIR="/usr/local/tomcat/apache-tomcat-8.0.35"
TOMCAT_DEPLOY_DIR="$TOMCAT_HOME_DIR/webapps"
TOMCAT_PORT="8091"
# 需要讀取相關(guān)的配置文件
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'`
# 定義相關(guān)的函數(shù)
# 返回 0 表示操作成功,小于 0 的所有返回值,均為執(zhí)行錯誤
# 安裝操作
function ciInstall {
### 創(chuàng)建CI工作區(qū)
echo -e "${BLUE_COLOR}[PO]>>>>>>>>>>>>>>>>> Create CI Dir >> >>>>>>>>>>>>>>>>${RES}"
#放心執(zhí)行,因為已經(jīng)存在的忽略掉的
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
}
# 配置設(shè)置
function ciConfig {
echo -e "${PINK}請輸入tomcat的所在目錄(默認(rèn):/usr/local/tomcat/apache-tomcat-8.0.35)? ${RES}"
read -p ":" _tomcatHome
if [ -z $_tomcatHome ]; then
echo -e "${PINK}確認(rèn)要使用默認(rèn)的安裝目錄: /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所使用的端口(默認(rèn):8091)?${RES}"
read -p ":" _tomcatPort
if [ -z $_tomcatPort ]; then
echo -e "${PINK}確認(rèn)要使用默認(rèn)的端口號: 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工作區(qū)的所有文件,慎用
function ciClean {
if [ ! -d $CI_HOME_DIR ]; then
#該目錄已經(jīng)不存在
echo -e "${PINK}目錄 : $CI_HOME_DIR 已不存在,無需刪除~ ${RES}"
return 22
fi
echo -e "${PINK}確認(rèn)要清除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工作區(qū)的 target & log目錄
function ciClear {
echo -e "${PINK}確認(rèn)要清除CI目錄的日志和目標(biāo)文件么?${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
}
# 構(gòu)建項目
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}"
# 這里需要替換成相應(yīng)的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
}
# 復(fù)制工程并重啟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
# 有時候會關(guān)閉掉,導(dǎo)致重啟不了
# 使用lsof強制進(jìn)行關(guān)閉
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]>>>>>> 是否使用當(dāng)前環(huán)境變量進(jìn)行發(fā)布?${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]>>>>>> 您輸入的參數(shù)錯誤,可選的參數(shù)如下: ${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 :將代碼發(fā)布到servlet容器中并重啟該容器 ${RES}"
echo -e "${GREEN_COLOR}[GO]>>>>>> ci conf :設(shè)置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
賦予可執(zhí)行的權(quán)限
$ chmod +x ci.sh
執(zhí)行即可
$ /home/ci.sh install && /home/ci.sh build && /home/ci.sh deploy
為了執(zhí)行更加方便,可以將腳本復(fù)制到用戶目錄下,這樣可以更加方便的執(zhí)行指令
$ cp /home/ci.sh /usr/bin/ci
這樣就可以直接在console中執(zhí)行
$ ci build
以上便完成了一個簡單的持續(xù)發(fā)布的功能
用時 : 18H
工具 : atom , xshell
腳本是在開發(fā)機的win上面寫的,寫好了通過xshell復(fù)制到目標(biāo)機器
學(xué)到了一個關(guān)于 vi 指令 的知識:
$ vi ci.sh
$ G (是的就是大寫)
$ :1,.d (這就是刪除文件中所有的文本)
然后 shift+insert 粘貼本地編寫好的腳本命令
[PS] 值得注意的一點就是:如果你需要用代碼比如:java,node,python來執(zhí)行這個sh腳本,里面用到的用戶安裝的程序比如:maven 需要使用完全限定的路徑,即使在環(huán)境變量文件中配置了也沒有用哦~,要么就安裝到系統(tǒng)的bin目錄下。
在這個shell腳本編寫的過程中學(xué)到的一些東西做一個簡單的匯總:
1.關(guān)于變量的使用
STR="abc" #中間是不允許出現(xiàn)空的的哦
#使用系統(tǒng)命令來定義變量
CODE="date '+%Y%m%d%H%M%S'" #這就使用了系統(tǒng)的date命令來生成一個時間變量
#使用變量
echo $CODE #在變量前面加上美元符號即可
#可以和任意的字符進(jìn)行拼接
echo "hello$CODE" #不需要任何的拼接字符
#可以使用變量定義的目錄直接運行
$MAVN_DIR/bin/mvn #直接執(zhí)行mvn指令
2.關(guān)于if的使用
if_[_a_=_"foo"_];_then
#code here
fi
#這里用_表示一定要鍵入空格,如果沒有空格,則會提示語法錯誤,切記不要忘記 fi來結(jié)束if語句
#關(guān)于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.關(guān)于用戶交互
#關(guān)于shell中獲取用戶的鍵盤輸入,需要用到關(guān)鍵字 read,比如:
read -p "確認(rèn)要清除CI目錄的日志和目標(biāo)文件么? plz type : y or n _____:" isYN
if [ $isYN = "y" ]; then
#code here...
else
echo "Bye"
fi
這里還有個比較棘手的問題還沒解決,就是在 read 狀態(tài)下,無法進(jìn)行退格[Backspace]操作,好糾結(jié)的問題
4.腳本配合參數(shù)
#執(zhí)行腳本時,可以通過傳入的參數(shù)執(zhí)行不同的操作,比如
#執(zhí)行安裝
$ ./ci.sh install
#執(zhí)行編譯
$ ./ci.sh build
#執(zhí)行部署
$ ./ci.sh deploy
這里緊跟在腳本后面的參數(shù)如何在shell中獲得呢?
這里需要用到一個神奇的變量
$1 $2 $3
這些變量是shell獲得到的執(zhí)行命令的參數(shù)值,比如:
如果指令是
$./ci.sh install build deploy
$1="install"
$2="build"
$3="deploy"
以此類推,當(dāng)然如果沒有參數(shù),這些值就是空的。
5.函數(shù)的使用
# 定義一個函數(shù) foo
function foo
{
echo "hello there~ $1"
return 0
# 注意一下,如果想要返回整數(shù),只能在 [0-255]之間,范圍之外的會執(zhí)行失敗
}
# 調(diào)用這個 foo函數(shù)
# 通過名稱即可
foo "Jack"
# $ hello there~ Jack
# 但是如何獲取這個函數(shù)的返回值呢?
retval=foo "Jack" #??? 千萬別這么做,這是個錯誤的示范
# 函數(shù)的返回值會放在 $? 這個神奇的變量中
foo "Jack"
retval=$?
#這樣就可以了;有點毀三觀哈。