如何在Docker中用Jenkins构建一个Java应用程序

360 阅读9分钟

如何用Docker中的Jenkins构建一个Java应用程序

JenkinsDocker等新工具的引入有助于提高生产力。在过去的三年里,我们构建软件的方式发生了重大变化。今天,开发人员可以在几个月内创建新的技术并进行部署。

我们可以通过在Docker 容器中运行Jenkins ,实现软件的自动构建、测试和部署。这有利于持续集成和交付。在Docker中包括Jenkins也解决了几个不兼容的问题。

Docker通过将运行Jenkins的任务简化为两个命令:docker pulldocker run

目标

在本教程中,我们将在Docker容器中设置Jenkins。我们还将构建和dockerize一个Java应用程序。

前提条件

  • Java、Maven、Git和命令行的基本知识。
  • 了解Docker及其命令。
  • 一个Java IDE--在本教程中,我们将使用IntelliJ Idea,但你也可以使用你选择的任何IDE。

创建一个演示的Java应用程序

我们将创建一个简单的Java控制台应用程序并对其进行单元测试。这个演示应用程序将只检查一个输入是even 还是odd

首先,让我们用IntelliJ IDEA 创建一个新的Maven 项目。

我们将使用以下IntelliJ设置。

intelliJ Settings

我们也可以通过command 行创建一个Maven 项目,使用Maven标准目录布局

要创建Maven 项目的目录布局,请运行。

    $ mkdir -p src/main/java

添加一个pom.xml 文件。

$ touch pom.xml

在我们的pom.xml 文件中,我们将添加以下代码。

    <?xml version="1.0" encoding="UTF-8"?>
    <project  xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
    
        <groupId>org.example</groupId>
        <artifactId>Java-jenkins-in-docker</artifactId>
        <version>1.0-SNAPSHOT</version>
    
        <properties>
            <java.version>1.8</java.version>
        </properties>
    
    </project>

为了完成我们的应用配置,我们需要添加JUnit 5 依赖关系,以便编写测试。

让我们更新一下pom.xml 文件,以确保这个依赖关系是存在的。

    <dependencies>
        <!-- junit 5, unit test -->
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-engine</artifactId>
            <version>5.3.1</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

开始编写代码

src/main/java 路径中,让我们创建一个名为Main 的类。它将包含我们简单的控制台应用程序的代码。

Main 类中,让我们添加main 方法来运行我们的代码。

注意,一些IDE(如NetBeans)通常会自动生成这段代码。

    public class Main {
        public static void main(String[] args) {
            //code will go in here
        }
    }

接下来,让我们创建一个简单的static 方法,名为checkIfInputIsAnEvenNumber

它将检查一个输入是偶数还是奇数。

    public static boolean checkIfInputIsAnEvenNumber(int number){
        return number % 2 == 0;
    }
  • 在上面的代码片段中,我们正在创建一个static 方法,以便我们可以编写单元测试。我们想看看Jenkins将如何实现自动化测试。

  • 如果输入的int 是偶数或奇数,该方法将分别返回真或假。

下面是Main 类的最终代码。

    public class Main {
        public static void main(String[] args) {
            System.out.println(checkIfInputIsAnEvenNumber(122)); // Testing in the main method
        }
    
        public static boolean checkIfInputIsAnEvenNumber(int number){
            return number % 2 == 0;
        }
    }

如果你运行上述代码,输出将是true

现在,让我们写一个单元测试来测试我们的checkIfInputIsAnEvenNumber 方法。首先,在src/test/java 路径中,让我们创建一个测试类TestMain 来测试这个方法。

    import org.junit.jupiter.api.Test;
    import static org.junit.jupiter.api.Assertions.assertTrue;

    public class TestMain {
    
        @Test
        public void testInputIsEven(){
            assertTrue(Main.checkIfInputIsAnEvenNumber(23)); // Assertion
        }
    }

你可以在你的IDE中运行上面的测试。

另外,我们也可以使用Maven 命令在命令行中运行我们所有的单元测试,如下图所示。

    $ mvn test

当我们使用23 作为我们的输入数据时,测试失败。

maven test fails

让我们把测试的输入数据改为22 ,并运行Maven 命令。

    assertTrue(Main.checkIfInputIsAnEvenNumber(22)); // Assertion

maven test passes

测试通过。在几个步骤中,我们将看到Jenkins如何将这个过程自动化。

在GitHub上托管演示应用程序

我们将把我们的Java 应用程序代码推送到GitHub 。当我们在GitHub上对我们的应用程序做任何修改(提交)时,Jenkins 将远程触发一个post-commit 构建过程。

  • 首先,[创建一个新的 GitHub 仓库]。

  • 然后打开终端。

  • 导航到我们的演示应用程序的目录并运行。

$ git init -b main //To initialize the local repository
  • 我们将使用下面的命令添加我们所有的应用程序文件。
$ git add .
  • 现在我们可以提交我们的文件了。
$ git commit -m "Added java demo application files"
  • 复制GitHub上创建的仓库克隆URL

  • 然后添加remote URL ,我们将推送本地仓库。

$ git remote add origin  <REMOTE_URL>

验证远程 URL 并将我们本地仓库的修改推送到 Github。

    $ git remote -v
    $ git push origin main

在Docker中设置Jenkins

Docker-in-Docker

当我们在Docker中设置Jenkins时,我们需要记住我们设置的目标:dockerizing of an application 。为了实现这个目标,我们需要执行docker commands ,以及访问其他容器。

为了实现这个功能,我们需要一个Dockerfile ,配置一个Jenkins environment 。它将能够运行Docker命令并管理docker容器。

在任何目录下创建一个Dockerfile ,并在Dockerfile中添加。

    from jenkins/jenkins:lts
    USER root
    RUN apt-get update -qq \
        && apt-get install -qqy apt-transport-https ca-certificates curl gnupg2 software-properties-common
    RUN curl -fsSL https://download.docker.com/linux/debian/gpg | apt-key add -
    RUN add-apt-repository \
       "deb [arch=amd64] https://download.docker.com/linux/debian \
       $(lsb_release -cs) \
       stable"
    RUN apt-get update  -qq \
        && apt-get install docker-ce=17.12.1~ce-0~debian -y
    RUN usermod -aG docker jenkins

现在让我们使用上面的Dockerfile ,创建一个jenkins-docker image

    $ docker image build -t jenkins-docker .

为了在命令行中运行我们的Jenkins-docker container ,我们使用下面的代码。

    $ docker run -it -p 8080:8080 -p 50000:50000 -v jenkins_home:/var/jenkins_home -v /var/run/docker.sock:/var/run/docker.sock --restart unless-stopped jenkins-docker
  • 上面的命令运行我们预先建立的jenkins-docker image-p 命令将容器的端口808050000 发布到主机上。

  • 我们应该在我们的Jenkins容器中运行Docker命令。然而,在我们的机器中,每次只有一个Docker daemon 在运行。所以我们需要做的是,在我们使用这个参数运行容器时,将我们的container 与我们的host machine daemon 绑定挂载-v /var/run/docker.sock:/var/run/docker.sock

  • -v jenkins_home:/var/jenkins_home 参数在我们的主机上创建一个显式卷。为什么?在我们的初始设置中,我们将配置Jenkins并下载插件。当我们停止/重启/删除我们的容器时,我们需要完整地保存我们的初始设置配置。我们不希望每次停止/重启/删除我们的容器时都要进行这些设置。

  • --restart unless-stopped 确保容器总是重新启动,除非使用 命令停止。docker stop <container_name/container_id>

运行上述命令后,访问localhostlocalhost:8080 来设置Jenkins。

getting started with jenkins

我们可以从什么命令returns ,得到admin 的密码。

看看是什么样子的。

initial admin password

我们也可以用下面的命令从/var/jenkins_home/secrets/initialAdminPassword 目录中获得初始管理员密码。

    $ docker exec -it <container_name/container_id> /bin/bash

并获得密码。

    $ cat /var/jenkins_home/secrets/initialAdminPassword

接下来,我们选择Install suggested plugins

Jenkins会自动下载必要的插件。

plugins installation

Jenkins全局配置

首先,我们将在我们的Jenkins控制台配置JDK,Maven, 和Git ,以使Jenkins能够克隆我们的版本库并构建我们的应用程序。

在我们的Jenkins控制台,进入Manage Jenkins

jenkins home

System Configurations 下,点击Global Tool Configuration

jenkins configuration

JDK配置

我们的Jenkins容器自带一个OpenJDK 。要找到它,我们需要进入容器的bash shell ,以获得JAVA_HOME 的路径。

为了得到容器的bash shell ,运行。

    $ docker exec -it <container_name/container_id> /bin/bash

然后,如果我们使用的是macOSLinux ,我们运行。

    echo $JAVA_HOME

jdk configuration

Maven配置

我们可以指示JenkinsApache servers ,而不是我们系统中的Maven directory ,下载Maven

遵循下图所示的指导原则。

maven configurations

请确保在退出页面前保存配置。

在使用Docker-in-Docker 构建时,我们可能会遇到问题。因此,对Docker-in-Docker 有一个基本的了解可以让我们轻松地调试应用程序。

把它放在一起

到目前为止,我们已经建立了一个简单的演示Java控制台应用程序,在Github上托管了我们的应用程序代码,并在Docker中设置了Jenkins。

现在,让我们把这一切结合起来,使用Jenkins自动构建、测试、docker化,并在每次提交到GitHub上的应用仓库后将我们的应用Docker镜像部署到Docker Hub。

首先,让我们创建一个新的Jenkins项目。

create a new item

然后选择Freestyle project

freestyle project

要配置我们的Freestyle project ,选择GitHub项目并添加项目的URL。

github url settings

对于我们的Source Code Management (或简称SCM),选择Git ,添加项目的remote Git repository URL ,并将branch field 留空,这样任何分支的提交都会触发我们的整个Jenkins 过程。

source code management

对于Build Triggers ,选择Poll SCM ,它检查我们是否做了修改(即新的提交),然后重建我们的项目。Poll SCM 定期检查SCM ,即使版本库中没有任何变化。

我们将通过这个演示应用给Schedule 五颗星,也就是每分钟轮询的cron表达式

build trigger

接下来,我们跳过Build Environment 标签。在Build 窗口中,我们将添加两个Invoke top-level Maven targets 步骤。

最后,我们点击apply ,保存我们的Freestyle project 配置。

build steps

上述构建步骤会自动运行$ mvn test$ mvn install 命令。如果你记得我们之前的步骤,我们手动运行了单元测试的测试命令。

为了测试的目的,让我们构建我们的项目,看看当前的配置是否有效。点击Build Now

build now

我们可以在Build History 中查看控制台的输出。

see console output

我们的控制台输出应该看起来很像下面的图片。

build console output

如果我们提交修改,我们不需要手动点击Build Now 。Jenkins会自动构建我们的Freestyle项目。

构建并将我们的Docker镜像部署到Docker Hub上

我们就快完成了。剩下的就是让我们配置Jenkins来构建我们Java应用程序的Docker镜像,并将该镜像部署到Docker Hub。

为了实现这个目标,我们需要安装一些Jenkins插件。

Manage Jenkins ,选择Manage Plugins ,在System Configurationssearchinstall ,以下插件。

  • docker-build-step
  • CloudBees Docker Build and Publish

docker plugins

为了检查插件是否已经安装,让我们回到我们的Freestyle项目配置,在Build 标签,点击Add build step

我们将看到Docker Build and Publish 选项。

check docker build step

为了构建一个Docker镜像,我们需要一个Dockerfile来通知docker从哪个基础镜像构建我们的镜像,以及其他与Java相关的配置。我们还需要生成一个JAR(Java ARchive)文件。

build profile ,导航到pom.xml 文件并添加一个finalName

这个finalname 将是我们的JAR name

    <build>
      <finalName>java-jenkins-docker</finalName>
    </build>

为了生成我们的JAR运行。

    $ mvn install

我们可以在项目的target/ 目录中找到我们的JAR。

现在让我们来创建我们的Dockerfile

打开terminal ,导航到我们的Java应用程序目录。

    $ touch Dockerfile

并在我们的Dockerfile:

    FROM openjdk:8
    ADD target/java-jenkins-docker.jar java-jenkins-docker.jar
    ENTRYPOINT ["java", "-jar","java-jenkins-docker.jar"]
    EXPOSE 8080

添加新的文件,然后提交修改到GitHub仓库。这将触发我们配置的Jenkins提交后构建过程。

现在我们可以添加我们的build steps 来构建和部署我们的Java应用的Docker镜像。为此,我们将需要一个Docker Hub account

然后,在build step 中设置。

  • 存储库名称:Docker_id/jar_name 示例kikiodazie/java-jenkins-docker
  • 在这个演示中,我们将其余的字段留空,然后Applysave

docker build step

Jenkins container 为了让Jenkins访问,我们需要通过命令行登录到我们的Docker Hub account 里面,如下图所示。

    $ docker exec -it <container_name/container_id> /bin/bash

然后在容器里面,运行Docker login 命令。

    $ docker login

为了完成这个过程,输入你的登录凭证。

docker hub login

回到你的项目中,点击Build Now ,然后导航到控制台的输出。输出应该如下图所示。

这意味着我们的镜像已经成功构建并推送到Docker Hub。

docker image push

结论

在本教程中,我们已经学会了如何在Docker中设置和配置Jenkins。我们还构建并测试了一个Java应用的代码,并将其托管在Github上。

我们让Jenkins访问我们的Docker Hub账户,以执行提交后的构建触发。最后,我们了解了Docker-in-Docker以及如何在Docker容器中构建Docker镜像。