• 隐藏侧边栏
  • 展开分类目录
  • 关注微信公众号
  • 我的GitHub
  • QQ:1753970025
Chen Jiehua

Docker镜像多阶段构建 

当我们采用容器化来部署项目时,对于大部分的程序(除开脚本语言)我们一般需要将源码编译成二进制的可执行文件,再将可执行文件打包成docker镜像。如果在一个Docker镜像中完成整个流程,那构建出来的镜像文件必然很大(包含了编译环境);如果把编译过程和最终的可执行文件拆分为两个镜像,又会增加维护成本。那么有什么方法来解决这个问题呢?

背景

在构建Docker镜像时,一个最大的挑战是如何减小目标镜像的体积。

在Dockerfile中,每一行指令(ADD、COPY、RUN)会给镜像增加一个新的层,所以一般情况下我们需要在当前层将下一层不再使用的内容清除掉,而这需要利用shell的各种小trick和一些特殊的写法。

在开头提到的问题中,先来看看两个镜像的做法,其中一个大镜像包含完整的编译环境,另一个小镜像只包含最终的可执行文件(用于生产环境运行)。因此,我们需要维护两个Dockerfile。

hello.go

package main

import (
        "fmt"
)

func main(){
        fmt.Println("hello world")
}

Dockerfile.build

FROM golang:1.17
WORKDIR /go/src/app
COPY hello.go .
RUN go build -o hello hello.go

Dockerfile

FROM alpine:latest
WORKDIR /app
COPY hello .
CMD ["./hello"]

build.sh

#!/bin/bash

echo Building hello-build

docker build -t myhello:build . -f Dockerfile.build
docker container create --name extract myhello:build
docker container cp extract:/go/src/app/hello .
docker container rm -f extract

echo Building hello-go
docker build --no-cache -t myhello:latest .

最终执行:

$./build.sh
$docker run --rm myhello
hello world

可以看到,即使是编译一个简单的程序,我们需要维护的Dockerfile和脚本也是如此复杂。

多阶段构建

利用Docker的多阶段构建,我们可以在一个Dockerfile中多次使用 FROM 语句,每一个FROM意味着使用不同的基础镜像并且开始一个新的构建,而且我们还可以直接在多个构建之间复制需要的文件。这样,我们就只需要维护一个Dockerfile。

FROM golang:1.17 AS builder
WORKDIR /go/src/app
COPY hello.go .
RUN go build -o hello hello.go


FROM alpine:latest
WORKDIR /app
COPY --from=builder /go/src/app/hello .
CMD ["./hello"]

构建镜像并运行:

$docker build -t myhello:latest .
$docker run --rm myhello
hello world

这样子整个流程就简单多了,我们不再创建中间镜像也不再需要将可执行文件复制到本地环境中。

在指定 --from 的时候,我们还可以使用外部镜像,比如:

COPY --from=nginx:latest /etc/nginx/nginx.conf /nginx.conf

构建指定阶段

如果我们的Dockerfile中包含多个构建,我们可以指定只构建某一部分,比如:

$docker build --target builder -t myhello:build .

这种方式在某些场景下会非常有用:

  • 调试某个特定的构建;
  • 使用 debug 来构建带有调试符号信息的程序和工具,而不影响production
  • 使用 testing 来构建带有测试数据的环境,而 production 始终使用真实数据;

参考:https://docs.docker.com/develop/develop-images/multistage-build/

码字很辛苦,转载请注明来自ChenJiehua《Docker镜像多阶段构建》

评论