目录
2、一个简单的“Hello World”Spring Boot 应用程序
3、如果可能,使用 Eclipse Temurin 而不是 JDK
9、使用 OpenTelemetry API 测量 Java 性能
一、前言
1、为什么容器化 Spring Boot 应用程序很重要?
2、一个简单的“Hello World”Spring Boot 应用程序
为了更好地理解无人关注的问题,让我们构建一个示例“Hello World”应用程序。通过下载这个预先初始化的项目并生成一个 ZIP 文件来应用程序。然后解压缩并完成以下步骤以运行该应用程序。
在该目录下,您可以使用以下内容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
如果您选择从构建中排除conf
、libraries
和,您的文件可能如下所示:plugins directory
6、支持多架构 Docker 镜像
您的 CPU 只能运行其本机架构的二进制文件。例如,为 x86 系统构建的 Docker 映像无法在基于 Arm 的系统上运行。随着 Apple 完全过渡到其定制的基于 Arm 的芯片,您的 x86(英特尔或 AMD)Docker 映像可能无法与 Apple 最近的 M 系列芯片一起使用。因此,始终建议构建多架构容器映像。下面是mplatform/mquery
Docker 镜像,可让您在任何公共注册表中查询任何公共镜像的多平台状态:
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/amd64
、linux/arm64
或darwin/amd64
):
docker buildx build --platform linux/amd64, linux/arm64 -t spring-helloworld .
7、出于安全考虑,以非 root 用户身份运行
以用户权限运行应用程序更安全,因为它有助于降低风险。这同样适用于 Docker 容器。默认情况下,Docker 容器及其运行的应用程序具有 root 权限。因此,最好以非 root 用户身份运行 Docker 容器。您可以通过USER
在Dockerfile
. 该USER
指令在运行映像时设置首选用户名(或 UID)和可选的用户组(或 GID) - 以及任何后续RUN
、CMD
或ENTRYPOINT
指令:
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 应用程序。首先,在您的Mac、Windows或Linux机器上安装Docker Desktop 4.8.0+并启用扩展市场。
Snyk 的扩展允许您快速扫描本地和远程 Docker 映像以检测漏洞。
安装Snyk
扩展并提供“Hello World”Docker 镜像。
Snyk 的工具发现了 70 个不同严重程度的漏洞。一旦你意识到这些,你就可以开始修复以激发你的形象。
💡 为了执行漏洞检查,您可以直接对 : 使用以下命令Dockerfile
:docker scan -f Dockerfile spring-helloworld
9、使用 OpenTelemetry API 测量 Java 性能
结论
在这篇博文中,您看到了通过精心制作 Dockerfile 并使用 Snyk Docker Extension Marketplace 保护您的镜像来优化 Docker 镜像的许多方法。