Skip to content

1.Buildkit

1.1为什么使用Buildkit

由于containerd无法构建docker镜像,所以需要依赖buildkit来构建镜像

1.2介绍

官当

Buildkit 是一款高效、Docekrfile 无关、更契合 “云原生应用” 的新一代镜像构建工具。

BuildKit 是源自 Docker 的 Moby 项目的第二代镜像构建工具。BuildKit 不限于仅与 Docker 一起使用。这是一种通用的镜像构建工具,可以作为独立的二进制文件(以守护程序或无守护程序模式使用)也可以作为库来使用。实际上,它可以将构建步骤转换成其低级构建器(LLB)表示形式,BuildKit 可用于构建任何制品(artifact)而不仅仅是容器镜像。我们主要在这里关注容器镜像的构建。

1.组成

1.服务端为buildkitd,负责和runc或containerd后端连接干活,目前只支持这两个后端。

2.客户端为buildctl,负责解析镜像构建文件Dockerfile,并向服务端发出构建指令,所以客户端可以和服务端不在一台机器上,也不需要root权限之类。

3.服务端默认使用runc后端,但是建议使用containerd后端,这样构建出的镜像就会存在containerd的buildkit名字空间下。

2.优势

相比于 Docker Daemon build,BuildKit 具有以下优势:

  • 更高效:支持并行的多阶段构建、更好的缓存管理;
  • 更安全:支持 secret mount,无需 root priviliege;
  • 更易于扩展:使用自定义中间语言 LLB,完全兼容 Dockerfile,也可支持第三方语言(目前仅有 Buildpacks),后台目前可支持 runC 和 containerd 两种 worker

3.原理

后台启动一个 buildkitd 守护进程,通过 http 通信的方式执行构建。

  • gRPC API: 使用 Google RPC 协议高效通信
  • Go client library: 基于 Go 的客户端方便调用
  • rootless execution: buildctl 不需要 root 权限就可以执行
  • OpenTracing: 支持镜像 layer 的逐层溯源
  • multi-worker model:支持多种 worker(runC 和 containerd),可扩展

1.3部署

1.单节点

自从 Containerd 发布 1.5 以后,Kubernetes 的CRI接口使用 Containerd 来替代 dockershim 时, 我们便可以使用 nerdctl 工具(替代 docker cli) 配合 Containerd 的情况下基本已经可以替换掉 Docker 和 Docker Compose 。只有 nerdctl 还不能打包镜像,还需要 BuildKit 服务配置完成打包镜像

版本兼容

buildkitcontainerddocker
v0.16.0>=v1.7.21>= v27.2.1

下载

bash
wget https://github.com/moby/buildkit/releases/download/v0.16.0/buildkit-v0.16.0.linux-amd64.tar.gz
wget https://github.com/moby/buildkit/releases/download/v0.16.0/buildkit-v0.16.0.linux-amd64.tar.gz
  • 解压
bash
tar xf buildkit-v0.16.0.linux-amd64.tar.gz

#复制文件
cp bin/{buildkitd,buildctl} /usr/local/bin
tar xf buildkit-v0.16.0.linux-amd64.tar.gz

#复制文件
cp bin/{buildkitd,buildctl} /usr/local/bin

创建init文件

  • buildkitd
bash
cat <<-EOF | tee /lib/systemd/system/buildkitd.service >> /dev/null
[Unit]
Description=BuildKit
Documentation=https://github.com/moby/buildkit
# Requires=buildkit.socket
After=buildkit.socket

[Service]
ExecStart=/usr/local/bin/buildkitd --oci-worker=false --containerd-worker=true

[Install]
WantedBy=multi-user.target
EOF
cat <<-EOF | tee /lib/systemd/system/buildkitd.service >> /dev/null
[Unit]
Description=BuildKit
Documentation=https://github.com/moby/buildkit
# Requires=buildkit.socket
After=buildkit.socket

[Service]
ExecStart=/usr/local/bin/buildkitd --oci-worker=false --containerd-worker=true

[Install]
WantedBy=multi-user.target
EOF
  • socket
bash
# buildkitd 服务依赖的 socket 文件
cat <<-EOF | tee /lib/systemd/system/buildkit.socket >> /dev/null
[Unit]
Description=BuildKit
Documentation=https://github.com/moby/buildkit

[Socket]
ListenStream=%t/buildkit/buildkitd.sock

[Install]
WantedBy=sockets.target
EOF
# buildkitd 服务依赖的 socket 文件
cat <<-EOF | tee /lib/systemd/system/buildkit.socket >> /dev/null
[Unit]
Description=BuildKit
Documentation=https://github.com/moby/buildkit

[Socket]
ListenStream=%t/buildkit/buildkitd.sock

[Install]
WantedBy=sockets.target
EOF
  • 启动服务
bash
 systemctl daemon-reload    
 systemctl start buildkitd.service
 systemctl enable buildkitd.service
 systemctl daemon-reload    
 systemctl start buildkitd.service
 systemctl enable buildkitd.service

设置别名

bash
alias docker=nerdctl  
alias docker-compose="nerdctl compose"

#持久化请将配置写入 ~/.bashrc 文件中
alias docker=nerdctl  
alias docker-compose="nerdctl compose"

#持久化请将配置写入 ~/.bashrc 文件中

验证效果

bash
[root@kube-master-01 Buildkit]# cat Dockerfile
FROM alpine
CMD ["echo", "Hello Docker!!!"]

nerdctl build -t hello:v1 .
[root@kube-master-01 Buildkit]# cat Dockerfile
FROM alpine
CMD ["echo", "Hello Docker!!!"]

nerdctl build -t hello:v1 .

2.docker节点

2018 年 7 月 BuildKit 正式内置于 Docker-ce 18.06.0 的 Docker daemon ,Mac 和 Linux 可以使用环境变量 DOCKER_BUILDKIT=1 开启,同年 10 月发布社区版本。

默认情况下,Buildx 插件以 Docker 驱动程序为目标,该驱动程序使用 Docker 守护程序提供的 BuildKit 库,但存在其固有的局限性。另一个驱动程序是 docker-container,它透明地在容器内启动 BuildKit 来执行构建。它可以提供 BuildKit 全部功能。

启用BUILDKIT

从 Docker 23.0 版本开始,Buildx 是默认的构建工具(Buildx 就是使用 BuildKit 作为构建工具),若使用传统的 docker build 命令,将会出现弃用提示:

DEPRECATED: The legacy builder is deprecated and will be removed in a future release.
            Install the buildx component to build images with BuildKit:
            https://docs.docker.com/go/buildx/
DEPRECATED: The legacy builder is deprecated and will be removed in a future release.
            Install the buildx component to build images with BuildKit:
            https://docs.docker.com/go/buildx/

若是 Docker 23.0 版本之前,则还需要通过两种方式启用 Buildkit 功能

export DOCKER_BUILDKIT=1
export DOCKER_BUILDKIT=1

或者

bash
vim /etc/docker/daemon.json
# 配置信息
"features": {"buildkit": true}
vim /etc/docker/daemon.json
# 配置信息
"features": {"buildkit": true}

3.Pod节点

https://github.com/moby/buildkit/tree/master/examples/kubernetes

https://blog.k8s.li/buildkit-on-kubernetes.html

https://blog.frognew.com/2021/06/relearning-container-13.html

2.案例

alpine linux的核心特点是体积小、简单和安全,因此很多人选择alpine镜像作为基础镜像

2.1 alpine

编写一个Dockerfile在docker官方alpine镜像的基础上,安装glibc,同时配置中国时区:

dockerfile
FROM alpine:3.13.5

# Here we install GNU libc (aka glibc) and set C.UTF-8 locale as default.
ENV LANG=C.UTF-8
RUN echo "**** install packages ****" && \
    sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories &&\
    ALPINE_GLIBC_BASE_URL="https://github.com/sgerrand/alpine-pkg-glibc/releases/download" && \
    ALPINE_GLIBC_PACKAGE_VERSION="2.33-r0" && \
    ALPINE_GLIBC_BASE_PACKAGE_FILENAME="glibc-$ALPINE_GLIBC_PACKAGE_VERSION.apk" && \
    ALPINE_GLIBC_BIN_PACKAGE_FILENAME="glibc-bin-$ALPINE_GLIBC_PACKAGE_VERSION.apk" && \
    ALPINE_GLIBC_I18N_PACKAGE_FILENAME="glibc-i18n-$ALPINE_GLIBC_PACKAGE_VERSION.apk" && \
    apk add --no-cache --virtual=.build-dependencies wget ca-certificates && \
    echo \
        "-----BEGIN PUBLIC KEY-----\
        MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApZ2u1KJKUu/fW4A25y9m\
        y70AGEa/J3Wi5ibNVGNn1gT1r0VfgeWd0pUybS4UmcHdiNzxJPgoWQhV2SSW1JYu\
        tOqKZF5QSN6X937PTUpNBjUvLtTQ1ve1fp39uf/lEXPpFpOPL88LKnDBgbh7wkCp\
        m2KzLVGChf83MS0ShL6G9EQIAUxLm99VpgRjwqTQ/KfzGtpke1wqws4au0Ab4qPY\
        KXvMLSPLUp7cfulWvhmZSegr5AdhNw5KNizPqCJT8ZrGvgHypXyiFvvAH5YRtSsc\
        Zvo9GI2e2MaZyo9/lvb+LbLEJZKEQckqRj4P26gmASrZEPStwc+yqy1ShHLA0j6m\
        1QIDAQAB\
        -----END PUBLIC KEY-----" | sed 's/   */\n/g' > "/etc/apk/keys/sgerrand.rsa.pub" && \
    wget \
        "$ALPINE_GLIBC_BASE_URL/$ALPINE_GLIBC_PACKAGE_VERSION/$ALPINE_GLIBC_BASE_PACKAGE_FILENAME" \
        "$ALPINE_GLIBC_BASE_URL/$ALPINE_GLIBC_PACKAGE_VERSION/$ALPINE_GLIBC_BIN_PACKAGE_FILENAME" \
        "$ALPINE_GLIBC_BASE_URL/$ALPINE_GLIBC_PACKAGE_VERSION/$ALPINE_GLIBC_I18N_PACKAGE_FILENAME" && \
    apk add --no-cache \
        "$ALPINE_GLIBC_BASE_PACKAGE_FILENAME" \
        "$ALPINE_GLIBC_BIN_PACKAGE_FILENAME" \
        "$ALPINE_GLIBC_I18N_PACKAGE_FILENAME" && \
    \
    rm "/etc/apk/keys/sgerrand.rsa.pub" && \
    /usr/glibc-compat/bin/localedef --force --inputfile POSIX --charmap UTF-8 "$LANG" || true && \
    echo "export LANG=$LANG" > /etc/profile.d/locale.sh && \
    \
    apk del glibc-i18n && \
    \
    rm "/root/.wget-hsts" && \
    apk del .build-dependencies && \
    rm \
        "$ALPINE_GLIBC_BASE_PACKAGE_FILENAME" \
        "$ALPINE_GLIBC_BIN_PACKAGE_FILENAME" \
        "$ALPINE_GLIBC_I18N_PACKAGE_FILENAME"


RUN apk update --no-cache && apk add ca-certificates --no-cache && \
    apk add tzdata --no-cache && \
    ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \
    echo "Asia/Shanghai" > /etc/timezone
FROM alpine:3.13.5

# Here we install GNU libc (aka glibc) and set C.UTF-8 locale as default.
ENV LANG=C.UTF-8
RUN echo "**** install packages ****" && \
    sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories &&\
    ALPINE_GLIBC_BASE_URL="https://github.com/sgerrand/alpine-pkg-glibc/releases/download" && \
    ALPINE_GLIBC_PACKAGE_VERSION="2.33-r0" && \
    ALPINE_GLIBC_BASE_PACKAGE_FILENAME="glibc-$ALPINE_GLIBC_PACKAGE_VERSION.apk" && \
    ALPINE_GLIBC_BIN_PACKAGE_FILENAME="glibc-bin-$ALPINE_GLIBC_PACKAGE_VERSION.apk" && \
    ALPINE_GLIBC_I18N_PACKAGE_FILENAME="glibc-i18n-$ALPINE_GLIBC_PACKAGE_VERSION.apk" && \
    apk add --no-cache --virtual=.build-dependencies wget ca-certificates && \
    echo \
        "-----BEGIN PUBLIC KEY-----\
        MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApZ2u1KJKUu/fW4A25y9m\
        y70AGEa/J3Wi5ibNVGNn1gT1r0VfgeWd0pUybS4UmcHdiNzxJPgoWQhV2SSW1JYu\
        tOqKZF5QSN6X937PTUpNBjUvLtTQ1ve1fp39uf/lEXPpFpOPL88LKnDBgbh7wkCp\
        m2KzLVGChf83MS0ShL6G9EQIAUxLm99VpgRjwqTQ/KfzGtpke1wqws4au0Ab4qPY\
        KXvMLSPLUp7cfulWvhmZSegr5AdhNw5KNizPqCJT8ZrGvgHypXyiFvvAH5YRtSsc\
        Zvo9GI2e2MaZyo9/lvb+LbLEJZKEQckqRj4P26gmASrZEPStwc+yqy1ShHLA0j6m\
        1QIDAQAB\
        -----END PUBLIC KEY-----" | sed 's/   */\n/g' > "/etc/apk/keys/sgerrand.rsa.pub" && \
    wget \
        "$ALPINE_GLIBC_BASE_URL/$ALPINE_GLIBC_PACKAGE_VERSION/$ALPINE_GLIBC_BASE_PACKAGE_FILENAME" \
        "$ALPINE_GLIBC_BASE_URL/$ALPINE_GLIBC_PACKAGE_VERSION/$ALPINE_GLIBC_BIN_PACKAGE_FILENAME" \
        "$ALPINE_GLIBC_BASE_URL/$ALPINE_GLIBC_PACKAGE_VERSION/$ALPINE_GLIBC_I18N_PACKAGE_FILENAME" && \
    apk add --no-cache \
        "$ALPINE_GLIBC_BASE_PACKAGE_FILENAME" \
        "$ALPINE_GLIBC_BIN_PACKAGE_FILENAME" \
        "$ALPINE_GLIBC_I18N_PACKAGE_FILENAME" && \
    \
    rm "/etc/apk/keys/sgerrand.rsa.pub" && \
    /usr/glibc-compat/bin/localedef --force --inputfile POSIX --charmap UTF-8 "$LANG" || true && \
    echo "export LANG=$LANG" > /etc/profile.d/locale.sh && \
    \
    apk del glibc-i18n && \
    \
    rm "/root/.wget-hsts" && \
    apk del .build-dependencies && \
    rm \
        "$ALPINE_GLIBC_BASE_PACKAGE_FILENAME" \
        "$ALPINE_GLIBC_BIN_PACKAGE_FILENAME" \
        "$ALPINE_GLIBC_I18N_PACKAGE_FILENAME"


RUN apk update --no-cache && apk add ca-certificates --no-cache && \
    apk add tzdata --no-cache && \
    ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \
    echo "Asia/Shanghai" > /etc/timezone

2.2 busybox

busybox是一个集成了一百多个最常用的Linux命令和工具的软件工具箱

dockerfile
FROM busybox:1.33.1-glibc

COPY zoneinfo /usr/share/zoneinfo/
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && echo 'Asia/Shanghai' >/etc/timezone
FROM busybox:1.33.1-glibc

COPY zoneinfo /usr/share/zoneinfo/
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && echo 'Asia/Shanghai' >/etc/timezone

参考: