正式なドキュメントは英語版であり、この日本語訳はAI支援翻訳により作成された参考用のものです。日本語訳の一部の内容は人間によるレビューがまだ行われていないため、翻訳のタイミングにより英語版との間に差異が生じることがあります。最新かつ正確な情報については、英語版をご参照ください。

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:dinddocker buildx使い慣れたDockerワークフロー
ネイティブBuildKit以下が必要ですdocker:dindbuildctlBuildKitの詳細な制御

前提要件

  • 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: レジストリURL
  • CI_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=true

BuildKitの代替メソッド

ルートレスビルドが不要な場合、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で条件ステートメントを使用することを検討してください。