기술나눔

docker buildx를 사용하여 크로스 플랫폼 이미지 빌드

2024-07-12

한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina

buildx는 Docker에서 공식적으로 제공하는 빌드 도구로, 사용자가 Docker 이미지를 빠르고 효율적으로 빌드하는 데 도움을 주며 다양한 플랫폼 구축을 지원합니다. buildx를 사용하면 사용자는 여러 빌드 명령을 수동으로 작동할 필요 없이 단일 명령으로 x86 및 arm 아키텍처와 같은 여러 아키텍처에 대한 이미지를 빌드할 수 있습니다. 또한 buildx는 Dockerfile의 다단계 구성 및 캐싱도 지원하므로 이미지 구성의 효율성과 속도를 크게 향상시킬 수 있습니다.

buildx는 Docker 빌드를 관리하는 CLI 플러그인입니다. 기본 계층은 BuildKit을 사용하여 Docker 빌드 기능을 확장합니다.

BuildKit은 Docker가 공식적으로 제공하는 고성능 빌드 엔진으로, Docker의 원래 빌드 엔진을 대체하는 데 사용할 수 있습니다. 원래 엔진과 비교하여 BuildKit은 더 빠른 빌드 속도, 더 높은 병렬성, 더 적은 리소스 사용량 및 더 나은 보안을 제공합니다.

buildx를 설치하고 사용하려면 Docker 엔진 버전 번호가 19.03 이상입니다.

크로스 플랫폼 이미지 구축 전략

빌더는 크로스 플랫폼 이미지 구축을 위한 다양한 전략을 지원합니다.

커널에서 QEMU 에뮬레이션 지원 사용

Docker Desktop을 사용하는 경우 QEMU는 이미 지원되며 크로스 플랫폼 이미지를 구축하기 위한 가장 간단한 전략입니다. 원래 Dockerfile을 변경할 필요가 없습니다. BuildKit은 Linux 커널 함수 binfmt_misc를 통해 크로스 플랫폼 프로그램 실행을 구현합니다.

작동 원리:

QEMU는 다양한 CPU 아키텍처를 시뮬레이션할 수 있는 프로세서 시뮬레이터입니다. buildx에서 QEMU는 빌드 프로세스 중에 비네이티브 아키텍처에 대한 바이너리를 실행하는 데 사용됩니다. 예를 들어 x86 호스트에서 ARM 이미지를 빌드할 때 QEMU는 ARM 환경을 에뮬레이트하고 ARM 바이너리를 실행할 수 있습니다.

binfmt_misc는 사용자가 실행 파일 형식과 해당 인터프리터를 등록할 수 있도록 하는 Linux 커널의 모듈입니다.커널이 알 수 없는 형식의 실행 파일을 발견하면 binfmt_misc를 사용하여 파일 형식(이 경우 QEMU)과 관련된 인터프리터를 찾고 파일을 실행합니다. . 이 기능은 rk3568 플랫폼에서는 꺼져 있습니다.

QEMU와 binfmt_misc의 조합은 buildx를 통해 크로스 플랫폼 구축을 가능하게 합니다. 이를 통해 실제 대상 하드웨어를 소유하지 않고도 다른 아키텍처의 호스트에 하나의 아키텍처에 대한 Docker 이미지를 구축할 수 있습니다.

Docker Desktop은 다른 플랫폼에 대한 binfmt_misc 지원으로 사전 구성되어 있지만 다른 Docker 버전의 경우 지원을 위해 권한 있는 컨테이너를 시작하려면 tonistiigi/binfmt 이미지를 사용해야 할 수도 있습니다.

docker run --privileged --rm tonistiigi/binfmt --install all

이 명령을 실행하면 다양한 아키텍처의 해석기 프로그램, 즉 qemu 시뮬레이터가 /usr/bin 디렉터리에 설치됩니다.

binfmt_misc 모듈은 컴파일 서버에 로드됩니다.

qemu를 사용하는 docker buildx의 역할

Docker Buildx는 다중 노드, qemu 등의 사용을 포함하여 Docker의 빌드 기능을 확장하는 Docker의 실험적 기능입니다. QEMU는 다양한 CPU 및 기타 하드웨어를 시뮬레이션할 수 있는 오픈 소스 가상 머신 소프트웨어로, 하나의 운영 체제에서 다른 운영 체제의 이미지를 구축할 수 있습니다.

Docker Buildx의 qemu 기능을 사용하면 다양한 아키텍처(예: ARM, MIPS 등)에 대한 Docker 이미지를 구축하는 데 도움이 될 수 있습니다.

다음은 Docker Buildx 및 QEMU를 사용하여 ARM 아키텍처용 Docker 이미지를 빌드하는 방법을 보여주는 간단한 예입니다.

  1. # 创建一个新的 buildkit 实例
  2. docker buildx create --name mybuilder --use
  3. # 启动 buildkit 实例
  4. docker buildx start mybuilder
  5. # 启用 QEMU 驱动支持
  6. docker buildx inspect --bootstrap
  7. # 构建一个面向 ARM 架构的 Docker 镜像
  8. docker buildx build --platform linux/arm/v7 -t myimage:latest .

이 예에서는--platform 매개변수는 우리가 빌드하려는 대상 플랫폼이 ARM v7임을 지정합니다. 이러한 방식으로 Docker는 QEMU를 사용하여 ARM 환경을 시뮬레이션하고 x86 아키텍처 시스템에서 ARM 아키텍처용 Docker 이미지를 구축합니다.

binfmt_misc 파일 시스템

binfmt-misc는 리눅스 커널에서 제공하는 기능으로 윈도우의 파일 연결과 유사하지만, 파일 연결보다 더 강력한 점은 파일 접미사 이름으로 판단할 수 있을 뿐만 아니라 기반으로 다른 프로그램으로 열 수도 있다는 점이다. 파일 내용(Magic Bytes)에 . 일반적인 사용 시나리오는 qemu를 사용하여 다른 아키텍처 플랫폼에서 바이너리 파일을 실행하는 것입니다.

binfmt-기타 활성화

일시적으로 활성화하려면 다음 명령을 사용하십시오.

$ sudo mount binfmt_misc -t binfmt_misc /proc/sys/fs/binfmt_misc

이 방법은 다시 시작한 후에는 유효하지 않게 됩니다. 오랫동안 적용하려면 /etc/fstab 파일에 다음 줄을 추가하면 됩니다.

none  /proc/sys/fs/binfmt_misc binfmt_misc defaults 0 0

다음 명령을 사용하여 열기가 성공했는지 확인할 수 있습니다.

  1. $ mount | grep binfmt_misc
  2. binfmt_misc on /proc/sys/fs/binfmt_misc type binfmt_misc (rw,relatime)
  3. $ ls -l /proc/sys/fs/binfmt_misc
  4. 总用量 0
  5. --w------- 1 root root 0 25 22:55 register
  6. -rw-r--r-- 1 root root 0 25 22:55 status

먼저 arm64 아키텍처로 프로그램을 준비하고 나면 오류가 보고됩니다.

bash: ./go-test:无法执行二进制文件: 可执行文件格式错误

이제 apt install qemu-user-binfmt 명령을 실행한 후, 위의 arm64 프로그램을 실행하여 정상적으로 실행되는지 확인해보자. qemu-user-binfmt를 설치하면 qemu-aarch64를 포함하여 /proc/sys/fs/binfmt_misc 디렉터리에 여러 파일이 생성됩니다.

  1. root@ubuntu:/proc/sys/fs/binfmt_misc# cat qemu-aarch64
  2. enabled
  3. interpreter /usr/bin/qemu-aarch64-static
  4. flags: OC
  5. offset 0
  6. magic 7f454c460201010000000000000000000200b700
  7. mask ffffffffffffff00fffffffffffffffffeffffff
  8. root@ubuntu:/proc/sys/fs/binfmt_misc#

이 파일은 규칙 파일을 설명합니다.

활성화된 첫 번째 줄은 규칙이 활성화되었음을 나타냅니다.

두 번째 줄 해석기 /usr/bin/qemu-aarch64-static은 /usr/bin/qemu-aarch64-static을 사용하여 바이너리 파일을 실행함을 나타냅니다.

세 번째 줄: OC는 실행 플래그를 나타내며 구체적인 의미는 다음과 같습니다.

P: Preserve-argv를 나타내며, 이는 시뮬레이터를 호출할 때 원래 매개변수(argv)가 보존됨을 의미합니다.이는 자동 프로그램이 런타임 시 자신의 이름(예: argv[0])을 알아야 하는 상황에 유용합니다.

O: 오프셋을 나타냅니다. 이는 시뮬레이터를 시작하기 전에 바이너리 파일에서 오프셋을 읽어야 하며 이 오프셋이 시뮬레이터의 매개변수로 사용된다는 의미입니다.

C: 자격 증명을 의미합니다. 이는 에뮬레이터가 원래 프로그램에서 사용된 것과 동일한 사용자 ID 및 그룹 ID로 실행된다는 의미입니다. 이는 에뮬레이터가 원래 프로그램과 동일한 권한으로 실행되도록 하는 데 도움이 됩니다.

네 번째 줄: 오프셋 0은 0 값에서 파일 읽기 시작을 의미합니다.

다섯 번째 줄: Magic 7f454c460201010000000000000000000200b700은 일치시킬 모듈로 바이트를 나타냅니다.

arm64 아키텍처의 ELF 파일 헤더에 있는 매직 필드는 다음과 같습니다. 이는 binfmt_misc 파일 시스템이 ELF 파일의 매직 필드를 기반으로 파일을 실행하는 데 사용할 아키텍처 시뮬레이터를 결정할 수 있음을 의미합니다.

아래에는 서로 다른 두 가지 아키텍처가 있습니다.

밉스 아키텍처: 7f454c4601020100000000000000000000020008
arm64 아키텍처: 7f454c460201010000000000000000000200b700

6행: 마스크 ffffffffffffff00ffffffffffffffffffffff는 파일에서 중요하지 않은 일부 바이트를 무시하는 데 사용할 수 있는 바이트 마스크를 나타냅니다.

x86_64 시스템에서 arm64 아키텍처 Docker 이미지 실행

이제 우리는도커이 명령은 arm64 이미지를 실행합니다.

  1. $ docker run -it arm64v8/ubuntu bash
  2. Unable to find image 'arm64v8/ubuntu:latest' locally
  3. latest: Pulling from arm64v8/ubuntu
  4. 005e2837585d: Pull complete
  5. Digest: sha256:ba545858745d6307f0d1064d0d25365466f78d02f866cf4efb9e1326a4c196ca
  6. Status: Downloaded newer image for arm64v8/ubuntu:latest
  7. standard_init_linux.go:207: exec user process caused "no such file or directory"

몇 가지 탐색 후에 다음 명령을 실행하는 한 발견했습니다.apt install qemu-user-static, 그런 다음 도커를 시작하세요.컨테이너정상입니다.

Dockerfile에서 다단계 교차 빌드 사용

크로스 컴파일의 복잡성은 Docker에 있는 것이 아니라 프로그램 자체에 있습니다. 예를 들어, Go 프로그램은 쉽게 크로스 컴파일될 수 있습니다. go build를 사용하여 프로그램을 빌드할 때 GOOS와 GOARCH 두 가지 환경 변수만 실행하면 됩니다.

빌더 생성

buildx를 사용하여 크로스 플랫폼 이미지를 빌드하려면 먼저 빌더로 변환할 수 있는 빌더를 만들어야 합니다.

빌더 목록을 보려면 docker buildx ls 명령을 사용하십시오.

  1. root@ubuntu:/proc# docker buildx ls
  2. NAME/NODE DRIVER/ENDPOINT STATUS PLATFORMS
  3. mybuild * docker-container
  4. mybuild0 unix:///var/run/docker.sock running linux/arm64*, linux/amd64, linux/amd64/v2, linux/amd64/v3, linux/amd64/v4, linux/386
  5. vigilant_hugle docker-container
  6. vigilant_hugle0 unix:///var/run/docker.sock stopped
  7. default docker
  8. default default running linux/amd64, linux/386

* 기호는 현재 사용 중인 빌더를 나타냅니다. docker build 명령을 실행할 때 이 빌더를 사용하여 이미지를 빌드합니다. 두 번째 열의 DRIVER/ENDPOINT는 사용된 드라이버를 나타냅니다. buildx는 다음 드라이버를 지원합니다.

  • docker: Docker 설치 후 기본 BuildKit인 Docker 데몬에 번들로 제공되는 BuildKit 라이브러리를 사용합니다.
  • docker-container: Docker를 사용하여 새로운 전용 BuildKit 컨테이너를 만듭니다.
  • kubernetes: kubernetes 클러스터에 BuildKit 포드를 생성합니다.
  • 원격: 수동으로 관리되는 BuildKit 데몬에 직접 연결합니다.

docker 드라이버를 사용하는 기본 빌더는 단일 명령을 사용하여 크로스 플랫폼 이미지 빌드를 지원하지 않기 때문에(기본 빌더의 --platform 매개변수는 단일 값만 허용함) docker-container 드라이버를 사용하여 새 빌더를 생성해야 합니다. .

명령 구문은 다음과 같습니다.

$ docker buildx create --name=<builder-name> --driver=<driver> --driver-opt=<driver-options>

매개변수의 의미는 다음과 같습니다.

--name: 생성된 이름, 필수입니다.

--driver: 빌더 드라이버, 기본값은 docker-container입니다.

--driver-opt: 드라이버 옵션. 예를 들어 --driver-opt=image=moby/buildkit:v0.11.3 옵션은 지정된 BuildKit 버전을 설치할 수 있습니다. 기본값은 moby/buildkit입니다.

다음 명령을 사용하여 새 빌더를 만들 수 있습니다.

  1. $ docker buildx create --name mybuilder
  2. mybuilder

빌더 목록을 다시 확인하세요.

  1. $ docker buildx ls
  2. NAME/NODE DRIVER/ENDPOINT STATUS BUILDKIT PLATFORMS
  3. mybuilder * docker-container
  4. mybuilder0 unix:///var/run/docker.sock inactive
  5. default docker
  6. default default running 20.10.21 linux/arm64, linux/amd64, linux/riscv64, linux/ppc64le, linux/s390x, linux/386, linux/arm/v7, linux/arm/v6
  7. desktop-linux docker
  8. desktop-linux desktop-linux running 20.10.21 linux/arm64, linux/amd64, linux/riscv64, linux/ppc64le, linux/s390x, linux/386, linux/arm/v7, linux/arm/v6

선택한 빌드가 Mybuilder로 전환된 것을 확인할 수 있습니다. 선택되어 있지 않은 경우 docker buildx use mybuilder 명령을 수동으로 사용하여 빌더를 전환해야 합니다.

빌더 시작

새로 생성된 mybuilder는 현재 비활성 상태이므로 사용하려면 먼저 시작해야 합니다.

  1. $ docker buildx inspect --bootstrap mybuilder
  2. [+] Building 16.8s (1/1) FINISHED
  3. => [internal] booting buildkit 16.8s
  4. => => pulling image moby/buildkit:buildx-stable-1 16.1s
  5. => => creating container buildx_buildkit_mybuilder0 0.7s
  6. Name: mybuilder
  7. Driver: docker-container
  8. Nodes:
  9. Name: mybuilder0
  10. Endpoint: unix:///var/run/docker.sock
  11. Status: running
  12. Buildkit: v0.9.3
  13. Platforms: linux/arm64, linux/amd64, linux/riscv64, linux/ppc64le, linux/s390x, linux/386, linux/mips64le, linux/mips64, linux/arm/v7, linux/arm/v6

검사 하위 명령은 빌드 상태를 확인하는 데 사용됩니다. mybuilder 빌더를 시작하려면 mybuilder 상태가 실행 중으로 변경되었습니다.

  1. $ docker buildx ls
  2. NAME/NODE DRIVER/ENDPOINT STATUS BUILDKIT PLATFORMS
  3. mybuilder * docker-container
  4. mybuilder0 unix:///var/run/docker.sock running v0.9.3 linux/arm64, linux/amd64, linux/riscv64, linux/ppc64le, linux/s390x, linux/386, linux/mips64le, linux/mips64, linux/arm/v7, linux/arm/v6
  5. default docker
  6. default default running 20.10.21 linux/arm64, linux/amd64, linux/riscv64, linux/ppc64le, linux/s390x, linux/386, linux/arm/v7, linux/arm/v6
  7. desktop-linux docker
  8. desktop-linux desktop-linux running 20.10.21 linux/arm64, linux/amd64, linux/riscv64, linux/ppc64le, linux/s390x, linux/386, linux/arm/v7, linux/arm/v6

PLATFORMS 열에 표시되는 값

linux/arm64, linux/amd64, linux/riscv64, linux/ppc64le, linux/s390x, linux/386, linux/mips64le, linux/mips64, linux/arm/v7, linux/arm/v6은 현재 빌더에서 지원됩니다. 모두 플랫폼.

이제 docker ps 명령을 사용하여 mybuilder 빌더에 해당하는 BuildKit 컨테이너가 시작되었는지 확인합니다.

  1. $ docker ps
  2. CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
  3. b8887f253d41 moby/buildkit:buildx-stable-1 "buildkitd" 4 minutes ago Up 4 minutes buildx_buildkit_mybuilder0

이 컨테이너는 크로스 플랫폼 이미지를 구축하는 데 사용됩니다. 수동으로 삭제하지 마세요.

빌더를 사용하여 크로스 플랫폼 이미지 빌드

$ docker buildx build --platform linux/arm64,linux/amd64 -t jianghushinian/hello-go .

docker buildx build의 구문은 docker build의 구문과 동일합니다. --platform 매개변수는 이미지 빌드를 위한 대상 플랫폼을 나타내고, -t는 이미지의 태그를 나타냅니다. .는 컨텍스트가 현재 디렉터리임을 나타냅니다.。 

작동하지 않는 유일한 것은 --platform 매개변수에 대한 지원입니다. docker build의 --platform 매개변수는 --platform linux/arm64와 같은 하나의 플랫폼 정보 전달만 지원합니다. 즉, 단일 플랫폼 이미지는 한 번에 구축할 수 있습니다.

docker buildx build를 사용하여 이미지를 빌드하면 여러 플랫폼 정보를 동시에 영어 쉼표로 구분하여 전송할 수 있으므로 단 하나의 명령으로 여러 크로스 플랫폼 이미지를 빌드하는 기능을 실현할 수 있습니다.

위의 명령을 실행하면 다음과 같은 경고가 표시됩니다.

WARNING: No output specified with docker-container driver. Build result will only remain in the build cache. To push result image into registry use --push or to load image into docker use --load

이 경고는 docker-container 드라이버에 대한 출력을 지정하지 않았음을 상기시켜줍니다. 생성된 결과는 빌드 캐시에만 보관됩니다. 이미지를 Docker Hub 원격 저장소에 푸시하고 --load를 사용하세요. 이미지를 로컬에 저장합니다.

이는 새로 생성된 mybuilder가 BuildKit을 실행하기 위해 컨테이너를 시작하기 때문입니다. 빌드된 크로스 플랫폼 이미지를 로컬 시스템에 직접 출력하거나 사용자가 출력 위치를 수동으로 지정해야 합니다.

--load를 지정하여 로컬 호스트에 이미지를 저장할 수 있습니다.

  1. $ docker buildx build --platform linux/arm64,linux/amd64 -t jianghushinian/hello-go . --load
  2. [+] Building 0.0s (0/0)
  3. ERROR: docker exporter does not currently support exporting manifest lists

결과는 오류 로그입니다. 크로스 플랫폼 이미지를 로컬로 내보내는 것을 지원하지 않는 것 같습니다. 이는 실제로 여러 개의 --platform이 하나의 플랫폼만 전달하는 경우 --load를 사용하여 빌드된 이미지를 출력할 수 있습니다. 기계.

그런 다음 --push 매개변수를 통해서만 크로스 플랫폼 이미지를 원격 창고에 푸시할 수 있습니다. 단, 이 작업을 수행하기 전에 반드시 docker login을 사용하여 로그인을 완료해야 합니다.

$ docker buildx build --platform linux/arm64,linux/amd64 -t jianghushinian/hello-go . --push

이제 Docker Hub에 로그인하면 푸시된 크로스 플랫폼 이미지를 볼 수 있습니다.

또한 Imagestools를 사용하여 크로스 플랫폼 이미지의 매니페스트 정보를 확인할 수도 있습니다. 이 명령은 웨어하우스의 이미지 정보를 얻는 데만 사용할 수 있으며 로컬 이미지는 볼 수 없습니다.

  1. $ docker buildx imagetools inspect jianghushinian/hello-go
  2. Name: docker.io/jianghushinian/hello-go:latest
  3. MediaType: application/vnd.docker.distribution.manifest.list.v2+json
  4. Digest: sha256:51199dadfc55b23d6ab5cfd2d67e38edd513a707273b1b8b554985ff562104db
  5. Manifests:
  6. Name: docker.io/jianghushinian/hello-go:latest@sha256:8032a6f23f3bd3050852e77b6e4a4d0a705dfd710fb63bc4c3dc9d5e01c8e9a6
  7. MediaType: application/vnd.docker.distribution.manifest.v2+json
  8. Platform: linux/arm64
  9. Name: docker.io/jianghushinian/hello-go:latest@sha256:fd46fd7e93c7deef5ad8496c2cf08c266bac42ac77f1e444e83d4f79d58441ba
  10. MediaType: application/vnd.docker.distribution.manifest.v2+json
  11. Platform: linux/amd64

 

보시다시피 이 크로스 플랫폼 이미지에는 linux/arm64 및 linux/amd64라는 두 가지 대상 플랫폼의 이미지가 포함되어 있습니다.