精益化完成java代碼發(fā)布的探索

背景:

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=$?
#這樣就可以了;有點毀三觀哈。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,609評論 19 139
  • Ubuntu的發(fā)音 Ubuntu,源于非洲祖魯人和科薩人的語言,發(fā)作 oo-boon-too 的音。了解發(fā)音是有意...
    螢火蟲de夢閱讀 100,723評論 9 468
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 179,139評論 25 708
  • Spring Boot 參考指南 介紹 轉(zhuǎn)載自:https://www.gitbook.com/book/qbgb...
    毛宇鵬閱讀 47,275評論 6 342
  • 無論怎樣,農(nóng)村出身的我們是有著滲透到骨子里的自卑的。因為在世界任何一個角落,尤其是在中國,農(nóng)村等同于貧窮與落后,而...
    Naleon閱讀 417評論 0 0

友情鏈接更多精彩內(nèi)容