一、背景和原理
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