Docker multi-stage build机制

随着17.05版本的发布,Docker对于镜像构建这块也作了一项重要更新,那就是 multi-stage build(多阶段构建),这对于长期因为构建镜像太大而困扰的小伙伴们来说真是雪中送炭。

不支持多阶段构建

在17.05版本之前,我们构建Docker镜像时,通常会采用两种方式:

  • 将所有的构建过程编写在同一个Dockerfile中,包括项目及其依赖库的编译、测试、打包等流程,这里可能会带来的一些问题:

    1. Dockerfile特别臃肿
    2. 镜像层次特别深
    3. 存在源码泄露的风险
  • 稍微优雅的一种方式,就是我们事先在外部将项目及其依赖库编译测试打包好后,再将其拷贝到构建目录中,这种虽然可以很好地规避第一种方式存在的风险点,但仍需要我们编写两套Dockerfile或者一些脚本才能将其两个阶段自动整合起来

这里以一个简单的JAVA项目镜像构建为例来说明这两种构建方式,该项目仅仅包含一个App.java类:

public class App {

    public static void main(String[] args) {
        System.out.println("Hello, multi-stage build...");
    }

}
  • 采用最简单的方式
FROM dojomadness/alpine-jdk8-maven:latest

# add pom.xml and source code
ADD ./pom.xml pom.xml
ADD ./src src/

# package jar and remove source code and temporary class files
RUN mvn clean package && cp -f target/msb-1.0.jar msb.jar && rm -rf pom.xml src/ target/

# run jar
CMD ["java", "-jar", "msb.jar"]

这里是将所有的构建流程都编写在同一个Dockerfile中,但为了尽可能地减小镜像层次,我们将多个执行命令合并到同一个RUN指令中,同时我们需要自行清理掉源码目录文件以及编译后的临时目录文件,以防止源码泄露。

  • 采用稍优雅的方式

这里我们需要分为两个阶段:
1)编译打包 Dockerfile.2.1

FROM maven:3.5.0-jdk-8-alpine

# add pom.xml and source code
ADD ./pom.xml pom.xml
ADD ./src src/

# package jar
RUN mvn clean package

2)构建镜像 Dockerfile.2.2

From openjdk:8-jre-alpine

# copy jar
COPY ./msb.jar msb.jar

# run jar
CMD ["java", "-jar", "msb.jar"]

3)整合两个构建阶段 build.sh

#!/bin/bash

# First stage: complete build environment
docker build -t msb:build -f Dockerfile.2.1 .
# create temporary container
docker create --name extract msb:build
# extract jar
docker cp extract:/target/msb-1.0.jar ./msb.jar
# remove temporary container
docker rm -f extract

# Second stage: minimal runtime environment
docker build --no-cache -t msb:build-2 -f Dockerfile.2.2 .

# remove local jar
rm -rf ./msb.jar

这里我们编写了两个Dockerfile和一个Shell脚本,通过两阶段将最终镜像构建出来,但可预见的一个问题是,假若有多个项目彼此关联和依赖,就需要我们维护多个Dockerfile,或者需要编写更复杂的build.sh脚本,导致后期维护成本很高。

支持多阶段构建

在Docker 17.05 多阶段构建推出之后,我们就可以很容易规避前面遇到的这些问题,并且只需要维护一个Dockerfile即可:

# First stage: complete build environment
FROM maven:3.5.0-jdk-8-alpine AS builder
# add pom.xml and source code
ADD ./pom.xml pom.xml
ADD ./src src/
# package jar
RUN mvn clean package

# Second stage: minimal runtime environment
From openjdk:8-jre-alpine
# copy jar from the first stage
COPY --from=builder target/msb-1.0.jar msb.jar
# run jar
CMD ["java", "-jar", "msb.jar"]

对于上面的Dockerfile是不是很熟悉,它仅仅是将第二种方式中的两个Dockerfile合并到同一个Dockerfile中,同时在构建过程中自动帮您完成了build.sh的流程。

对于multi-stage build,其关键点主要有两点:

  • 在前面阶段的FROM指令后面增加了一个AS参数,可为该构建阶段命名,便于后续构建阶段引用,格式如下:
FROM image[:tag | @digest] AS stage
  • 在后续阶段的COPY指令后面增加了--from参数,指明引用前面哪一个构建阶段的成果,格式如下:
COPY --from=stage ...

同理,多阶段构建同样可以很方便地将多个彼此依赖的项目通过一个Dockerfile就可轻松构建出期望的容器镜像,而不用担心镜像太大、源码泄露等风险。

容器镜像服务

时间: 2024-07-31 03:35:52

Docker multi-stage build机制的相关文章

Docker 容器健康检查机制

在分布式系统中,经常需要利用健康检查机制来检查服务的可用性,防止其他服务调用时出现异常. 对于容器而言,最简单的健康检查是进程级的健康检查,即检验进程是否存活.Docker Daemon会自动监控容器中的PID1进程,如果docker run命令中指明了restart policy,可以根据策略自动重启已结束的容器.在很多实际场景下,仅使用进程级健康检查机制还远远不够.比如,容器进程虽然依旧运行却由于应用死锁无法继续响应用户请求,这样的问题是无法通过进程监控发现的. 在Kubernetes提供了

Docker镜像的存储机制

近几年 Docker 风靡技术圈,不少从业人员都或多或少使用过,也了解如何通过 Dockerfile 构建镜像,从远程镜像仓库拉取自己所需镜像,推送构建好的镜像至远程仓库,根据镜像运行容器等.这个过程十分简单,只需执行 docker build.docker pull.docker push.docker run 等操作即可.但大家是否想过镜像在本地到底是如何存储的?容器又是如何根据镜像启动的?推送镜像至远程镜像仓库时,服务器又是如何存储的呢?下面我们就来简单聊一聊. Docker 镜像本地存储

你真的了解Docker吗?——Docker插件机制详解

云栖TechDay活动第十八期中,阿里云容器服务团队的核心成员陈萌辉带来了题为<Docker插件机制详解>的分享,分享中,他结合阿里云容器服务实践介绍了Docker插件的基本原理.实现方法以及插件机制未来的演进. 幻灯片下载地址:https://yq.aliyun.com/attachment/download/?filename=bdefe06ba7a14d7604af5a63a4bcc4f3.pdf 以下为现场分享观点整理. 为什么需要Docker插件?   Docker之所以这么火并且有

云上应用docker化持续交付实践 — 【包含Qcon讲稿】

因为我非常啰嗦,所以写的分享也太长,全部内容被内部同学review后的反馈是: 像看小说一样-- 所以为了防止大家看了开头就去逛别的小网站了,开篇我先点个题, 这篇文件最终的目的是讲清楚下面这张图:  就是一个完整的,应用Docker化持续交付需要做的事情. 并且,这篇文章不是硬广, 图中涉及到的服务也是基础服务,提供便捷的配置方式,最佳实践的推荐. 我们并不去定义标准和规范,会兼容业内所有的规范和标准的玩法. 下面开始正文: 本文涉及到的平台有: 阿里云持续交付平台 https://crp.

Jenkins和Docker在HULK的落地实践

本文讲的是Jenkins和Docker在HULK的落地实践[编者的话]巧妇难为无米之炊,玩容器,"镜像"就是下锅的米,我们私有云Hulk平台的容器服务,向用户提供UI页面化的一整套的镜像定制.制作.管理.私有镜像仓库的服务,这套服务的背后技术实现,Jenkins算是"引擎",本文简要介绍这其中的技术方案. [3 天烧脑式基于Docker的CI/CD实战训练营 | 北京站]本次培训围绕基于Docker的CI/CD实战展开,具体内容包括:持续集成与持续交付(CI/CD)

基于Docker的Jenkins持续交付实践

讲师介绍  叶峰 有容云资深前端开发工程师   现负责有容云容器云平台Web架构设计和CI(持续集成)产品的研发 拥有丰富的Web前端开发经验.   主题简介: Jenkins pipeline基础概念 Jenkins pipeline如何带来工作便利 基于容器的Jenkins CI流程 Jenkins.Docker.Kubernetes整合的集成部署   传统交付方案   传统我们的项目开发模式是产品调研提出需求,开发团队研究决定开发方案选型.然后开始一个周期的开发,模块开发完成之后开始模块间

Maven Docker镜像使用技巧

Maven是目前最流行的Java项目管理工具之一,提供了强大的包依赖管理和应用构建功能. Docker提供了官方的Maven镜像可以用于管理和构建Java应用.与直接安装使用Maven工具相比,使用Docker镜像具有更好的可移植性,可以方便地进行版本切换,非常适合在持续集成过程中使用. 关于Maven官方镜像的用法可以参考使用文档 使用阿里云加速 Maven官方仓库在国内网络下的下载速度实在是让人欲哭无泪,利用阿里云的Maven镜像可以大大提升软件包下载速度. 我们可以在官方Maven镜像的基

使用Docker Compose部署基于Sentinel的高可用Redis集群

大家一定非常熟悉如何利用Docker启动单个Redis容器用于开发环境,本文将介绍如何利用Docker Compose模板在本机和云端部署基于Sentinel的高可用Redis 3集群. Redis集群可以在一组redis节点之间实现高可用性和sharding.今天我们重点围绕master-slave的高可用模式来进行讨论,在集群中会有1个master和多个slave节点.当master节点失效时,应选举出一个slave节点作为新的master.然而Redis本身(包括它的很多客户端)没有实现自

企业为什么要使用基于Docker的PaaS/CaaS平台

作者:精灵云 前言 早在十多年前国内外的一些大厂就开始投入研发和使用容器技术,比如Google,对他们来说,使用容器能够充分利用计算资源节省硬件成本.而这几年--众所周知--真正把容器技术发扬光大的是Docker.Docker的slogan"Build,Ship & Run anywhere"定位非常清晰,Docker的出现打破了传统运维模式里从打包到部署的过程中环境.语言.平台不一致的乱象,将这一整套开发运维模式标准化了,从而真正帮助企业实践了DevOps和微服务化. 但是,