使用 BuildKit 构建 Docker 镜像
- 层级:Free, Premium, Ultimate
- 提供方式:GitLab.com, GitLab Self-Managed, GitLab Dedicated
BuildKit 是 Docker 使用的构建引擎, 提供多平台构建和构建缓存功能。
BuildKit 方法
BuildKit 提供以下构建 Docker 镜像的方法:
| 方法 | 安全要求 | 命令 | 适用场景 |
|---|---|---|---|
| BuildKit rootless | 无需特权容器 | buildctl-daemonless.sh |
最大安全性或 Kaniko 的替代方案 |
| Docker Buildx | 需要 docker:dind |
docker buildx |
熟悉的 Docker 工作流 |
| Native BuildKit | 需要 docker:dind |
buildctl |
高级 BuildKit 控制 |
前置条件
- 带 Docker executor 的 GitLab Runner
- 使用 Docker Buildx 需要 Docker 19.03 或更高版本
- 包含
Dockerfile的项目
BuildKit rootless
独立模式的 BuildKit 提供无需 Docker 守护进程依赖的 rootless 镜像构建。 此方法完全消除了特权容器,并提供了 Kaniko 构建的直接替代方案。
与其他方法的主要区别:
- 使用
moby/buildkit:rootless镜像 - 包含
BUILDKITD_FLAGS: --oci-worker-no-process-sandbox用于 rootless 操作 - 使用
buildctl-daemonless.sh自动管理 BuildKit 守护进程 - 无需 Docker 守护进程或特权容器依赖
- 需要手动配置注册表认证
向容器注册表认证
GitLab CI/CD 通过预定义变量为 GitLab 容器注册表提供自动认证。 对于 BuildKit rootless,您必须手动创建 Docker 配置文件。
向 GitLab 容器注册表认证
GitLab 自动提供这些预定义变量:
CI_REGISTRY: 注册表 URLCI_REGISTRY_USER: 注册表用户名CI_REGISTRY_PASSWORD: 注册表密码
要配置 rootless 构建的认证,在您的作业中添加 before_script 配置。
例如:
before_script:
- mkdir -p ~/.docker
- echo "{\"auths\":{\"$CI_REGISTRY\":{\"username\":\"$CI_REGISTRY_USER\",\"password\":\"$CI_REGISTRY_PASSWORD\"}}}" > ~/.docker/config.json向多个注册表认证
要向额外的容器注册表认证,在您的 before_script 部分组合认证条目。
例如:
before_script:
- mkdir -p ~/.docker
- |
echo "{
\"auths\": {
\"${CI_REGISTRY}\": {
\"auth\": \"$(printf "%s:%s" "${CI_REGISTRY_USER}" "${CI_REGISTRY_PASSWORD}" | base64 | tr -d '\n')\"
},
\"docker.io\": {
\"auth\": \"$(printf "%s:%s" "${DOCKER_HUB_USER}" "${DOCKER_HUB_PASSWORD}" | base64 | tr -d '\n')\"
}
}
}" > ~/.docker/config.json向依赖代理认证
要通过 GitLab 依赖代理拉取镜像,在您的 before_script 部分配置认证。
例如:
before_script:
- mkdir -p ~/.docker
- |
echo "{
\"auths\": {
\"${CI_REGISTRY}\": {
\"auth\": \"$(printf "%s:%s" "${CI_REGISTRY_USER}" "${CI_REGISTRY_PASSWORD}" | base64 | tr -d '\n')\"
},
\"$(echo -n $CI_DEPENDENCY_PROXY_SERVER | awk -F[:] '{print $1}')\": {
\"auth\": \"$(printf "%s:%s" ${CI_DEPENDENCY_PROXY_USER} "${CI_DEPENDENCY_PROXY_PASSWORD}" | base64 | tr -d '\n')\"
}
}
}" > ~/.docker/config.json有关更多信息,请参阅 CI/CD 中的认证。
在 rootless 模式下构建镜像
要构建无需 Docker 守护进程依赖的镜像,添加类似以下示例的作业:
build-rootless:
image: moby/buildkit:rootless
stage: build
variables:
BUILDKITD_FLAGS: --oci-worker-no-process-sandbox
before_script:
- mkdir -p ~/.docker
- echo "{\"auths\":{\"$CI_REGISTRY\":{\"username\":\"$CI_REGISTRY_USER\",\"password\":\"$CI_REGISTRY_PASSWORD\"}}}" > ~/.docker/config.json
script:
- |
buildctl-daemonless.sh build \
--frontend dockerfile.v0 \
--local context=. \
--local dockerfile=. \
--output type=image,name=$CI_REGISTRY_IMAGE:$CI_COMMIT_SHA,push=true在 rootless 模式下构建多平台镜像
要在 rootless 模式下为多个架构构建镜像,配置您的作业以指定目标平台。 例如:
build-multiarch-rootless:
image: moby/buildkit:rootless
stage: build
variables:
BUILDKITD_FLAGS: --oci-worker-no-process-sandbox
before_script:
- mkdir -p ~/.docker
- echo "{\"auths\":{\"$CI_REGISTRY\":{\"username\":\"$CI_REGISTRY_USER\",\"password\":\"$CI_REGISTRY_PASSWORD\"}}}" > ~/.docker/config.json
script:
- |
buildctl-daemonless.sh build \
--frontend dockerfile.v0 \
--local context=. \
--local dockerfile=. \
--opt platform=linux/amd64,linux/arm64 \
--output type=image,name=$CI_REGISTRY_IMAGE:$CI_COMMIT_SHA,push=true在 rootless 模式下使用缓存
要启用基于注册表的缓存以加快后续构建速度,在您的构建作业中配置缓存导入和导出。 例如:
build-cached-rootless:
image: moby/buildkit:rootless
stage: build
variables:
BUILDKITD_FLAGS: --oci-worker-no-process-sandbox
CACHE_IMAGE: $CI_REGISTRY_IMAGE:cache
before_script:
- mkdir -p ~/.docker
- echo "{\"auths\":{\"$CI_REGISTRY\":{\"username\":\"$CI_REGISTRY_USER\",\"password\":\"$CI_REGISTRY_PASSWORD\"}}}" > ~/.docker/config.json
script:
- |
buildctl-daemonless.sh build \
--frontend dockerfile.v0 \
--local context=. \
--local dockerfile=. \
--export-cache type=registry,ref=$CACHE_IMAGE \
--import-cache type=registry,ref=$CACHE_IMAGE \
--output type=image,name=$CI_REGISTRY_IMAGE:$CI_COMMIT_SHA,push=true配置代理设置
如果您的 GitLab Runner 在 HTTP(S) 代理后运行,在您的作业中将代理设置配置为变量。 例如:
build-behind-proxy:
image: moby/buildkit:rootless
stage: build
variables:
BUILDKITD_FLAGS: --oci-worker-no-process-sandbox
http_proxy: <your-proxy>
https_proxy: <your-proxy>
no_proxy: <your-no-proxy>
before_script:
- mkdir -p ~/.docker
- echo "{\"auths\":{\"$CI_REGISTRY\":{\"username\":\"$CI_REGISTRY_USER\",\"password\":\"$CI_REGISTRY_PASSWORD\"}}}" > ~/.docker/config.json
script:
- |
buildctl-daemonless.sh build \
--frontend dockerfile.v0 \
--local context=. \
--local dockerfile=. \
--build-arg http_proxy=$http_proxy \
--build-arg https_proxy=$https_proxy \
--build-arg no_proxy=$no_proxy \
--output type=image,name=$CI_REGISTRY_IMAGE:$CI_COMMIT_SHA,push=true在此示例中,将 <your-proxy> 和 <your-no-proxy> 替换为您的代理配置。
添加自定义证书
要使用自定义 CA 证书推送到注册表,在构建前将证书添加到容器的证书存储中。 例如:
build-with-custom-certs:
image: moby/buildkit:rootless
stage: build
variables:
BUILDKITD_FLAGS: --oci-worker-no-process-sandbox
before_script:
- |
echo "-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----" >> /etc/ssl/certs/ca-certificates.crt
- mkdir -p ~/.docker
- echo "{\"auths\":{\"$CI_REGISTRY\":{\"username\":\"$CI_REGISTRY_USER\",\"password\":\"$CI_REGISTRY_PASSWORD\"}}}" > ~/.docker/config.json
script:
- |
buildctl-daemonless.sh build \
--frontend dockerfile.v0 \
--local context=. \
--local dockerfile=. \
--output type=image,name=$CI_REGISTRY_IMAGE:$CI_COMMIT_SHA,push=true在此示例中,将证书占位符替换为您的实际证书内容。
从 Kaniko 迁移到 BuildKit
BuildKit rootless 是 Kaniko 的安全替代方案。 它提供改进的性能、更好的缓存和增强的安全功能,同时保持 rootless 操作。
更新您的配置
更新您现有的 Kaniko 配置以使用 BuildKit rootless 方法。 例如:
之前,使用 Kaniko:
build:
image:
name: gcr.io/kaniko-project/executor:debug
entrypoint: [""]
script:
- /kaniko/executor
--context $CI_PROJECT_DIR
--dockerfile $CI_PROJECT_DIR/Dockerfile
--destination $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA之后,使用 BuildKit rootless:
build:
image: moby/buildkit:rootless
variables:
BUILDKITD_FLAGS: --oci-worker-no-process-sandbox
before_script:
- mkdir -p ~/.docker
- echo "{\"auths\":{\"$CI_REGISTRY\":{\"username\":\"$CI_REGISTRY_USER\",\"password\":\"$CI_REGISTRY_PASSWORD\"}}}" > ~/.docker/config.json
script:
- |
buildctl-daemonless.sh build \
--frontend dockerfile.v0 \
--local context=. \
--local dockerfile=. \
--output type=image,name=$CI_REGISTRY_IMAGE:$CI_COMMIT_SHA,push=true其他 BuildKit 方法
如果您不需要 rootless 构建,BuildKit 提供其他需要 docker:dind 服务但提供熟悉工作流或高级功能的方法。
Docker Buildx
Docker Buildx 使用 BuildKit 功能扩展 Docker 构建能力,同时保持熟悉的命令语法。
此方法需要 docker:dind 服务。
构建基础镜像
要使用 Buildx 构建 Docker 镜像,配置您的作业使用 docker:dind 服务并创建 buildx 构建器。
例如:
variables:
DOCKER_TLS_CERTDIR: "/certs"
build-image:
image: docker:latest
services:
- docker:dind
stage: build
before_script:
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
- docker buildx create --use --driver docker-container --name builder
- docker buildx inspect --bootstrap
script:
- docker buildx build --tag $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA --push .
after_script:
- docker buildx rm builder构建多平台镜像
多平台构建在单个构建命令中为不同架构创建镜像。 生成的清单支持多种架构,Docker 会自动为每个部署目标选择适当的镜像。
要为多个架构构建镜像,添加 --platform 标志以指定目标架构。
例如:
variables:
DOCKER_TLS_CERTDIR: "/certs"
build-multiplatform:
image: docker:latest
services:
- docker:dind
stage: build
before_script:
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
- docker buildx create --use --driver docker-container --name multibuilder
- docker buildx inspect --bootstrap
script:
- docker buildx build
--platform linux/amd64,linux/arm64
--tag $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
--push .
after_script:
- docker buildx rm multibuilder使用构建缓存
基于注册表的缓存将构建层存储在容器注册表中以便在构建间重用。
mode=max 选项将所有层导出到缓存中,为后续构建提供最大的重用潜力。
要使用构建缓存,在您的构建命令中添加缓存选项。 例如:
variables:
DOCKER_TLS_CERTDIR: "/certs"
CACHE_IMAGE: $CI_REGISTRY_IMAGE:cache
build-with-cache:
image: docker:latest
services:
- docker:dind
stage: build
before_script:
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
- docker buildx create --use --driver docker-container --name cached-builder
- docker buildx inspect --bootstrap
script:
- docker buildx build
--cache-from type=registry,ref=$CACHE_IMAGE
--cache-to type=registry,ref=$CACHE_IMAGE,mode=max
--tag $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
--push .
after_script:
- docker buildx rm cached-builderNative BuildKit
使用原生 BuildKit buildctl 命令来更精细地控制构建过程。
此方法需要 docker:dind 服务。
要直接使用 BuildKit,配置您的作业使用 BuildKit 镜像和 docker:dind 服务。
例如:
variables:
DOCKER_TLS_CERTDIR: "/certs"
build-with-buildkit:
image: moby/buildkit:latest
services:
- docker:dind
stage: build
before_script:
- mkdir -p ~/.docker
- echo "{\"auths\":{\"$CI_REGISTRY\":{\"username\":\"$CI_REGISTRY_USER\",\"password\":\"$CI_REGISTRY_PASSWORD\"}}}" > ~/.docker/config.json
script:
- |
buildctl build \
--frontend dockerfile.v0 \
--local context=. \
--local dockerfile=. \
--output type=image,name=$CI_REGISTRY_IMAGE:$CI_COMMIT_SHA,push=true故障排除
构建因认证错误失败
如果您遇到注册表认证失败:
- 验证
CI_REGISTRY_USER和CI_REGISTRY_PASSWORD变量是否可用。 - 检查您是否有推送到目标注册表的权限。
- 对于外部注册表,确保认证凭据在项目的 CI/CD 变量中正确配置。
Rootless 构建因权限错误失败
对于 rootless 模式中的权限相关问题:
- 确保
BUILDKITD_FLAGS: --oci-worker-no-process-sandbox已设置。 - 验证 GitLab Runner 已分配足够的资源。
- 检查您的
Dockerfile中是否尝试了特权操作。
多平台构建失败
对于多平台构建问题:
- 验证您的
Dockerfile中的基础镜像是否支持目标架构。 - 检查所有目标平台的架构特定依赖是否可用。
- 考虑在您的
Dockerfile中使用条件语句进行架构特定逻辑。