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

1. 写在结尾

为了调通这长长的一串破费了整整4天工夫。。。写完后将之前写的API都采取了这样的形式进行部署,极大水平的压缩了须要我部署的工夫,还是十分值得的。

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

因为流程很长,如果你在看这篇博客的时候有任何问题能够通过邮箱:tangym@runnable.run分割我,我会提供我能帮忙到的。

1.1 实现的性能

  • 一次构建,能够实现如下所有操作

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

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

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

2. 搭建过程

2.1 筹备内容

搭建环境:

  • 一个简略的Spring Boot我的项目,应用Java17,我曾经筹备好了这个,倡议先clone到本地:https://github.com/MingGH/dem...
  • 阿里云账号(推送nexus和docker image)
  • 一台曾经装置了docker的电脑或者服务器,如果服务器装置docker有难度,能够参考这篇博客:应用官网装置脚本主动装置

2.2 通过Docker装置Jenkins

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

mkdir -p /dockerData/jenkins/jenkins-data

进入到/dockerData/jenkins 目录,咱们在这创立Dockerfile

cd /dockerData/jenkinsvim Dockerfile

复制以下内容到文件Dockerfile

FROM jenkins/jenkins:2.375.1USER rootRUN apt-get update && apt-get install -y lsb-releaseRUN curl -fsSLo /usr/share/keyrings/docker-archive-keyring.asc \  https://download.docker.com/linux/debian/gpgRUN 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.listRUN apt-get update && apt-get install -y docker-ce-cliUSER jenkinsRUN 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/bashmkdir -p /root/.sshcd ~/.ssh/touch known_hostsknown_hostsssh-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 */@Controllerpublic 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-busterARG JAR_NAMEENV PROJECT_NAME ${JAR_NAME}ENV PROJECT_HOME /usr/local/${PROJECT_NAME}RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtimeRUN echo 'Asia/Shanghai' >/etc/timezoneRUN mkdir $PROJECT_HOME && mkdir $PROJECT_HOME/logsARG JAR_FILECOPY ${JAR_FILE} $PROJECT_HOME/${JAR_NAME}.jarENTRYPOINT 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 -sCONTAINER ID   IMAGE                                                                          COMMAND                  CREATED         STATUS         PORTS                                       NAMES                        SIZE9c0ee6e2726f   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