参数化构建代码发布
整体思路
一定要看视频,有点蒙
依赖环境及工具
- Git
- Centos7及以上
- Gitlab
- Jenkins
- shell
- ansible
安装基础环境
Ansible install
yum安装
yum install -y epel-release
yum install -y ansible
配置文件
/etc/ansible/ansible.cfg ###主要为ansible一些基本配置
/etc/ansible/hosts ## ansible groups hosts 配置
shell
- control.sh 控制脚本调用ansible
#!/bin/bash
## version:1.2
## date: 2018-04-29
# ENV
PROJECT_NAME=$1
GITTYPE=$2
SERVICE=$3
HARDID= $4
# ansible hosts address
ANSIBLE_HOSTS_ADDR=/cron/base_conf/ansible_conf/ansible/hosts-xxx
#ansible command
/usr/bin/ansible -i $ANSIBLE_HOSTS_ADDR $PROJECT_NAME -m shell -a "/bin/bash /cron/xxx-scripts/update_code.sh $PROJECT_NAME $GITTYPE $SERVICE $HARDID"
- update code shell
#!/bin/bash
## version:1.2
## date: 2018-11-29 update
PROJECT=$1
PROJECT_TYPE=pro
# 判断环境
if [[ ${PROJECT:0-2} == 'hd' || ${PROJECT:0-2} == 'Hd' || ${PROJECT:0-2} == 'hD' || ${PROJECT:0-2} == 'HD' ]];then
PROJECT_TYPE='hd'
PROJECT=${PROJECT%${PROJECT:0-2}*}
elif [[ ${PROJECT:0-2} == 'cc' || ${PROJECT:0-2} == 'Cc' || ${PROJECT:0-2} == 'cC' || ${PROJECT:0-2} == 'CC' ]];then
PROJECT_TYPE='cc'
PROJECT=${PROJECT%${PROJECT:0-2}*}
fi
# 定义变量
PROJECT_NAME=$PROJECT
GIT_SSH_ADDR=git@gitlab.xxxxx:ERP/$PROJECT_NAME.git ### gitlab库
FILE_OWNER=carry
SCIRPTS_DIR=/cron/erp-scripts
if [ -d "/data/$PROJECT_NAME" ];then
CODE_DIR=/data
else
CODE_DIR=/app
fi
START_LOG=/tmp/$PROJECT\_version_iterate.log
rm -f $START_LOG
touch $START_LOG
# 检查项目名
if [ -z "$1" ];then
echo "please input project name!!!" >> $START_LOG 2>&1
exit 1
fi
#工程赋权
function chownpj()
{
cd $CODE_DIR/$PROJECT_NAME
for i in $(ls |grep -v 'upload')
do
chown -R $FILE_OWNER.$FILE_OWBER $i >> $START_LOG 2>&1
done
}
##拷贝函数,视情况进行相应设计。
function copy_file()
{
#appMobile
# cp /bak/$PROJECT/$PROJECT--$CUDATE/ini/{mongoConfig.xml,config.properties,task.xml} $CODE_DIR/$PROJECT_NAME/ini/ >> $START_LOG 2>&1
#appSyncBaseMsg
# cp /bak/$PROJECT/$PROJECT--$CUDATE/ini/{mongoConfig.xml,config.properties} $CODE_DIR/$PROJECT_NAME/ini/ >> $START_LOG 2>&1
#appSyncBiz
cp /bak/$PROJECT/$PROJECT--$CUDATE/ini/{jdbc.properties,config-timer-jdbc.properties,mongoConfig.xml,appTaskStartConfig.xml,task.xml,config.properties,appMainConfig.xml} $CODE_DIR/$PROJECT_NAME/ini/ >> $START_LOG 2>&1
# cp /bak/$PROJECT/$PROJECT--$CUDATE/WEB-INF/web.xml $CODE_DIR/$PROJECT_NAME/WEB-INF/ >> $START_LOG 2>&1
#webMobile2/webMobile3/webErp2/webFile
# cp /bak/$PROJECT/$PROJECT--$CUDATE/WEB-INF/classes/{config.properties,mongoConfig.xml,redis.properties} $CODE_DIR/$PROJECT_NAME/WEB-INF/classes >> $START_LOG 2>&1
#webErpReport
# cp /bak/$PROJECT/$PROJECT--$CUDATE/WEB-INF/classes/{config.properties,mongoConfig.xml,redis.properties} $CODE_DIR/$PROJECT_NAME/WEB-INF/classes >> $START_LOG 2>&1
# cp /bak/$PROJECT/$PROJECT--$CUDATE/WEB-INF/web.xml $CODE_DIR/$PROJECT_NAME/WEB-INF/ >> $START_LOG 2>&1
}
function code_clone()
{
chown -R $FILE_OWNER.$FILE_OWBER $START_LOG
runuser -l $FILE_OWNER -c "/bin/bash $SCIRPTS_DIR/newrestart.sh stop $PROJECT" >> $START_LOG 2>&1
if [ -d "/data/$PROJECT_NAME" ];then
cd /data/$PROJECT_NAME
GITREMOTE=`git remote -v 2>/dev/null|grep $PROJECT_NAME` >> $START_LOG 2>&1
if [[ -z $GITREMOTE ]];then
cd /data
mkdir -pv /bak/$PROJECT
CUDATE=`date +"%Y-%m-%d-%H-%M"`
mv /data/$PROJECT_NAME /bak/$PROJECT/$PROJECT--$CUDATE >> $START_LOG 2>&1
git clone $GIT_SSH_ADDR >> $START_LOG 2>&1
copy_file
else
cd /data/$PROJECT_NAME
git reset --hard origin/master
git pull -f >> $START_LOG 2>&1
fi
elif [ -f /app/$PROJECT_NAME/bin/server.sh ];then
cd /app/$PROJECT_NAME
GITREMOTE=`git remote -v 2>/dev/null|grep $PROJECT_NAME` >> $START_LOG 2>&1
if [[ -z $GITREMOTE ]];then
cd /app
mkdir -pv /bak/$PROJECT
CUDATE=`date +"%Y-%m-%d-%H-%M"`
mv /app/$PROJECT_NAME /bak/$PROJECT/$PROJECT--$CUDATE >> $START_LOG 2>&1
git clone $GIT_SSH_ADDR >> $START_LOG 2>&1
copy_file
else
cd /app/$PROJECT_NAME
git reset --hard origin/master
git pull -f >> $START_LOG 2>&1
fi
else
cd /data
git clone $GIT_SSH_ADDR > /dev/null 2>&1
fi
chownpj
}
function reback_one()
{
cd $CODE_DIR/$PROJECT_NAME
git reset --hard HEAD^ >> $START_LOG 2>&1
chownpj
}
function reback_two()
{
cd $CODE_DIR/$PROJECT_NAME
git reset --hard HEAD^^ >> $START_LOG 2>&1
chownpj
}
function reback_hard() {
cd $CODE_DIR/$PROJECT_NAME
git reset --hard $4 >> $START_LOG 2>&1
chownpj
}
## $2 git command
case "$2" in
pull)
code_clone
;;
reback_one)
reback_one
;;
reback_two)
reback_two
;;
reback_hard)
reback_hard
;;
none)
;;
*)
printf 'Usage: %s {pull|reback_one|reback_two|reback_hard}\n' "$"
exit 1
;;
esac
## restart service
chown -R $FILE_OWNER.$FILE_OWBER $START_LOG
runuser -l $FILE_OWNER -c "/bin/bash $SCIRPTS_DIR/newrestart.sh $3 $PROJECT" >> $START_LOG 2>&1
if [[ $? -eq 0 ]]; then
PROJECT_PID=`ps -ef | grep $PROJECT | grep java|awk '{print $2}'`
if [[ ! -z $PROJECT_PID ]];then
echo "@@@@@@@@ service $PROJECT $PROJECT_TYPE $3 Successfully!!!!,PID is: $PROJECT_PID. @@@@@@@@"
else
echo "!!!!!!!! service $PROJECT $PROJECT_TYPE $3 failed. !!!!!!!!"
fi
else
echo "!!!!!!!! service $PROJECT $3 $PROJECT_TYPE failed. !!!!!!!!"
fi
jenkins配置
所需插件
- Publish Over SSH
任务配置
可讲上述最后一步骤简化为
其他简化
简化后的control.sh
#!/bin/bash
## version:1.2
## date: 2018-04-29 update
## mail
# ENV
PROJECT_NAME=`cat /tmp/gitlab_jenkins_ansible.txt |awk '{print $1}'`
GITTYPE=`cat /tmp/gitlab_jenkins_ansible.txt |awk '{print $2}'`
SERVICE=`cat /tmp/gitlab_jenkins_ansible.txt |awk '{print $3}'`
#PROJECT_NAME=$1
#GITTYPE=$2
#SERVICE=$3
#HARDID= $4
echo $PROJECT_NAME $GITTYPE $SERVICE >/tmp/contorl.txt
# ansible hosts address
ANSIBLE_HOSTS_ADDR=/cron/ansible/hosts-nginx
#ansible command
/usr/bin/ansible -i $ANSIBLE_HOSTS_ADDR $PROJECT_NAME -m shell -a "/bin/bash /cron/nginx-scripts/update_code.sh $PROJECT_NAME $GITTYPE $SERVICE "
简化版本二:
#!/bin/bash
## version:1.0
## date: 2018-04-29 update
# ENV
PROJECT_NAME=`cat /tmp/gitlab_jenkins_ansible.txt |awk '{print $1}'`
GITTYPE=`cat /tmp/gitlab_jenkins_ansible.txt |awk '{print $2}'`
SERVICE=`cat /tmp/gitlab_jenkins_ansible.txt |awk '{print $3}'`
update_code_host="10.3.138.17"
ssh $update_code_host "/usr/bin/sh /cron/update_code.sh $PROJECT_NAME $GITTYPE $SERVICE"
简化后的update_code.sh
if [ $1 == nginx ];then
case $2 in
pull)
cd /usr/share/nginx/html/my-test1 && git pull;;
reback_one)
cd /usr/share/nginx/html/my-test1 && git reset --hard HEAD^ ;;
reback_two)
cd /usr/share/nginx/html/my-test1 && git reset --hard HEAD^^ ;;
*)
sleep 1;;
esac
case $3 in
restart)
nginx -s reload;;
start)
nginx;;
stop)
nginx -s quit;;
esac
fi
jenkins 流水线实例 了解
在插件里面搜索pipeline ,凡是有pipeline的都安装,完成后,重启jenkins
1、pipline 语法介绍
声明式的pipeline语法格式
1. 所有的声明都必须包含在pipeline{}中
2. 块只能有节段,指令,步骤或者赋值语句组成
3. 阶段:agent,stages,post,steps
4. 指令:environment,options,parameters,triggers,stage,input,tool,when
2、阶段
agent: 该指令用于指定构建代理的配置。agent any 表示在任何可用的构建代理上执行流水线。可以使用其他选项如 agent none(不在任何代理上执行)、agent {label 'label-name'}(在具有特定标签的代理上执行)等。
# jenkins 添加节点
stages: stages 指令用于定义流水线中的阶段。阶段是流水线的主要分组单元,用于将构建过程分解为不同的步骤。每个阶段可以包含一个或多个步骤。
steps: steps 指令用于定义流水线中某个阶段的步骤。步骤是构建过程中的具体操作,可以是 shell 脚本、构建命令、插件调用等。
post: post 指令用于定义在所有阶段完成后执行的操作。可以使用不同的条件来指定执行操作的时机,如 always(无论构建结果如何始终执行)、success(仅在构建成功时执行)等。在 post 指令内部,可以定义多个操作,如发送电子邮件通知、触发其他构建等。
3、指令
environment: environment 指令用于定义流水线中的环境变量。可以在流水线的任何阶段或步骤中使用这些环境变量。它们可以用于存储和传递配置信息、凭据、版本号等。
options: options 指令用于定义全局选项和配置。可以使用不同的选项来控制流水线的行为,如超时设置、并行执行、跳过失败的阶段等。
parameters: parameters 指令用于定义流水线的参数。参数可以用于接收用户输入,从而自定义构建过程。可以定义不同类型的参数,如字符串、布尔值、选择列表等。
triggers: triggers 指令用于定义触发流水线执行的条件或事件。可以使用不同的触发器来实现自动触发流水线,如定时触发、代码推送触发、其他流水线完成触发等。
stage: stage 指令用于定义流水线中的阶段。阶段是流水线的主要分组单元,用于将构建过程分解为不同的步骤。每个阶段可以包含一个或多个步骤。
input: input 指令用于在流水线的执行过程中暂停并等待用户输入。可以定义一个或多个输入步骤,以便用户提供必要的确认或参数输入,然后流水线继续执行。
tool: tool 指令用于在流水线中配置和使用工具。可以指定使用特定版本的构建工具、测试工具等。
when: when 指令用于根据条件来控制流水线中某个步骤或阶段的执行。可以使用不同的条件表达式来判断是否执行特定的步骤或阶段,如构建参数的值、环境变量的状态等。
4、示例
# 以下示例结合了部分常用的指令及阶段
pipeline {
agent any
options {
timeout(time: 1, unit: 'HOURS')
disableConcurrentBuilds()
}
parameters {
string(name: 'TARGET_ENV', defaultValue: 'dev', description: 'Target environment for deployment')
booleanParam(name: 'RUN_TESTS', defaultValue: true, description: 'Run tests during the build')
}
triggers {
cron('0 0 * * *') // 每天午夜触发
upstream(upstreamProjects: 'my-other-pipeline', threshold: hudson.model.Result.SUCCESS)
}
stages {
stage('Checkout') {
steps {
git branch: 'main', credentialsId: 'my-git-credentials', url: 'https://github.com/my-repo.git'
}
}
stage('Build') {
steps {
sh 'mvn clean package'
}
}
stage('Test') {
when {
expression { params.RUN_TESTS == true }
}
steps {
sh 'mvn test'
}
}
stage('Deploy') {
when {
environment name: 'TARGET_ENV', value: 'prod'
}
steps {
sh 'deploy-to-prod.sh'
}
}
}
post {
always {
emailext (
subject: 'Jenkins Pipeline - Build Status',
body: '''
构建完成
''',
to: 'my-email@example.com',
attachLog: true
)
}
}
}
使用 agent any 指定在任何可用的代理上运行流水线。
使用 options 指令设置了超时时间和禁用并发构建。
使用 parameters 指令定义了两个参数,用于接收目标环境和是否运行测试的用户输入。
使用 triggers 指令设置了每天午夜触发和上游流水线成功触发的条件。
使用 stages 指令定义了几个阶段,包括代码检出、构建、测试和部署。
使用 when 指令在测试和部署阶段根据条件进行了控制。
使用 post 指令定义了 always 块,在流水线执行结束后发送电子邮件通知构建状态,并附带构建日志。
pipeline:代表整条流水线,包含整条流水线的逻辑
agent:指定流水线的执行器 (在节点上)和工作区
stages:封装了用于定义流水线主体和逻辑的所有单个阶段定义
- 至少包含一个stage
stage:代表流水线的阶段,每个阶段都必须有名称
示例1 git 插件
pipeline {
agent any
stages {
stage('Checkout') {
steps {
git credentialsId: '2734cedf-7c61-400b-9562-2154c05f43d5', branch: 'main', url: 'git@192.168.96.164:xa2301/mypark.git'
sh "echo 代码拉取成功"
}
}
}
}
示例2 环境变量配置及使用
pipeline{
environment{
FIRSTNAME = "san"
LASTNAME = "zhang"
USERNAME = "${LASTNAME}${FIRSTNAME}"
}
agent any
stages{
stage('build'){
steps{
echo "名字${USERNAME}"
}
}
}
}
其中 environment 定义环境变量
示例3 emailext 插件
pipeline {
agent any
stages {
stage('代码授权') {
steps {
echo "测试"
}
}
}
post {
always {
emailext (
subject: '项目 【$PROJECT_NAME】 第【$BUILD_NUMBER】次构建 - $BUILD_STATUS!',
body: '''
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>${ENV, var="JOB_NAME"}-第${BUILD_NUMBER}次构建日志</title>
</head>
<body leftmargin="8" marginwidth="0" topmargin="8" marginheight="4"
offset="0">
<table width="95%" cellpadding="0" cellspacing="0" style="font-size: 11pt; font-family: Tahoma, Arial, Helvetica, sans-serif">
<h3>本邮件由系统自动发出,请勿回复!</h3>
<tr>
<br/>
各位同事,大家好,以下为${PROJECT_NAME }项目构建信息</br>
<td><font color="#CC0000">构建结果 - ${BUILD_STATUS}</font></td>
</tr>
<tr>
<td><br />
<b><font color="#0B610B">构建信息</font></b>
<hr size="2" width="100%" align="center" /></td>
</tr>
<tr>
<td>
<ul>
<li>项目名称 : ${PROJECT_NAME}</li>
<li>构建编号 : 第${BUILD_NUMBER}次构建</li>
<li>触发原因: ${CAUSE}</li>
<li>构建状态: ${BUILD_STATUS}</li>
<li>构建日志: <a href="${BUILD_URL}console">${BUILD_URL}console</a></li>
<li>构建 Url : <a href="${BUILD_URL}">${BUILD_URL}</a></li>
<li>工作目录 : <a href="${PROJECT_URL}ws">${PROJECT_URL}ws</a></li>
<li>项目 Url : <a href="${PROJECT_URL}">${PROJECT_URL}</a></li>
</ul>
<h4><font color="#0B610B">最近提交</font></h4>
<ul>
<hr size="2" width="100%" />
${CHANGES_SINCE_LAST_SUCCESS, reverse=true, format="%c", changesFormat="<li>%d [%a] %m</li>"}
</ul>
详细提交: <a href="${PROJECT_URL}changes">${PROJECT_URL}changes</a><br/>
</td>
</tr>
</table>
</body>
</html>
''',
to: '1161733918@qq.com',
attachLog: true
)
}
}
}
示例4 前后端分离项目上线
pipeline {
agent any
environment {
git_branch = "master"
git_cid = "2734cedf-7c61-400b-9562-2154c05f43d5"
git_url = "git@192.168.96.164:xa2301/ruoyi.git"
PATH = "/opt/node/bin:${env.PATH}"
}
tools {
maven 'maven388'
}
stages {
stage('代码拉取') {
steps {
script {
def cid = env.git_cid
def branch = env.git_branch
def url = env.git_url
git credentialsId: cid, branch: branch, url: url
echo "${url} CheckOut完成"
}
}
}
stage('前端打包') {
steps {
sh "cd ruoyi-ui && npm install && npm run build:prod"
}
}
stage('后端打包') {
steps {
sh "mvn package"
}
}
stage('代码拷贝') {
steps {
sh "` && cp -r dist/* /usr/share/nginx/html && chown nginx.nginx /usr/share/nginx/html -R"
sh "nohup java -jar -server -Xmx1024m -Xms1014m ./ruoyi-admin/target/ruoyi-admin.jar"
}
}
}
post {
always {
emailext (
subject: '项目 【$PROJECT_NAME】 第【$BUILD_NUMBER】次构建 - $BUILD_STATUS!',
body: '''
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>${ENV, var="JOB_NAME"}-第${BUILD_NUMBER}次构建日志</title>
</head>
<body leftmargin="8" marginwidth="0" topmargin="8" marginheight="4"
offset="0">
<table width="95%" cellpadding="0" cellspacing="0" style="font-size: 11pt; font-family: Tahoma, Arial, Helvetica, sans-serif">
<h3>本邮件由系统自动发出,请勿回复!</h3>
<tr>
<br/>
各位同事,大家好,以下为${PROJECT_NAME }项目构建信息</br>
<td><font color="#CC0000">构建结果 - ${BUILD_STATUS}</font></td>
</tr>
<tr>
<td><br />
<b><font color="#0B610B">构建信息</font></b>
<hr size="2" width="100%" align="center" /></td>
</tr>
<tr>
<td>
<ul>
<li>项目名称 : ${PROJECT_NAME}</li>
<li>构建编号 : 第${BUILD_NUMBER}次构建</li>
<li>触发原因: ${CAUSE}</li>
<li>构建状态: ${BUILD_STATUS}</li>
<li>构建日志: <a href="${BUILD_URL}console">${BUILD_URL}console</a></li>
<li>构建 Url : <a href="${BUILD_URL}">${BUILD_URL}</a></li>
<li>工作目录 : <a href="${PROJECT_URL}ws">${PROJECT_URL}ws</a></li>
<li>项目 Url : <a href="${PROJECT_URL}">${PROJECT_URL}</a></li>
</ul>
<h4><font color="#0B610B">最近提交</font></h4>
<ul>
<hr size="2" width="100%" />
${CHANGES_SINCE_LAST_SUCCESS, reverse=true, format="%c", changesFormat="<li>%d [%a] %m</li>"}
</ul>
详细提交: <a href="${PROJECT_URL}changes">${PROJECT_URL}changes</a><br/>
</td>
</tr>
</table>
</body>
</html>
''',
to: '1161733918@qq.com',
attachLog: true
)
}
}
}
T_URL}ws
- 项目 Url : ${PROJECT_URL}
''', to: '1161733918@qq.com', attachLog: true ) } } }<h4><font color="#0B610B">最近提交</font></h4> <ul> <hr size="2" width="100%" /> ${CHANGES_SINCE_LAST_SUCCESS, reverse=true, format="%c", changesFormat="<li>%d [%a] %m</li>"} </ul> 详细提交: <a href="${PROJECT_URL}changes">${PROJECT_URL}changes</a><br/> </td> </tr> </table>