有时网络冲浪看到文章说 docker build 传统方式在不久的将来会被废弃时,我感到莫名其妙。不过官方同时建议更换 docker buildx 来替代。此时我与你一样有疑惑。

Docker Buildx 首次出现在 19.03 版本中,于 2019 年 7 月发布。距离今日已经过去5年,我现在才感觉到它的存在。但平常可能不经意间已经受益于它的一些特性。

cover

Docker Build 不好吗?

在过去的开发环境中,当然是足够好的。但原因是来自于人性的贪婪。没错,我们想要更多更好的特性。很不幸,原来的架构不支持,只好放弃。

Docker Buildx 带来了什么?

能实现更复杂更现代化开发需求的功能:

  1. 生成多平台编译:可以在一次打包编译命令输出 arm/x86 等多平台的镜像
  2. 增强缓存:自动跳过未使用的构建阶段,优化使用修改文件的上下文
  3. 并行构建:并行构建独立的阶段,加快编译速度
  4. 支持更高级的 Dockerfile 语法
  5. …

如何使用 Docker Buildx

Docker Desktop、Docker Engine 大于 23.0 版本已经默认启用。

Docker Buildx 是交互客户端,而背后是全新的 BuildKit 提供了实际编译构建的服务进程。在你执行 docker build 时已经在使用 Buildx。Buildx 会解析用户传入的命令参数,并发送给后端 BuildKit 执行。(所以从另一个角度讲,BuildKit 才是核心功能的实现方。不使用 Buildx 也可以,选用其他支持的客户端同样能运用 BuildKit 的新特性。)

如何验证你是否安装了 BuildKit

1
docker buildx version

如何手动启用

在 Docker Engine 23.0 之前的需要手动开启该功能

  1. 使用环境变量

    DOCKER_BUILDKIT=1 docker build .

  2. 编辑 Docker daemon 配置文件

    配置文件路径在:/etc/docker/daemon.json

    1
    2
    3
    4
    5
    {
    "features": {
    "buildkit": true
    }
    }

    最后重启 Docker

    sudo systemctl restart docker

重要特性一探

生成多平台镜像

使用 --platform 参数来生成目标镜像:

1
docker buildx build --platform linux/amd64,linux/arm64

并行构建

传统的 build 会顺序依次执行构建命令,这样花费的时间非常长,没有优化方案。但是 BuildKit 则会分析相关性和依赖性。如果不同的 stage 阶段没有相互依赖,则会同时构建。大大缩短构建时间。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
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

可以看到 base-builder-extended 和 golang 以及 source-code 是相互没有依赖的 stage,所以构建时会同时执行。

结语

Docker 已经大大改变了现代软件工程的开发构建方式,对运维部署则是完全革命性的工具。随着网络世界的进一步发展,Docker 也在跟进,从而变得更现代化能够适应各类状况。