持续集成 - springboot构建成docker镜像部署到云主机上

目标

在这里插入图片描述
如图:需要做到当本地提交一个代码到github后,通过webhook通知jenkins触发一次构建。jenkins会从github拉代码,编译构建成docker image,将image推送到harbor(私服,也可以选用docker.hub)。然后通知云主机B去重新deploy应用。

说明: 图中我用了2台云主机,如果只是在内网中部署,可以将github换成gitlab,建立个私有的gitlab.

1. 建立一个很简单的springboot工程

到https://start.spring.io/ 上建立一个 web 的工程。

2. 提交code到github

3. jenkins建立构建项目并触发

在云主机A上安装jenkins。然后新建项目,填入项目名称,比如demo,
再选pipline构建.
在这里插入图片描述

确定后,进入下面的页面。在build triggers里填写1个token,token可以自己命名
在这里插入图片描述
到github上添加一个webhook如下
在这里插入图片描述
在这里插入图片描述

JENKINS_IP 为jenkins的ip ,我的jenkins安装在云主机上,ip是我云主机A的地址。

设置 JENKINS 的 Configure Global Security
在这里插入图片描述
在这里插入图片描述

这样每当代码提交到github,github就会通过webhook向jenkins推送一条构建的请求。

4. jenkins的pipeline构建

第3步解决了触发问题。这步需要解决构建的具体步骤,主要通过pipeline script来做。选中之前建立的demo,在pipeline里写入如下脚本;
在这里插入图片描述
脚本内容

pipeline {
    agent any 
    environment {
        git_url='git@github.com:rechardguo/springboot-simple.git'
        registory_url = 'rechard.hub.com/simple-springboot'
        MODULE='demo'
        SCRIPT_HOME='/usr/local/scripts'
        JENKINS_WORKSPACE='/root/.jenkins/workspace'
    }
    stages {
        stage('获取代码'){
            steps{
             echo "start pull code from git:${git_url}"
             deleteDir()
             git "${git_url}"
            }
        }
        stage('编译代码'){
            steps{
              echo 'start compile'
              sh "mvn clean package -DskipTests"
            }
        }
        stage('构建镜像并deploy'){
            steps{
             echo 'build image'
             sh '${SCRIPT_HOME}/build-image.sh ${JENKINS_WORKSPACE} ${MODULE}'
            }
        }
        
    }
}

上面的shell很说明

  • 获取代码 :会把代码pull到/<user>/.jenkins/workspace/demo下,我是用root安装的,路径是/root/.jenkins/workspace/demo 。 demo 是新建立的jenkins构建项目的名称
  • 构建镜像并deploy :主要是用shell脚本来做的。新建build-image.sh放在${SCRIPT_HOME}下,内容如下:
#!/bin/bash

JENKINS_WORKSPACE=$1
MODULE=$2
IMAGE_VERSION=`date +"%Y%m%d%H%M"`
IMAGE_NAME=<harbor_ip>/simple-springboot/${MODULE}:${IMAGE_VERSION}

WEB_SERVICE_URL='129.211.26.245'
WEB_SERVICE_USER='root'
WEB_SERVICE_DEPLOY_PATH='/usr/local/deploy'
PORT=9898

cd ${JENKINS_WORKSPACE}/${MODULE}

# 构建镜像
docker build -t "${IMAGE_NAME}" .
# 推送镜像到harbor地址
docker push ${IMAGE_NAME}

# 将pom.xml远程拷贝到 dockerswarm的主机上
scp ${PWD}/pom.xml ${WEB_SERVICE_USER}@${WEB_SERVICE_URL}:${WEB_SERVICE_DEPLOY_PATH}/pom.xml

# 远程执行 dockerswarm的主机上的deploy.sh
ssh ${WEB_SERVICE_USER}@${WEB_SERVICE_URL} sh ${WEB_SERVICE_DEPLOY_PATH}/deploy.sh ${MODULE} ${PORT} ${IMAGE_NAME}

cd -  

说明:

  • 云主机A需要先做免密登录云主机B

  • 构建镜像
    cd ${JENKINS_WORKSPACE}/${MODULE} 会进入到jenkins拉取得springboot工程的代码存放的文件夹。docker build -t "${IMAGE_NAME}" .会执行工程目录下的一个Dockerfile

在springboot工程里建立一个Dockerfile,内容如下:

FROM daocloud.io/liushaoping/maven:latest as builder
WORKDIR /build
COPY pom.xml .
RUN mvn dependency:go-offline

COPY src/ /build/src/
RUN mvn package

FROM openjdk:8u222-jre
EXPOSE 9898
CMD exec java -Dloader.path="/home/libs/" -jar /home/app.jar
COPY --from=builder /build/target/*.jar /home/app.jar
#COPY --from=builder /build/target/libs /home/libs/
RUN mkdir /home/libs

docker build -t “${IMAGE_NAME}” . 就会构建出一个镜像,注意到
java -Dloader.path="/home/libs/" -jar /home/app.jar 里有个/home/libs/为空。这个是镜像中预留的的一个存放jar包的文件夹。在运行镜像时候可以使用-v来绑定宿主机里的文件夹到容器里的文件夹,如下:

docker run -d --name demo -v /usr/local/lib:/home/libs  ${IMAGE_NAME}

其中 /user/local/lib 是宿主机的文件夹,里面含有第三方的jar。

  • 为什么要将pom.xml远程拷贝到 云主机B上?
    上面第三方的jar 需要预先在云主机B里先放到,通过以下命令
mvn dependency:copy-dependencies -f pom.xml -DoutputDirectory=/usr/local/lib

可以将jar放到/usr/local/lib里

5. 对打包出来的jar瘦身

由于上面的步骤已经将第三方的jar提取出来,通过mvn package 构建出来的xx.jar就可以去除掉第三方的jar包。使用 maven的插件如下:

<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
				<configuration>
					<layout>ZIP</layout>
					<includes>
					   <!--指定本地开发的项目的依赖,第三方就不需要了-->
						<include>
							<groupId>${project.groupId}</groupId>
							<artifactId>${project.artifactId}</artifactId>
						</include>
					</includes>
				</configuration>
			</plugin>			
		</plugins>
	</build>

mvn package
可以看出打印出来的jar很小

6. 通知云主机B进行部署

#!bin/bash

JAR_LIB_PATH=/usr/local/lib
MOUDLE=$1
PORT=$2
IMAGE_NAME=$3

workdir=$(cd $(dirname $0); pwd)
# 从pom.xml里buid出jar包放到$JAR_LIB_PATH
mvn dependency:copy-dependencies -f ${workdir}/pom.xml -DoutputDirectory=$JAR_LIB_PATH

#停止容器
docker stop $MOUDLE
#删除容器
docker rm -f $MOUDLE
#下载最新的$IMAGE_NAME并运行,注意-v里$JAR_LIB_PATH是从pom.xml里build出来的
docker run -d --name $MOUDLE -v $JAR_LIB_PATH:/home/libs -p $PORT:$PORT $IMAGE_NAME

用图来说明如下4-5做的流程:
在这里插入图片描述

可以通过http://云主机B:9898/来访问。

待续

这次只是将服务部署到一台主机上,下一步就是建立个swarm或k8s后,将服务部署到swarm或k8s上。

参考

docker springboot项目镜像优化

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值