InfoGrab Docs

BuildKit으로 Docker 이미지 빌드

요약

BuildKit은 Docker에서 사용하는 빌드 엔진으로 멀티 플랫폼 빌드와 빌드 캐싱을 제공합니다. BuildKit은 Docker 이미지를 빌드하기 위한 다음 방법을 제공합니다: 독립 실행형 모드의 BuildKit은 Docker 데몬 의존성 없이 rootless 이미지 빌드를 제공합니다.

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 이미지 사용
  • rootless 작동을 위한 BUILDKITD_FLAGS: --oci-worker-no-process-sandbox 포함
  • BuildKit 데몬을 자동으로 관리하는 buildctl-daemonless.sh 사용
  • Docker 데몬 또는 권한 있는 컨테이너 의존성 없음
  • 수동 레지스트리 인증 설정 필요

컨테이너 레지스트리 인증#

GitLab CI/CD는 사전 정의된 변수를 통해 GitLab 컨테이너 레지스트리에 대한 자동 인증을 제공합니다. BuildKit rootless의 경우 Docker 구성 파일을 수동으로 생성해야 합니다.

GitLab 컨테이너 레지스트리 인증#

GitLab은 다음과 같은 사전 정의된 변수를 자동으로 제공합니다:

  • CI_REGISTRY: 레지스트리 URL
  • CI_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:
    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

rootless 모드에서 멀티 플랫폼 이미지 빌드#

rootless 모드에서 여러 아키텍처용 이미지를 빌드하려면 대상 플랫폼을 지정하도록 작업을 구성합니다. 예를 들어:

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

rootless 모드에서 캐싱 사용#

후속 빌드를 더 빠르게 하기 위한 레지스트리 기반 캐싱을 활성화하려면 빌드 작업에서 캐시 가져오기 및 내보내기를 구성합니다. 예를 들어:

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

rootless 모드에서 레지스트리 미러 사용#

레지스트리 미러는 이미지 가져오기를 더 빠르게 하고 속도 제한이나 네트워크 제한을 해결하는 데 도움이 됩니다.

레지스트리 미러를 구성하려면 미러 엔드포인트를 지정하는 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 인증서를 사용하는 레지스트리에 푸시하려면 빌드 전에 컨테이너의 인증서 저장소에 인증서를 추가합니다. 예를 들어:

build-with-custom-certs:
  image:
    name: moby/buildkit:rootless
    entrypoint: [""]
  stage: build
  variables:
    BUILDKITD_FLAGS: --oci-worker-no-process-sandbox
  before_script:
    - export SSL_CERT_FILE="$HOME/ca_chain.pem"
    - cat /etc/ssl/certs/ca-certificates.crt > "$SSL_CERT_FILE"
    - echo "$MY_CA_CERT" >> "$SSL_CERT_FILE"
    - 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

이 예시에서 MY_CA_CERT 변수에 루트 및 중간 인증서를 포함한 CA 인증서의 전체 내용을 입력합니다.

Kaniko에서 BuildKit으로 마이그레이션#

BuildKit rootless는 Kaniko의 안전한 대안입니다. rootless 작동을 유지하면서 향상된 성능, 더 나은 캐싱, 강화된 보안 기능을 제공합니다.

구성 업데이트#

BuildKit rootless 방법을 사용하도록 기존 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 rootless 이후:

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 방법#

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: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

Native 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_USERCI_REGISTRY_PASSWORD 변수를 사용할 수 있는지 확인합니다.
  • 대상 레지스트리에 푸시 권한이 있는지 확인합니다.
  • 외부 레지스트리의 경우 프로젝트의 CI/CD 변수에 인증 자격 증명이 올바르게 구성되어 있는지 확인합니다.

rootless 빌드가 권한 오류로 실패#

rootless 모드의 권한 관련 문제:

  • BUILDKITD_FLAGS: --oci-worker-no-process-sandbox가 설정되어 있는지 확인합니다.
  • GitLab Runner에 충분한 리소스가 할당되어 있는지 확인합니다.
  • Dockerfile에 권한 있는 작업이 시도되지 않는지 확인합니다.

Kubernetes 러너에서 [rootlesskit:child ] error: failed to share mount point: /: permission denied를 받는 경우 AppArmor가 BuildKit에 필요한 마운트 시스템 호출을 차단하고 있습니다.

이 문제를 해결하려면 러너 구성에 다음을 추가합니다:

[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에서 조건부 구문 사용을 고려합니다.

BuildKit으로 Docker 이미지 빌드

Tier: Free, Premium, Ultimate
Offering: GitLab.com, GitLab Self-Managed, GitLab Dedicated
원문 보기
요약

BuildKit은 Docker에서 사용하는 빌드 엔진으로 멀티 플랫폼 빌드와 빌드 캐싱을 제공합니다. BuildKit은 Docker 이미지를 빌드하기 위한 다음 방법을 제공합니다: 독립 실행형 모드의 BuildKit은 Docker 데몬 의존성 없이 rootless 이미지 빌드를 제공합니다.

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 이미지 사용
  • rootless 작동을 위한 BUILDKITD_FLAGS: --oci-worker-no-process-sandbox 포함
  • BuildKit 데몬을 자동으로 관리하는 buildctl-daemonless.sh 사용
  • Docker 데몬 또는 권한 있는 컨테이너 의존성 없음
  • 수동 레지스트리 인증 설정 필요

컨테이너 레지스트리 인증#

GitLab CI/CD는 사전 정의된 변수를 통해 GitLab 컨테이너 레지스트리에 대한 자동 인증을 제공합니다. BuildKit rootless의 경우 Docker 구성 파일을 수동으로 생성해야 합니다.

GitLab 컨테이너 레지스트리 인증#

GitLab은 다음과 같은 사전 정의된 변수를 자동으로 제공합니다:

  • CI_REGISTRY: 레지스트리 URL
  • CI_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:
    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

rootless 모드에서 멀티 플랫폼 이미지 빌드#

rootless 모드에서 여러 아키텍처용 이미지를 빌드하려면 대상 플랫폼을 지정하도록 작업을 구성합니다. 예를 들어:

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

rootless 모드에서 캐싱 사용#

후속 빌드를 더 빠르게 하기 위한 레지스트리 기반 캐싱을 활성화하려면 빌드 작업에서 캐시 가져오기 및 내보내기를 구성합니다. 예를 들어:

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

rootless 모드에서 레지스트리 미러 사용#

레지스트리 미러는 이미지 가져오기를 더 빠르게 하고 속도 제한이나 네트워크 제한을 해결하는 데 도움이 됩니다.

레지스트리 미러를 구성하려면 미러 엔드포인트를 지정하는 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 인증서를 사용하는 레지스트리에 푸시하려면 빌드 전에 컨테이너의 인증서 저장소에 인증서를 추가합니다. 예를 들어:

build-with-custom-certs:
  image:
    name: moby/buildkit:rootless
    entrypoint: [""]
  stage: build
  variables:
    BUILDKITD_FLAGS: --oci-worker-no-process-sandbox
  before_script:
    - export SSL_CERT_FILE="$HOME/ca_chain.pem"
    - cat /etc/ssl/certs/ca-certificates.crt > "$SSL_CERT_FILE"
    - echo "$MY_CA_CERT" >> "$SSL_CERT_FILE"
    - 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

이 예시에서 MY_CA_CERT 변수에 루트 및 중간 인증서를 포함한 CA 인증서의 전체 내용을 입력합니다.

Kaniko에서 BuildKit으로 마이그레이션#

BuildKit rootless는 Kaniko의 안전한 대안입니다. rootless 작동을 유지하면서 향상된 성능, 더 나은 캐싱, 강화된 보안 기능을 제공합니다.

구성 업데이트#

BuildKit rootless 방법을 사용하도록 기존 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 rootless 이후:

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 방법#

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: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

Native 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_USERCI_REGISTRY_PASSWORD 변수를 사용할 수 있는지 확인합니다.
  • 대상 레지스트리에 푸시 권한이 있는지 확인합니다.
  • 외부 레지스트리의 경우 프로젝트의 CI/CD 변수에 인증 자격 증명이 올바르게 구성되어 있는지 확인합니다.

rootless 빌드가 권한 오류로 실패#

rootless 모드의 권한 관련 문제:

  • BUILDKITD_FLAGS: --oci-worker-no-process-sandbox가 설정되어 있는지 확인합니다.
  • GitLab Runner에 충분한 리소스가 할당되어 있는지 확인합니다.
  • Dockerfile에 권한 있는 작업이 시도되지 않는지 확인합니다.

Kubernetes 러너에서 [rootlesskit:child ] error: failed to share mount point: /: permission denied를 받는 경우 AppArmor가 BuildKit에 필요한 마운트 시스템 호출을 차단하고 있습니다.

이 문제를 해결하려면 러너 구성에 다음을 추가합니다:

[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에서 조건부 구문 사용을 고려합니다.