随着越来越多的组织转向容器和虚拟服务器,Docker正成为软件开发工作流程中一个更重要的部分。为此,Spring Boot 2.3中最新的功能之中,提供了为Spring Boot应用程序创建 Docker 镜像的能力。

这篇文章的目的,就是为了给大家介绍如何为 Spring Boot 应用程序创建 Docker 镜像。

1. 传统Docker构建

使用Spring Boot 构建 Docker 镜像的传统方法是使用 Dockerfile 。下面是一个简单的例子:

FROM openjdk:8-jdk-alpine
EXPOSE 8080
ARG JAR_FILE=target/demo-app-1.0.0.jar
ADD ${JAR_FILE} app.jar
ENTRYPOINT ["java","-jar","/app.jar"]

然后我们可以使用 docker build 命令来创建 Docker 映像。这对大多数应用程序都很好,但也有一些缺点。

首先,我们使用的是 Spring Boot 创建的 fat jar。这会影响启动时间,尤其是在集装箱环境中。我们可以通过添加jar文件的分解内容来节省启动时间。

其次,Docker镜像是分层构建的。Spring Boot fat jar 的特性使得所有的应用程序代码和第三方库都放在一个层中。这意味着即使只有一行代码更改,也必须重新构建整个层。

通过在构建之前分解 jar ,应用程序代码和第三方库各自获得自己的层。这样,我们便可以利用Docker的缓存机制。现在,当某一行代码被更改时,只需要重新构建相应的层。

考虑到这一点,让我们看看Spring Boot 如何改进创建Docker镜像的过程。

2. Buildpacks

BuildPacks 是一种提供框架和应用程序依赖性的工具。

例如,给定一个Spring Boot fat jar,一个buildpack将为我们提供Java运行时。这使我们可以跳过 Dockerfile 并自动获得一个合理的docker 镜像。

Spring Boot 包括对 bulidpacks 的Maven和Gradle支持。例如,使用Maven构建时,我们将运行以下命令:

./mvnw spring-boot:build-image

我们观察下一些相关的输出,看看发生了什么:

[INFO] Building jar: target/demo-0.0.1-SNAPSHOT.jar
...
[INFO] Building image 'docker.io/library/demo:0.0.1-SNAPSHOT'
...
[INFO] > Pulling builder image 'gcr.io/paketo-buildpacks/builder:base-platform-api-0.3' 100%
...
[INFO] [creator] ===> DETECTING
[INFO] [creator] 5 of 15 buildpacks participating
[INFO] [creator] paketo-buildpacks/bellsoft-liberica 2.8.1
[INFO] [creator] paketo-buildpacks/executable-jar 1.2.8
[INFO] [creator] paketo-buildpacks/apache-tomcat 1.3.1
[INFO] [creator] paketo-buildpacks/dist-zip 1.3.6
[INFO] [creator] paketo-buildpacks/spring-boot 1.9.1
...
[INFO] Successfully built image 'docker.io/library/demo:0.0.1-SNAPSHOT'
[INFO] Total time: 44.796 s

第一行显示我们构建了标准的 fat jar,与其他典型的maven包一样。

下一行开始Docker映像构建。然后,看到这个 bulid 拉取了 packeto 构建器。

packeto 是基于云原生 bulidpacks 的实现。它负责分析我们的项目并确定所需的框架和库。在我们的例子中,它确定我们有一个Spring Boot项目并添加所需的构建包。

最后,我们看到生成的Docker映像和总构建时间。注意,在第一次构建时,花了相当多的时间下载构建包并创建不同的层。

buildpacks 的一大特点是Docker映像是多层的。因此,如果我们只更改应用程序代码,后续构建将更快:

...
[INFO] [creator] Reusing layer 'paketo-buildpacks/executable-jar:class-path'
[INFO] [creator] Reusing layer 'paketo-buildpacks/spring-boot:web-application-type'
...
[INFO] Successfully built image 'docker.io/library/demo:0.0.1-SNAPSHOT'
...
[INFO] Total time: 10.591 s

3. 层级jar包

在某些情况下,我们可能不喜欢使用 bulidpacks ——也许我们的基础架构已经绑定到另一个工具上,或者我们已经有了我们想要重新使用的自定义 Dockerfiles 。

基于这些原因,Spring Boot 还支持使用分层jars 构建Docker映像。为了了解它的工作原理,让我们看看一个典型的Spring Boot fat jar 布局:

org/
springframework/
boot/
loader/
...
BOOT-INF/
classes/
...
lib/
...

fat jar 由3个主要区域组成:

  • 启动Spring应用程序所需的引导类
  • 应用程序代码
  • 第三方库

使用分层jar,结构看起来很相似,但是我们得到了一个新的 layers.idx 将 fat jar 中的每个目录映射到一个层的文件:

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

Out-of-the-box, Spring Boot provides four layers:

开箱即用,Spring Boot 提供4层:

  • dependencies: 来自第三方的依赖
  • snapshot-dependencies: 来自第三方的 snapshot 依赖
  • resources: 静态资源
  • application: 应用程序代码和资源(resources)

我们的目标是将应用程序代码和第三方库放置到层中,以反映它们更改的频率。

例如,应用程序代码可能是更改最频繁的代码,因此它有自己的层。此外,每一层都可以独立演化,只有当一层发生变化时,才会为它重建 Docker 镜像。

现在我们了解了分层 jar 结构,接下来看看如何利用它来制作 Docker 映像。

3.1.创建分层 jar

首先,我们必须建立一个项目来创建一个分层的jar。对于Maven,则需要在POM的 Spring Boot plugin 部分添加一个新的配置:

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

有了这个配置,Maven package 命令(包括它的其他依赖命令)将使用前面提到的四个默认层生成一个新的分层jar。

3.2. 查看和提取分层

下一步,我们需要从 jar 中提取层,这样Docker镜像才能拥有正确的层。

要检查分层jar的任何层,可以运行以下命令:

java -Djarmode=layertools -jar demo-0.0.1.jar list

然后提取它们,运行命令:

java -Djarmode=layertools -jar demo-0.0.1.jar extract

3.3. 创建Docker映像

将这些层合并到 Docker 映像中的最简单方法是使用 Dockerfile :

FROM adoptopenjdk:11-jre-hotspot as builder
ARG JAR_FILE=target/*.jar
COPY ${JAR_FILE} application.jar
RUN java -Djarmode=layertools -jar application.jar extract FROM adoptopenjdk:11-jre-hotspot
COPY --from=builder dependencies/ ./
COPY --from=builder snapshot-dependencies/ ./
COPY --from=builder spring-boot-loader/ ./
COPY --from=builder application/ ./
ENTRYPOINT ["java", "org.springframework.boot.loader.JarLauncher"]

这个 Dockerfile 从fat jar中提取层,然后将每个层复制到Docker映像中。

每个COPY指令最终都会在Docker映像中生成一个新层。

如果我们构建这个Dockerfile,我们可以看到分层jar中的每个层都作为自己的层添加到Docker镜像中:

...
Step 6/10 : COPY --from=builder dependencies/ ./
---> 2c631b8f9993
Step 7/10 : COPY --from=builder snapshot-dependencies/ ./
---> 26e8ceb86b7d
Step 8/10 : COPY --from=builder spring-boot-loader/ ./
---> 6dd9eaddad7f
Step 9/10 : COPY --from=builder application/ ./
---> dc80cc00a655
...

4.总结

在本文中,我们学习了使用 Spring Boot 构建 Docker 映像的各种方法。

使用 buildpacks,我们可以获得合适的Docker镜像,而无需模板或自定义配置。

或者,再多花点功夫,我们就可以使用分层 jar 来获得一个更加定制的Docker镜像。

如果你觉得文章还不错,记得关注公众号: 锅外的大佬

刘一手的博客

Spring Boot 创建 Docker 镜像的更多相关文章

  1. 使用Spring Boot创建docker image

    目录 简介 传统做法和它的缺点 使用Buildpacks Layered Jars 自定义Layer 简介 在很久很久以前,我们是怎么创建Spring Boot的docker image呢?最最通用的 ...

  2. maven 打包 spring boot 生成docker 镜像

    1.所使用材料 ,spring boot 项目 基于maven ,maven 工具, docker工具 ps:为啥使用 docker 公司微服务需要启动太多,有两个优点吧! 1.方便管理,2.减少服务 ...

  3. CentOS7 下 配置Docker远程访问 与 windows下使用maven构筑Spring Boot 的 Docker镜像到远程服务端

    1.设置Docker服务端,以支持远程访问: 修改docker服务端配置文件,命令: vim /usr/lib/systemd/system/docker.service 修改后: [Unit] De ...

  4. Spring Boot 和 Docker 实现微服务部署

    Spring boot 开发轻巧的微服务提供了便利,Docker 的发展又极大的方便了微服务的部署.这篇文章介绍一下如果借助 maven 来快速的生成微服务的镜像以及快速启动服务. 其实将 Sprin ...

  5. Spring Boot与Docker部署

    开启Docker远程访问 首先需要开启docker远程访问功能,以便可以进行远程操作. CentOS 6 修改/etc/default/docker文件,重启后生效(service docker re ...

  6. Spring Boot with Docker

    翻译自:https://spring.io/guides/gs/spring-boot-docker/ Spring Boot with Docker 这篇教程带你一步步构建一个Docker镜像用来运 ...

  7. spring boot——结合docker

    spring boot——结合docker 前言 Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的 liunx机器上,也可以实现虚 ...

  8. spring cloud教程之使用spring boot创建一个应用

    <7天学会spring cloud>第一天,熟悉spring boot,并使用spring boot创建一个应用. Spring Boot是Spring团队推出的新框架,它所使用的核心技术 ...

  9. 使用Maven插件构建Spring Boot应用程序镜像

    使用Maven插件构建Spring Boot应用程序的Docker镜像. 环境准备 1.Linux系统 2.安装JDK,Maven 3.安装Docker 应用实践 1.在应用程序根目录下添加Docke ...

随机推荐

  1. 利用Python求解二元一次方程

    本程序流程如下: (1)输入A.B.C (2)计算△ (3)判断解的个数 (4)计算解 (5)输出解 求:x2-3x+2=0的解 #输入A.B.C A=float(input("输入A:&q ...

  2. 多测试_linux_003_肖sir

    一.linux 介绍os 操作系统:windows,dos,android ,ios,unix ,linux linux系统:是一个免费,开源的操作系统,能多cpu,多用户,多线程的操作系统,比win ...

  3. 从源码角度来分析线程池-ThreadPoolExecutor实现原理

    作为一名Java开发工程师,想必性能问题是不可避免的.通常,在遇到性能瓶颈时第一时间肯定会想到利用缓存来解决问题,然而缓存虽好用,但也并非万能,某些场景依然无法覆盖.比如:需要实时.多次调用第三方AP ...

  4. pytest文档51-内置fixture之cache使用

    前言 pytest 运行完用例之后会生成一个 .pytest_cache 的缓存文件夹,用于记录用例的ids和上一次失败的用例. 方便我们在运行用例的时候加上--lf 和 --ff 参数,快速运行上一 ...

  5. Logstash 国内加速下载 转

    Logstash. 国内直接从官网(https://www.elastic.co)下载比较困难,需要一些技术手段.这里提供一个国内的镜像下载地址列表,方便网友下载. 找不到想要的版本?您可以访问 索引 ...

  6. 手把手教你如何制作和使用lib和dll

    本文的内容经过本人亲自调试,确保可用,实用,测试环境为win10+vs2015+C++ 目录 静态库 什么是静态库? 怎么创建 如何使用 静态库的第一种使用方法 静态库的第二种使用方法 动态链接库 动 ...

  7. MVC登录

    前言 最近没什么好写的,准备把MVC的登录再写一下,巩固一下 HTML @{ Layout = null; } <!DOCTYPE html> <html> <head& ...

  8. Scala 特殊符号含义

    date: 2019-08-01 11:15:27 updated: 2019-08-22 15:22:32 Scala 特殊符号含义 参考地址 1. ::: :::(三个冒号)只用于连接两个 Lis ...

  9. Hadoop框架:HDFS高可用环境配置

    本文源码:GitHub·点这里 || GitEE·点这里 一.HDFS高可用 1.基础描述 在单点或者少数节点故障的情况下,集群还可以正常的提供服务,HDFS高可用机制可以通过配置Active/Sta ...

  10. python的多线程和java的多线程之间的区别

    在python中,由于Cpython解释器的全局解释器的存在,那么多线程的话在同一时刻只能有一个线程执行,意思就是python中的多线程只能并发执行, 没有办法实现真正的并行,也就是无法利用多核CPU ...