如图:需要做到当本地提交一个代码到github后,通过webhook通知jenkins触发一次构建。jenkins会从github拉代码,编译构建成docker image,将image推送到harbor(私服,也可以选用docker.hub)。然后通知云主机B去重新deploy应用。
说明: 图中我用了2台云主机,如果只是在内网中部署,可以将github换成gitlab,建立个私有的gitlab.
到https://start.spring.io/ 上建立一个 web 的工程。
在云主机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推送一条构建的请求。
第3步解决了触发问题。这步需要解决构建的具体步骤,主要通过pipeline script来做。选中之前建立的demo,在pipeline里写入如下脚本;
脚本内容
pipeline {
agent any
environment {
git_url='[email protected]: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很说明
//.jenkins/workspace/demo
下,我是用root安装的,路径是/root/.jenkins/workspace/demo
。 demo 是新建立的jenkins构建项目的名称#!/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。
mvn dependency:copy-dependencies -f pom.xml -DoutputDirectory=/usr/local/lib
可以将jar放到/usr/local/lib里
由于上面的步骤已经将第三方的jar提取出来,通过mvn package 构建出来的xx.jar就可以去除掉第三方的jar包。使用 maven的插件如下:
<build>
<plugins>
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
<configuration>
<layout>ZIPlayout>
<includes>
<include>
<groupId>${project.groupId}groupId>
<artifactId>${project.artifactId}artifactId>
include>
includes>
configuration>
plugin>
plugins>
build>
mvn package
可以看出打印出来的jar很小
#!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
可以通过http://云主机B:9898/来访问。
这次只是将服务部署到一台主机上,下一步就是建立个swarm或k8s后,将服务部署到swarm或k8s上。
docker springboot项目镜像优化