BuildKit 使用介绍

发布时间: 更新时间: 总字数:2145 阅读时间:5m 作者: IP:上海 网址

Docker 利用 BuildKit 扩展镜像构建功能,如构建多种系统架构的镜像。

介绍

Docker 18.09 引入的 BuildKit,19.03+ 版本开始可以使用 docker buildx build 命令利用 BuildKit 构建镜像。

  • 源码:https://github.com/moby/buildkit/
  • 镜像:https://hub.docker.com/r/moby/buildkit
  • Docker Hub 支持 buildx 实现

启用 BuildKit 特性

  • docker v20.10 后默认开启,查看版本是否支持 BuildKit,如下 buildx 字样
$ docker buildx version
github.com/docker/buildx v0.8.2-docker 6224def4dd2c3d347eee19db595348c50d7cb491
$ docker info
Client:
 Context:    default
 Debug Mode: false
 Plugins:
  ...
  buildx: Docker Buildx (Docker Inc., v0.8.2-docker)
  ...
Server:
 ...
 Server Version: 20.10.17
 ...
  • 若不出现,可以采用如下方式启用该特性
$ cat > ~/.docker/config.json <<EOF
{
  "experimental": "enabled"
}
EOF

原理

  • 本质上 buildx 通过调用 buildkitapi 管理构建任务
  • Docker 在 Linux 系统架构下是不支持 arm 架构镜像,通过运行一个新的 buildkit 容器让其支持该特性;Docker 桌面版则无需进行此项设置(Mac)
  • buildkit 镜像可参考:https://github.com/docker-practice/buildx
  • 构建时,通过配置 --platform 标志来指定构建输出的目标架构(例如 linux/amd64linux/arm64darwin/amd64

安装 buildkit

buildkitd 守护进程需要安装以下组件:

  • runc 或 crun
  • 容器(如果你想使用容器工作)

启动 buildkitd 守护进程:您需要在主机上以 root 用户身份运行 buildkitd

$ sudo buildkitd
  • 配置为系统服务,参考
cat <<EOF > /usr/lib/systemd/system/buildkitd.service
[Unit]
Description=buildkitd
After=network.target

[Service]
ExecStart=/usr/local/buildkit/bin/buildkitd

[Install]
WantedBy=multi-user.target
EOF

# 重新加载Unit file
systemctl daemon-reload
# 启动服务
systemctl start buildkitd
# 开机自启动
systemctl enable buildkitd

buildctl 命令使用

  • Dockerfile
FROM alpine
RUN echo "built with BuildKit!" >  file
CMD ["/bin/sh"]
  • 构建
buildctl build \
--frontend=dockerfile.v0 \
--local context=. \
--local dockerfile=. \
--output type=docker,name=myimage,dest=out.tar

# 将out.tar导入到containerd中的某个命名空间下
ctr -n test image import out.tar

# 查看镜像
ctr -n test image ls

使用

help

docker buildx ...

新建 builder 实例

$ docker buildx create --name builder --driver docker-container
  • 国内加速镜像
$ docker buildx create --use --name=builder-cn --driver docker-container --driver-opt image=dockerpracticesig/buildkit:master

# 腾讯云优化
$ docker buildx create --use --name=builder-cn --driver docker-container --driver-opt image=dockerpracticesig/buildkit:master-tencent
  • 查看 builder 实例
$ docker buildx ls
NAME/NODE  DRIVER/ENDPOINT             STATUS   PLATFORMS
builder    docker-container
  builder0 unix:///var/run/docker.sock inactive
default *  docker
  default  default                     running  linux/amd64, linux/386
  • 使用 builder 实例
$ docker buildx use builder

# * 存在的为当前使用的
$ docker buildx ls
NAME/NODE  DRIVER/ENDPOINT             STATUS   PLATFORMS
builder *  docker-container
  builder0 unix:///var/run/docker.sock inactive
default    docker
  default  default                     running  linux/amd64, linux/386

Demo Dockerfile

  • Dockerfile
$ mkdir ~/demo
$ cd ~/demo
$ cat > Dockerfile <<EOF
FROM --platform=$TARGETPLATFORM alpine
RUN uname -a > /os.txt
CMD cat /os.txt
EOF

说明:

  • $TARGETPLATFORM 是内置变量,由 --platform 参数来指定
  • alpine 镜像支持的架构包括:
    • linux/amd64
    • linux/arm/v6
    • linux/arm/v7
    • linux/arm64/v8
    • linux/386
    • linux/ppc64le
    • linux/s390x

构建镜像

# 登录docker hub
$ docker login

# 构建并推送
$ docker buildx build --platform linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64/v8,linux/386,linux/ppc64le,linux/s390x -t xiexianbin/multi-hello . --push

说明:

  • --push 可选,直接推送镜像到 docker hub
  • 构建过程,默认拉去 pulling image moby/buildkit:buildx-stable-1 镜像,本地启动容器 creating container buildx_buildkit_builder0 即为 buildkit 的 builder 容器
  • 构建日志如下
docker buildx build xxx ...

查看构建的镜像

需要指定 --pull 参数才能查看

$ docker buildx imagetools inspect xiexianbin/multi-hello
Name:      docker.io/xiexianbin/multi-hello:latest
MediaType: application/vnd.docker.distribution.manifest.list.v2+json
Digest:    sha256:2b15dfe786cdecb59dcc1f710a776a0a3454c1c6923a02a11d0fae495efb7a82

Manifests:
  Name:      docker.io/xiexianbin/multi-hello:latest@sha256:eeeafa444f5b56d0650b48f0368ebf9034ce1d923d7579c85117367aaf8c8c5d
  MediaType: application/vnd.docker.distribution.manifest.v2+json
  Platform:  linux/amd64

  Name:      docker.io/xiexianbin/multi-hello:latest@sha256:a2dd3f3b7778cb1da2e1bc0560300f9dbd7c2dafcfe7186fa6748b6b3c7aa830
  MediaType: application/vnd.docker.distribution.manifest.v2+json
  Platform:  linux/arm/v6

  Name:      docker.io/xiexianbin/multi-hello:latest@sha256:cae98fd2fc1b281dea54b1f353797004907a53b331060661ba8548cec4d1e642
  MediaType: application/vnd.docker.distribution.manifest.v2+json
  Platform:  linux/arm/v7

  Name:      docker.io/xiexianbin/multi-hello:latest@sha256:754f3e4b7cdfb2ec2c36ce911330b5ea8ebc8f9166f96592ea077a4aa8864ca1
  MediaType: application/vnd.docker.distribution.manifest.v2+json
  Platform:  linux/arm64

  Name:      docker.io/xiexianbin/multi-hello:latest@sha256:88671d1de992488e818a2fd224cf2d83a6f72c7b014494a17d75897f2d603ad6
  MediaType: application/vnd.docker.distribution.manifest.v2+json
  Platform:  linux/386

  Name:      docker.io/xiexianbin/multi-hello:latest@sha256:6c3d94d4dcb3a61c105581f89ef31689708bf0b1e12eff7b943fa8dfb3baa592
  MediaType: application/vnd.docker.distribution.manifest.v2+json
  Platform:  linux/ppc64le

  Name:      docker.io/xiexianbin/multi-hello:latest@sha256:44a705da5e4e212c13b3b03fc651e463a2bcb92f1bc3422eecee3fe6599790c1
  MediaType: application/vnd.docker.distribution.manifest.v2+json
  Platform:  linux/s390x

builder 状态

$ docker buildx ls
NAME/NODE  DRIVER/ENDPOINT             STATUS  PLATFORMS
builder *  docker-container
  builder0 unix:///var/run/docker.sock running linux/amd64, linux/amd64/v2, linux/amd64/v3, linux/386
default    docker
  default  default                     running linux/amd64, linux/386

Dockerfile

变量

Dockerfile 支持如下架构相关的变量

  • TARGETPLATFORM 构建镜像的目标平台,例如 linux/amd64, linux/arm/v7
    • TARGETOS TARGETPLATFORM 的 OS 类型,例如 linux, windows
    • TARGETARCH TARGETPLATFORM 的架构类型,例如 amd64, arm
    • TARGETVARIANT TARGETPLATFORM 的变种,该变量可能为空,例如 v7
  • BUILDPLATFORM 构建镜像主机平台,例如 linux/amd64
    • BUILDOS BUILDPLATFORM 的 OS 类型,例如 linux
    • BUILDARCH BUILDPLATFORM 的架构类型,例如 amd64
    • BUILDVARIANT BUILDPLATFORM 的变种,该变量可能为空,例如 v7

RUN –mount=type=cache

# syntax = docker/dockerfile:experimental
FROM node:alpine as builder
​
WORKDIR /app
​
COPY package.json /app/
​
RUN --mount=type=cache,target=/app/node_modules,id=my_app_npm_module,sharing=locked \
    --mount=type=cache,target=/root/.npm,id=npm_cache \
    npm i
​
COPY src /app/src
​
RUN --mount=type=cache,target=/app/node_modules,id=my_app_npm_module,sharing=locked \
  npm run build
​
FROM nginx:alpine
​
RUN --mount=type=cache,target=/root/.npm,from=builder,source=/app/dist \
  mkdir -p /app/dist && cp -r /root/.npm/* /app/dist
  • --mount=type=cache: 这是 BuildKit 特有的挂载语法。它告诉 Docker 引擎:请给我准备一个持久化的缓存卷

    • 这个缓存卷的内容在多次构建(Build)之间是保留的。
    • 即使这一层(Layer)的缓存失效了(例如你修改了 package.json),这个挂载卷里的内容依然存在。
  • target=/root/.npm: 这是指定缓存挂载到容器内部的目录路径。

    • 为什么是 /root/.npm 因为这是 npm 默认存放下载缓存(Local Cache)的地方(假设你是以 root 用户运行构建)。
    • 注意:这里挂载的不是 node_modules,而是 npm 的下载缓存。npm install 会先去这个目录找有没有下载过的包,如果有就直接解压,不需要从互联网下载。

github action

github-action-buildkit ...

扩展

  • argo-workflows 使用 buildkit 参考
  • Earthly (Makefile + Dockerfile = Earthfile)
本文总阅读量 次 本站总访问量 次 本站总访客数