”工欲善其事,必先利其器。“—孔子《论语.录灵公》
首页 > 编程 > 使用 Buildpack 创建 Spring Boot 应用程序的 Docker 映像

使用 Buildpack 创建 Spring Boot 应用程序的 Docker 映像

发布于2024-11-05
浏览:837

Creating Docker Image of Spring Boot Application using Buildpacks

介绍

您已经创建了一个 Spring Boot 应用程序。它在您的本地计算机上运行良好,现在您需要将该应用程序部署到其他地方。在某些平台上,您可以直接提交jar文件,它将被部署。在某些地方,您可以启动虚拟机,下载源代码,构建并运行它。但是,大多数时候您需要使用容器来部署应用程序。大多数时候,Docker 用于在容器中构建和运行镜像。此外,当您将 jar 文件上传到某些平台时,应用程序会在后台的容器内运行。

因此,在本博客中,我们将看到 3 种不同的方法来为给定的 Spring Boot 应用程序构建 Docker 映像。让我们开始吧:

基础容器镜像

为任何应用程序构建 Docker 映像的简单且不充分的方法是使用一个简单的 Dockerfile,它将 jar 文件复制到映像中并使用 java -jar 命令运行它。

创建 Dockerfile

这是可以放在项目根目录的 Dockerfile:

FROM eclipse-temurin:21-jre-ubi9-minimal

ARG JAR_FILE

COPY ${JAR_FILE} application.jar

ENTRYPOINT ["java", "-jar", "/application.jar"]

我们指定了一个参数 JAR_FILE,它是要使用的 jar 文件的位置。

构建 Docker 镜像

创建上述Dockerfile后,使用以下步骤创建Docker镜像:

  1. 为 Spring Boot 项目构建 jar 文件:

    ./gradlew bootJar # For Gradle build system
    

    或者

    ./mvnw spring-boot:build-jar # For Maven build system
    
  2. 使用 Dockerfile 使用最新的 jar 文件构建 Docker 映像。在以下命令中,将 {IMAGE_NAME} 替换为所需的映像名称,将 {JAR_FILE} 替换为生成的 jar 文件的路径。图像名称还包含一个标签,例如 - mycompany/product-service:0.0.1-SNAPSHOT:

    docker build --build-arg JAR_FILE={JAR_FILE} --tag {IMAGE_NAME} .
    
  3. 验证 Docker 镜像是否是使用以下命令构建的。您应该能够看到上面命令中指定名称的图像:

    docker images
    

使用分层 Jar 的高效容器镜像

虽然可以轻松地将 Spring Boot uber jar 打包为 Docker 映像(如前面的方法中所述),但在 Docker 映像中按原样复制和运行 fat jar 有很多缺点。例如,

  • 在不解压的情况下运行 uber jar 会产生一些额外的开销。
  • 将应用程序的代码及其所有依赖项放在单个层中并不是最佳选择。

由于我们编译代码的频率比升级 Spring Boot 版本的频率高,因此最好将各个部分分开一些。如果我们将那些很少更改的jar文件放在应用层之前的层中,那么Doc​​ker通常只需要更改底层,并且可以从其缓存中选取其余的。

启用分层 Jar

要创建分层的 Docker 镜像,我们需要首先创建分层的 jar。如今,它在 Gradle 和 Maven 中默认启用。您可以使用以下设置启用或禁用分层 jar 行为:

// build.gradle
tasks.named("bootJar") {
    layered {
        enabled = false
    }
}
// build.gradle.kts
tasks.named("bootJar") {
   layered {
      enabled.set(false)
   }
}


   
      
         
            org.springframework.boot
            spring-boot-maven-plugin
            
               
                  true
               
            
         
      
   

您甚至可以调整图层的创建方式。请参阅 gradle 或 maven 配置的文档。

创建 Dockerfile

下面是 Dockerfile,可用于利用分层 jar 并创建 Spring Boot 应用程序的分层 Docker 映像。

# Perform the extraction in a separate builder container
FROM eclipse-temurin:21-jre-ubi9-minimal AS builder

WORKDIR /builder

# This points to the built jar file in the target folder
# Adjust this to 'build/libs/*.jar' if you're using Gradle
ARG JAR_FILE=target/*.jar

# Copy the jar file to the working directory and rename it to application.jar
COPY ${JAR_FILE} application.jar

# Extract the jar file using an efficient layout
RUN java -Djarmode=tools -jar application.jar extract --layers --destination extracted

# This is the runtime container
FROM eclipse-temurin:21-jre-ubi9-minimal

WORKDIR /application

# Copy the extracted jar contents from the builder container into the working directory in the runtime container
# Every copy step creates a new docker layer
# This allows docker to only pull the changes it really needs
COPY --from=builder /builder/extracted/dependencies/ ./
COPY --from=builder /builder/extracted/spring-boot-loader/ ./
COPY --from=builder /builder/extracted/snapshot-dependencies/ ./
COPY --from=builder /builder/extracted/application/ ./

# Start the application jar - this is not the uber jar used by the builder
# This jar only contains application code and references to the extracted jar files
# This layout is efficient to start up and CDS friendly
ENTRYPOINT ["java", "-jar", "application.jar"]

构建 Docker 镜像

构建分层 Docker 镜像的步骤与构建基本 Docker 镜像相同。请参考那里。

云原生构建包

如果我告诉你无需创建 Dockerfile 就可以创建 Docker 映像怎么办?我们可以使用 Cloud Native Buildpacks 直接从 Gralde 或 Maven 插件构建 docker 镜像。一些平台(如 Heroku 或 Cloud Foundry)使用 Buildpack 将提供的 jar 文件转换为可运行的映像。

Spring Boot 包括直接对 Maven 和 Gradle 的构建包支持。我们不需要包含任何额外的插件。只需运行以下命令:

./gradlew bootBuildImage # For gradle build system

或者

./mvnw spring-boot:build-image # For maven build system

上述命令生成默认名称为 {PROJECT_NAME}:${PROJECT_VERSION} 的图像。如果要配置生成图片的名称,可以按照以下步骤操作:

为 Gradle 构建系统配置镜像名称

我们可以配置 bootBuildImage 任务来设置镜像的名称,如下所示:

// For build.gradle.kts
val imagePrefix = "javarush"
val dockerImageName = "docker-example"
tasks.named("bootBuildImage") {
   imageName.set("${imagePrefix}/${dockerImageName}:${version}")
}
// For build.gradle
def imagePrefix = "javarush"
def dockerImageName = "docker-example"
tasks.named("bootBuildImage") {
   imageName = "${imagePrefix}/${dockerImageName}:${version}"
}

为 Maven 构建系统配置镜像名称

我们可以配置 spring-boot-maven-plugin 使用另一个镜像名称,如下所示:


   javarush


...


    
        
            
                org.springframework.boot
                spring-boot-maven-plugin
                
                    
                        ${imagePrefix}/${project.artifactId}:${project.version}
                    
                
            
        
    

运行命令时配置镜像名称

我们甚至可以在运行构建镜像的命令时定义镜像的名称。

./gradlew bootBuildImage --imageName=javarush/docker-example:1.0.0 # For grade build system

./mvnw spring-boot:build-image -Dspring-boot.build-image.imageName=javarush/docker-example:1.0.0 # For maven build system

可以查看文档进一步配置Gradle或Maven插件。
这是我为任何 Spring Boot 应用程序创建 Docker 映像的首选方法。

运行 Docker 容器

创建 docker 镜像后,您需要确保它按预期工作。确保镜像创建完成后,可以直接使用 docker run 命令运行它。例如,

docker run -p "8080:8080" {IMAGE_NAME}

但是,这不是图像在生产应用程序中的使用方式。 Docker Compose 用于运行和管理多个 docker 镜像。

结论

在这篇博客中,我们了解了如何使用不同的方法为 Spring Boot 应用程序构建 Docker 镜像。能够为您的应用程序构建 Docker 镜像是一项必须了解的技能,因为镜像是交付的内容。感谢您阅读本文直到最后。我很感激。我会在下一篇与你见面。一如既往,欢迎所有反馈和建议。

版本声明 本文转载于:https://dev.to/himanshu-pareek/creating-docker-image-of-spring-boot-application-using-buildpacks-5dbo?1如有侵犯,请联系[email protected]删除
最新教程 更多>
  • MySQL中如何高效地根据两个条件INSERT或UPDATE行?
    MySQL中如何高效地根据两个条件INSERT或UPDATE行?
    在两个条件下插入或更新或更新 solution:的答案在于mysql的插入中...在重复键更新语法上。如果不存在匹配行或更新现有行,则此功能强大的功能可以通过插入新行来进行有效的数据操作。如果违反了唯一的密钥约束。实现所需的行为,该表必须具有唯一的键定义(在这种情况下为'名称'...
    编程 发布于2025-06-05
  • 如何使用Regex在PHP中有效地提取括号内的文本
    如何使用Regex在PHP中有效地提取括号内的文本
    php:在括号内提取文本在处理括号内的文本时,找到最有效的解决方案是必不可少的。一种方法是利用PHP的字符串操作函数,如下所示: 作为替代 $ text ='忽略除此之外的一切(text)'; preg_match('#((。 &&& [Regex使用模式来搜索特...
    编程 发布于2025-06-05
  • Java中Lambda表达式为何需要“final”或“有效final”变量?
    Java中Lambda表达式为何需要“final”或“有效final”变量?
    Lambda Expressions Require "Final" or "Effectively Final" VariablesThe error message "Variable used in lambda expression shou...
    编程 发布于2025-06-05
  • C++中如何将独占指针作为函数或构造函数参数传递?
    C++中如何将独占指针作为函数或构造函数参数传递?
    在构造函数和函数中将唯一的指数管理为参数 unique pointers( unique_ptr [2启示。通过值: base(std :: simelor_ptr n) :next(std :: move(n)){} 此方法将唯一指针的所有权转移到函数/对象。指针的内容被移至功能中,在操作...
    编程 发布于2025-06-05
  • 解决MySQL插入Emoji时出现的\\"字符串值错误\\"异常
    解决MySQL插入Emoji时出现的\\"字符串值错误\\"异常
    Resolving Incorrect String Value Exception When Inserting EmojiWhen attempting to insert a string containing emoji characters into a MySQL database us...
    编程 发布于2025-06-05
  • `console.log`显示修改后对象值异常的原因
    `console.log`显示修改后对象值异常的原因
    foo = [{id:1},{id:2},{id:3},{id:4},{id:id:5},],]; console.log('foo1',foo,foo.length); foo.splice(2,1); console.log('foo2', foo, foo....
    编程 发布于2025-06-05
  • 在程序退出之前,我需要在C ++中明确删除堆的堆分配吗?
    在程序退出之前,我需要在C ++中明确删除堆的堆分配吗?
    在C中的显式删除 在C中的动态内存分配时,开发人员通常会想知道是否有必要在heap-procal extrable exit exit上进行手动调用“ delete”操作员,但开发人员通常会想知道是否需要手动调用“ delete”操作员。本文深入研究了这个主题。 在C主函数中,使用了动态分配变量(H...
    编程 发布于2025-06-05
  • PHP阵列键值异常:了解07和08的好奇情况
    PHP阵列键值异常:了解07和08的好奇情况
    PHP数组键值问题,使用07&08 在给定数月的数组中,键值07和08呈现令人困惑的行为时,就会出现一个不寻常的问题。运行print_r($月)返回意外结果:键“ 07”丢失,而键“ 08”分配给了9月的值。此问题源于PHP对领先零的解释。当一个数字带有0(例如07或08)的前缀时,PHP将其...
    编程 发布于2025-06-05
  • 如何干净地删除匿名JavaScript事件处理程序?
    如何干净地删除匿名JavaScript事件处理程序?
    删除匿名事件侦听器将匿名事件侦听器添加到元素中会提供灵活性和简单性,但是当要删除它们时,可以构成挑战,而无需替换元素本身就可以替换一个问题。 element? element.addeventlistener(event,function(){/在这里工作/},false); 要解决此问题,请考虑...
    编程 发布于2025-06-05
  • 为什么Microsoft Visual C ++无法正确实现两台模板的实例?
    为什么Microsoft Visual C ++无法正确实现两台模板的实例?
    The Mystery of "Broken" Two-Phase Template Instantiation in Microsoft Visual C Problem Statement:Users commonly express concerns that Micro...
    编程 发布于2025-06-05
  • Go语言垃圾回收如何处理切片内存?
    Go语言垃圾回收如何处理切片内存?
    在Go Slices中的垃圾收集:详细的分析在GO中,Slice是一个动态数组,引用了基础阵列。使用切片时,了解垃圾收集行为至关重要,以避免潜在的内存泄漏。考虑使用slice使用slice的以下实现:字符串{ R:=(*Q)[0] *q =(*q)[1:len(*q)] 返回...
    编程 发布于2025-06-05
  • CSS可以根据任何属性值来定位HTML元素吗?
    CSS可以根据任何属性值来定位HTML元素吗?
    靶向html元素,在CSS 中使用任何属性值,在CSS中,可以基于特定属性(如下所示)基于特定属性的基于特定属性的emants目标元素: 字体家庭:康斯拉斯(Consolas); } 但是,出现一个常见的问题:元素可以根据任何属性值而定位吗?本文探讨了此主题。的目标元素有任何任何属性值,属...
    编程 发布于2025-06-05
  • 您可以使用CSS在Chrome和Firefox中染色控制台输出吗?
    您可以使用CSS在Chrome和Firefox中染色控制台输出吗?
    在javascript console 中显示颜色是可以使用chrome的控制台显示彩色文本,例如红色的redors,for for for for错误消息?回答是的,可以使用CSS将颜色添加到Chrome和Firefox中的控制台显示的消息(版本31或更高版本)中。要实现这一目标,请使用以下模...
    编程 发布于2025-06-05
  • 将图片浮动到底部右侧并环绕文字的技巧
    将图片浮动到底部右侧并环绕文字的技巧
    在Web设计中围绕在Web设计中,有时可以将图像浮动到页面右下角,从而使文本围绕它缠绕。这可以在有效地展示图像的同时创建一个吸引人的视觉效果。 css位置在右下角,使用css float and clear properties: img { 浮点:对; ...
    编程 发布于2025-06-05
  • 如何使用“ JSON”软件包解析JSON阵列?
    如何使用“ JSON”软件包解析JSON阵列?
    parsing JSON与JSON软件包 QUALDALS:考虑以下go代码:字符串 } func main(){ datajson:=`[“ 1”,“ 2”,“ 3”]`` arr:= jsontype {} 摘要:= = json.unmarshal([] byte(...
    编程 发布于2025-06-05

免责声明: 提供的所有资源部分来自互联网,如果有侵犯您的版权或其他权益,请说明详细缘由并提供版权或权益证明然后发到邮箱:[email protected] 我们会第一时间内为您处理。

Copyright© 2022 湘ICP备2022001581号-3