精益化完成java代码发布的探索

背景:

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=$?
#这样就可以了;有点毁三观哈。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 201,784评论 5 474
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,745评论 2 378
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 148,702评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,229评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,245评论 5 363
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,376评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,798评论 3 393
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,471评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,655评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,485评论 2 318
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,535评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,235评论 3 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,793评论 3 304
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,863评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,096评论 1 258
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,654评论 2 348
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,233评论 2 341

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,573评论 18 139
  • Ubuntu的发音 Ubuntu,源于非洲祖鲁人和科萨人的语言,发作 oo-boon-too 的音。了解发音是有意...
    萤火虫de梦阅读 99,102评论 9 467
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,331评论 25 707
  • Spring Boot 参考指南 介绍 转载自:https://www.gitbook.com/book/qbgb...
    毛宇鹏阅读 46,714评论 6 342
  • 无论怎样,农村出身的我们是有着渗透到骨子里的自卑的。因为在世界任何一个角落,尤其是在中国,农村等同于贫穷与落后,而...
    Naleon阅读 335评论 0 0