Profile picture

[Docker] 멀티 아키텍처 플랫폼 - Buildx (Docker Multi-Archtecture image)

JaehyoJJAng2023년 04월 12일

멀티 아키텍처 플랫폼

나의 경우 맥북 환경에서 fastAPI 프로젝트를 도커로 이미지화 시킨 후 윈도우에서 해당 도커 이미지를 받아와 실행시키니 아래와 같은 에러 로그가 컨테이너 로그에 출력되었다.

$ docker logs app
exec user process caused “exec format error” 

원인은 운영체제 차이인데 멀티 플랫폼 빌드를 사용하여 쉽게 해결할 수 있다.


이미지의 실행 환경(CPU Archtecture)가 다르기 때문에 발생하는 에러이기 때문에(Mac m1 : ARM) 맥북에서 빌드한 이미지가 다양한 플랫폼에서 지원될 수 있도록 빌드 시 옵션을 지정해주어야 한다.
image


Buildx

Docker는 Multi-Archtecture 빌드 등 다양한 빌드 옵션을 지원하는 CLI 플러그인을 제공하고 있다.

Buildx의 경우 Docker 19.03 버전 이후부터 사용이 가능하다고 하니 멀티 아키텍처 빌드 전 도커의 버전을 확인해봐야 한다.

Docker Desktop을 사용하는 윈도우나 MacOS 사용자 혹은 DEB,RPM 패키지로 도커를 설치한 사용자들은 자동으로 Buildx 플러그인이 내장되어 있다.


사용 가능한지 체크

docker buildx 명령어를 터미널에 입력했을 때 아래와 같은 buildx 사용법이 제대로 출력된다면 buildx를 사용할 수 있는 것이다.

$ docker buildx
Usage:  docker buildx [OPTIONS] COMMAND

Extended build capabilities with BuildKit

Options:
      --builder string   Override the configured builder instance

Management Commands:
  imagetools  Commands to work on images in registry

Commands:
  bake        Build from a file
  build       Start a build
  create      Create a new builder instance
  du          Disk usage
  inspect     Inspect current builder instance
  ls          List builder instances
  prune       Remove build cache
  rm          Remove a builder instance
  stop        Stop builder instance
  use         Set the current builder instance
  version     Show buildx version information

Run 'docker buildx COMMAND --help' for more information on a command.

일부 하위 버전에서 buildx 플러그인을 사용하려면 ~/.docker/config.json 파일에 아래의 옵션을 추가해주어야 한다.

$ cat ~/.docker/config.json
{
    ...
    "experimental": "enabled"
}

플랫폼 종류 확인

나는 M1 맥북에서 Docker Desktop을 사용하고 있는데, Docker Desktop에서는 이미 자주 사용되는 플랫폼의 환경설정이 되어있다.

터미널에서 docker buildx ls로 Docke Desktop에서 이미 제공하는 플랫폼들의 종류를 확인할 수 있다

$ docker buildx ls
NAME/NODE             DRIVER/ENDPOINT  STATUS  BUILDKIT PLATFORMS
awesome_goldwasser *  docker-container
  awesome_goldwasser0 desktop-linux    running v0.12.2  linux/arm64, linux/amd64, linux/amd64/v2, linux/riscv64, linux/ppc64le, linux/s390x, linux/386, linux/mips64le, linux/mips64, linux/arm/v7, linux/arm/v6
default               docker
  default             default          running 20.10.22 linux/arm64, linux/amd64, linux/riscv64, linux/ppc64le, linux/s390x, linux/386, linux/arm/v7, linux/arm/v6
desktop-linux         docker
  desktop-linux       desktop-linux    running 20.10.22 linux/arm64, linux/amd64, linux/riscv64, linux/ppc64le, linux/s390x, linux/386, linux/arm/v7, linux/arm/v6

Builder 생성 및 사용 설정

$ docker buildx create --name [builder instance 명] --driver [드라이버 이름] --use
# multi-arch-builder로 사용 설정
$ docker buildx create --name multi-arch-builder --driver docker-container --use
multi-arch-builder

# 현재 Builder Instance 정보
$ docker buildx inspect --bootstrap
Name:          awesome_goldwasser
Driver:        docker-container
Last Activity: 2023-10-05 22:15:58 +0000 UTC

Nodes:
Name:      awesome_goldwasser0
Endpoint:  desktop-linux
Status:    running
Buildkit:  v0.12.2
Platforms: linux/arm64, linux/amd64, linux/amd64/v2, linux/riscv64, linux/ppc64le, linux/s390x, linux/386, linux/mips64le, linux/mips64, linux/arm/v7, linux/arm/v6

Buildx로 이미지 빌드하기

Buildx를 사용하여 멀티 플랫폼 이미지를 만들어보자.

Example

$ docker buildx build --platform=linux/amd64,linux/arm64

fastapi 프로젝트를 amd64 플랫폼 이미지로 빌드

$ docker buildx build --platform linux/amd64 --load --tag yshrim12/app:latest .
[+] Building 19.0s (11/11) FINISHED
 => [internal] load build definition from Dockerfile                                                0.0s
 => => transferring dockerfile: 267B                                                                0.0s
 => [internal] load metadata for docker.io/library/python:3.10                                      0.9s
 => [internal] load .dockerignore                                                                   0.0s
 => => transferring context: 2B                                                                     0.0s
 => [1/5] FROM docker.io/library/python:3.10@sha256:1e5e9ee5b5d12ec9c803eb6166ae4862641d21ed259d08  0.0s
 => => resolve docker.io/library/python:3.10@sha256:1e5e9ee5b5d12ec9c803eb6166ae4862641d21ed259d08  0.0s
 => [internal] load build context                                                                   0.0s
 => => transferring context: 141B                                                                   0.0s
 => CACHED [2/5] WORKDIR /usr/src/app                                                               0.0s
 => CACHED [3/5] COPY ./requirements/*.txt ./requirements.txt                                       0.0s
 => CACHED [4/5] RUN pip install --upgrade pip && pip install -r requirements.txt                   0.0s
 => CACHED [5/5] COPY ./ ./                                                                         0.0s
 => exporting to docker image format                                                               18.0s
 => => exporting layers                                                                             0.0s
 => => exporting manifest sha256:742645be226bfb66783ca6c087834bce6d264a3d548bce21eb6fb036d043fa36   0.0s
 => => exporting config sha256:7305650367e00c5711ae8a09e199d4b2b9b19dec271de82819e462d966b4318e     0.0s
 => => sending tarball                                                                             18.0s
 => importing to docker

--platform=linux/amd64,linux/arm64 : amd64arm64를 모두 지원하는 이미지로 빌드

--load : 이미지를 만들고 호스트의 docker image에 저장

--push : --load 옵션과 반대로 docker registry로 바로 Push 함.

이미지 실행 및 확인

# 도커 이미지 확인
$ docker images | grep 'fastapi'
yshrim12/app                             latest            7305650367e0   39 minutes ago   1.03GB

# 이미지 컨테이너로 실행
$ docker run -d -it --name fastapi -p 80:8080 yshrim12/app 

# 아키텍처 확인
$ docker exec -it fastapi dpkg -s libc6 | grep 'Arch'
Architecture: amd64
Multi-Arch: same

Loading script...