BuildKitでDockerイメージを作成
- プラン: Free、Premium、Ultimate
- 提供形態: GitLab.com、GitLab Self-Managed、GitLab Dedicated
BuildKitは、Dockerが使用するビルドエンジンであり、マルチプラットフォームのビルドとビルドキャッシュを提供します。
BuildKitのメソッド
BuildKitには、Dockerイメージをビルドするための次のメソッドがあります:
| メソッド | セキュリティ要件 | コマンド | 必要な場合 |
|---|---|---|---|
| BuildKitルートレス | 特権コンテナなし | buildctl-daemonless.sh | 最大限のセキュリティ、またはKanikoの代替 |
| Docker Buildx | 以下が必要ですdocker:dind | docker buildx | 使い慣れたDockerワークフロー |
| ネイティブBuildKit | 以下が必要ですdocker:dind | buildctl | BuildKitの詳細な制御 |
前提要件
- Docker executorを使用するGitLab Runner
- Docker Buildxを使用するには、Docker 19.03以降が必要です
Dockerfileを使用したプロジェクト
BuildKitルートレス
スタンドアロンモードのBuildKitは、Dockerデーモンの依存関係なしに、ルートレスイメージのビルドを提供します。この方法では、特権コンテナが完全に排除され、Kanikoビルドの直接的な代替手段が提供されます。
他の方法との主な違い:
moby/buildkit:rootlessイメージを使用- ルートレス操作のために
BUILDKITD_FLAGS: --oci-worker-no-process-sandboxを含める buildctl-daemonless.shを使用して、BuildKitデーモンを自動的に管理する- Dockerデーモンまたは特権コンテナの依存関係なし
- 手動レジストリ認証の設定が必要
コンテナレジストリで認証する
GitLab CI/CDは、定義済み変数を介して、GitLabコンテナレジストリの自動認証を提供します。BuildKitルートレスの場合は、Docker設定ファイルを手動で作成する必要があります。
GitLabコンテナレジストリを使用して認証する
GitLabは、これらの定義済み変数を自動的に提供します:
CI_REGISTRY: レジストリURLCI_REGISTRY_USER: レジストリユーザー名CI_REGISTRY_PASSWORD: レジストリパスワード
ルートレスビルドの認証を構成するには、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内で認証するを参照してください。
ルートレスモードでイメージをビルドする
Dockerデーモンの依存関係なしにイメージをビルドするには、この例のようなジョブを追加します:
build-rootless:
image:
name: moby/buildkit:rootless
entrypoint: [""]
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ルートレスモードでマルチプラットフォームイメージをビルドする
ルートレスモードで複数のアーキテクチャのイメージをビルドするには、ターゲットプラットフォームを指定するようにジョブを構成します。例:
build-multiarch-rootless:
image:
name: moby/buildkit:rootless
entrypoint: [""]
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ルートレスモードでキャッシュを使用する
後続のビルドを高速化するためにレジストリベースのキャッシュを有効にするには、ビルドジョブでキャッシュのインポートとエクスポートを構成します。例:
build-cached-rootless:
image:
name: moby/buildkit:rootless
entrypoint: [""]
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ルートレスモードでレジストリミラーを使用する
レジストリミラーを使用すると、イメージのプルが高速化され、レート制限やネットワーク制限に役立ちます。
レジストリミラーを構成するには、ミラーエンドポイントを指定するbuildkit.tomlファイルを作成します。例:
build-mirror-rootless:
image:
name: moby/buildkit:rootless
entrypoint: [""]
stage: build
variables:
BUILDKITD_FLAGS: --oci-worker-no-process-sandbox --config /tmp/buildkit.toml
before_script:
- mkdir -p ~/.docker
- echo "{\"auths\":{\"$CI_REGISTRY\":{\"username\":\"$CI_REGISTRY_USER\",\"password\":\"$CI_REGISTRY_PASSWORD\"}}}" > ~/.docker/config.json
- cat <<'EOF' > /tmp/buildkit.toml
[registry."docker.io"]
mirrors = ["mirror.example.com"]
EOF
script:
- |
buildctl-daemonless.sh build \
--frontend dockerfile.v0 \
--local context=. \
--local dockerfile=. \
--output type=image,name=$CI_REGISTRY_IMAGE:$CI_COMMIT_SHA,push=trueこの例では、mirror.example.comをレジストリミラーURLに置き換えます。
プロキシ設定を構成する
GitLab RunnerがHTTP(S) プロキシの背後で動作する場合は、ジョブで変数としてプロキシ設定を構成します。例:
build-behind-proxy:
image:
name: moby/buildkit:rootless
entrypoint: [""]
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証明書を追加する
カスタムCA証明書を使用してレジストリにプッシュするには、ビルドする前にコンテナの証明書ストアに証明書を追加します。例:
build-with-custom-certs:
image:
name: moby/buildkit:rootless
entrypoint: [""]
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ルートレスは、Kanikoの安全な代替手段です。パフォーマンスの向上、キャッシュの改善、セキュリティ機能の強化を実現しながら、ルートレス操作を維持します。
設定を更新
BuildKitルートレスメソッドを使用するように、既存のKaniko構成を更新します。例:
前: 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ルートレスを使用:
build:
image:
name: moby/buildkit:rootless
entrypoint: [""]
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=trueBuildKitの代替メソッド
ルートレスビルドが不要な場合、BuildKitにはdocker:dindサービスを必要とする追加のメソッドが用意されていますが、使い慣れたワークフローまたは高度な機能が提供されます。
Docker Buildx
Docker Buildxは、使い慣れたコマンド構文を維持しながら、BuildKit機能を使用してDockerビルド機能を拡張します。この方法では、docker:dindサービスが必要です。
基本的なイメージをビルドする
DockerイメージをBuildxでビルドするには、docker:dindサービスでジョブを構成し、buildxビルダーを作成します。例:
variables:
DOCKER_TLS_CERTDIR: "/certs"
build-image:
image: docker:cli
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:cli
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:cli
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-builderネイティブ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変数で認証情報が正しく構成されていることを確認してください。
ルートレスビルドが権限エラーで失敗する
ルートレスモードでの権限関連の問題の場合:
BUILDKITD_FLAGS: --oci-worker-no-process-sandboxが設定されていることを確認してください。- GitLab Runnerに十分なリソースが割り当てられていることを確認します。
Dockerfileで特権操作が試行されていないことを確認します。
Kubernetes Runnerで[rootlesskit:child ] error: failed to share mount point: /: permission deniedが表示される場合、AppArmorはBuildKitに必要なマウントsyscallをブロックしています。
この問題を解決するには、Runner構成に以下を追加します:
[runners.kubernetes.pod_annotations]
"container.apparmor.security.beta.kubernetes.io/build" = "unconfined"エラー: invalid local: stat path/to/image/Dockerfile: not a directory
invalid local: stat path/to/image/Dockerfile: not a directoryというエラーが表示されることがあります。
この問題は、--local dockerfile=パラメータのディレクトリパスの代わりにファイルを指定すると発生します。BuildKitは、Dockerfileという名前のファイルを含むディレクトリパスを予期しています。
この問題を解決するには、ファイル全体のパスの代わりにディレクトリパスを使用します。例:
- 使用:
--local dockerfile=path/to/image - 使用しない:
--local dockerfile=path/to/image/Dockerfile
マルチプラットフォームビルドが失敗する
マルチプラットフォームビルドの問題の場合:
Dockerfileのベースイメージがターゲットアーキテクチャをサポートしていることを確認します。- アーキテクチャ固有の依存関係が、すべてのターゲットプラットフォームで使用できることを確認します。
- アーキテクチャ固有のロジックのために、
Dockerfileで条件ステートメントを使用することを検討してください。