译者按: 最新版Docker将支持多步构建(Multi-stage build),这样使用单个Dockerfile就可以定义多个中间镜像用于构建,测试以及发布等多个步骤,并且有效减小最终镜像的大小。

原文: Creating Smaller Java Image using Docker Multi-stage Build

译者: Fundebug

为了保证可读性,本文采用意译而非直译。

Github仓库: arun-gupta/docker-java-multistage

DockerCon 2017中与Java开发者直接相关的内容有:

这篇博客介绍了为什么需要Docker多步构建(Docker Multi-stage build),并且通过一个示例展示了如何构建更小的Java镜像。

为什么需要多步构建?

为Java应用构建Docker镜像意味着编译源代码以及打包目标代码。开发者通常会使用Maven或者Gradle来构建JAR或WAR文件。若使用Maven镜像作为基础镜像来构建Java应用,则需要下载所有Maven依赖。下载的JAR包数目由pm.xml决定,有可能会非常多。这样的话,生成的Docker镜像中将留下太多多余的文件。

下面为示例Dockerfile:

FROM maven:3.5-jdk-8
 
COPY src /usr/src/myapp/src
COPY pom.xml /usr/src/myapp
RUN mvn -f /usr/src/myapp/pom.xml clean package
 
ENV WILDFLY_VERSION 10.1.0.Final
ENV WILDFLY_HOME /usr
 
RUN cd $WILDFLY_HOME && curl http://download.jboss.org/wildfly/$WILDFLY_VERSION/wildfly-$WILDFLY_VERSION.tar.gz | tar zx && mv $WILDFLY_HOME/wildfly-$WILDFLY_VERSION $WILDFLY_HOME/wildfly
 
RUN cp /usr/src/myapp/target/people-1.0-SNAPSHOT.war $WILDFLY_HOME/wildfly/standalone/deployments/people.war
 
EXPOSE 8080
 
CMD ["/usr/wildfly/bin/standalone.sh", "-b", "0.0.0.0"]

由Dockerfile可知:

  • maven:3.5-jdk-8 是基础镜像
  • 将源代码拷贝到镜像中
  • Maven用于构建应用
  • 下载并安装WildFly
  • 将生成的.war文件拷贝到WildFly的deployments目录
  • 启动WildFly

这个Dockefile存在这些问题:

  • 使用Maven作为基础镜像的话,还需要安装和配置WildFly。
  • 构建应用时需要下载很多Maven依赖,它们会继续留在镜像中,但是运行应用时并不需要它们。这导致了镜像过大。
  • 修改WildFly版本则需要修改Dockerfile,并重新构建镜像。如果直接使用WildFly镜像作为基础镜像,情况会简单很多。
  • 打包应用之前,需要进行单元测试,那么,测试的依赖也需要留在生成的镜像中,这其实是没必要的。

当然,也可以采用其他方式构建Docker镜像。比如,可以将Dockerfile拆分为两个。第一个Dockerfile以Maven镜像为基础镜像,用于构建应用,并将构建好的.war文件通过数据卷(volume)复制到共享的目录;第二个Dockerfile以WildFly镜像作为基础镜像,从数据卷将.war文件拷贝出来就好了。这个方法也是有问题的,因为需要维护多个Dockerfile,并且通过数据卷拷贝文件也不方便。

什么是Docker多步构建?

多步构建(multi-stage build)允许在Dockerfile中使用多个FROM指令。两个FROM指令之间的所有指令会生产一个中间镜像,最后一个FROM指令之后的指令将生成最终镜像。中间镜像中的文件可以通过COPY --from=<image-number>指令拷贝,其中image-number为镜像编号,0为第一个基础镜像。没有被拷贝的文件都不会存在于最终生成的镜像,这样可以减小镜像大小。

FROM指令可以使用as <stage-name>来指定步骤名称(stage name):

FROM maven:3.5-jdk-8 as BUILD

这样的话,COPY指令的--from选项可以使用步骤名称代替镜像编号。

下面为示例Dockerfile:

FROM maven:3.5-jdk-8 as BUILD
 
COPY src /usr/src/myapp/src
COPY pom.xml /usr/src/myapp
RUN mvn -f /usr/src/myapp/pom.xml clean package
 
FROM jboss/wildfly:10.1.0.Final
 
COPY --from=BUILD /usr/src/myapp/target/people-1.0-SNAPSHOT.war /opt/jboss/wildfly/standalone/deployments/people.war

由Dockerfile可知:

  • 一共有两个FROM指令,因此为两步构建。
  • maven:3.5-jdk-8 是第一步构建的基础镜像。这一步用于构建应用的WAR文件。这一步的名称为build
  • jboss/wildfly:10.1.0.Final 是第二步构建的基础镜像。第一步构建的WAR文件通过COPY --from指令拷贝到WildFly的deloyments目录。

Docker多步构建有什么好处?

  • 仅需要一个Dockerfile来定义整个构建过程。这样,不需要定义多个Dockerfile,也不需要使用数据卷来拷贝文件。
  • 可以为最终镜像选择合适的基础镜像,来满足生产环境的需求,这样可以有效减小最终镜像的大小。另外,构建步骤的多余文件都被丢弃了。
  • 使用官方的WildFly镜像作为生产镜像的基础镜像,而不是手动安装和配置WildFly。这样,WildFly升级时将非常方便。

注:Docker多步构建正在开发中,还没有正式发布。可以通过 curl -fsSL https://test.docker.com/ | sh命令安装最新的测试版Docker试用多步构建。

使用第一个Dockerfile构建的镜像为816MB,而使用多步构建的话,镜像只有584MB。

docker-java-multistage $ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
people multistage d36a4b82ad87 59 seconds ago 584MB
people singlestage 13dbcf8f54f6 5 minutes ago 816MB

可知,使用多步构建可以有效减小镜像大小。

查看PR #31257,有更加详细的讨论。

关于Fundebug:

Fundebug专注于JavaScript、微信小程序、微信小游戏、支付宝小程序、React Native、Node.js和Java实时BUG监控。 自从2016年双十一正式上线,Fundebug累计处理了7亿+错误事件,得到了Google、360、金山软件、百姓网等众多知名用户的认可。欢迎免费试用!

 

版权声明:

转载时请注明作者Fundebug以及本文地址: https://blog.fundebug.com/2017/05/02/about-docker-sock/

Docker多步构建更小的Java镜像的更多相关文章

  1. 积跬步,聚小流------java信息生成图片

    需求: 是在做证书的时候碰到的这个问题. 当时需求是能够进行在线打印证书,第一次进行的操作是直接打印html,并且已经排好版(用jqprint插件)进行打印.在打印时碰到了兼容的问题,另外因为背景图片 ...

  2. 积跬步,聚小流------java获取图片的尺寸

    在一篇文章中获取到通过例如以下两种方式进行获取: 1.使用ImageReader进行获取: 2.使用BufferedImage进行获取: 而且经过验证ImageReader进行操作的耗时远远低于Buf ...

  3. Gradle更小、更快构建APP的奇淫技巧

    本文已获得原作者授权同意,翻译以及转载原文链接:Build your Android app Faster and Smaller than ever作者:Jirawatee译文链接:Gradle更小 ...

  4. 最小化 Java 镜像的常用技巧

    背景 随着容器技术的普及,越来越多的应用被容器化.人们使用容器的频率越来越高,但常常忽略一个基本但又非常重要的问题 - 容器镜像的体积.本文将介绍精简容器镜像的必要性并以基于 spring boot ...

  5. 不妨试试更快更小更灵活Java开发框架Solon

    @ 目录 概述 定义 性能 架构 实战 Solon Web示例 Solon Mybatis-Plus示例 Solon WebSocket示例 Solon Remoting RPC示例 Solon Cl ...

  6. Jib构建你的第一个java镜像

    jib Official:GoogleContainerTools/jib 本文示例完整demo github地址 github.com/moxingwang/- 想要了解并且使用jib,首先你得知道 ...

  7. Docker多阶段构建实战(multi-stage builds)

    在编写Dockerfile构建docker镜像时,常遇到以下问题: RUN命令会让镜像新增layer,导致镜像变大,虽然通过&&连接多个命令能缓解此问题,但如果命令之间用到docker ...

  8. Docker学习笔记之一,搭建一个JAVA Tomcat运行环境

    Docker学习笔记之一,搭建一个JAVA Tomcat运行环境 前言 Docker旨在提供一种应用程序的自动化部署解决方案,在 Linux 系统上迅速创建一个容器(轻量级虚拟机)并部署和运行应用程序 ...

  9. 微信小程序+java后台

    博主是大四学生,毕业设计做的是微信小程序+java后台.陆陆续续经历了三个月(因为白天要实习又碰上过年玩了一阵子),从对微信小程序一无所知到完成毕设,碰到许多问题,在跟大家分享一下自己的经历和一个小程 ...

随机推荐

  1. Flume 示例

    1.Syslog Tcp Source sysylog通过配置一个端口,flume能够监控这个端口的数据.如果通往这个端口发送数据可以被flume接收到.可以通过socket发送. #配置文件:sys ...

  2. Windows 10 IoT Serials 10 – 如何使用OCR引擎进行文字识别

    1. 引言 OCR (Optical Character Recognition,光学字符识别)是指电子设备(例如扫描仪或数码相机)检查纸上打印的字符,通过检测暗.亮的模式确定其形状,然后用字符识别方 ...

  3. Javascript高级编程学习笔记(48)—— HTML5

    HTML变动最大的版本应该就是HTML5了,这里就介绍一些 HTML5新增的DOM相关的API 与类相关的扩充 HTML4在普及后有一个十分重要的变化,即class属性使用的场景越来越多 所以HTML ...

  4. Javascript高级编程学习笔记(46)—— 选择符API

    选择符API 在DOM1中DOM只提供了 getElementById.getElementsByTagName 两种获取文档元素的方法 很多时候这两种方法往往不能较为方便地获取我们所需要的元素 所以 ...

  5. 每天学点SpringCloud(九):SpringCloud最常用配置详解

    Eureka 属性名 说明 默认值 eureka.server.enable-self-preservation 关闭注册中心的保护机制,Eureka 会统计15分钟之内心跳失败的比例低于85%将会触 ...

  6. Python中变量的基本使用

    变量的基本使用 程序就是用来处理数据的,而变量就是用来存储数据的 目标 变量定义 变量的类型 变量的命名 01. 变量定义 在 Python 中,每个变量 在使用前都必须赋值,变量 赋值以后 该变量 ...

  7. 【spring boot】idea下springboot打包成jar包和war包,并且可以在外部tomcat下运行访问到(转)

    转自:https://www.cnblogs.com/sxdcgaq8080/p/7727249.html   接着上一章走呗:http://www.cnblogs.com/sxdcgaq8080/p ...

  8. jQuery源码——.html()方法原理解析

    在将字符串转化为html碎片时,一般会将字符串作为容器的innerHTML属性赋值.但innerHTML有很多局限性,比如我们想转化的字符串中有<script>标签并且包含一个立即执行的函 ...

  9. ElasticSearch入门1: mac 安装

    入门学习顺序: 1. 安装: 1.1 单实例安装: Elastic官方网站: http://www.elastic.co 下载 ElasticSearch: 第一步:点击下载 第二步:点击downlo ...

  10. Elasticsearch实践(三):Mapping

    版本:Elasticsearch 6.2.4. Mapping类似于数据库中的表结构定义,主要作用如下: 定义Index下字段名(Field Name) 定义字段的类型,比如数值型,字符串型.布尔型等 ...