目录

一、前言

1、为什么容器化 Spring Boot 应用程序很重要?

2、一个简单的“Hello World”Spring Boot 应用程序

二、容器化 Spring Boot 代码的 9 个技巧

1、自动化所有手动步骤

2、使用特定的基础图像标签,而不是最新的

3、如果可能,使用 Eclipse Temurin 而不是 JDK

4、 使用多阶段构建

5、使用 .dockerignore

6、支持多架构 Docker 镜像

7、出于安全考虑,以非 root 用户身份运行

8、修复 Java 映像中的安全漏洞

9、使用 OpenTelemetry API 测量 Java 性能

结论


一、前言

1、为什么容器化 Spring Boot 应用程序很重要?

2、一个简单的“Hello World”Spring Boot 应用程序

为了更好地理解无人关注的问题,让我们构建一个示例“Hello World”应用程序。通过下载这个预先初始化的项目并生成一个 ZIP 文件来应用程序。然后解压缩并完成以下步骤以运行该应用程序。

容器化 Spring Boot 代码的 9 个技巧-LMLPHP

在该目录下,您可以使用以下内容src/main/java/com/example/dockerapp/修改您的文件:DockerappApplication.java

package com.example.dockerapp;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;


@RestController
@SpringBootApplication
public class DockerappApplication {


    @RequestMapping("/")
    public String home() {
        return "Hello World!";
    }

        public static void main(String[] args) {
                SpringApplication.run(DockerappApplication.class, args);
        }

}

以下命令获取您编译的代码并将其打包成可分发的格式,例如 JAR:

./mvnw package
java -jar target/*.jar

现在,您应该可以通过http://localhost:8080访问“Hello World” 。

为了 Dockerize 这个应用程序,你需要使用Dockerfile. ADockerfile是一个文本文档,其中包含用户可以在命令行上调用以组装 Docker 映像的每条指令。一个 Docker 镜像由一堆层组成,每个层代表Dockerfile. 每个后续层都包含对其底层的更改。

通常,开发人员使用以下Dockerfile模板来构建 Docker 映像。

FROM eclipse-temurin
ARG JAR_FILE=target/*.jar
COPY ${JAR_FILE} app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "/app.jar"]

第一行定义了大约 457 MB 的基本映像。ARG指令指定可用于COPY指令的  变量。COPY将JAR 文件从target/文件夹复制到 Docker 映像的根目录。EXPOSE指令通知 Docker 容器在运行时侦听指定的网络端口。最后,ENTRYPOINT允许您配置作为可执行文件运行的容器。它对应于您的命令。java -jar target/*.jar 

您将使用docker build命令构建图像,如下所示:

$ docker build -t spring-boot-docker .
Sending build context to Docker daemon  15.98MB
Step 1/5 : FROM eclipse-temurin
 ---a3562aa0b991
Step 2/5 : ARG JAR_FILE=target/*.jar
 ---Running in a8c13e294a66
Removing intermediate container a8c13e294a66
 ---aa039166d524
Step 3/5 : COPY ${JAR_FILE} app.jar
COPY failed: no source files were specified

上述示例的一个主要缺点是它没有完全容器化。./mvnw您必须首先通过在主机系统上运行package命令来 创建 JAR 文件。这需要您手动安装 Java、设置  JAVA_HOME 环境变量并安装 Maven。简而言之,你的 JDK 必须驻留在你的 Docker 容器之外——这给你的构建环境增加了更多的复杂性。一定有更好的方法。

二、容器化 Spring Boot 代码的 9 个技巧

1、自动化所有手动步骤

建议在您自己的构建过程中构建 JAR Dockerfile。以下RUN说明触发解决所有项目依赖项的目标,包括插件、报告及其依赖项:

FROM eclipse-temurin
WORKDIR /app

COPY .mvn/ .mvn
COPY mvnw pom.xml ./
RUN ./mvnw dependency:go-offline

COPY src ./src

CMD ["./mvnw", "spring-boot:run"]

💡 避免在编写 Dockerfile 时手动复制 JAR 文件

2、使用特定的基础图像标签,而不是最新的

💡避免FROM eclipse-temurin:latest在你的Dockerfile

3、如果可能,使用 Eclipse Temurin 而不是 JDK

FROM eclipse-temurin:17-jdk-jammy

WORKDIR /app

COPY .mvn/ .mvn
COPY mvnw pom.xml ./
RUN ./mvnw dependency:go-offline

COPY src ./src

CMD ["./mvnw", "spring-boot:run"]

4、 使用多阶段构建

FROM eclipse-temurin:17-jdk-jammy
ARG JAR_FILE=target/*.jar
COPY ${JAR_FILE} app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "/app.jar"]

在第一阶段,将提取依赖项。在第二阶段,将提取的依赖项复制到最终图像中:

FROM eclipse-temurin:17-jdk-jammy as builder
WORKDIR /opt/app
COPY .mvn/ .mvn
COPY mvnw pom.xml ./
RUN ./mvnw dependency:go-offline
COPY ./src ./src
RUN ./mvnw clean install


FROM eclipse-temurin:17-jre-jammy
WORKDIR /opt/app
EXPOSE 8080
COPY --from=builder /opt/app/target/*.jar /opt/app/*.jar
ENTRYPOINT ["java", "-jar", "/opt/app/*.jar" ]

5、使用 .dockerignore

为了提高构建性能,建议.dockerignore在您的Dockerfile. 对于本教程,您的.dockerignore文件应该只包含一行:


target

.dockerignore如果您选择从构建中排除conflibraries和,您的文件可能如下所示:plugins directory

容器化 Spring Boot 代码的 9 个技巧-LMLPHP

6、支持多架构 Docker 镜像

您的 CPU 只能运行其本机架构的二进制文件。例如,为 x86 系统构建的 Docker 映像无法在基于 Arm 的系统上运行。随着 Apple 完全过渡到其定制的基于 Arm 的芯片,您的 x86(英特尔或 AMD)Docker 映像可能无法与 Apple 最近的 M 系列芯片一起使用。因此,始终建议构建多架构容器映像。下面是mplatform/mqueryDocker 镜像,可让您在任何公共注册表中查询任何公共镜像的多平台状态:

docker run --rm mplatform/mquery eclipse-temurin:17-jre-alpine
Image: eclipse-temurin:17-jre-alpine (digest: sha256:ac423a0315c490d3bc1444901d96eea7013e838bcf7cc09978cf84332d7afc76)
 * Manifest List: Yes (Image type: application/vnd.docker.distribution.manifest.list.v2+json)
 * Supported platforms:
   - linux/amd64



这里介绍了docker buildx帮助您构建多架构映像的命令。Buildx是一个 Docker 组件,它支持许多强大的构建功能和熟悉的 Docker 用户体验。通过 Buildx 执行的所有构建都通过Moby BuildKit构建器引擎运行。BuildKit 旨在擅长多平台构建,或者不仅仅是针对用户本地平台的构建。当您调用构建时,您可以设置--platform标志来指定构建输出的目标平台,(如linux/amd64linux/arm64darwin/amd64):


docker buildx build --platform linux/amd64, linux/arm64 -t spring-helloworld .

7、出于安全考虑,以非 root 用户身份运行

以用户权限运行应用程序更安全,因为它有助于降低风险。这同样适用于 Docker 容器。默认情况下,Docker 容器及其运行的应用程序具有 root 权限。因此,最好以非 root 用户身份运行 Docker 容器。您可以通过USERDockerfile. 该USER指令在运行映像时设置首选用户名(或 UID)和可选的用户组(或 GID) - 以及任何后续RUNCMDENTRYPOINT指令:

FROM eclipse-temurin:17-jdk-alpine
RUN addgroup demogroup; adduser  --ingroup demogroup --disabled-password demo
USER demo

WORKDIR /app

COPY .mvn/ .mvn
COPY mvnw pom.xml ./
RUN ./mvnw dependency:go-offline

COPY src ./src

CMD ["./mvnw", "spring-boot:run"]

8、修复 Java 映像中的安全漏洞

今天的开发人员在构建他们的服务时依赖第三方代码和应用程​​序。不小心使用外部软件,您的代码可能更容易受到攻击。利用受信任的图像并持续监控您的容器对于解决这个问题至关重要。每当您构建“Hello World”Docker 映像时,Docker Desktop 都会提示您运行映像的安全扫描以检测任何已知漏洞,例如 Log4Shell:

exporting to image                                                      0.0s
 == exporting layers                                                    0.0s
 == writing image sha256:cf6d952a1ece4eddcb80c8d29e0c5dd4d3531c1268291  0.0s
 == naming to docker.io/library/spring-boot1                            0.0s

Use 'docker scan' to run Snyk tests against images to find vulnerabilities and learn how to fix them

使用Snyk Extension for Docker Desktop来检查Spring Boot 应用程序。首先,在您的MacWindowsLinux机器上安装Docker Desktop 4.8.0+并启用扩展市场

容器化 Spring Boot 代码的 9 个技巧-LMLPHP

Snyk 的扩展允许您快速扫描本地和远程 Docker 映像以检测漏洞。

容器化 Spring Boot 代码的 9 个技巧-LMLPHP

安装Snyk扩展并提供“Hello World”Docker 镜像。

容器化 Spring Boot 代码的 9 个技巧-LMLPHP

Snyk 的工具发现了 70 个不同严重程度的漏洞。一旦你意识到这些,你就可以开始修复以激发你的形象。

💡 为了执行漏洞检查,您可以直接对 : 使用以下命令Dockerfiledocker scan -f Dockerfile spring-helloworld

 

9、使用 OpenTelemetry API 测量 Java 性能

结论

在这篇博文中,您看到了通过精心制作 Dockerfile 并使用 Snyk Docker Extension Marketplace 保护您的镜像来优化 Docker 镜像的许多方法。

07-06 09:24