本文翻译自国外论坛 medium,原文地址:https://medium.com/@bubu.tripathy/dockerizing-your-spring-boot-application-75bf2c6568d0
Docker 是一个强大的工具,允许开发人员将他们的应用程序打包在容器中可以在任何平台上轻松部署和运行。在对 Spring Boot 应用程序进行 Docker 化时,每个开发人员都应遵循一些最佳实践,以确保应用程序平稳高效地运行。在本文中,我们将探索这些最佳实践并提供代码示例和解释,以帮助大家对 Spring Boot 应用程序进行 Docker 化改造。
在对 Spring Boot 应用程序进行 Docker 化时,为应用程序选择正确的基础镜像非常重要。基础镜像提供应用程序所需的底层操作系统和依赖项。选择正确的基础镜像有助于确保应用程序在 Docker 容器中平稳高效地运行。
对于 Spring Boot 应用程序,我们建议使用 OpenJDK 基础镜像。 OpenJDK 是 Java 开发工具包 (JDK) 的开源实现,并提供 Java 运行时环境。 OpenJDK 基础镜像有不同的版本,例如 Java 8、Java 11 和 Java 16。下面是一个使用 OpenJDK 11 基础镜像的 Dockerfile 示例:
- FROM openjdk:11
- COPY target/my-application.jar app.jar
- ENTRYPOINT ["java", "-jar", "/app.jar"]
在此示例中,我们使用 openjdk:11
基础镜像为 Spring Boot 应用程序创建 Docker 镜像。我们将 my-application.jar
文件复制到容器中,并使用 java
命令运行应用程序。
❝为 Spring Boot 应用程序使用正确的基础镜像有助于确保应用程序在 Docker 容器中平稳高效地运行。 OpenJDK 是 Java 应用程序的热门选择,因为它提供了轻量级且安全的 Java 运行时环境。
❞
在对 Spring Boot 应用程序进行 Docker 化时,保持 Docker 镜像的大小尽可能小很重要。较小的镜像大小有几个优点,例如更快的镜像传输时间、更低的存储要求和更快的容器启动时间。
实现较小镜像大小的一种方法是在 Dockerfile 中使用多阶段构建。在多阶段构建中,我们可以使用多个 FROM
指令来定义构建过程中的不同阶段。每个阶段都可以有自己的一组指令和依赖项,最终镜像只包含最后一个阶段的文件和依赖项。下面是一个使用多阶段构建来创建 slim(精简) Spring Boot 镜像的 Dockerfile 示例:
- # 第一阶段:构建应用
- FROM maven:3.8.3-jdk-11 AS build
- COPY . /app
- WORKDIR /app
- RUN mvn package -DskipTests
-
- # 第二阶段: 创建一个 slim 镜像
- FROM openjdk:11-jre-slim
- COPY --from=build /app/target/my-application.jar /app.jar
- ENTRYPOINT ["java", "-jar", "/app.jar"]
在此示例中,第一阶段使用 Maven 基础镜像构建 Spring Boot 应用程序并生成 jar 文件。第二阶段使用 OpenJDK slim 基础镜像,它是基础镜像的较小版本,仅包含 Java 运行时环境。
COPY --from=build
指令将 jar 文件从第一阶段复制到第二阶段,ENTRYPOINT
指令指定容器启动时应运行的命令。
❝以这种方式使用多阶段构建允许我们创建一个精简的 Docker 镜像,它只包含运行 Spring Boot 应用程序所需的依赖项和文件。通过这样做,可以减小图像的大小并提高应用程序的性能。
❞
在对 Spring Boot 应用程序进行 Docker 化时,使用环境变量来配置应用程序很重要。使用环境变量允许更改应用程序的配置而无需重建 Docker 镜像。
Spring Boot 应用程序可以使用 application.properties
或 application.yml
文件来指定配置属性。这些属性可以在运行时使用环境变量覆盖,Spring Boot 会自动将其映射到属性。下面是一个 Dockerfile 示例,它设置了一个环境变量来为 Spring Boot 应用程序指定使用哪个配置文件:
- FROM openjdk:11
- ENV SPRING_PROFILES_ACTIVE=production
- COPY target/my-application.jar app.jar
- ENTRYPOINT ["java", "-jar", "/app.jar"]
在此示例中,我们将 SPRING_PROFILES_ACTIVE
环境变量设置为 production
,这将激活 Spring Boot 应用程序中的 production
配置文件。
当容器启动时,在 ENTRYPOINT
指令中指定的 java
命令与 -jar
选项一起运行以启动 Spring Boot 应用程序。由于我们设置了 SPRING_PROFILES_ACTIVE
环境变量,应用程序将自动使用 production
配置文件。
❝以这种方式使用环境变量可以轻松更改 Spring Boot 应用程序的配置,而无需重建 Docker 镜像。我们可以在运行容器时使用
❞-e
选项设置环境变量,或者使用 Docker Compose 文件来定义环境变量。
在对 Spring Boot 应用程序进行 Docker 化时,使用 Docker Compose 来定义应用程序的服务和依赖项非常重要。 Docker Compose 是一个用于定义和运行多容器 Docker 应用程序的工具。它允许我们在单个文件中定义应用程序的 services, networks, 和 volumes,从而轻松管理和部署我们的应用程序。这是一个定义 Spring Boot 应用程序和 MySQL 数据库的示例 Docker Compose 文件:
- version: '3'
- services:
- db:
- image: mysql:5.7
- environment:
- MYSQL_ROOT_PASSWORD: my-secret-pw
- MYSQL_DATABASE: my-database
- volumes:
- - db_data:/var/lib/mysql
- web:
- build: .
- ports:
- - "8080:8080"
- environment:
- SPRING_DATASOURCE_URL: jdbc:mysql://db:3306/my-database
- SPRING_DATASOURCE_USERNAME: root
- SPRING_DATASOURCE_PASSWORD: my-secret-pw
- volumes:
- db_data:
在这个例子中,我们定义了两个服务:db
和 web
。 db
服务使用官方 MySQL 镜像,并使用环境变量设置 root 密码和数据库名称。它还为持久存储创建一个命名卷 db_data
。
Web
服务使用 .
构建上下文并公开端口 8080
。它还为数据库 URL、用户名和密码设置环境变量,Spring Boot 应用程序使用这些变量连接到 MySQL 数据库。
❝以这种方式使用 Docker Compose 可以让我们轻松管理和部署 Spring Boot 应用程序及其依赖项。可以使用单个命令启动 Docker Compose 文件中定义的所有服务,并且可以根据需要扩展或缩减服务。此外,还可以使用 Docker Compose 定义额外的配置选项,例如 volumes、networks和environment 变量,从而轻松管理和部署应用程序。
❞
在对 Spring Boot 应用程序进行 Docker 化时,使用反向代理来处理传入流量并将其分发到应用程序的容器非常重要。反向代理是位于应用程序和互联网之间的服务器,它根据特定规则将请求转发到应用程序的容器。
使用反向代理有几个优点,例如负载平衡、SSL 终止和改进的安全性。通过使用反向代理,可以在多个容器之间平均分配传入流量,在代理级别终止 SSL 连接以减少应用程序容器的负载,并为应用程序添加额外的安全层。下面是一个定义 Spring Boot 应用程序和 Nginx 反向代理的 Docker Compose 文件示例:
- version: '3'
- services:
- web:
- build: .
- environment:
- SPRING_PROFILES_ACTIVE: production
- ports:
- - "8080:8080"
- proxy:
- image: nginx
- ports:
- - "80:80"
- volumes:
- - ./nginx.conf:/etc/nginx/nginx.conf:ro
- depends_on:
- - web
在这个例子中,我们定义了两个服务:web
和 proxy
。 Web
服务构建Spring Boot应用,暴露 8080
端口,proxy
服务使用官方Nginx镜像,根据 nginx.conf
文件中定义的规则,将请求转发给 Web
服务。
下面是一个示例 nginx.conf
文件,它定义了将请求转发到 Web
服务的规则:
- events {
- }
-
- http {
- server {
- listen 80;
-
- location / {
- proxy_pass http://web:8080;
- proxy_set_header Host $host;
- proxy_set_header X-Real-IP $remote_addr;
- proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
- proxy_set_header X-Forwarded-Proto $scheme;
- }
- }
- }
在此示例中,我们使用 proxy_pass
指令将请求转发到端口 8080
上的 Web
服务。我们还设置了各种标头以保留原始客户端 IP 和协议信息。
❝以这种方式使用反向代理有助于提高 Spring Boot 应用程序 Docker 化后的可扩展性、安全性和性能。通过使用反向代理,我们可以轻松地跨多个容器分发传入流量,为应用程序添加额外的安全层,并通过在代理级别终止 SSL 连接来减少应用程序容器的负载。
❞
在对 Spring Boot 应用程序进行 Docker 化时,使用健康检查来监控应用程序的健康状况并确保其正常运行非常重要。健康检查可用于检测应用程序何时不健康,并根据应用程序的健康状况自动执行恢复或缩放。
要向 Docker 镜像添加健康检查,可以在 Dockerfile 中使用 HEALTHCHECK
指令。 HEALTHCHECK
指令告诉 Docker 如何检查应用程序的健康状况。下面是一个 Dockerfile 示例,它向 Spring Boot 应用程序添加了健康检查:
- FROM openjdk:11
- COPY target/my-application.jar app.jar
- HEALTHCHECK --interval=5s \
- --timeout=3s \
- CMD curl -f http://localhost:8080/actuator/health || exit 1
- ENTRYPOINT ["java", "-jar", "/app.jar"]
在此示例中,我们使用 HEALTHCHECK
指令来检查 Spring Boot 应用程序的运行状况。 --interval
选项指定运行状况检查的频率,--timeout
选项指定等待响应的时间。 CMD
指令运行健康检查命令,这是一个 curl
命令,检查应用程序的 /actuator/health
端点。
运行容器时,可以使用 docker ps 命令查看容器的健康状态:
- $ docker ps
- CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
- e8e1a6440e5e my-application:1.0 "java -jar /app.jar" 5 seconds ago Up 4 seconds 0.0.0.0:8080->8080/tcp my-application
- $ docker inspect --format='{{json .State.Health}}' my-application
- {"Status":"healthy","FailingStreak":0,"Log":[{"Start":"2023-03-25T09:21:08.272130387Z","End":"2023-03-25T09:21:08.310105965Z","ExitCode":0,"Output":"\n"}]}
在此示例中,docker ps
命令显示容器已启动并在端口 8080
上运行。docker inspect
命令显示容器的健康状态,当前为健康状态。如果健康检查失败,容器将被标记为不健康,我们可以使用 Docker Compose 或 Kubernetes 等工具自动恢复或扩展容器。
❝以这种方式使用健康检查有助于提高 Spring Boot 应用程序 Docker 化后的可靠性和可用性。通过使用健康检查,我们可以自动检测应用程序中的问题并从中恢复,确保应用程序始终可供用户使用。
❞
在对 Spring Boot 应用程序进行 Docker 化时,使用 Docker 缓存来加快构建过程并减少构建新 Docker 镜像所需的时间非常重要。 Docker 缓存允许重用之前构建的 Docker 镜像层,避免每次构建新镜像时都需要重建这些层。下面是一个使用 Docker 缓存来加速构建过程的 Dockerfile 示例:
- FROM openjdk:11 as builder
- WORKDIR /app
- COPY pom.xml .
- RUN mvn dependency:go-offline
-
- COPY src/ ./src/
- RUN mvn package -DskipTests
-
- FROM openjdk:11
- COPY --from=builder /app/target/my-application.jar app.jar
- ENTRYPOINT ["java", "-jar", "/app.jar"]
在此示例中,我们使用多阶段构建首先在单独的层中构建 Spring Boot 应用程序,然后将构建的 jar 文件复制到最终图像中。通过为构建过程使用一个单独的层,我们可以利用 Docker 缓存来避免每次构建新图像时都重建依赖项。
构建过程的第一阶段使用 openjdk:11
基础镜像并将 pom.xml
文件复制到容器中。然后它运行 mvn dependency:go-offline
命令来下载应用程序所需的所有依赖项。此命令确保所有需要的依赖项都在本地可用,这将加快后续构建的速度。
构建过程的第二阶段使用 openjdk:11
基础镜像并将源代码复制到容器中。然后它运行 mvn package
命令来构建应用程序 jar 文件。由于我们在前一阶段已经下载了依赖,Docker会使用缓存层,跳过依赖下载这一步。
最后,COPY --from=builder
指令将构建的 jar 文件从构建器阶段复制到最终镜像,ENTRYPOINT
指令指定容器启动时应运行的命令。
❝以这种方式使用 Docker 缓存有助于减少构建新 Docker 镜像所需的时间并加快部署过程。通过利用 Docker 缓存,可以避免不必要的重建,并确保尽可能快速高效地构建 Docker 镜像。
❞
在对 Spring Boot 应用程序进行 Docker 化时,使用 .dockerignore
文件从 Docker 构建上下文中排除不必要的文件和目录非常重要。构建上下文是 Docker 用来构建 Docker 镜像的一组文件和目录。通过使用 .dockerignore
文件,可以排除 Docker 镜像不需要的文件和目录,从而减少构建上下文的大小并提高构建性能。这是 Spring Boot 应用程序的示例 .dockerignore
文件:
- # 忽略根目录中的所有文件
- *
- # 包含 src 目录
- !src/
- # 包含 pom.xml 文件
- !pom.xml
- # 排除目标目录及其内容
- target/
在此示例中,我们使用 .dockerignore
文件排除根目录 (*)
中的所有文件,但构建 Spring Boot 应用程序所需的 src/
目录和 pom.xml
文件除外。我们还排除了 target/
目录,它包含构建的工件并且 Docker 镜像不需要。
通过使用 .dockerignore
文件,我们可以减少构建上下文的大小并提高构建性能。 Docker 只会复制构建上下文中包含的文件和目录,而忽略 .dockerignore
文件中排除的文件和目录。
使用 .dockerignore
文件是对 Spring Boot 应用程序进行 Docker 化的一种好做法,因为它有助于确保尽可能高效快速地构建 Docker 镜像。
此外,使用 .dockerignore
文件还可以帮助提高 Docker 镜像的安全性。通过排除不必要的文件和目录,可以减少 Docker 镜像的攻击面,并最大限度地降低暴露敏感信息或凭据的风险。例如,如果在构建目录中存储了配置文件或凭据,将它们排除在 .dockerignore
文件中将阻止它们包含在 Docker 镜像中。
还值得注意的是,.dockerignore
文件遵循与 .gitignore
文件类似的语法,后者用于从 Git 存储库中排除文件和目录。如果熟悉 .gitignore
文件,我们应该会发现 .dockerignore
文件易于使用。
❝总之,使用 .dockerignore 文件是对 Spring Boot 应用程序进行 Docker 化的一种好做法。它有助于减小构建上下文的大小、提高构建性能并提高 Docker 镜像的安全性。
❞
在对 Spring Boot 应用程序进行 Docker 化时,使用标签将元数据添加到 Docker 镜像非常重要。标签是键值对,可以添加到 Docker 镜像以提供有关镜像的其他信息,例如版本、维护者或构建日期。下面是一个使用标签将元数据添加到 Spring Boot 应用程序的 Dockerfile 示例:
- FROM openjdk:11
- LABEL maintainer="John Doe
" - LABEL version="1.0"
- LABEL description="My Spring Boot application"
- COPY target/my-application.jar app.jar
- ENTRYPOINT ["java", "-jar", "/app.jar"]
在此示例中,我们使用 LABEL
指令将元数据添加到 Docker 镜像。我们为镜像的维护者、版本和描述添加了标签。这些标签提供有关 Docker 镜像的附加信息,并帮助用户了解镜像包含的内容及其构建方式。
我们可以使用 docker inspect
命令查看 Docker 镜像的标签:
- $ docker inspect my-application
- [
- {
- "Id": "sha256:...",
- "RepoTags": [
- "my-application:latest"
- ],
- "Labels": {
- "maintainer": "John Doe
" , - "version": "1.0",
- "description": "My Spring Boot application"
- },
- ...
- }
- ]
在此示例中,docker inspect
命令显示 my-application
Docker 镜像的标签。标签提供有关图像的附加信息,可以帮助用户了解图像的构建方式和使用方式。
❝以这种方式使用标签有助于提高 Docker 镜像的可用性和可维护性。通过将元数据添加到 Docker 镜像,可以帮助用户了解镜像包含的内容以及它是如何构建的。随着时间的推移,此信息可用于调试、故障排除和维护 Docker 镜像。
❞
在对 Spring Boot 应用程序进行 Docker 化时,使用容器编排工具在生产环境中管理和扩展应用程序非常重要。容器编排工具可以帮助我们自动化部署、扩展和管理 Docker 容器,从而更轻松地管理分布式环境中的大量容器。
一些流行的 Docker 容器编排工具包括 Kubernetes、Docker Swarm 和 Apache Mesos。这些工具提供负载平衡、自动缩放、服务发现和滚动更新等功能,有助于确保应用程序可用并响应用户。以下是 Spring Boot 应用程序的 Kubernetes 部署文件示例:
- apiVersion: apps/v1
- kind: Deployment
- metadata:
- name: my-application
- labels:
- app: my-application
- spec:
- replicas: 3
- selector:
- matchLabels:
- app: my-application
- template:
- metadata:
- labels:
- app: my-application
- spec:
- containers:
- - name: my-application
- image: my-registry/my-application:1.0
- ports:
- - containerPort: 8080
在此示例中,我们使用 Kubernetes 部署文件来部署 Spring Boot 应用程序。部署文件指定我们要运行应用程序的三个副本,并使用选择器来识别应该成为部署一部分的 pod。部署文件还指定了应该用于运行应用程序的容器镜像,以及应用程序应该侦听的端口。
❝以这种方式使用容器编排工具可以帮助提高 Spring Boot 应用程序 Docker 化后的可扩展性、可靠性和可用性。通过使用容器编排工具,可以在分布式环境中轻松管理和扩展应用程序,从而更轻松地确保应用程序可用并响应用户。
❞
Docker 化 Spring Boot 应用程序可能是一个复杂的过程,但通过遵循这些最佳实践,开发人员可以确保他们的应用程序在 Docker 容器中平稳高效地运行。通过实施这些最佳实践,可以利用 Docker 的优势并将应用程序轻松部署到任何平台。
❝关注公众号【waynblog】每周分享技术干货、开源项目、实战经验、高效开发工具等,您的关注将是我的更新动力!
❞