Docker - 持续集成



使用 Docker 进行持续集成是指在开发工作流中自动化创建、测试和部署 Docker 容器的过程。这意味着提交到版本控制系统(如 Git)中的更改将自动在 CI 管道中从更新的代码构建 Docker 镜像。然后,该镜像会通过一系列自动化测试,以检查应用程序是否按预期工作。

假设测试通过,则可以将镜像推送到容器注册表并在暂存或生产环境中部署。Docker 与 CI/CD 通过确保从开发到生产的完全相同的环境,在所有开发和部署阶段提供一致性。这有助于最大程度地减少与环境相关的问题。

在本章中,让我们了解如何构建一个集成了 Docker 的基本 CI/CD 管道。

如何使用 Docker 构建 CI/CD 管道?

在本节中,我们将了解如何使用 Docker 和 Jenkins 创建端到端 CI/CD 管道,并通过它构建、测试和运行 Java 应用程序。

步骤 1:安装 Docker

第一步是在您的机器上安装 Docker。您可以参考我们之前的章节之一,并按照适用于您的操作系统的安装说明进行操作,从 Docker 网站 下载 Docker。

步骤 2:在 Docker 容器中运行 Jenkins

接下来,您可以运行以下命令以在 Docker 容器中启动 Jenkins:

$ docker run -d --name jenkins -p 8080:8080 -p 50000:50000 -v jenkins_home:/var/jenkins_home jenkins/jenkins:lts
Docker Continuous Integration 1

以上命令将拉取最新的 Jenkins LTS 镜像并运行它。您可以在 https://127.0.0.1:8080 访问 Jenkins 仪表板。

步骤 3:Jenkins 初始设置

1. 访问 Jenkins - 打开您的浏览器并导航到 https://127.0.0.1:8080。

2. 解锁 Jenkins - 按照说明获取初始管理员密码。

Docker Continuous Integration 2

运行以下命令以获取密码:

$ docker exec jenkins cat /var/jenkins_home/secrets/initialAdminPassword
Docker Continuous Integration 3

3. 安装建议的插件 - 输入密码后,选择“安装建议的插件”。

Docker Continuous Integration 4

Docker Continuous Integration 5

4. 创建管理员用户 - 创建您的管理员用户来管理 Jenkins。

Docker Continuous Integration 6

步骤 4:在 Jenkins 中配置 Docker

安装 Docker Pipeline 插件

  • 转到 Jenkins 仪表板 -> 管理 Jenkins -> 管理插件 -> 可用。
  • 搜索“Docker Pipeline”并安装它。
Docker Continuous Integration 7

添加 Docker Hub 凭据

  • 转到 Jenkins 仪表板 -> 管理 Jenkins -> 管理凭据。
  • 使用您的 Docker Hub 用户名和密码添加一组新的凭据。
Docker Continuous Integration 8

步骤 5:创建 Java 应用程序

创建一个具有以下结构的简单 Java 应用程序:

my-java-app/
├── src/
│   ├── main/
│   │   └── java/
│   │       └── org/
│   │           └── example/
│   │               └── Main.java
│   └── test/
│       └── java/
│           └── org/
│               └── example/
│                   └── MainTest.java
├── Dockerfile
├── Jenkinsfile
├── pom.xml

App.java

package org.example;
public class Main {
   public static void main(String[] args) {
      System.out.println("Hello, Docker CI/CD with Jenkins!");
   }
}

AppTest.java

package org.example;

import static org.junit.Assert.assertTrue;

import org.junit.Test;

public class MainTest {
   @Test
   public void shouldAnswerWithTrue() {
      assertTrue(true);
   }
}

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>my-java-app</artifactId>
   <version>1.0-SNAPSHOT</version>

   <properties>
      <maven.compiler.source>8</maven.compiler.source>
      <maven.compiler.target>8</maven.compiler.target>
      <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
   </properties>

   <dependencies>
      <!-- JUnit 4 dependency -->
      <dependency>
         <groupId>junit</groupId>
         <artifactId>junit</artifactId>
         <version>4.13.2</version>
         <scope>test</scope>
      </dependency>
   </dependencies>
</project>

步骤 6:更新 Dockerfile

在项目的根目录中创建一个 Dockerfile:

FROM maven:3.6.3-jdk-8 AS build
WORKDIR /app
COPY pom.xml .
COPY src /app/src
RUN mvn clean package

FROM openjdk:8-jre-alpine
WORKDIR /app
COPY --from=build /app/target/my-java-app-1.0-SNAPSHOT.jar app.jar
ENTRYPOINT ["java", "-jar", "app.jar"]

步骤 7:更新 Jenkinsfile

在项目的根目录中创建一个 Jenkinsfile 来定义您的 CI/CD 管道:

pipeline {
   agent any

   tools {
      maven 'Maven 3.6.3' // Define the Maven version installed on your Jenkins server
   }

   stages {
      stage('Build') {
         steps {
            script {
               // Build the Docker image
               docker.build("my-java-app:${env.BUILD_ID}")
            }
         }
      }
      stage('Test') {
         steps {
            script {
               // Run tests inside the Docker container
               docker.image("my-java-app:${env.BUILD_ID}").inside {
                  sh 'mvn test'
               }
            }
         }
      }
      stage('Push') {
         steps {
            script {
               // Push the Docker image to Docker Hub
               docker.withRegistry('https://index.docker.io/v1/', 'dockerhub-credentials') {
                  docker.image("my-java-app:${env.BUILD_ID}").push('latest')
               }
            }
         }
      }
      stage('Deploy') {
         steps {
            script {
               // Deploy the Docker image to the production environment
               sh 'docker run -d -p 8080:8080 my-java-app:latest'
            }
         }
      }
   }
   post {
      always {
         cleanWs()
      }
   }
}

步骤 8:配置 Jenkins 作业

1. 创建一个新的作业 - 转到 Jenkins 仪表板 -> 新建 Item。

  • 选择“Pipeline”并将其命名为 my-java-app-pipeline。
  • 在管道配置中,选择“Pipeline 脚本”并将 Jenkinsfile 内容复制到这里。
  • 或者,您也可以“从 SCM 获取 Pipeline 脚本”并选择“Git”,并提供托管 Java 应用程序的存储库 URL。
  • 指定要构建的分支(例如,main 或 master)。
  • 指定 Jenkinsfile 路径。
Docker Continuous Integration 9

Docker Continuous Integration 10

2. 构建作业 - 保存配置并单击“立即构建”以启动管道。

步骤 9:监控管道

  • 构建阶段 - 使用 Dockerfile 构建 Docker 镜像。
  • 测试阶段 - 使用 mvn test 命令在 Docker 容器内运行应用程序测试。执行 MainTest.java 文件,并报告结果。
  • 推送阶段 - 将 Docker 镜像推送到 Docker Hub。
  • 部署阶段 - 将 Docker 镜像部署到服务器。

通过遵循这些步骤,您现在拥有了一个功能齐全的 CI/CD 管道,其中包括使用 Docker 和 Jenkins 对 Java 应用程序进行测试的阶段。

结论

在本章中,我们讨论了如何使用 Docker 和 Jenkins 创建一个功能齐全的 CI/CD 管道,并构建、测试和运行 Java 应用程序。Docker 的容器化确保了开发、测试和部署环境之间的一致性,从而提高了可靠性和可重复性。Jenkins 自动化了从构建 Docker 镜像和运行测试到部署应用程序的管道,从而实现了持续改进的快速反馈。

在这种设置中使用 Maven 和 JUnit 的测试方法促进了强大的测试方法,以确保质量和可靠性。凭借这些最佳实践,团队可以推动高效、可扩展、弹性的软件交付,使其继续与敏捷开发和现代部署周期的需求保持一致。

关于 Docker 持续集成的常见问题

1. 如何将 Docker 与 Jenkins 集成以进行 CI/CD?

将 Docker 与 Jenkins 集成的第一步是在 Jenkins 服务器上安装 Docker 插件,使 Jenkins 可以与 Docker 进行交互,并使其能够构建镜像、运行容器并将它们推送到注册表。之后,您可以选择在 Jenkins 中使用 Docker 命令来构建和部署应用程序定义您的 CI/CD 管道。

2. 如何在 Jenkins 中使用 Docker Compose?

Docker Compose 用于定义和管理多容器应用程序。您可以在 Jenkins 中使用 Docker Compose 插件进行复杂的部署,例如按正确的顺序、配置等启动多个容器;这在应用程序中有多个服务时特别有用。

3. 如何为构建 Docker 镜像设置 Jenkins 管道?

您可以使用 Jenkinsfile 创建一个 Jenkins 管道,其中定义了构建和部署 Docker 镜像的所有步骤。此管道从源代码控制中提取源代码,创建 Docker 镜像,运行测试,将镜像推送到某个注册表,并将其部署到目标环境。

广告