随着越来越多的组织转向容器和虚拟服务器,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. axio跨域请求,vue中的config的配置项。

    这是我用 vue cli 脚手架搭建的跨域.以上是可以请求到的.

  2. 2020年java全套教程,此套java涵盖了pdf,java源码,项目案例,完整视频约3000G的资源

    疫情期间,百无聊赖,是不是需要充电一下,让自己更有竞争力呢?学习java一定要快呦! 废话不多说了,网盘已经爆炸了,把2006年-2020年的全部资料都发给爱学习的你吧, 希望可以改变你的命运,或者是 ...

  3. c3算法

    # L(G) = [G] + [O] # G = [O] # = GO # L[E] = EO # L[F] = [F] + [GO] # F = [GO] # = FGO # L[B] = [B] ...

  4. linux 压缩 tar命令

    linux中tar命令用法    总结 *.tar 用 tar –xvf 解压 *.gz 用 gzip -d或者gunzip 解压 *.tar.gz和*.tgz 用 tar –xzf 解压 *.bz2 ...

  5. 跟我一起学Redis之看完这篇比常人多会三种类型实战(又搞了几个小时)

    前言 对于Redis而言,很多小伙伴只关注其关键的五大基础类型:string.hash.list.set.sorted set(有序集合),其实还有三种特殊类型在很多应用场景也比较适合使用,分别是:b ...

  6. 【Azure DevOps系列】Azure DevOps使用Docker将.NET应用程序部署在云服务器

    Docker持续集成 本章我们要实现的是通过我们往代码仓库push代码后,我们将每次的push进行一次docker自动化打包发布到docker hub中,发布到之后我将进行部署环节,我们将通过ssh方 ...

  7. RocketMQ主从搭建

    RocketMQ可分为以下几种模式: 单点模式 主从模式 双从模式 双主双从模式,多主多从模式 搭建主从模式 tar -zxvf rocketmq-4.6.0.tar.gz -C /usr/local ...

  8. JS里各种类型的循环

    for... for( 初始条件; 判断条件; 递增条件 ) { ... } for ... in 可以把一个对象里面的所有属性依次循环出来 var person = { name: 'Jack', ...

  9. catch之后的代码什么时候执行

    1.若catch(){}块中,如果有throw 语句,则,try{}catch(){} finally{}块之外的代码不执行: 否则,执行. 2.try{}中有异常,则异常下面代码不执行. 3.fin ...

  10. ssh免密登陆 2

    应用场景之一:java 程序调用shell脚本,通过ssh 免密登陆数据库服务器,进行数据的抽取打包工作. 免密设置步骤: 1.客户端生成公私钥,在任意目录下执行命令ssh-keygen(一路回车默认 ...