大幅提升 Docker 构建性能的 3 个步骤

2025-06-05

大幅提升 Docker 构建性能的 3 个步骤

Docker 是我们日常开发中使用的工具,但是你在等待 Docker 构建完成上浪费了多少时间?你又该如何处理巨大的镜像呢?

如果我告诉您有更好的方法来构建您的容器呢?

您最喜欢的下一个工具叫做 Buildkit!

在本教程中,我们将深入探讨 Docker 的高级用法,以优化您的开发流程,包括构建时间和镜像本身的大小。我们将使用 Buildkit并行多阶段构建来实现。

Buildkit

Buildkit是Moby 项目开发的工具包,用于增强使用容器的软件构建和打包。

主要特点

Buildkit 提供多种功能,包括自动垃圾收集以清理不需要的资源、并发依赖项解析以及高效的指令缓存。Buildkitdocker build自 Docker 18.06 起成为其中的一部分。

如何启用 Buildkit

如果您想使用 Buildkit 驱动的构建引擎,您可以使用环境变量来实现DOCKER_BUILDKIT=1 docker build

也可以默认启用 Buildkit:

  • 编辑守护进程配置/etc/docker/daemon.json并添加
{ "features": { "buildkit": true } }
Enter fullscreen mode Exit fullscreen mode
  • 使用以下命令重启守护进程
sudo systemctl daemon-reload
sudo systemctl restart docker
Enter fullscreen mode Exit fullscreen mode

代码示例

在本教程中,我们将准备一个镜像,用于在生产环境中部署Prometheus实例。我们将从一个标准的 Dockerfile 开始,并对其进行重构以提高性能。

旧版 Dockerfile

我们将从源代码构建 Prometheus,为此我们需要一个包含所有构建依赖项的 Docker 镜像golang、、nodejsyarnmake

FROM ubuntu:bionic

ENV GOPATH=$HOME/go
ENV PATH=$PATH:/usr/local/go/bin:$GOPATH/bin

RUN apt-get update \
    && apt-get install -y curl git build-essential \
    && curl -sL https://deb.nodesource.com/setup_14.x | bash - \
    && apt-get install -y nodejs \
    && npm install -g yarn \
    && curl -O https://storage.googleapis.com/golang/go1.15.2.linux-amd64.tar.gz \
    && tar -xvf go1.15.2.linux-amd64.tar.gz \
    && mv go /usr/local \
    && git clone https://github.com/prometheus/prometheus.git prometheus/ \
    && cd prometheus/ \
    && make build 
# RUN ./prometheus --config.file=your_config.yml
Enter fullscreen mode Exit fullscreen mode

让我们用以下代码来构建它:

$ time docker build --no-cache -t prometheus . -f Dockerfile.prometheus

...

Successfully built 54b5d99ef76a
Successfully tagged prometheus:latest

real    19m56,395s
user    0m0,506s
sys     0m0,334s
Enter fullscreen mode Exit fullscreen mode

图像尺寸为:

$ docker images
REPOSITORY                    TAG                 IMAGE ID            CREATED              SIZE
prometheus                    latest              54b5d99ef76a        25 minutes ago       2.38GB
Enter fullscreen mode Exit fullscreen mode

旧版构建性能

从结果来看,我们花了将近20 分钟才创建一个大小为2.38GB的​​ Prometheus 实例。
这将是我们的起点。

多阶段构建

现在我们已经有了一个可以投入生产的图像,所以我们很高兴,对吗?

不,我们绝对不是

你可能已经注意到,我们刚刚创建的镜像非常庞大,使用 Docker 的高级功能“多阶段构建”绝对可以做得更好。Docker
从 17.05 版本开始支持多阶段构建,这是优化镜像大小的首选方法。你可以使用FROM ... AS ...指令定义构建阶段,并使用COPY --from指令在阶段之间共享构建成果。

重构旧版 Dockerfile 以使用多阶段构建

让我们将这些概念应用到旧的 Dockerfile 中。

FROM ubuntu:bionic as base-builder

ENV GOPATH=$HOME/go
ENV PATH=$PATH:/usr/local/go/bin:$GOPATH/bin

RUN apt-get update \
    && apt-get install -y curl git build-essential \
    && curl -sL https://deb.nodesource.com/setup_14.x | bash - \
    && apt-get install -y nodejs \
    && npm install -g yarn \
    && curl -O https://storage.googleapis.com/golang/go1.15.2.linux-amd64.tar.gz \
    && tar -xvf go1.15.2.linux-amd64.tar.gz \
    && mv go /usr/local \
    && git clone https://github.com/prometheus/prometheus.git prometheus/ \
    && cd prometheus/ \
    && make build
FROM ubuntu:bionic as final
COPY --from=base-builder prometheus/prometheus prometheus
# RUN ./prometheus --config.file=your_config.yml
Enter fullscreen mode Exit fullscreen mode

我们需要做的是创建一个仅包含 Prometheus 可执行文件的微型阶段。我们可以利用上一个阶段final来完成。COPY --from

现在是时候构建 Docker 镜像了。

$ time docker build --no-cache -t prometheus-multistage . -f Dockerfile.prometheus-multistage
...

Successfully built ab2217626102
Successfully tagged prometheus-multistage:latest

real    19m19,570s
user    0m0,418s
sys     0m0,459s
Enter fullscreen mode Exit fullscreen mode

图像尺寸为。

$ docker images
REPOSITORY              TAG                 IMAGE ID            CREATED             SIZE
prometheus-multistage   latest              ab2217626102        31 seconds ago      151MB
Enter fullscreen mode Exit fullscreen mode

多阶段构建性能

从新的结果来看,我们花了 19 分钟来构建图像,但尺寸的改善却显著减少了 99.94%!

并行多阶段构建

因此,我们能够减小镜像大小,但构建时间仍然过长。我们仍然可以利用Buildkit 构建引擎来优化这一点。
旧版 Docker 构建引擎按顺序执行各个阶段的构建,而 Buildkit 会计算各个阶段的依赖关系图并并行执行构建。考虑到这一点,我们可以重构 Dockerfile 来加快构建时间。

重构 Dockerfile 以使用并行多阶段构建

让我们看看如何做到这一点。

FROM ubuntu:bionic as base-builder

ENV GOPATH=$HOME/go
ENV PATH=$PATH:/usr/local/go/bin:$GOPATH/bin

RUN apt-get update \
    && apt-get install -y curl git build-essential

FROM base-builder as base-builder-extended
RUN curl -sL https://deb.nodesource.com/setup_14.x | bash - \
    && apt-get install -y nodejs \
    && npm install -g yarn

FROM base-builder as golang
RUN curl -O https://storage.googleapis.com/golang/go1.15.2.linux-amd64.tar.gz \
    && tar -xvf go1.15.2.linux-amd64.tar.gz

FROM base-builder as source-code
RUN git clone https://github.com/prometheus/prometheus.git prometheus/

FROM base-builder-extended as builder
COPY --from=golang go /usr/local
COPY --from=source-code prometheus/ prometheus/
RUN cd prometheus/ && make build

FROM ubuntu:bionic as final
COPY --from=builder prometheus/prometheus prometheus
# RUN ./prometheus --config.file=your_config.yml
Enter fullscreen mode Exit fullscreen mode

我们创建一个名为 的第一阶段base-builder,其中包含基本工具,并将作为后续层的基础。
继承自 ,base-builder我们定义:

  • golang,包含go
  • source-code,我们用它来获取 Prometheus 源代码;
  • base-builder-extendedbase-builder这是包含nodejs的增强yarn

这三个阶段彼此不依赖,因此构建将并行进行。

至此,我们已准备好构建代码builder。在此阶段,我们将COPY --from前几个阶段所需的构件整合到构建中。然后,我们再次创建一个final仅包含 Prometheus 可执行文件的微型阶段。

现在我们可以运行构建了。

$ DOCKER_BUILDKIT=1 docker build --no-cache -t prometheus-parallel-multistage . -f Dockerfile.prometheus-parallel-multistage
[+] Building 734.4s (13/13) FINISHED                                                                                                  
 => [internal] load build definition from Dockerfile.prometheus-parallel-multistage                                              1.1s
 => => transferring dockerfile: 963B                                                                                             0.1s
 => [internal] load .dockerignore                                                                                                0.8s
 => => transferring context: 2B                                                                                                  0.1s
 => [internal] load metadata for docker.io/library/ubuntu:bionic                                                                 0.0s
 => CACHED [final 1/2] FROM docker.io/library/ubuntu:bionic                                                                      0.0s
 => [base-builder 2/2] RUN apt-get update     && apt-get install -y curl git build-essential                                   195.6s
 => [source-code 1/1] RUN git clone https://github.com/prometheus/prometheus.git prometheus/                                    77.6s 
 => [base-builder-extended 1/1] RUN curl -sL https://deb.nodesource.com/setup_14.x | bash -     && apt-get install -y nodejs   102.1s 
 => [golang 1/1] RUN curl -O https://storage.googleapis.com/golang/go1.15.2.linux-amd64.tar.gz     && tar -xvf go1.15.2.linux  149.8s 
 => [builder 1/3] COPY --from=golang go /usr/local                                                                              13.6s 
 => [builder 2/3] COPY --from=source-code prometheus/ prometheus/                                                                9.5s 
 => [builder 3/3] RUN cd prometheus/ && make build                                                                             338.6s 
 => [final 2/2] COPY --from=builder prometheus/prometheus prometheus                                                             2.6s 
 => exporting to image                                                                                                           1.9s 
 => => exporting layers                                                                                                          1.6s 
 => => writing image sha256:c0e59c47a790cb2a6b1229a5fec0014aa2b4540fc79c51531185c9466c9d5584                                     0.1s 
 => => naming to docker.io/library/prometheus-parallel-multistage                                                                0.1s
Enter fullscreen mode Exit fullscreen mode

并检查图像大小。

$ docker images
REPOSITORY                       TAG                 IMAGE ID            CREATED             SIZE
prometheus-parallel-multistage   latest              c0e59c47a790        About a minute ago  151MB
prometheus-multistage            latest              ab2217626102        9 minutes ago       151MB
prometheus                       latest              54b5d99ef76a        39 minutes ago      2.38GB
Enter fullscreen mode Exit fullscreen mode

并行多阶段构建性能

从新的结果来看,我们花了将近 12.5 分钟来构建图像,减少了 30%,同时保持了相同的图像大小。

结果回顾

下表总结了三个不同示例中的构建时间和图像大小。

Dockerfile 构建时间 图像大小
prometheus-并行-多阶段 12.5米 151MB
普罗米修斯多阶段 19米 151MB
普罗米修斯 20米 2.38GB

如您所见,无论是构建时间还是镜像大小,改进都非常显著。在生产环境中,使用多阶段并行构建方法非常有用,因为较小的 Docker 镜像就能带来显著的提升。您只需记住 Buildkit 的工作原理,思考 Dockerfile 中哪些部分可以并行化,并进行相应的开发即可。您可以轻松地将 Buildkit 集成到 Docker 的构建/测试/标记/推送流水线中。

就是这个!

我希望这对你有用,现在去重构你的旧 Dockerfile!

通过 Twitter @gasparevitta联系我让我了解您的性能改进

您可以在Github上找到代码片段

本文最初发表在我的博客上。如果你喜欢这篇文章,并且想阅读其他类似的文章,欢迎访问我的博客!

文章来源:https://dev.to/gasparev/3-steps-to-drastically-improve-your-docker-build-performances-17jg
PREV
JavaScript 中的 25 种数组方法
NEXT
如何在 C# 中使用工厂方法设计模式 工厂方法设计模式简介