镜像说明
镜像ponylee/jenkins-centos7:v2.0基于镜像ponylee/jenkins-centos7:v1.0(镜像ponylee/jenkins-centos7:v1.0基于jenkins/jenkins:lts-centos7-jdk8, 添加 git maven jdk8 等java部署常用的工具。同时改变运行用户jenkins为root,放大权限)。
添加node-v14.18.2, 更改 openjdk 为 oracle jdk1.8,具体请参考。
启动jenkins
- host mode
docker run -d \
--network host \
-v /data/jenkins/jenkins_home:/var/jenkins_home \
-v /etc/localtime:/etc/localtime \
--name jenkins \
ponylee/jenkins-centos7:v2.0
- bridge mode
docker run -d \
-p 8080:8080 \
-p 50000:50000 \
-v /data/jenkins/jenkins_home:/var/jenkins_home \
-v /etc/localtime:/etc/localtime \
--name jenkins \
ponylee/jenkins-centos7:v2.0
jenkins配置
用到的plugins: Publish Over SSH、SSH plugin、Maven Integration、Date Parameter、NodeJS Plugin和 jenkins社区推荐的插件
General
选择参数配置
status选择
hosts
字符串参数配置
rollback_date
时间参数配置
依赖Date Parameter插件
选丢弃旧的构建
源码管理
Repositories 配置
git Credentials 配置
- 生成秘钥
ssh-keygen -t rsa -C "xxx@xx.com" #邮箱
git config --global user.name xxx
git config --global user.email xxx@xx.com
ssh -vT xx.github.com #验证联通性
cd ~/.ssh/
cat ~/.ssh/id_rsa.pub | clip #复制公钥
- 上传公钥
- 配置Credentials
Manage Jenkins -> Manage Credentials -> 全局凭据 ->添加凭据
构建
执行shell
后端构建
后端构建shell:
if [ ${status} = "deploy" ]
then
echo "================开始maven构建===================="
. /etc/bashrc
mvn -U clean package -Dmaven.test.skip=true -P release
else
echo "================开始回滚===================="
fi
前端构建
构建环境
构建
前端构建shell
if [ ${status} = "deploy" ]
then
echo "================开始构建===================="
npm install -unsafe-perm=true
npm run build
mv dist frontend
zip -qr frontend-${deploy_date}.zip frontend
else
echo "================开始回滚===================="
fi
Send files or execute commands over SSH
将后端/前端构建完成的包传送到指定的服务器节点
后端
前端
Publish over SSH 配置
Manage Jenkins -> Configure System -> Publish over SSH
Execute shell script on remote host using ssh
构建镜像
建构镜像shell
if [ ${status} = "deploy" ]
then
echo "================开始部署===================="
echo "开始构建镜像!!!"
cd /root/Images/
/bin/bash -x /root/Images/build.sh ${deploy_date} app-backend
else
echo "================开始回滚===================="
fi
后端部署服务
后端部署服务shell
if [ ${hosts} = "192.168.1.1" -o ${hosts} = "all" ]
then
echo "================开始部署192.168.1.1服务器===================="
/bin/bash -x /root/deploy/start/app-backend-start.sh ${status} app-backend ${deploy_date} ${rollback_date}
echo "================app-backend部署成功====================";
sleep 180;#热部署
fi
前端部署服务
前端服务不需要构建镜像,只需要部署服务
前端部署服务shell:
echo "================构建完成,开始发布===================="
/bin/bash /root/deploy/start/frontend-start.sh ${status} frontend01 ${deploy_date} ${rollback_date}
SSH site 配置
Manage Jenkins -> Configure System -> SSH remote hosts
SSH remote hosts Credentials配置
Manage Jenkins -> Manage Credentials -> 全局凭据 ->添加凭据
build.sh脚本
构建docker 镜像并推送到镜像私服
#!/bin/bash
#build.sh
BACKEND_PROJECTS="xx-backend-service1|xx-backend-service2"
function build(){
if (( $# < 2 )) ;then
echo "Please specify images version date parameters and project . eg: [20221215150431] [$BACKEND_PROJECTS]"
exit;
fi
IMAGE_VERSION=v${1}
PROJECT=${2}
#DATE=$(date '+%Y%m%d%H%M%S')
IMAGE="172.16.0.19:5000/${PROJECT}:$IMAGE_VERSION"
echo "docker build -t $IMAGE ."
docker build -t "${IMAGE}" .
echo "push ${IMAGE} ... "
docker push $IMAGE
echo "push success!"
mv *.jar ../builds/${PROJECT}-${1}.jar
echo "backup jar success!"
}
build $@
Dockerfile
#from java:8-jre-alpine
From anapsix/alpine-java
VOLUME /tmp
ADD *.jar app.jar
RUN sh -c 'touch /app.jar'
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && echo 'Asia/Shanghai' >/etc/timezone
ENV JAVA_OPTS="-Xms8g -Xmx8g -XX:NewRatio=1 -XX:SurvivorRatio=8 -XX:+UseG1GC -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/var/log/gc/heapdump.hprof"
ENV JAVA_LOG_OPTS="-Xloggc:/var/log/gc/gc_%t.log -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=10 -XX:GCLogFileSize=500m -XX:+PrintGCDateStamps -XX:+PrintGCDetails -XX:+PrintHeapAtGC -XX:+PrintGCApplicationStoppedTime -XX:+PrintGCApplicationConcurrentTime -XX:+PrintCommandLineFlags"
ENTRYPOINT [ "/bin/sh", "-c", "java $JAVA_OPTS $JAVA_LOG_OPTS -Djava.security.egd=file:/dev/./urandom -jar /app.jar $0 $@" ]
#ENTRYPOINT [ "/bin/sh", "-c", "java $JAVA_OPTS $JAVA_LOG_OPTS -Djava.security.egd=file:/dev/./urandom -jar /app.jar" ]
#CMD exec java $JAVA_OPTS $JAVA_LOG_OPTS -Djava.security.egd=file:/dev/./urandom -jar /app.jar
部署脚本
后端部署脚本
#!/bin/bash
#backend-start.sh
BACKEND_PROJECTS="xx-backend-service1|xx-backend-service2"
#TEST="sleep 100000"
[ -d /root/deploy/versions ] || mkdir -p /root/deploy/versions
IP=`hostname -i | awk '{print $1}'`
function deploy() {
if (( $# < 2 )) ;then
echo "Please specify images version date parameters and project . eg: [20221215150431] [$BACKEND_PROJECTS]"
exit 1;
fi
PROJECT=${1}
IMAGE_VERSION=v${2}
NEW_IMAGE=x.x.x.x:5000/${PROJECT}:$IMAGE_VERSION
LAST_CONTAINER=$(docker ps -a |awk '{print $NF}'| grep ${PROJECT})
touch /root/deploy/versions/$PROJECT
LAST_IMAGE=`awk 'END {print}' /root/deploy/versions/$PROJECT`
if [ -n $LAST_IMAGE ]
then
echo "當前版本: " $LAST_IMAGE
else
echo "当前为第一次部署"
fi
echo "docker pull $NEW_IMAGE"
docker pull $NEW_IMAGE
if [ $? -eq 0 ]; then
echo "镜像下载完毕"
else
echo "镜像下载失败,停止部署!"
exit 1;
fi
echo "即将部署新版本: $NEW_IMAGE"
echo "开始启动${PROJECT}服务 ..."
#shutdown 旧的服务
# stop the previous image and remove it
if [ -n "${LAST_CONTAINER}" ]; then
docker stop $LAST_CONTAINER
docker rm -f $LAST_CONTAINER
fi
if [[ $PROJECT =~ "backend" ]]
then
docker run -d \
-v /etc/localtime:/etc/localtime \
-v /data/log/:/var/log/app \
-v /data/gc:/var/log/gc \
-p 8080:8080\
--name=${PROJECT} \
--restart=always \
--privileged=true \
"$NEW_IMAGE" $TEST
else
if [ $IP="192.168.1.2" ]
then
PORT=8080
else
PORT=8081
fi
docker run -d \
-p $PORT:8080\
--restart=always \
--name=${PROJECT} \
-v /data/log:/var/log \
-v /etc/localtime:/etc/localtime \
-v /data/uploadFileTemp:/uploadFileTemp \
-v /data/gc:/var/log/gc \
--privileged=true \
$NEW_IMAGE $TEST
fi
echo $NEW_IMAGE >> /root/deploy/versions/$PROJECT
echo "服务${PROJECT}启动完成!"
if [ -n "${LAST_IMAGE}" ]; then
docker rmi $LAST_IMAGE
fi
}
function rollback() {
if (( $# < 1 )) ;then
echo "Please specify the project . eg: [${BACKEND_PROJECTS}] ,or [20221215150431] [${BACKEND_PROJECTS}] "
exit 1;
fi
PROJECT=${1}
IMAGE_VERSION=v${2}
NEW_IMAGE=x.x.x.x:5000/${PROJECT}:$IMAGE_VERSION
LAST_IMAGE=`awk 'END {print}' /root/deploy/versions/$PROJECT`
if [ $? -ne 0 ]; then
echo "尚未上綫,不可回滾,請開始第一次部署吧!"
exit 1;
fi
[ $LAST_IMAGE == $NEW_IMAGE ] && echo "當前版本已經是: " $NEW_IMAGE && exit 1
if [ ${IMAGE_VERSION} = v ]
then
# rollback_date無值,上一版本
CNT=`cat /root/deploy/versions/$PROJECT | wc -l`
if (( $CNT < 2 ))
then
echo "已经是最初的版本,已经没有版本可以回滚!!!"
exit 1;
fi
NEW_IMAGE=`cat /root/deploy/versions/$PROJECT | grep -B 1 $IMAGE_VERSION | awk 'NR==1{print}'`
fi
docker pull $NEW_IMAGE
if [ $? -eq 0 ]; then
echo "镜像下载完毕"
else
echo "镜像下载失败,停止回滚!"
exit 1;
fi
echo "即将回滚镜像至: $NEW_IMAGE"
echo "开始回滾${PROJECT}服务 ..."
#shutdown 旧的服务
LAST_CONTAINER=$(docker ps -a |awk '{print $NF}'| grep ${PROJECT})
# stop the previous image and remove it
if [ -n "${LAST_CONTAINER}" ]; then
docker stop $LAST_CONTAINER
docker rm -f $LAST_CONTAINER
fi
if [[ $PROJECT =~ "backend" ]]
then
docker run -d \
-v /etc/localtime:/etc/localtime \
-v /data/log/:/var/log/ \
-v /data/gc:/var/log/gc \
-p 8080:8080\
--name=${PROJECT} \
--restart=always \
--privileged=true \
${NEW_IMAGE} $TEST
else
if [ $IP = "192.168.1.2" ]
then
PORT=8080
else
PORT=8081
fi
docker run -d \
-p $PORT:8080\
--restart=always \
--name=${PROJECT} \
-v /data/log:/var/log/ \
-v /etc/localtime:/etc/localtime \
-v /data/uploadFileTemp:/uploadFileTemp \
-v /data/gc:/var/log/gc \
--privileged=true \
${NEW_IMAGE} $TEST
fi
echo $NEW_IMAGE >> /root/deploy/versions/$PROJECT
echo "服务${PROJECT}回滚完成!"
if [ -n "${LAST_IMAGE}" ]; then
docker rmi $LAST_IMAGE
fi
}
function printUsage(){
echo -e "Usage: [status] [project] [deploy_date] [rollback_date] . eg: [deploy|rollback] [${BACKEND_PROJECTS}] [20221215150431] [20221215150431] "
}
case "$1" in
(deploy)
deploy $2 $3
;;
(rollback)
rollback $2 $4
;;
(*)
printUsage
exit 1;
;;
esac
前端部署脚本
#!/bin/bash
#frontend-start.sh
FRONT_PROJECTS="frontend01|frontend02|frontend03"
[ -d /root/deploy/versions ] || mkdir -p /root/deploy/versions
[ -d /root/deploy/builds ] || mkdir -p /root/deploy/builds
function deploy() {
if (( $# < 2 )) ;then
echo "Please specify the version date parameters and the project . eg: [20221215150431] [${FRONT_PROJECTS}]"
exit 1;
fi
PROJECT=${1}
DATE=${2}
NEW_VERSION=${PROJECT}-$DATE.zip
ls /root/deploy/builds/${PROJECT}-${DATE}.zip
if [ $? -ne 0 ]; then
echo "新版本不存在或未构建成功,停止部署!"
exit 1;
fi
CURRENT_VERSION=`cat /root/deploy/versions/$PROJECT`
if [ $? -ne 0 ]; then
echo "當前版本: " `cat /root/deploy/versions/$PROJECT`
else
echo "当前为第一次部署"
fi
echo "即将部署新版本: $NEW_VERSION"
echo "开始部署${PROJECT}服务 ..."
set -e
cd /root/deploy
rm -rf ${PROJECT}
unzip -q builds/${NEW_VERSION} -d ./
/usr/sbin/nginx -s reload
echo $NEW_VERSION >> ./versions/$PROJECT
echo "服务${PROJECT}部署完成!"
}
function rollback() {
if (( $# < 1 )) ;then
echo "Please specify the project . eg: [${FRONT_PROJECTS}] ,or [20221215150431] [${FRONT_PROJECTS}] "
exit 1;
fi
PROJECT=${1}
DATE=${2}
CURRENT_VERSION=`cat /root/deploy/versions/$PROJECT`
if [ $? -ne 0 ]; then
echo "尚未上綫,不可回滾,請開始第一次部署吧!"
exit 1;
fi
if [ x${DATE} != x ]
then
# rollback_date有值,指定版本
ls /root/deploy/builds/${PROJECT}-${DATE}.zip
if [ $? -ne 0 ]; then
echo "要回滾的版本不存在,停止部署!"
exit 1;
fi
OLD_VERSION=${PROJECT}-${DATE}.zip
[ $CURRENT_VERSION == $OLD_VERSION ] && echo "當前版本已經是: " $CURRENT_VERSION && exit 1
else
# rollback_date無值,上一版本
CNT=`ls /root/deploy/builds | grep ${PROJECT} | grep p -B 1 $CURRENT_VERSION | wc -l`
if (( $CNT < 2 || $? ))
then
echo "已经是最早的版本,已经没有版本可以回滚!!!"
exit 1;
fi
OLD_VERSION=`ls /root/deploy/builds | grep ${PROJECT} | grep -B 1 $CURRENT_VERSION | awk 'NR==1{print}'`
fi
echo "當前版本: " $CURRENT_VERSION
echo "即将回滚版本至: $OLD_VERSION"
echo "开始回滾${PROJECT}服务 ..."
set -e
cd /root/deploy
rm -fr ${PROJECT}
unzip -q builds/${OLD_VERSION} -d ./
/usr/sbin/nginx -s reload
echo $OLD_VERSION >> versions/$PROJECT
echo "服务${PROJECT}回滚完成!"
}
function printUsage(){
echo -e "Usage: [status] [project] [deploy_date] [rollback_date] . eg: [deploy|rollback] [${FRONT_PROJECTS}] [20221215150431] [20221215150431] "
}
case "$1" in
(deploy)
deploy $2 $3
;;
(rollback)
rollback $2 $4
;;
(*)
printUsage
exit 1;
;;
esac
jenkins 部署
jenkins部署自动化实现,git仓库拉去代码、打包(包括后端打包和前端打包)、docker镜像构造、服务部署、版本控制。实现了一键部署和一键回滚。