微服务CI/CD实践系列:
微服务CI/CD实践(一)环境准备及虚拟机创建
微服务CI/CD实践(二)服务器先决准备
微服务CI/CD实践(三)gitlab部署及nexus3部署
微服务CI/CD实践(四)Jenkins部署及环境配置
微服务CI/CD实践(五)Jenkins + Dokcer 部署微服务前端VUE项目
微服务CI/CD实践(六)Jenkins + Dokcer 部署微服务后端项目
微服务CI/CD实践(七)Minio服务器部署及应用
文章目录
- 一、先决条件
- 1.1 服务器先决条件
- 1.2 项目配置
- 1.2.1 Dockerfile
- 1.2.2 pom配置
- 1.2.3 部署脚本
- 二、Jenkins构建部署
- 2.1 创建项目
- 2.2 配置项目基本信息
- 2.3 定义 Pipeline script
- 2.4 构建部署项目
- 三、其他方式构建部署后端服务
- 使用Maven构建Docker镜像
后端微服务项目是基于JDK1.8 + SpringCloudAlibaba框架开发,我们通过Jenkins流水线作业将后端工程打包成Docker镜像的方式进行部署。构建部署流程如下:
- 拉取代码
- jenkins服务器maven编译代码
- 使用dockerfile构建镜像并打包镜像
- 上传镜像包
- 执行sh
一、先决条件
1.1 服务器先决条件
Jenkins 和 server服务器先决条件参考微服务CI/CD实践(二)服务器先决准备 和 微服务CI/CD实践(四)Jenkins部署及环境配置
1.2 项目配置
后端项目基于maven Dockerfile 构建镜像。
1.2.1 Dockerfile
# docker image deploy
FROM openjdk:8-jdk-alpine
COPY /uaa-center-server/target/app.jar /app.jarENTRYPOINT ["java", "-jar", "-Dspring.profiles.active=dev","/app.jar"]
上述配置仅是一个最基本Java工程镜像构建脚本,如果需要集成其他插件需要对应修改脚本
以下示例展示了如何通过Dockerfile集成arshs 和 skywalking:
FROM openjdk:8-jdk-alpine
COPY /uaa-center-server/target/app.jar /app.jar
# copy arthas
COPY ‐‐from=hengyunabc/arthas:latest /opt/arthas /opt/arthas
# copy skywalking
COPY /uaa-center-server/agent /usr/local/agent
# 这里可以传递skywalking‐agent 配置
ENTRYPOINT [ "sh", "‐c", "java ‐javaagent:/usr/local/agent/skywalking‐agent.jar ‐
Dskywalking.agent.service_name=yourappname ‐
Dskywalking.collector.backend_service=xx.xx.xx.xx:11800 ‐Dspring.profiles.active=dev ‐
jar /app.jar" ]
可以在ENTRYPOINT 端点指定相关agent配置,也可以在docker run执行脚本中指定。
1.2.2 pom配置
后端工程pom添加maven打包依赖:
<build><finalName>app</finalName><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><version>${spring-boot-dependencies.version}</version><executions><execution><goals><goal>repackage</goal></goals></execution></executions></plugin><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>3.8.1</version> <!-- 使用与你的 Maven 版本兼容的版本 --><configuration><source>1.8</source><target>1.8</target><annotationProcessorPaths><path><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.24</version> <!-- 使用与你的 Maven 版本兼容的版本 --></path><path><groupId>org.mapstruct</groupId><artifactId>mapstruct-processor</artifactId><version>${org.mapstruct.version}</version></path></annotationProcessorPaths><compilerArgs><arg>-Aprojectlombok.classpath=${project.build.outputDirectory}</arg></compilerArgs></configuration></plugin></plugins></build>
后端工程Dockerfile目录结构如下:
Dockerfile 和 具体的server工程在同级目录
1.2.3 部署脚本
后端服务和前端服务部署脚本基本一致,也是通过传入动态参数方式执行sh脚本,sh脚本执行步骤解释参考 微服务CI/CD实践(五)Jenkins + Dokcer 部署微服务前端VUE项目 1.2 项目配置。完整的后端部署脚本如下:
#!/usr/bin/env bashecho "param validate"
if [ $# -lt 5 ]; thenecho "you must use like this : /usr/docker-sh/publish_project_name.sh <container_name> <image_name> <version> [portal port] [server port] [portal ssl port] [server ssl port]" exit
ficontainer_name="$1"
image_name="$2"
version="$3"
portal_port="$4"
server_port="$5"
if [ "$6" != "" ]; thenportal_ssl_port="$6"
fi
echo "portal_ssl_port=" $portal_ssl_port
if [ "$7" != "" ]; thenserve_sslr_port="$7"
fiecho "执行docker ps"
docker ps
if [[ "$(docker inspect $container_name 2> /dev/null | grep $container_name)" != "" ]];
thenecho $container_name "容器存在,停止并删除"echo "docker stop" $container_namedocker stop $container_nameecho "docker rm" $container_namedocker rm $container_name
elseecho $container_name "容器不存在"
fi
# 删除镜像
echo "执行docker images"
docker images
if [[ "$(docker images -q $image_name 2> /dev/null)" != "" ]];
thenecho $image_name '镜像存在,删除镜像'docker rmi $(docker images -q $image_name 2> /dev/null) --force
elseecho $image_name '镜像不存在'
fi#bak image
echo "bak image" $image_name
BAK_DIR=/opt/bak/docker/$image_name/`date +%Y%m%d`
mkdir -p "$BAK_DIR"
cp "/opt/tmp/$container_name.tar" "$BAK_DIR"/"$image_name"_`date +%H%M%S`.tarecho "docker load" $image_name
docker load --input /opt/tmp/$container_name.tarecho "docker run" $image_name
# 这里因为服务本身还运行了netty,所以需要将netty的端口也做映射,如果没有仅需要配置server_port
docker run -d -p $portal_port:$server_port -p $portal_ssl_port:$portal_ssl_port --name=$container_name --network=my-network -e TZ="Asia/Shanghai" --restart=always -v ./logs:/usr/local/server-log/uaa-center-server $image_nameecho "remove tmp " $image_name
rm -rf /opt/tmp/$container_name.tarecho "Docker Portal is starting,please try to access $container_name conslone url"
二、Jenkins构建部署
2.1 创建项目
新建一个流水线任务
2.2 配置项目基本信息
创建完成项目,点击项目进入项目页面,点击左侧菜单》配置,进行项目基本配置
step1 项目构建历史存储策略配置
这里存储策略根据自己项目要求进行配置。
step2 配置参数化构建过程
Jenkins List Git Branches插件 构建选择指定git分支,点击添加参数选择List Git branchers选项进行Jenkins List Git Branches插件配置
Jenkins List Git Branches插件配置流程如下:
- 配置name
- 配置仓库并选择凭证
- 选择Parameter Type
- 配置Branch Filter
2.3 定义 Pipeline script
pipeline {agent anyenvironment { REPOSITORY="http://192.168.1.101:8929/hka/hkabackgroud/business/uaa-center.git"projectdir="uaa-center-pipeline"projectname="uaa-center-server"apiname="uaa-center-api"}stages {stage('获取代码') {steps {echo "start fetch code from git:${REPOSITORY} ${branch}"deleteDir()checkout([$class: 'GitSCM',branches: [[name: '${branch}']],doGenerateSubmoduleConfigurations: false,extensions: [],userRemoteConfigs: [[credentialsId: '2',url: 'http://192.168.1.101:8929/hka/hkabackgroud/business/uaa-center.git']]])}}stage('替换') {steps {echo "start replace"sh " cd ${WORKSPACE}/${projectname} "sh " rm -f target/${projectname}.jar "sh "mv ${WORKSPACE}/${projectname}/src/main/resources/bootstrap.yml.example ${WORKSPACE}/${projectname}/src/main/resources/bootstrap.yml "sh "mv ${WORKSPACE}/${projectname}/src/main/resources/bootstrap-dev.yml.example ${WORKSPACE}/${projectname}/src/main/resources/bootstrap-dev.yml "}}stage('打包') {steps {echo "start build"withMaven(maven: 'maven3.8.1') {sh " mvn -f ${WORKSPACE}/${apiname}/pom.xml clean deploy -DskipDockerTag -DskipDockerPush "sh " mvn -f ${WORKSPACE}/${projectname}/pom.xml clean install -DskipDockerTag -DskipDockerPush "}}}stage('Delete Old Docker Container') {steps {echo "delete docker container"sh '''if [[ "$(docker inspect ${projectname} 2> /dev/null | grep ${projectname})" != "" ]]; then echo ${projectname} "容器存在,停止并删除"echo "docker stop" ${projectname}docker stop ${projectname}echo "docker rm" ${projectname}docker rm ${projectname}else echo ${projectname} "容器不存在"fi'''}}stage('Delete Old Docker Image') {steps {echo "delete docker image"sh '''if [[ "$(docker images -q ${projectname} 2> /dev/null)" != "" ]]; then echo ${projectname} \'镜像存在,删除镜像\'docker rmi $(docker images -q ${projectname} 2> /dev/null) --forceelse echo ${projectname} \'镜像不存在,创建镜像\'fi'''}}stage('Build Docker Image') {steps {echo "start docker build ${projectname} code"sh 'docker build -t ${projectname} .'echo "save docker images tar"sh 'docker save -o ${projectname}.tar ${projectname}'}}stage('Delete New Docker Image') {steps {echo "delete docker image"sh '''if [[ "$(docker images -q ${projectname} 2> /dev/null)" != "" ]]; then echo ${projectname} \'镜像存在,删除镜像\'docker rmi $(docker images -q ${projectname} 2> /dev/null) --forceelse echo ${projectname} \'镜像不存在,创建镜像\'fi'''}}stage('Upload img tar') {steps {sshPublisher(publishers: [sshPublisherDesc(configName: '103',transfers: [sshTransfer(cleanRemote: false,excludes: '',makeEmptyDirs: false,noDefaultExcludes: false,patternSeparator: '[, ]+',remoteDirectory: '',remoteDirectorySDF: false,removePrefix: '',sourceFiles: 'uaa-center-server.tar')],usePromotionTimestamp: false,useWorkspaceInPromotion: false,verbose: false)])}}stage('Execute Command sh') {steps {sshPublisher(publishers: [sshPublisherDesc(configName: '103',transfers: [sshTransfer(execCommand: '/usr/docker-sh/publish_uaa-center-server.sh uaa-center-server uaa-center-server latest 10005 10005 9000 9000',execTimeout: 300000)],usePromotionTimestamp: false,useWorkspaceInPromotion: false,verbose: false)])}}stage('Publish Results') {steps {echo "End Publish ${projectname}" }}}
}
2.4 构建部署项目
回到项目页面,点击参数化构建,选择用于构建的分支点击Build执行构建任务。
当jenkins 流水线执行完成后可到对应Server服务器验证服务是否部署成功
[root@k8s-rancher-node02 ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
5d65d80b5350 uaa-center-server "java -jar -Dspring.…" 2 days ago Up 31 hours 0.0.0.0:9000->9000/tcp, :::9000->9000/tcp, 0.0.0.0:10005->10005/tcp, :::10005->10005/tcp uaa-center-server
三、其他方式构建部署后端服务
上述基于Jenkins流水线方式部署流程稍显复杂,优势是可以灵活配置构建步骤,特别是对于多环境多服务器的支持更加具有优势,比如通过Jenkins实现本地自动化部署并将镜像推送到AWS云原生平台的测试和生产环境,仅需要添加相应流水线流程即可。
stage('push image to aws ecr') {steps {echo "start push"script {docker.withRegistry('https://xxxx.dkr.ecr.cn-north-1.amazonaws.com.cn', 'ecr:cn-north-1:aws_ecr') {docker.image('${projectname}').push('${BUILD_NUMBER}')}}}}stage('push image to aws ecr us-west-2') {steps {echo "start push"script {docker.withRegistry('https://xxxxx.dkr.ecr.us-west-2.amazonaws.com', 'ecr:us-west-2:aws_us_west_2_ecr') {docker.image('${projectname}').push('${BUILD_NUMBER}')}}}}
如果仅在单环境部署,可以考虑使用Maven构建Docker镜像方式构建镜像,该方式流程简单。
使用Maven构建Docker镜像
step1 应用pom文件添加maven-docker-plugin配置
<plugin><groupId>com.spotify</groupId><artifactId>docker-maven-plugin</artifactId><version>1.1.0</version><executions><execution><id>build-image</id><phase>package</phase><goals><goal>build</goal></goals></execution></executions><configuration><imageName>${project.artifactId}:${project.version}</imageName><dockerHost>http://registry服务器地址:2375</dockerHost><baseImage>openjdk:8-jdk-alpine</baseImage><entryPoint>["java", "-jar","/${project.build.finalName}.jar"]</entryPoint><resources><resource><targetPath>/</targetPath><directory>${project.build.directory}</directory><include>${project.build.finalName}.jar</include></resource></resources></configuration>
</plugin>
配置说明:
executions.execution.phase:此处配置了在maven打包应用时构建docker镜像;
imageName:用于指定镜像名称, p r o j e c t . a r t i f a c t I d 为镜像名称, {project.artifactId}为镜像名称, project.artifactId为镜像名称,{project.version}为仓库版本;
dockerHost:打包后上传到的docker服务器地址;
baseImage:该应用所依赖的基础镜像,此处为java;
entryPoint:docker容器启动时执行的命令;
resources.resource.targetPath:将打包后的资源文件复制到该目录;
resources.resource.directory:需要复制的文件所在目录,maven打包的应用jar包保存在target目录下面;
resources.resource.include:需要复制的文件,打包好的应用jar包。
step2 Jenkins创建项目
Jenkins—》添加Items
根据自己所有选择合适项目类型,这里我们选择Freestyle project,以便我们自定义构建流程。也可以从其他项目copy配置。
step3 配置代码源
说明:
Repository URL:远程代码仓库地址
Credentials:凭据,可选择已添加的全局凭据,或者在此页面自定义全局凭据
指定分支(为空时代表any):指定项目构建分支
构建触发器:可自定义构建触发,如钩子函数、定时任务等
step4 构建流程配置
这一步是因为项目的配置管理策略有关,本地配置均不提交到服务器,如何没有采用该策略可以忽略
点击增加构建步骤>选择执行shell步骤
构建步骤5 使用maven打包构建镜像并推送到server
点击增加构建步骤>选择顶层Maven目标步骤
构建步骤6 远程执行shell,部署镜像
点击增加构建步骤>选择远程执行shell步骤
使用maven-docker-plugin方式构建后端项目流程简单且Jenkins服务器不需要安装额外的Docker,也不需要编写Dokcerfile文件,劣势是无法灵活管理构建步骤。