利用Spring Boot创建docker image的完整步骤

前言

在很久很久以前,我们是怎么创建Spring Boot的docker image呢?最最通用的办法就是将Spring boot的应用程序打包成一个fat jar,然后写一个docker file,将这个fat jar制作成为一个docker image然后运行。

今天我们来体验一下Spring Boot 2.3.3 带来的快速创建docker image的功能。

传统做法和它的缺点

现在我们创建一个非常简单的Spring Boot程序:

@SpringBootApplication
@RestController
public class Application {

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

 @GetMapping("/getInfo")
 public String getInfo() {
 return "www.flydean.com";
 }
}

默认情况下,我们build出来的是一个fat jar:springboot-with-docker-0.0.1-SNAPSHOT.jar

我们解压看一下它的内容:

Spring boot的fat jar分为三个部分,第一部分就是BOOT-INF, 里面的class目录放的是我们自己编写的class文件。而lib目录存放的是项目依赖的其他jar包。

第二部分是META-INF,里面定义了jar包的属性信息。

第三部分是Spring Boot的类加载器,fat jar包的启动是通过Spring Boot的jarLauncher来创建LaunchedURLClassLoader,通过它来加载lib下面的jar包,最后以一个新线程启动应用的Main函数。

这里不多讲Spring Boot的启动。

我们看一下,如果想要用这个fat jar来创建docker image应该怎么写:

FROM openjdk:8-jdk-alpine
EXPOSE 8080
ARG JAR_FILE=target/springboot-with-docker-0.0.1-SNAPSHOT.jar
ADD ${JAR_FILE} app.jar
ENTRYPOINT ["java","-jar","/app.jar"]

这样写有两个问题。

第一个问题:我们是用的far jar,在使用far jar的过程中会有一定的性能问题,肯定要比解压过后的性能要低,尤其是在容器环境中运行的情况下,可能会更加突出。

第二个问题:我们知道docker的image是按layer来构建的,按layer构建的好处就是可以减少image构建的时间和重用之前的layer。

但是如果使用的是fat jar包,即使我们只修改了我们自己的代码,也会导致整个fat jar重新更新,从而影响docker image的构建速度。

使用Buildpacks

传统的办法除了有上面的两个问题,还有一个就是需要自己构建docker file,有没有一键构建docker image的方法呢?

答案是肯定的。

Spring Boot在2.3.0之后,引入了Cloud Native 的buildpacks,通过这个工具,我们可以非常非常方便的创建docker image。

在Maven和Gradle中,Spring Boot引入了新的phase: spring-boot:build-image

我们可以直接运行:

mvn spring-boot:build-image

运行之,很不幸的是,你可能会遇到下面的错误:

[ERROR] Failed to execute goal org.springframework.boot:spring-boot-maven-plugin:2.3.3.RELEASE:build-image (default-cli) on project springboot-with-docker: Execution default-cli of goal org.springframework.boot:spring-boot-maven-plugin:2.3.3.RELEASE:build-image failed: Docker API call to 'localhost/v1.24/images/create?fromImage=gcr.io%2Fpaketo-buildpacks%2Fbuilder%3Abase-platform-api-0.3' failed with status code 500 "Internal Server Error" and message "Get https://gcr.io/v2/: net/http: request canceled while waiting for connection (Client.Timeout exceeded while awaiting headers)" -> [Help 1]

这是因为我们无法从gcr.io中拉取镜像!

没关系,如果你会正确的上网方式的话,那么我估计你已经找到了一个代理。

将你的代理配置到Docker的代理项里面,我使用的是Docker desktop,下面是我的配置:

重新运行 mvn spring-boot:build-image

等待执行结果:

[INFO] --- spring-boot-maven-plugin:2.3.3.RELEASE:build-image (default-cli) @ springboot-with-docker ---
[INFO] Building image 'docker.io/library/springboot-with-docker:0.0.1-SNAPSHOT'
[INFO]
[INFO]  > Pulling builder image 'gcr.io/paketo-buildpacks/builder:base-platform-api-0.3' 0%
[INFO]  > Pulling builder image 'gcr.io/paketo-buildpacks/builder:base-platform-api-0.3' 0%
[INFO]  > Pulling builder image 'gcr.io/paketo-buildpacks/builder:base-platform-api-0.3' 0%
[INFO]  > Pulling builder image 'gcr.io/paketo-buildpacks/builder:base-platform-api-0.3' 0%
[INFO]  > Pulling builder image 'gcr.io/paketo-buildpacks/builder:base-platform-api-0.3' 0%
[INFO]  > Pulling builder image 'gcr.io/paketo-buildpacks/builder:base-platform-api-0.3' 0%

你可以看到,我们的确是需要从gcr.io拉取image。

Layered Jars

如果你不想使用Cloud Native Buildpacks,还是想使用传统的Dockerfile。 没关系,SpringBoot为我们提供了独特的分层jar包系统。

怎么开启呢? 我们需要在POM文件中加上下面的配置:

<build>
 <plugins>
  <plugin>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-maven-plugin</artifactId>
  <configuration>
   <layers>
   <enabled>true</enabled>
   </layers>
  </configuration>
  </plugin>
 </plugins>
 </build>

再次打包,看下jar包的内容:

看起来和之前的jar包没什么不同,只不过多了一个layers.idx 这个index文件:

- "dependencies":
 - "BOOT-INF/lib/"
- "spring-boot-loader":
 - "org/"
- "snapshot-dependencies":
- "application":
 - "BOOT-INF/classes/"
 - "BOOT-INF/classpath.idx"
 - "BOOT-INF/layers.idx"
 - "META-INF/"

index文件主要分为4个部分:

  • dependencies – 非SNAPSHOT的依赖jar包
  • snapshot-dependencies – SNAPSHOT的依赖jar包
  • spring-boot-loader – Spring boot的class loader文件
  • application – 应用程序的class和resources文件

注意,这里的index文件是有顺序的,它和我们将要添加到docker image中的layer顺序是一致的。

最少变化的将会最先添加到layer中,变动最大的放在最后面的layer。

我们可以使用layertools jarmode来对生成的fat jar进行校验或者解压缩:

java -Djarmode=layertools -jar springboot-with-docker-0.0.1-SNAPSHOT.jar
Usage:
 java -Djarmode=layertools -jar springboot-with-docker-0.0.1-SNAPSHOT.jar

Available commands:
 list List layers from the jar that can be extracted
 extract Extracts layers from the jar for image creation
 help Help about any command

使用list命令,我们可列出jar包中的layer信息。使用extract我们可以解压出不同的layer。

我们执行下extract命令,看下结果:

可以看到,我们根据layers.idx解压出了不同的文件夹。

我们看一下使用layer的dockerFile应该怎么写:

FROM adoptopenjdk:11-jre-hotspot as builder
WORKDIR application
ARG JAR_FILE=target/*.jar
COPY ${JAR_FILE} application.jar
RUN java -Djarmode=layertools -jar application.jar extract

FROM adoptopenjdk:11-jre-hotspot
WORKDIR application
COPY --from=builder application/dependencies/ ./
COPY --from=builder application/spring-boot-loader/ ./
COPY --from=builder application/snapshot-dependencies/ ./
COPY --from=builder application/application/ ./
ENTRYPOINT ["java", "org.springframework.boot.loader.JarLauncher"]

这样我们的一个分层的DockerImage就创建完成了。

自定义Layer

如果我们需要自定义Layer该怎么做呢?

我们可以创建一个独立的layers.xml文件:

<layers xmlns="http://www.springframework.org/schema/boot/layers"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://www.springframework.org/schema/boot/layers
  https://www.springframework.org/schema/boot/layers/layers-2.3.xsd">
 <application>
 <into layer="spring-boot-loader">
  <include>org/springframework/boot/loader/**</include>
 </into>
 <into layer="application" />
 </application>
 <dependencies>
 <into layer="snapshot-dependencies">
  <include>*:*:*SNAPSHOT</include>
 </into>
 <into layer="company-dependencies">
  <include>com.flydean:*</include>
 </into>
 <into layer="dependencies"/>
 </dependencies>
 <layerOrder>
 <layer>dependencies</layer>
 <layer>spring-boot-loader</layer>
 <layer>snapshot-dependencies</layer>
 <layer>company-dependencies</layer>
 <layer>application</layer>
 </layerOrder>
</layers>

怎么使用这个layer.xml呢?

添加到build plugin中就可以了:

<build>
 <plugins>
  <plugin>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-maven-plugin</artifactId>
  <configuration>
   <layers>
   <enabled>true</enabled>
   <configuration>${project.basedir}/src/main/resources/layers.xml</configuration>
   </layers>
  </configuration>
  </plugin>
 </plugins>
 </build>

本文的例子: springboot-with-docker

总结

到此这篇关于利用Spring Boot创建docker image完整步骤的文章就介绍到这了,更多相关Spring Boot创建docker image内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 利用Spring Boot创建docker image的完整步骤

    前言 在很久很久以前,我们是怎么创建Spring Boot的docker image呢?最最通用的办法就是将Spring boot的应用程序打包成一个fat jar,然后写一个docker file,将这个fat jar制作成为一个docker image然后运行. 今天我们来体验一下Spring Boot 2.3.3 带来的快速创建docker image的功能. 传统做法和它的缺点 现在我们创建一个非常简单的Spring Boot程序: @SpringBootApplication @Res

  • Spring boot创建自定义starter的完整步骤

    前言: Springboot的出现极大的简化了开发人员的配置,而这之中的一大利器便是springboot的starter,starter是springboot的核心组成部分,springboot官方同时也为开发人员封装了各种各样方便好用的starter模块,例如: spring-boot-starter-web//spring MVC相关 spring-boot-starter-aop //切面编程相关 spring-boot-starter-cache //缓存相关 starter的出现极大的

  • Spring boot搭建邮件服务的完整步骤

    前言: 发送邮件,肯定是每个公司都会有的基本业务.很多公司都会选择把发送邮件作为一个基础服务,对外提供接口.直接调用就可发邮件了.但是我们都知道发送邮件耗时都比较长.那么今天就介绍下使用Spring boot+eventbus来打造一个简单邮件服务 规划接口列表 发送邮件的类型准备的有三种 发送普通邮件 发送html邮件 发送图文邮件 还有一个细节,如果我们同步的取发送邮件会有两个问题. 接口响应时间比较长 遇到并发的情况,容易导致服务器压力过大或者邮箱服务封ip 所以我们准备使用队列来执行发送

  • Spring Boot加载配置文件的完整步骤

    前言 本文针对版本2.2.0.RELEASE来分析SpringBoot的配置处理源码,通过查看SpringBoot的源码来弄清楚一些常见的问题比如: SpringBoot从哪里开始加载配置文件? SpringBoot从哪些地方加载配置文件? SpringBoot是如何支持yaml和properties类型的配置文件? 如果要支持json配置应该如何做? SpringBoot的配置优先级是怎么样的? placeholder是如何被解析的? 带着我们的问题一起去看一下SpringBoot配置相关的源

  • 利用Spring Boot和JPA创建GraphQL API

    目录 一.生成项目 1. 添加依赖项 二.Schema 三.Entity 和 Repository 四.Queries & Exceptions 1. 查询 2. Mutator 3. Exceptions 前言: GraphQL既是API查询语言,也是使用当前数据执行这些查询的运行时.GraphQL让客户能够准确地要求他们所需要的东西,仅此而已,使API随着时间的推移更容易发展,并通过提供API中数据的清晰易懂的描述,支持强大的开发工具. 在本文中,我们将创建一个简单的机场位置应用程序. 一.

  • 利用Spring boot如何创建简单的web交互应用

    关于页面渲染 其实在工作中,一直都是前后端分离,也就是说,我的工作从来都是提供接口,而不写 html css js 之类的,所以在这方面也没有经验. 这里为了给大家介绍下模板引擎,我将会写个非常非常简单的页面,如果不好看,请见谅~ Spring Boot 官方推荐的模板引擎是 Thymeleaf ,点击可以进入其官网了解详情. 本章目标 让 Spring Boot 应用可以访问到静态资源文件 创建用户登录表单,并对用户名.密码进行校验 校验失败,将返回登录页,并展示错误信息 校验成功,重定向到苹

  • Spring Boot与Docker部署详解

    本文介绍了Spring Boot与Docker部署,分享给大家,希望对大家有帮助 开启Docker远程访问 首先需要开启docker远程访问功能,以便可以进行远程操作. CentOS 6 修改/etc/default/docker文件,重启后生效(service docker restart). DOCKER_OPTS="-H=unix:///var/run/docker.sock -H=0.0.0.0:2375"  CentOS 7 打开/usr/lib/systemd/system

  • Spring Boot和Docker实现微服务部署的方法

    Spring boot 开发轻巧的微服务提供了便利,Docker 的发展又极大的方便了微服务的部署.这篇文章介绍一下如果借助 maven 来快速的生成微服务的镜像以及快速启动服务. 其实将 Spring Boot 项目用 Docker 部署也不是什么多么神秘的技术,也要先生成镜像,再用镜像启动容器,如果说有什么方便的地方,也就是一些工具可以帮助我们节省手动操作的过程. 知识背景: 掌握 docker 的安装以及基本的操作,熟悉 Dockerfile 文件创建镜像的方法. 创建 Spring bo

  • 最简单的spring boot打包docker镜像的实现

    这个spring boot项目只在网页输出一个hello world文本,没有其他复杂的配置和页面,属于入门级,可以放心食用. 本项目通过maven打包,打包和构建镜像的命令为: mvn clean install package docker:build spring boot打包docker镜像步骤如下: (一) 在pom.xml文件中添加docker配置: <!--docker maven plugin,在目录src/main/docker下创建Dockerfile文件,Dockerfil

  • Spring Boot应用Docker化的步骤详解

    概述 Spring Boot简化了Spring应用的开发过程,遵循约定优先配置的原则提供了各类开箱即用(out-of-the-box)的框架配置.另一方面,Spring Boot还具备将代码直接构建为可执行jar包的能力,这个jar包是一个可以独立运行的部署单元.基于以上特性,现在普遍认为Spring Boot提供了一种快速构造微服务(Micro-Service)的能力. 当下web服务端开发中最火的名词中绝对有微服务的一席之地,其也成为当下互联网后端服务架构演进历程中最闪亮的技术之一.微服务的

随机推荐