Dockerfile 多阶段构建实践

写在前面
在Docker Engine 17.05 中引入了多阶段构建,以此降低构建复杂度,同时使缩小镜像尺寸更为简单。这篇小作文我们来学习一下如何编写实现多阶段构建的Dockerfile
关于dockerfile基础编写可参考之前docker容器dockerfile详解
一 、不使用多阶段构建
我们知道在Dockerfile中每新增一个指令都会在镜像中生产新的层,一个高效的Dockerfile应该在继续下一层之前清除之前所有不需要的资源。
不使用多阶段构建时,我们通常会创建两dockerfile文件,一个用于开发及编译应用,另一个用于构建精简的生产镜像。这样能比较大限度的减小生产镜像的大小。
我们以一个go应用来看看。我首先会创建一个dockerfile,构建这个镜像的主要目的就是编译我们的应用。
FROM golang:1.16
WORKDIR /go/src
COPY app.go ./
#go编译
RUN go build -o myapp app.go
构建镜像
[root@localhost dockerfiles]# docker build -t builder_app:v1 .
Sending build context to Docker daemon 3.072kB
Step 1/4 : FROM golang:1.16
---> 019c7b2e3cb8
Step 2/4 : WORKDIR /go/src
---> Using cache
---> 15362720e897
Step 3/4 : COPY app.go ./
---> Using cache
---> 8f14ac97a68a
Step 4/4 : RUN go build -o myapp app.go
---> Running in 4368cc4617a7
Removing intermediate container 4368cc4617a7
---> 631f67587803
Successfully built 631f67587803
Successfully tagged builder_app:v1
这样在这个镜像中就包含了我们编译后的应用myapp,现在我们可以创建容器将myapp拷贝到宿主机等待后续使用。
# docker create --name builder builder_app:v1
fafc1cf7ffa42e06d19430b807d24eafe0bf731fc45ff0ecf31ada5a6075f1d5
# docker cp builder:/go/src/myapp ./
我们有了应用,下一步就是构建生产镜像
FROM scratch
WORKDIR /server
COPY myapp ./
CMD ["./myapp"]
由于此时我们不需要其他依赖环境,所以我们采用scratch这个空镜像,不仅可以减小容器尺寸,还可以提高安全性。
构建镜像
#docker build --no-cache -t server_app:v1 .
我们看一次构建的两个镜像大小
# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
server_app v1 6ebc0833cad0 6 minutes ago 1.94MB
builder_app v1 801f0b615004 23 minutes ago 921MB
显然在不使用多阶段构建时,我们也可以构建出生产镜像,但是我们需要维护两个dockerfile,需要将app遗留到本地,并且带来了更多存储空间开销。在使用多阶段构建时能比较好的解决以上问题。
二、使用多阶段构建
在一个Dockerfile中使用多个FROM指令,每个FROM都可以使用不同的基镜像,并且每条指令都将开始新阶段构建。在多阶段构建中,我们可以将资源从一个阶段复制到另一个阶段,在最终镜像中只保留我们所需要的内容。
我们将上面实例的两个Dockerfile合并为如下:
#阶段1
FROM golang:1.16
WORKDIR /go/src
COPY app.go ./
RUN go build app.go -o myapp
#阶段2
FROM scratch
WORKDIR /server
COPY --from=0 /go/src/myapp ./
CMD ["./myapp"]
构建镜像
# docker build --no-cache -t server_app:v2 .
查看构建好的镜像
# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
server_app v2 20225cb1ea6b 12 seconds ago 1.94MB
这样我们无需创建额外镜像,以更简单的方式构建出了同样微小的目标镜像。可以看到在多阶段构建dockerfile中最关键的是COPY --from=0 /go/src/myapp ./ 通过 --from=0指定我们资源来源,这里的0即是指第一阶段。
命令构建阶段
默认情况下构建阶段没有名称,我们可以通过整数0~N来引用,即第一个from从0开始。其实我们还可以在FROM指令中添加AS <NAME> 来命名构建阶段,接着在COPY指令中通过<NAME>引用。我们对上面dockerfile修改如下:
#阶段1命名为builder
FROM golang:1.16 as builder
WORKDIR /go/src
COPY app.go ./
RUN go build app.go -o myapp
#阶段2
FROM scratch
WORKDIR /server
#通过名称引用
COPY --from=builder /go/src/myapp ./
CMD ["./myapp"]
只构建某个阶段
构建镜像时,您不一定需要构建整个 Dockerfile,我们可以通过--target参数指定某个目标阶段构建,比如我们开发阶段我们只构建builder阶段进行测试。
#docker build --target builder -t builder_app:v2 .
使用外部镜像
使用多阶段构建时,我们局限于从之前在 Dockerfile 中创建的阶段进行复制。还可以使用COPY --from指令从单独的镜像复制,如本地镜像名称、本地或 Dockerhub上可用的标签或标签 ID。Docker 客户端在必要时会拉取需要的镜像到本地。
COPY --from httpd:latest /usr/local/apache2/conf/httpd.conf ./httpd.conf
从上一阶段创建新的阶段
我们可以通过FROM指令来引用上一阶段作为新阶段的开始
#阶段1命名为builder
FROM golang:1.16 as builder
WORKDIR /go/src
COPY app.go ./
RUN go build app.go -o myapp
#阶段2
FROM builder as builder_ex
ADD dest.tar ./
...
通过上面我们对dockerfile多阶段构建有了一个整体的了解。
NEXT
- Dockerfile 与Docker容器安全实践
希望小作文对你有些许帮助,如果内容有误请指正。
您可以随意转载、修改、发布本文章,无需经过本人同意。 个人blog:iqsing.github.io
Dockerfile 多阶段构建实践的更多相关文章
- Dockerfile多阶段构建原理和使用场景
本文转载自Dockerfile多阶段构建原理和使用场景 导语 Docker 17.05版本以后,新增了Dockerfile多阶段构建.所谓多阶段构建,实际上是允许一个Dockerfile 中出现多个 ...
- Dockerfile多阶段构建
多阶段构建 之前的做法: 在Docker17.05版本之前,构建Docker镜像,通常采用两种方式: 1.全部放入一个Dockerfile 一种方式是将所有的构建过程全都包含在一个Dockerfile ...
- Dockerfile构建实践
Dockerfile构建实践 本文介绍了用于构建有效图像的推荐最佳实践和方法. Docker通过从一个Dockerfile文本文件中读取指令来自动构建映像,该文本文件按顺序包含构建给定映像所需的所有命 ...
- 8、Dockerfile介绍和最佳实践
一.Dockerfile 概念 1.Dockerfile是什么 Docker 镜像是一个特殊的文件系统,除了提供容器运行时所需的程序.库.资源.配置等文件外,还包含了一些为运行时准备的一些配置参数(如 ...
- 多阶段构建Docker镜像
在Docker 17.05及更高的版本中支持支持一种全新的构建镜像模式:多阶段构建: 多阶段构建Docker镜像的最大好处是使构建出来的镜像变得更小: 目前常见的两个构建镜像的方式为: 1.直接使用某 ...
- [Docker] 使用 Dockerfile 的多级构建 (multi-stage builds)
Multi-stage build 即在一个 Dockerfile 中使用多个 FROM 指令. 每个 FROM 指令可以使用不同的基础镜像,并且每一个都开启新的构建阶段. 你可以有选择地 ...
- docker 多阶段构建
构建镜像最具挑战性的一点是使镜像大小尽可能的小.Dockerfile中的每条指令都为图像添加了一个图层,您需要记住在移动到下一层之前清理任何不需要的工件.对于多阶段构建,您可以在Dockerfile中 ...
- Docker多阶段构建实战(multi-stage builds)
在编写Dockerfile构建docker镜像时,常遇到以下问题: RUN命令会让镜像新增layer,导致镜像变大,虽然通过&&连接多个命令能缓解此问题,但如果命令之间用到docker ...
- 《Docker从入门到跑路》之多阶段构建
多阶段构建就是在一个Dokcerfile中定义多个FROM,每个FROM都可以使用不同的基础镜像,并表示开始一个新的构建阶段,我们可以很方便的将一个阶段的文件复制到另外一个阶段中,在最终的阶段保存你需 ...
随机推荐
- Java | 参数传值机制
值传递 java中,方法中所有的参数的都是"值传递",就是传递的是原来值的副本,不是原来的参数,因此,改变不会影响到原来的参数. 基本数据类型参数的传值 传递的都是副本,改变以后不 ...
- [刘阳Java]_TortoiseSVN基础应用_第1讲
TortoiseSVN是一个免费的SVN客户端,非常好用.这里我们介绍一下TortoiseSVN基础应用. 下面的内容是转载博客园的某兄弟写的,个人觉得很不错.所以尊重转载的这篇文章,必须要给出这篇博 ...
- 《面试八股文》之 Redis 16卷
微信公众号:moon聊技术 关注选择" 星标 ", 重磅干货,第一 时间送达! [如果你觉得文章对你有帮助,欢迎关注,在看,点赞,转发] 大家好,我是 moon. redis 作为 ...
- VSCode 如何远程连接其他主机的 WSL2
VSCode 如何远程连接其他主机的 WSL2 VSCode 的 Remote Deployment 插件对 WSL2 直接提供了支持,能够很方便的连接本机的 WSL2 ,但是并没有提供一个连接远程 ...
- Guava - Set集合
当我们在统计一个字符串中每个单词出现的次数时,通常的做法是分割字符串,遍历字符串,然后放到一个map里面,来进行统计,Guava中提供了类似功能的集合,Multiset String strWorld ...
- CSS样式实现表头和列固定
效果图:第一行和第一列固定 <!DOCTYPE html> <html lang="zh"> <head> <meta cha ...
- jvm源码解读--14 defNewGeneration.cpp gc标记复制之后,进行空间清理
进入Eden()->clean()函数 void EdenSpace::clear(bool mangle_space) { ContiguousSpace::clear(mangle_spac ...
- 添加xxx到右键菜单
1. 添加notepad++到右键菜单[1] 添加到 右键菜单 将以下内容保存为 OpenWithNotepad++.reg 文件,双击运行即可(其中可执行文件路径和菜单项名称请自行替换): 注: 下 ...
- atom之插件安装及相关
1. simplified-chinese-menu 汉化软件 2. file-icons 加上文件图标 3. language-vue 加上vue语言支持 4. platformio-ide-ter ...
- loadrunner 利用JDBC操作mysql数据库
import lrapi.lr;import java.util.ArrayList;import java.util.List; import java.sql.Connection; import ...