一、背景和原理
1.1 背景
由于公司新项目线采用K8S来管理应用,所以会出现应用频繁发版的情况。
1.2 原理
大致过程就是从gitlab上拉取代码,然后编译,修改配置文件为生产环境配置,通过写好的dockerfile打包应用成镜像,然后push到远程镜像仓库,最后通过kubectl set image实现服务无中断更新。
二、基础jenkins项目搭建过程
2.1 参数化构建项目 【This project is parameterized】
2.1.1 projectVals
项目名称由两部分组成,“,”前面的是k8s中的deploymentName,“,”后面的是服务名称;这些参数在下面的执行时shell会使用到。
2.2.2 gitVersion
应用的git版本号,这个参数由用户传入。
2.1.3 isSpringBoot
boolean 类型的参数,用来判断应用是否为springboot项目,默认不勾选为springMVC项目
2.1.4 isMvnBuild
boolean 类型的参数,用来判断应用是否需要编译,默认勾选启用编译
2.1.5 dockerStore
choice 类型的参数,阿里云远程镜像仓库名称
2.1.6 dockerHubName/dockerHubPasswd
远程镜像仓库名称,因为把镜像push到远程镜像仓库是需要用户名和密码的,这些参数作为参数传递进去。
2.1.7 isUpdateDPM
是否需要更新应用镜像,默认勾选
2.1.8 nameSpace
选择生产环境执行在那个命名空间更新镜像
2.2 限制项目运行的节点 【Restrict where this project can be run】
2.3 通过执行时shell构建项目 【Execute shell】
2.3.1 执行时shell
- 执行时shell需要根据自身的应用针对性的修改下,以下执行时shell只是提供参考
contentName="$project"
currentTime=`date "+%Y%m%d%H%M"`
echo $currentTime
export PATH="/opt/apache-maven-3.3.3/bin:$PATH"
projectVals=(${projectVals//,/ })
projectName=${projectVals[0]}
project=${projectVals[1]}
finalName=${projectVals[2]}
if [ "$finalName" == "" ]; then
finalName=$project
fi
tag=$finalName-${gitVersion##*/}-$currentTime
if [ "true" = "$isMvnBuild" ]; then
echo "编译开始……"
cd /programs
if [ -d $project ]; then
echo $project" is exist"
else
git clone [email protected]:backstage/$project.git
fi
cd /programs/$project/
if [ "true" = "$isMvnBuild" ]; then
git fetch origin
git checkout $gitVersion
git pull origin $gitVersion
fi
rm -rf ~/.m2/repository/com/mogucaifu/
if [ "mogu-im" = "$project" ]; then
sh insurance.sh
else
mvn clean package -Dmaven.test.skip=true
fi
echo "编译完成。"
fi
cd /programs/$project/
if [ "true" != "$isSpringBoot" ] ; then
cd target/$finalName/WEB-INF/classes
pwd
ls
if [ -f "$finalName-mq.properties" ] ; then
sed -i 's|.mg.addr|1-mg-addr|g' $finalName-mq.properties
sed -i 's|mq-mg-addr|mq1-mg-addr|g' $finalName-mq.properties
fi
echo "set prod zookeeper"
sed -i 's|{dubbo.registry.address}|{dubbo.registry.cluster.address}|g' $finalName-*.xml
if [ ! -z "`grep 'redis' $finalName-spring-context-server.xml`" ]; then
echo "set prod redis config"
sed -i 's|redis-cluster|redis|g' $finalName-spring-context-server.xml
sed -i 's|=redis.mg.addr|=mgy-insurance-redis.redis.rds.aliyuncs.com|g' $finalName-*redis.properties
sed -i 's|=Mogu07550831..|=Mogu07550831**|g' $finalName-*redis.properties
fi
if [ ! -z "`grep 'jdbc.properties' $finalName-spring-context-server.xml`" ]; then
echo "set prod mysql config"
sed -i 's|jdbc.mg.addr|mgy-insurance.mysql.rds.aliyuncs.com|g' *jdbc.properties
sed -i 's|jdbc.moni.username=moni|jdbc.moni.username=insurance|g' *jdbc.properties
sed -i 's|jdbc.moni.password=moni_test|jdbc.moni.password=Insurance07550831**|g' *jdbc.properties
sed -i 's|jdbc.game.username=game|jdbc.game.username=insurance|g' *jdbc.properties
sed -i 's|jdbc.game.password=game_test|jdbc.game.password=Insurance07550831**|g' *jdbc.properties
fi
if [ ! -z "`grep 'mongo.properties' $finalName-spring-context-server.xml`" ]; then
echo "set prod mongo config"
sed -i 's|=mongo.mg.addr:27017|=mgyinsurance.mongodb.rds.aliyuncs.com:3717,mgyinsurancesec.mongodb.rds.aliyuncs.com:3717|g' *-mongo.properties
sed -i 's|mongo.mg.addr|mgyinsurancesec.mongodb.rds.aliyuncs.com|g' *-mongo.properties
sed -i 's|mongo.readonly.mg.addr|mgyinsurancesec.mongodb.rds.aliyuncs.com|g' *-mongo.properties
sed -i 's|27017|3717|g' *-mongo.properties
fi
if [ ! -z "`grep 'redisson' $finalName-spring-context-server.xml`" ]; then
echo "set prod redisson config"
sed -i 's|redisson-cluster.xml|redisson.xml|g' $finalName-spring-context-server.xml
fi
if [ -f "mogu-user-center-server-conf.properties" ] ; then
sed -i 's|sys.orgId=1000|sys.orgId=12000|g' mogu-user-center-server-conf.properties
fi
cd /programs/$project/target
cp /programs/Dockerfile .
sed -i "s|{project}|${finalName}|g" Dockerfile
else
cd /programs/$project/target
jarfile=`ls *.jar | head -1`
pwd
ls
if [ "chicken-server" = "$project" ]; then
jar -xf $jarfile
sed -i 's|dubbo.registry.address|dubbo.registry2.address|g' BOOT-INF/classes/application.properties
sed -i 's|dubbo.registry.cluster.address|dubbo.registry.address|g' BOOT-INF/classes/application.properties
sed -i 's|jdbc.mg.addr|mgy-insurance.mysql.rds.aliyuncs.com|g' BOOT-INF/classes/application.properties
sed -i 's|spring.datasource.username=moni|spring.datasource.username=insurance|g' BOOT-INF/classes/application.properties
sed -i 's|spring.datasource.password=moni_test|spring.datasource.password=Insurance07550831**|g' BOOT-INF/classes/application.properties
sed -i 's|redis.conf.path=redis-cluster.properties|redis.conf.path=redis.properties|g' BOOT-INF/classes/application.properties
sed -i 's|redis.xml.path=chicken-server-redis-cluster.xml|redis.xml.path=chicken-server-redis.xml|g' BOOT-INF/classes/application.properties
sed -i 's|redis.mg.addr|mgy-insurance-redis.redis.rds.aliyuncs.com|g' BOOT-INF/classes/redis.properties
sed -i 's|Mogu07550831..|Mogu07550831**|g' BOOT-INF/classes/redis.properties
sed -i 's|.mg.addr|1-mg-addr|g' BOOT-INF/classes/chicken-server-mq.properties
sed -i 's|mq-mg-addr|mq1-mg-addr|g' BOOT-INF/classes/chicken-server-mq.properties
sed -i 's|=mongo.mg.addr|=mgyinsurance.mongodb.rds.aliyuncs.com|g' BOOT-INF/classes/mongodb.properties
sed -i 's|27017|3717|g' BOOT-INF/classes/mongodb.properties
cp -f BOOT-INF/classes/application.properties classes/
jar -uvf $jarfile BOOT-INF/classes/application.properties BOOT-INF/classes/mongodb.properties BOOT-INF/classes/redis.properties BOOT-INF/classes/chicken-server-mq.properties
fi
cp -f /programs/sbDockerfile Dockerfile
sed -i "s|{project}|${project}|g" Dockerfile
sed -i "s|{jarfile}|${jarfile}|g" Dockerfile
fi
sudo docker login --username $dockerHubName --password $dockerHubPasswd registry-internal.cn-shenzhen.aliyuncs.com
sudo docker build -t registry-internal.cn-shenzhen.aliyuncs.com/moguyun-prod/$dockerStore:$tag .
sudo docker push registry-internal.cn-shenzhen.aliyuncs.com/moguyun-prod/$dockerStore:$tag
echo "tag=${tag}" > /programs/temp-propfile.txt
echo "projectName=${projectName}" >> /programs/temp-propfile.txt
- 执行时shell用到的Dockerfile
FROM registry.moguyun.com/tomcat:9.26
MAINTAINER XXX moguyun.com
ENV SOURCEPATH {project}
ENV TARGETPATH /opt/tomcat/webapps
ENV RUN_OPTION "-Xms1g -Xmx4g -Xmn256m -Dfile.encoding=UTF-8"
ADD $SOURCEPATH $TARGETPATH/$SOURCEPATH
RUN echo 'echo "export dubboPort=$DUBBO_PORT" >> /etc/profile' >> /bin/sysinit.sh
EXPOSE 8080
CMD ["sh", "-c", "/bin/sysinit.sh \"$RUN_OPTION\" \"$PNAME\" 0 \"$DUBBO_PORT\" "]
- 执行时shell用到的sbDockerfile
FROM registry.moguyun.com/centos:7.6
MAINTAINER XXX moguyun.com
ENV JAR_FILE {jarfile}
ENV RUN_PORT 8080
ENV RUN_OPTION "-server -Xms1g -Xmx4g -Xmn256m -Dfile.encoding=UTF-8"
COPY $JAR_FILE /opt/app.jar
COPY classes/application* /opt/
WORKDIR /opt
RUN cd /opt && mkdir logs && sh -c "touch /opt/app.jar"
ENTRYPOINT ["sh","-c","java $RUN_OPTION -jar app.jar --server.port=$RUN_PORT "]
2.3.2 注入环境变量 【Inject environment variables】
- 把执行时shell生成的包含tag和project的文件填入配置文件路径
- 配置文件内容
2.4 生成后操作 【Post-build Actions】
- 由于生产环境K8S只允许内网访问,上面项目运行的 “docker-build” 机器为测试环境机器。所以需要跳到生产内网机器【监控看板】上执行 k8s-dpm-update这个自由风格的项目。
2.5 参数化构建项目 【build with parameter】
- 选好参数就可以进行构建了,这个项目会触发"k8s-dpm-update"这个自由风格的项目,下面我们看看被触发的项目是怎么定义的
三、更新镜像jenkins项目搭建过程
3.1 项目运行节点 【Restict where this project can be run】
- podK8SNode是生产内网的一台机器,可以通过kubctl访问到生产K8S
3.2 执行时shell
- 由于 “基础jenkins项目” 已经注入了环境变量,所以这些变量可以在这个项目中直接使用,就可以实现更新镜像了
echo "isUpdateDPM=${isUpdateDPM}"
echo "imageTag=${imageTag}"
echo "depName=${depName}"
echo "dockerStore=${dockerStore}"
echo "nameSpace=${nameSpace}"
if [ "true" = "$isUpdateDPM" ] ; then
kubectl set image deployment/$depName $depName=registry-vpc.cn-shenzhen.aliyuncs.com/XXXX/$dockerStore:$imageTag -n $nameSpace
fi