说明:
提示:这篇文章仅是记录自己成长路上的愚笨,不喜勿喷,同时也希望各路大神提出优秀的观点。谢谢!!
问题描述:
使用Jenkins自动化构建、部署远程服务器tomcat项目
废话不多说,直接上代码:
- pipeline脚本
def createVersion() {
return new Date().format('yyyyMMddHHmmss') + "_${env.BUILD_ID}"
}
pipeline {
//定义执行任务的代理
agent any
//设置环境变量
environment {
_version = createVersion()
// 工作空间目录
workspace = pwd()
// 需要修改此处,定义项目名称
project = "server-customer-api-1.0-SNAPSHOT"
// 定义项目git地址
git_url = "http://192.168.0.193:9988/property/server-api.git"
//定义tomcat目录
tomcat_dir = "/home/web_programs/house_keeper/apache-tomcat-8.5.28/"
// 定义项目的webroot目录
project_dir = "${tomcat_dir}webapps/"
//定义项目的版本目录,一般不用更改
version_dir = "${workspace}/bak/"
//resource文件地址,根据项目不同而更改
resource_dir = "${workspace}/server-customer-api/target/"
}
options {
timestamps()
//禁用Jenkins同时执行多次该pipeline
disableConcurrentBuilds()
//pipeline运行超时时间
timeout(time: 20, unit: 'MINUTES')
//保留最近历史构建记录的数量
buildDiscarder(logRotator(numToKeepStr: '5'))
}
parameters {
string(name: 'branch', defaultValue: 'master', description: '请输入将要构建的代码分支')
choice(name: 'mode', choices: ['deploy', 'rollback'], description: '请选择发布或者回滚?')
string(name: 'version_id', defaultValue: '0', description: '回滚时用,默认回滚到上一次构建,如需要回滚到更早构建,请输入对应构建ID')
}
stages {
stage('拉取代码') {
steps {
echo 'Checkout'
script {
try {
git branch: "${branch}", url: "${git_url}"
} catch (err) {
echo "${err}"
}
}
}
}
stage('定义版本管理脚本') {
steps {
script {
try {
sh '''
# 《注意点一》
cat > keepfive.sh << 'EOF'
#! /bin/bash
cd ${version_dir}
while true;do
FILE_COUNT=$(ls *.war | wc -l)
FILE_NAME=$(ls -lrt *.war | tail -n 1 | awk \'{print $9}\')
if [[ $FILE_COUNT -gt 5 ]];then rm -rf $FILE_NAME;else break;fi;done
cd -
EOF
'''
} catch (err) {
echo "${err}"
}
}
}
}
stage('定义部署脚本') {
steps {
script {
try {
sh '''
cat << 'EOF' > deploy.sh
#! /bin/bash
# 《注意点二》
export JENKINS_NODE_COOKIE=dontKillMe
# "创建编译主机上的版本目录"
if [ ! -d "${version_dir}" ]; then
mkdir -p ${version_dir}
fi
# "将正在运行的代码同步到编译主机版本目录"
jar -cvfM0 ${version_dir}${_version}.war -C ${project_dir}/ROOT .
# "使版本目录保持五个版本历史"
chmod 755 keepfive.sh
# 《注意点三》
source ./keepfive.sh
# "将项目部署到服务器目录"
cp ${resource_dir}${project}.war "${project_dir}ROOT.war"
# 本地服务器重启
cd ${tomcat_dir}bin
# 《注意点四》
source /home/admin/.bash_profile
# 《注意点五》
export BUILD_ID=dontKillMe
# 《注意点六》
./restart.sh
cd -
# 远程部署
scp ${resource_dir}${project}.war admin@192.168.2.192:${project_dir}ROOT.war
# 远程重启服务器
ssh admin@192.168.2.192 << RS
cd /home/web_programs/house_keeper/apache-tomcat-8.5.28/bin
# 《注意点七》
./restart.sh
# 《注意点八》
exit
RS
EOF
'''
} catch (err) {
echo "${err}"
}
}
}
}
stage('部署') {
//定义阶段执行的条件
when {
environment name: 'mode', value: 'deploy'
}
steps {
script {
try {
sh '''mvn clean package -Dmaven.test.skip=true -P test
chmod 755 deploy.sh
source ./deploy.sh'''
} catch (err) {
echo "${err}"
}
}
}
}
stage('回滚') {
when {
environment name: 'mode', value: 'rollback'
}
steps {
script {
try {
if (params.version_id == '0') {
sh '''echo "选择回滚的版本是默认,将回滚到上次制品,回滚即将进行..."
cd ${version_dir}
file_name=`ls -lt *.war | tail -1 | awk \'{print $9}\'`
# 拷贝文件到本地服务器地址
cp ${version_dir}${file_name} ${project_dir}ROOT.war
# 本地服务器重启
cd ${tomcat_dir}/bin
./restart.sh
cd -
# 拷贝文件到远程服务器
scp ${version_dir}${file_name} admin@192.168.2.192:${project_dir}ROOT.war
# 远程服务器重启
ssh admin@192.168.2.192 << EOF
cd ${tomcat_dir}/bin
./restart.sh
exit
EOF
echo "=============="
echo "项目已回滚完成!"
echo "=============="'''
} else {
sh '''echo "选择回滚的版本是:${version_id},将回滚到 ${version_id} 的制品,回滚即将进行..."
cd ${version_dir}
# 拷贝文件到本地服务器地址
cp ${version_dir}${version_id} ${project_dir}ROOT.war
# 本地服务器重启
cd ${tomcat_dir}/bin
./restart.sh
cd -
# 拷贝文件到远程服务器
scp ${version_dir}${version_id} admin@192.168.2.192:${project_dir}ROOT.war
# 远程服务器重启
ssh admin@192.168.2.192 << EOF
cd ${tomcat_dir}/bin
./restart.sh
exit
EOF
echo "项目回滚到 ${version_id} 完成!"'''
}
} catch (err) {
echo "${err}"
}
}
}
}
}
}
- tomcat重启脚本(restart.sh)
#! /bin/bash
# =======================================================
# Author:yimeng
# Date:2021-01-24
# Description:tomcat服务器重启脚本
# =======================================================
# 定义项目文件名称
readonly PROJECT_FILE="ROOT.war"
PRG="$0"
# 获取重启脚本路径
PRGDIR=$(dirname ${PRG})
# 获取tomcat服务器目录
[ -z "${CATALINA_HOME}" ] && CATALINA_HOME=$(
# shellcheck disable=SC2164
cd "${PRGDIR}"/.. >/dev/null
pwd
)
# 执行前检查
function check() {
if [[ ! -f ${CATALINA_HOME}/bin/${PRG} ]]; then
echo "not found script"
exit 1
fi
if [[ ! -x ${CATALINA_HOME}/bin/${PRG} ]]; then
echo "the script is not executable"
exit 1
fi
if [[ ! -f ${CATALINA_HOME}/webapps/${PROJECT_FILE} ]]; then
echo "not found web file"
exit 1
fi
}
function restart() {
rm -rf ${CATALINA_HOME}/webapps/ROOT
# shellcheck disable=SC2006
PID=`ps -ef | grep -v grep | grep "${CATALINA_HOME}/bin/bootstrap.jar" | awk '{print $2}'`
if [ "${PID}" = "" ]; then
echo "tomcat is not active, next, to start"
${CATALINA_HOME}/bin/startup.sh
echo "tomcat is started"
else
#${CATALINA_HOME}/bin/shutdown.sh
sleep 3
kill -9 ${PID}
${CATALINA_HOME}/bin/startup.sh
echo "tomcat is started"
fi
}
check && restart
注意点:
-
注意点一:
带有重定向符的EOF一定要顶头写,否则结尾符号(暂且就这样叫吧)EOF不会起作用。并且 EOF带有单引号和不带有单引号的区别是:当带有单引号的EOF时,在EOF框定的脚本中的表达式不会解析,会原样输出,而不带单引号时,EOF框定的脚本中的表达式会被解析。
-
注意点二:
注意点二和注意点五都是阻止Jenkins在pipeline执行完毕后会杀死子进程的情况发生,详细了解可以查看Jenkins的说明。如果在脚本执行前不加那句export BUILD_ID=dontkillme,可以在Jenkins启动的时候加上:-Dhudson.util.ProcessTree.disable=true这句话(我是使用war包启动的)。 -
注意点三:一定要使用source执行处理历史版本的shell脚本,否则执行keepfive.sh会报 not found script 错误,至于sh、bash、./、source执行脚本的区别大家可以自行去度娘(fork、source、exec)。
-
注意点四:加载脚本的执行环境,以防止脚本执行的时候环境加载不全而导致某些命令报错(eg:not found command)
-
注意点六:此时就不可以使用source来执行了,一定要创建子进程来执行tomcat重启脚本(其实如果使用source来执行也不是不可以,只是tomcat重启脚本就需要改造了,而且会因服务器不同而造成脚本代码不同)。
-
注意点七:远程执行的命令就直接使用./来执行并且也不需要添加《注意点二》的代码了
-
注意点八:远程执行完一定要退出远程登录。因为是远程执行命令,所以知道为啥《注意点七》不用加那句话了吧。
最后:
好了,就先记录到这儿吧,欢迎大家提出优秀的观点和意见。
天天搬砖天天有,天天有砖天天搬。
加油!!!