4

Spring Boot Docker入门模板与4个最佳实践

 6 months ago
source link: https://www.jdon.com/72636.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

Spring Boot Docker入门模板与4个最佳实践

在本博客中,您将学习一些主要针对 Spring Boot 应用程序的 Docker 最佳实践。您将通过将这些实践应用到示例应用程序来学习这些实践。享受!

入门模板
将用作入门模板起点的 Dockerfile 如下:

FROM eclipse-temurin:17.0.5_8-jre-alpine@sha256:02c04793fa49ad5cd193c961403223755f9209a67894622e05438598b32f210e
WORKDIR /opt/app
RUN addgroup --system javauser && adduser -S -s /usr/sbin/nologin -G javauser javauser
ARG JAR_FILE
COPY target/${JAR_FILE} app.jar
RUN chown -R javauser:javauser .
USER javauser
ENTRYPOINT ["java", "-jar", "app.jar"]

这个 Dockerfile 执行以下操作:

  • FROM:以eclipse-temurin:17Java Docker镜像为基础镜像;
  • WORKDIR:设置/opt/app为工作目录;
  • RUN:创建系统组和系统用户;
  • ARG:提供一个参数JAR_FILE,这样就不必将 jar 文件名硬编码到 Dockerfile 中;
  • COPY:将jar文件复制到Docker镜像中;
  • RUN:将 的所有者更改WORKDIR为之前创建的系统用户;
  • USER:确保使用之前创建的系统用户;
  • ENTRYPOINT:启动 Spring Boot 应用程序。

在接下来的部分中,您将更改此 Dockerfile 以遵循最佳实践。每个段落生成的 Dockerfile 可在 git 存储库的Dockerfiles目录中找到。在每个段落的末尾,将在适用的情况下提及相应的最终 Dockerfile 的名称。

本博客中使用的代码可在GitHub上找到。

1、健康检查
将运行状况检查添加到 Dockerfile 中,以暴露容器的运行状况。根据此状态,可以重新启动容器。这可以通过HEALTHCHECK命令来完成。添加以下健康检查:

EALTHCHECK --interval=30s --timeout=3s --retries=1 CMD wget -qO- http://localhost:8080/actuator/health/ | grep UP || exit 1
  • interval间隔:每 30 秒执行一次愈合检查。对于生产应用,最好选择 5 分钟这样的间隔。为了进行一些测试,选择一个较小的值会比较容易。这样就不必每次都等待五分钟。
  • timeout超时:执行健康检查的三秒超时。
  • retries重试:表示在健康状态发生变化之前必须连续执行的检查次数。默认值为 3,这在生产中是个不错的数字。出于测试目的,可将其设置为一次,这意味着在一次不成功的检查后,健康状态将变为不健康。
  • command命令:Spring 激励器端点将用作健康检查。获取响应并将其导入 grep,以验证健康状态是否为 UP。建议不要为此目的使用 curl,因为并非每个镜像都有 curl。你需要在镜像中额外安装 curl,这会使镜像增大数 MB。

2、Docker Compose
Docker Compose 为您提供了用一条命令同时启动多个容器的机会。除此之外,它还能让你记录你的服务,即使你只有一个服务需要管理。Docker Compose 过去是与 Docker 分开安装的,但如今它已成为 Docker 本身的一部分。你需要编写一个包含该配置的 compose.yml 文件。让我们看看在健康检查中使用的两个容器是如何配置的。

services:
  dockerbestpractices:
    image: mydeveloperplanet/dockerbestpractices:0.0.1-SNAPSHOT

autoheal:
    image: willfarrell/autoheal:1.2.0
    restart: always
    environment:
      AUTOHEAL_CONTAINER_LABEL: all
    volumes:
      - type: bind
        source: /var/run/docker.sock
        target: /var/run/docker.sock

配置了两个服务(读作:容器)。一个用于 dockerbestpractices 镜像,一个用于 autoheal 镜像。自动修复镜像会在重启后重新启动,它定义了一个环境变量,并挂载了一个卷。

在可以找到 compose.yml 文件的目录下执行以下命令:
$ docker compose up

在日志记录中,你会看到两个容器都已启动。打开另一个终端窗口,导航到可以找到 compose.yml 的目录。很多命令都可以与 Docker Compose 结合使用。

3、多阶段构建
有时,在 Docker 容器中构建应用程序会很方便。这样做的好处是,你不需要在系统中安装完整的开发环境,而且可以更方便地交换开发环境。不过,在容器内构建应用程序也有一个问题。尤其是当您想使用同一个容器运行应用程序时。源代码和完整的开发环境将出现在生产容器中,从安全角度来看,这不是一个好主意。

您可以编写单独的 Dockerfile 来规避这个问题:一个用于构建,一个用于运行应用程序。但这相当麻烦。解决办法是使用多阶段构建。

使用多阶段构建,可以将构建阶段与运行阶段分开。Dockerfile 文件如下:

FROM maven:3.8.6-eclipse-temurin-17-alpine@sha256:e88c1a981319789d0c00cd508af67a9c46524f177ecc66ca37c107d4c371d23b AS builder
WORKDIR /build
COPY . .
RUN mvn clean package -DskipTests

FROM eclipse-temurin:17.0.5_8-jre-alpine@sha256:02c04793fa49ad5cd193c961403223755f9209a67894622e05438598b32f210e
WORKDIR /opt/app
RUN addgroup --system javauser && adduser -S -s /usr/sbin/nologin -G javauser javauser
COPY --from=builder /build/target/mydockerbestpracticesplanet-0.0.1-SNAPSHOT.jar app.jar
RUN chown -R javauser:javauser .
USER javauser
HEALTHCHECK --interval=30s --timeout=3s --retries=1 CMD wget -qO- http://localhost:8080/actuator/health/ | grep UP || exit 1
ENTRYPOINT ["java", "-jar", "app.jar"]

如您所见,该 Dockerfile 包含两条 FROM 语句。第一条用于构建应用程序:

  • FROM:包含 Maven 和 Java 17 的 Docker 镜像,这是构建应用程序所需的;
  • WORKDIR:设置工作目录;
  • COPY:将当前目录复制到容器中的工作目录;
  • RUN:构建 jar 文件的命令。

FROM 语句中还添加了其他内容。最后,添加 AS 生成器。这样,这个容器就有了标签,可以用来构建运行应用程序的镜像。第二部分与之前的 Dockerfile 完全相同,除了两行。

删除以下两行:
ARG JAR_FILE
COPY target/${JAR_FILE} app.jar

这几行确保将本地构建的 jar 文件复制到镜像中。这几行被替换为下面一行:
COPY --from=builder /build/target/mydockerbestpracticesplanet-0.0.1-SNAPSHOT.jar app.jar

通过这一行,您可以表明要将文件从生成容器复制到新镜像中。

当你构建这个 Dockerfile 时,你会发现构建容器会执行构建,最后创建了用于运行应用程序的镜像。在构建镜像的过程中,你还会注意到所有 Maven 依赖项都已下载。

生成的 Dockerfile 可在 git 仓库中找到,名称为 7-Dockerfile-multi-stage-build。

4、Spring Boot Docker 层

  • Docker 镜像由层组成。
  • Dockerfile 中的每一条命令都会产生一个新层。
  • 当你初始化 Docker 镜像时,所有层都会被检索和存储。
  • 如果你更新了 Docker 镜像,但只更改了 jar 文件,那么其他层就不会被重新检索。

这样,Docker 镜像的存储效率会更高。

但是,在使用 Spring Boot 时,会创建一个胖 jar。
也就是说,当你只修改了部分代码时,就会创建一个新的胖jar,其依赖关系保持不变。
因此,每次创建新的 Docker 镜像时,都会在新的层中添加几兆字节,而没有任何必要。

简而言之,Spring Boot 可以将胖 jar 分割成多个目录:

  • /dependencies
  • /spring-boot-loader
  • /snapshot-dependencies
  • /application

应用程序代码将存放在 application 目录中,而依赖项则存放在 dependencies 目录中。

为此,您将使用多阶段构建。

第一阶段将把 jar 文件复制到 JDK Docker 镜像中,然后提取胖 jar。

FROM eclipse-temurin:17.0.4.1_1-jre-alpine@sha256:e1506ba20f0cb2af6f23e24c7f8855b417f0b085708acd9b85344a884ba77767 AS builder
WORKDIR application
ARG JAR_FILE
COPY target/${JAR_FILE} app.jar
RUN java -Djarmode=layertools -jar app.jar extract

第二部分将把分割的目录复制到新的镜像中。COPY 命令会替换 jar 文件。

FROM eclipse-temurin:17.0.4.1_1-jre-alpine@sha256:e1506ba20f0cb2af6f23e24c7f8855b417f0b085708acd9b85344a884ba77767
WORKDIR /opt/app
RUN addgroup --system javauser && adduser -S -s /usr/sbin/nologin -G javauser javauser
COPY --from=builder application/dependencies/ ./
COPY --from=builder application/spring-boot-loader/ ./
COPY --from=builder application/snapshot-dependencies/ ./
COPY --from=builder application/application/ ./
RUN chown -R javauser:javauser .
USER javauser
HEALTHCHECK --interval=30s --timeout=3s --retries=1 CMD wget -qO- http://localhost:8080/actuator/health/ | grep UP || exit 1
ENTRYPOINT ["java", "org.springframework.boot.loader.JarLauncher"]

构建并运行容器。在运行容器时,你不会注意到任何不同之处。主要优势在于 Docker 镜像的存储方式。

生成的 Dockerfile 位于 git 仓库,名称为 8-Dockerfile-spring-boot-docker-layers。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK