Java 开发者必看!手把手带你搞定 Jenkins+Maven 仓库 +Docker 仓库 + 部署 + 自动更新 pom 版本 一条龙部署服务

本贴最后更新于 720 天前,其中的信息可能已经天翻地覆

原文发布于:Java 开发者必看!手把手带你搞定 Jenkins+Maven 仓库 +Docker,欢迎使用 RSS 订阅获取最新更新。

1. 写在开头

为了调通这长长的一串花费了整整 4 天时间。。。写完后将之前写的 API 都采取了这样的方式进行部署,极大程度的压缩了需要我部署的时间,还是非常值得的。

比起上次写的 使用 Jenkins 对 springboot 项目进行 docker 镜像一键部署,jenkins + docker + springboot 集成了更多的内容,也更加动态化。

因为流程很长,如果你在看这篇博客的时候有任何问题可以通过博客主页的邮箱联系我,我会提供我能帮助到的。

1.1 实现的功能

  • 一次构建,可以完成如下所有操作

checkout codebuild jar packagepush package to nexusbuild docker imagepush image to repositoriesdeployupdate pom.xml version

https://runnable.oss-cn-guangzhou.aliyuncs.com/blog/2023-01-03-093744.png

当中没有接入 Sonarqube 或者墨菲安全之类的 stage 是因为我把这个部份做到了 code 一提交时触发的 GitHub Actions 中。

废话不多说,马上开始教程。

2. 搭建过程

2.1 准备内容

搭建环境:

2.2 通过 Docker 安装 Jenkins

创建一个目录,用来存在 Jenkins 的数据

mkdir -p /dockerData/jenkins/jenkins-data

进入到 /dockerData/jenkins 目录,我们在这创建 Dockerfile

cd /dockerData/jenkins
vim Dockerfile

复制以下内容到文件 Dockerfile

FROM jenkins/jenkins:2.375.1
USER root
RUN apt-get update && apt-get install -y lsb-release
RUN curl -fsSLo /usr/share/keyrings/docker-archive-keyring.asc \
  https://download.docker.com/linux/debian/gpg
RUN echo "deb [arch=$(dpkg --print-architecture) \
  signed-by=/usr/share/keyrings/docker-archive-keyring.asc] \
  https://download.docker.com/linux/debian \
  $(lsb_release -cs) stable" > /etc/apt/sources.list.d/docker.list
RUN apt-get update && apt-get install -y docker-ce-cli
USER jenkins
RUN jenkins-plugin-cli --plugins "blueocean:1.26.0 docker-workflow:563.vd5d2e5c4007f"

从 Dockerfile 中构建镜像

docker build -t myjenkins-blueocean:2.375.1-1 .

构建完成之后,使用 docker images 可以看到刚刚构建的镜像。

运行一个 Jenkins 容器

docker run \
  -u root \
  --name jenkins \
  --restart=on-failure \
  --detach \
  --publish 8080:8080 \
  --publish 50000:50000 \
  --volume /etc/localtime:/etc/localtime \
  --volume /var/run/docker.sock:/var/run/docker.sock -v /usr/bin/docker:/usr/bin/docker \
  --volume /dockerData/jenkins/jenkins-data:/var/jenkins_home \
  myjenkins-blueocean:2.375.1-1

对当中的一些参数进行解释:

  • -u root 容器中的进程以 root 用户权限运行
  • --restart=on-failure 如果容器由于错误而退出,则将其重新启动
  • --detach 保持容器在后台持续运行
  • --publish 8080:8080 映射宿主机 8080 端口给容器 8080 端口
  • --publish 50000:50000 映射宿主机 50000 端口给容器 50000 端口
  • --volume /etc/localtime:/etc/localtime 容器时间如何与宿主机同步
  • --volume /var/run/docker.sock:/var/run/docker.sock -v /usr/bin/docker:/usr/bin/docker 挂载宿主机的 /var/run/docker.sock 给容器,这样 Jenkins 容器就可以调用宿主机的 docker,创建其他的容器服务于 CICD
  • --volume /dockerData/jenkins/jenkins-data:/var/jenkins_home 挂载 Jenkins 容器的数据到宿主机目录下

解决 ECDSA host key is known for github.com and you have requested strict checking 问题

运行成功之后,别急,还有一步需要操作,进入到 Jenkins 容器配置 ssh,如果不进行配置当拉取代码的时候会抛出异常 ECDSA host key is known for github.com and you have requested strict checking,你也可以在这篇文章找到更加详细的说明:Jenkins 执行 pipeline 抛出异常 No ECDSA host key is known for github.com and you****

进入 Jenkins 容器并执行以下操作

docker exec -it -u root jenkins /bin/bash
mkdir -p /root/.ssh
cd ~/.ssh/
touch known_hostsknown_hosts
ssh-keyscan github.com >> ~/.ssh/known_hosts

你会看到以下输出,就表示 ok 了

然后输出 exit 可以直接推出容器

如果你是某某云的服务器,需要到某某云的控制台开放安全组端口才能进行访问

现在我们就可以以 ip+端口 的形式进行访问到 Jenkins,打开浏览器 http://服务器公网ip:8080 提示我们需要输入密码。

我们可以直接使用 docker logs jenkins 拿到密码

2.3 Jenkins 配置:时区

选择安装完推荐的插件之后,Jenkins 会进行重启,等待一段时间,然后刷新登录

时区配置

进入到 系统管理→脚本命令行

执行如下命令,设置时区为上海

System.setProperty('org.apache.commons.jelly.tags.fmt.timeZone', 'Asia/Shanghai')

2.4 Jenkins 配置:GitHub 凭据

回到系统管理,点击 Manage Credentials

创建新的凭据

private-key 的来源:在部署 Jenkins 的服务器上生成对应的公钥

ssh-keygen -t rsa -b 4096 -C "your_email@example.com"

会有三个文件生成

然后公钥文件 id_rsa.pub 中的内容复制到 GitHub SSH 配置中

然后把私钥文件 id_rsa 中的内容配置到刚刚 Jenkins 的那个地方

id_rsa 的文件内容类似:

-----BEGIN OPENSSH PRIVATE KEY-----

xxxxxxxxxxxxxxx==
-----END OPENSSH PRIVATE KEY-----

生成公钥的问题可以参考这篇博客:Git SSH 公钥配置

2.5 准备阿里云效的 Maven 仓库

地址:https://packages.aliyun.com/maven

注册并登录进去之后,我们可以看到有两个对应的仓库,生产库-release非生产库-snapshot,分别用来存放我们不同环境的 jar 包,如果你的 pom.xml 中的 version 带 -snapshot,那么推送的就是 非生产库, 如果不带 -snapshot ,推送的就是生产库。这里需要注意的是,生产库的 jar 包是不允许重复推送的。

点进非生产库-snapshot,在仓库指南中,我们下载对应的 settings.xml 文件,这个文件当 Jenkins 需要推送 Jar 到 Maven 仓库的时候需要用到

在旁边的包文件列表可以看到之后 Jenkins 推送上去的包

将这个文件上传到服务器 /root/.m2/ 目录下

2.6 准备 Docker容器镜像仓库

阿里云容器镜像服务地址: https://cr.console.aliyun.com/

登录之后选择个人版

创建命名空间

创建 API 对应的镜像仓库

创建完成点击进去 基本信息 一栏有公网地址,这就是 Docker Image 需要推送的地址,我们可以先复制出来。

设置密码

在个人版中,访问凭证中,设置 固定密码 ,这个密码之后会在项目 demo-springboot-simple 中的 deploy_docker.sh 用到。

之后 Jenkins 推送镜像上来,可以在这里 镜像版本 找到对应的镜像

3. 通过 pipeline 把上面内容都串起来

有了上面的准备的内容,那我们就可以通过 Jenkins pipeline 把这些内容都串在一起了。

3.1 Jenkins 新建 pipeline

再次登录 Jenkins,这次我们新建一条 pipeline,pipeline 的名字就叫 API 的名字,这里大家照着我的配置一样的填写就行,需要注意的地方我会说出来。

点击确定后配置一些参数

添加参数化构建过程,总共会添加三个参数 ENV_INFO,GIT_Branch,Deploy_Port

ENV_INFO

GIT_Branch

Deploy_Port

Pipeline script from SCM

点击新建,此时一条 pipeline 就创建成功,是不是已经迫不及待的想点击 build 试试?等等,先听我把后面这一部份讲完,当出现问题时才知道去哪找解决方案

3.2 项目 demo-springboot-simple 讲解

回到最开始需要让你下载那个项目:demo-springboot-simple

application-dev.yamlapplication-prod.yaml

项目是一个很简单的 Spring Boot 项目, 默认端口是 5002。定义了两个不同的配置文件,分别是 application-dev.yamlapplication-prod.yaml 用来模拟不同环境时切换不同的参数。

HelloController

创建了一个 HelloController 用来演示最简单的 GET 请求,会根据不同的部署环境,返回不同的内容。

HelloController 的内容如下:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import run.runnable.demospringbootsimple.config.AppConfig;

/**
 * @author Asher
 * on 2023/1/3
 */
@Controller
public class HelloController {

    @GetMapping("/hello")
    @ResponseBody
    public String hello(){
        return "hello " + appConfig.getEnv();
    }

    private AppConfig appConfig;
    @Autowired
    public void setAppConfig(AppConfig appConfig) {
        this.appConfig = appConfig;
    }
}

3.3 项目配置:Jenkinsfile (有需要修改内容)

当 Jenkins 在面板上点击构建时,会找到对应目录下的 Jenkinsfile,所以第一个我们需要说明的就是 Jenkinsfile。

在 Jenkinsfile 中我定义了 7 个 stage,分别是 Build, Unit Test, Push Nexus, Package Image, Push Image, Deploy, Update version

当 Jenkins 进行 build 的时候就会出现对应的这几个阶段。

这里因为篇幅过长,使用了新的一篇文章来进行讲解:demo-springboot-simple 中 Jenkinsfile 详解

需要修改的内容为:

在这个 Update version Stage 中需要修改你的 git 邮箱地址和 username,因为在步骤 2.4 中已经配置了公钥在 GitHub 上,且在 Jenkins agent 中配置了 /root/.ssh 的目录映射,所以这里只需要配置用户名和邮箱就行。

3.5 项目配置:deploy_docker.sh

说完了 Jenkinsfile,希望你已经明白 Jenkins 执行时的主要的流程,那么在 deploy_docker.sh 中的内容是 docker 部署到本地和 docker 推送到Docker 容器镜像仓库时的一些命令。

你需要配置的内容如图:

3.4 项目配置:pom.xml (有需要修改内容)

需要修改的配置

pom.xml 文件中你需要修改 properties 中的内容,

  • docker.namespace 是在阿里云的 Docker 容器镜像仓库时创建的。
  • docker.registry.address 则是镜像仓库基本信息中的公网地址,例如:registry.cn-hangzhou.aliyuncs.com
        <properties>
		<java.version>17</java.version>
		<docker.namespace></docker.namespace>
		<docker.registry.address></docker.registry.address>
	</properties>

在 plugin 中我增加了 dockerfile-maven-plugin,通过这个 plugin 可以使用 maven 构建 docker image,但是需要项目中存在 Dockerfile,这个会马上说到。

<plugin>
	<groupId>com.spotify</groupId>
	<artifactId>dockerfile-maven-plugin</artifactId>
	<version>1.4.13</version>
	<configuration>
		<repository>${docker.registry.address}/${docker.namespace}/${project.artifactId}</repository>
		<tag>${project.version}</tag>
		<buildArgs>
			<JAR_NAME>${project.artifactId}</JAR_NAME>
			<JAR_FILE>target/${project.build.finalName}.jar</JAR_FILE>
		</buildArgs>
	</configuration>
</plugin>

这里需要注意的是标签 <buildArgs> 下定义的 <JAR_NAME><JAR_FILE> 将会传递到 Dockerfile 中用于进行构建镜像

3.4 项目配置:Dockerfile (无修改)

Dockerfile 中配置了构建 image 时的一些参数,如下:

FROM openjdk:17-jdk-slim-buster

ARG JAR_NAME
ENV PROJECT_NAME ${JAR_NAME}
ENV PROJECT_HOME /usr/local/${PROJECT_NAME}

RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
RUN echo 'Asia/Shanghai' >/etc/timezone
RUN mkdir $PROJECT_HOME && mkdir $PROJECT_HOME/logs

ARG JAR_FILE
COPY ${JAR_FILE} $PROJECT_HOME/${JAR_NAME}.jar

ENTRYPOINT java -jar -Xmn128m -Xms256m -Xmx256m $PROJECT_HOME/$PROJECT_NAME.jar

当中一些参数的解释,如果需要更加详细的说明,可以参考这个:什么是 Dockerfile?

  • FROM openjdk:17-jdk-slim-buster image 基于 openjdk:17-jdk-slim-buster
  • ENV PROJECT_NAME ${JAR_NAME} 设置环境变量,定义了环境变量,那么在后续的指令中,就可以使用这个环境变量。这个参数中的 ${JAR_NAME} 的来源是 pom.xml 中的 <JAR_NAME>${project.artifactId}</JAR_NAME>
  • RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime 指定容器运行时区
  • RUN mkdir $PROJECT_HOME && mkdir $PROJECT_HOME/logs 创建项目路径
  • COPY ${JAR_FILE} $PROJECT_HOME/${JAR_NAME}.jar 将 maven 构建出来的 Jar 文件复制到容器的具体位置
  • ENTRYPOINT java -jar -Xmn128m -Xms256m -Xmx256m $PROJECT_HOME/$PROJECT_NAME.jar 容器的入口,通过 java -jar 进行启动,并指定运行时的一些参数

完成以上配置之后,提交你的代码到具体的分支。

4. Build with Parameters

终于到了最后一步,回到 Jenkins 的面板, 点击 Build with Parameters, 填入你的参数,进行构建

此时你就可以看到 pipeline 已经在跑了

执行完成的状态应该是所有的 stage 都是绿色,且在你服务器上能看到有一个新的容器产生

[root@ecs-205431 ~]# docker ps -s
CONTAINER ID   IMAGE                                                                          COMMAND                  CREATED         STATUS         PORTS                                       NAMES                        SIZE
9c0ee6e2726f   registry.cn-hangzhou.aliyuncs.com/xxxx/demo-springboot-simple:0.0.4-SNAPSHOT   "/bin/sh -c 'java -j…"   3 minutes ago   Up 3 minutes   0.0.0.0:5002->5002/tcp, :::5002->5002/tcp   demo-springboot-simple-dev   32.8kB (virtual 419MB)

5. 问题排查

因为流程很长,出现问题不要慌。直接点击那一个构建过程,进去看看日志。

6. 参考内容

The Problem With ‘src refspec does not match any’

Error: src refspec master does not match any – How to Fix in Git

git 获取当前分支名

git: rename local branch failed

Change System Time Zone

Jenkins 分布式构建与并行构建

build-a-java-app-with-maven

Installing Jenkins

cut or awk command to print first field of first row

How to automatically increment pom version with maven, for example 1.2.0 to 1.3.0

Starting Spring Boot Application in Docker With Profile

使用 Jenkins 对 springboot 项目进行 docker 镜像一键部署,jenkins + docker + springboot

  • Java

    Java 是一种可以撰写跨平台应用软件的面向对象的程序设计语言,是由 Sun Microsystems 公司于 1995 年 5 月推出的。Java 技术具有卓越的通用性、高效性、平台移植性和安全性。

    3190 引用 • 8214 回帖
  • Jenkins

    Jenkins 是一套开源的持续集成工具。它提供了非常丰富的插件,让构建、部署、自动化集成项目变得简单易用。

    53 引用 • 37 回帖 • 2 关注
  • Maven

    Maven 是基于项目对象模型(POM)、通过一小段描述信息来管理项目的构建、报告和文档的软件项目管理工具。

    186 引用 • 318 回帖 • 282 关注

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...