-
docker 멀티 아키텍처 빌드하는 방법클라우드 2025. 5. 16. 22:54
문제 상황
docker로 이미지 빌드해서 EC2에서 실행 시키려 하였는데 CPU 아키텍처가 달라 실행되지 않았습니다.
CPU 아키텍처의 종류
크게 amd랑 arm이 있습니다.
저는 다음 블로그를 참조하면서 이해가 잘 되었습니다.
https://velog.io/@480/이제는-개발자도-CPU-아키텍처를-구분해야-합니다
문제 원인
제가 사용하는 노트북인 M1 Mac은 arm 아키텍처를 사용하여 docker build를 하였을 때 arm을 기준으로 빌드하였고, 이는 arm 명령어를 사용하여 arm CPU롤 조작하려 하기 때문에 EC2의 amd CPU에서는 동작되지 않는 것이였습니다.
해결 방법
첫번째 해결 방법은 EC2를 시작할 때 arm 아키텍처로 설정하는 방법이였습니다. arm 아키텍처인 EC2에 올려서 실행시키니 잘 동작하였습니다.
근데, arm 아키텍처 ec2는 t2.micro 같은걸 사용 못하고 처음 나오는 인스턴스 타입이 t4g.nano 였습니다. 잘 쓰이지 않아서 별로 인스턴스가 없나봅니다.
그래서 다른 방법이 없을까 하며 찾아보다 두번째 해결방법을 찾았습니다.
두번째 해결 방법은 이 글의 주제인, 멀티 아키텍처로 이미지를 빌드하여 각 환경에 맞는 CPU 아키텍처를 골라 pull 받을 수 있는 방법이였습니다.
이걸 찾은 계기는, docker hub에 올라가 있는 공식적인 이미지는 어느 아키텍처에서 pull 받고 사용해도 잘 돌아갔었고, 찾아보니 docker buildx를 사용하면 멀티 아키텍처로 빌드할 수 있다고 합니다.
이게 어떻게 가능한지 살펴보니, docker buildx는 내부에서 QEMU 라는 애뮬레이터를 활용하여 다른 CPU의 아키텍처를 흉내내면서 빌드할 수 있다고 합니다.
멀티 아키텍처 빌드 실습
간단하게 설명하겠습니다.
우선 buildx를 설치해야합니다.
curl -SL <https://github.com/docker/buildx/releases/download/v0.14.1/buildx-v0.14.1.linux-arm64> -o ~/.docker/cli-plugins/docker-buildx
저는 다음 명령어를 통해 buildx를 다운 받았고
docker buildx version
을 입력하면 버전이 나옵니다.
이후 다음 명령어를 입력했습니다.
export DOCKER_CLI_EXPERIMENTAL=enabled docker buildx create --name mybuilder --use docker buildx inspect --bootstrap
첫번째 명령어는 Experimental 기능입니다.
Docker는 안정적인 기능만 기본으로 제공하고, 빌드 확장 기능 같은 최신 실험 기능은 Experimental 모드를 켜야 쓸 수 있게 된다고 합니다.
두번째 명령어는 새로운 builder 인스턴스를 만들고 이 builder를 기본 빌더로 설정하는 명령어입니다.
세번째 명령어는 빌더를 초기화하고 상태를 점검하는 명령어 입니다. 이를 통해 멀티 아키텍처 빌드를 시작할 수 있습니다.
이제 간단한 Dockerfile을 만들겠습니다.
vi Dockerfile
입력 후
# 아주 간단한 웹 서버 FROM busybox CMD ["sh", "-c", "while true; do echo hello world; sleep 1; done"]
1초마다 hello world를 출력하는 간단한 웹서버를 만듭니다.
이를 멀티아키텍처로 빌드할것입니다.
docker buildx build --platform linux/amd64,linux/arm64 \\ -t your_dockerhub_id/hello-multiarch:latest --push .
다음 명령어를 통해 빌드합니다.
—platform 을 사용하여 arm, amd 두가지 아키텍처로 빌드가 가능합니다. 이때 주의할점은 linux/amd64, 뒤에 공백을 입력하면 명령어 실행 실패로 처리됩니다.
이렇게 빌드된 이미지가 올라간 것을 확인하고
다음 명령어를 사용하여 여러 이미지가 올라갔는지 확인해봤습니다.
docker manifest inspect your_dockerhub_id/hello-multiarch:latest
다음과 같은 결과가 나왔고 unknown이 왜 나오는지 궁금했습니다.
{ "schemaVersion": 2, "mediaType": "application/vnd.oci.image.index.v1+json", "manifests": [ { "mediaType": "application/vnd.oci.image.manifest.v1+json", "size": 480, "digest": "sha256:c7bae06bdd926540039547166f319478ba2351770c118d1a7f6f0f2bb0022a7c", "platform": { "architecture": "amd64", "os": "linux" } }, { "mediaType": "application/vnd.oci.image.manifest.v1+json", "size": 480, "digest": "sha256:3d0d5c5bc49a650ed2772ad363db37c0ed47e2450f6693f1fac0cac13c55d991", "platform": { "architecture": "arm64", "os": "linux" } }, { "mediaType": "application/vnd.oci.image.manifest.v1+json", "size": 566, "digest": "sha256:94914bbdfe90abfe3d4a979aa5da5f25da2f53d83e80af23eacaa0758b3478c4", "platform": { "architecture": "unknown", "os": "unknown" } }, { "mediaType": "application/vnd.oci.image.manifest.v1+json", "size": 566, "digest": "sha256:ad1f797ed3c87499aa489461b9cb82c7df96a405a29e790f9632a43182ff6cea", "platform": { "architecture": "unknown", "os": "unknown" } } ] }
사실 찾아보다가 궁금해서 nginx manifest도 봤는데 unknown이 나와서 찾아보니 빌드나 푸시하는 과정 중에 정상적인 플랫폼 정보를 갖지 못한 임시 이미지 레이어가 같이 등록된 것이라고 합니다.
이게 발생하는 이유는 빌드 중 생성 된 다른 중간 이미지를 정리 안하고 푸시하면 플랫폼 정보가 없는 더미 레이어도 manifest에 같이 들어가는 거라고 합니다.
이걸 필요한 amd랑 arm만 넣고 싶으면 명령어를 좀 다르게 입력해야합니다.
docker buildx build --platform linux/amd64,linux/arm64 \\ --provenance=false --sbom=false \\ -t your-docker-hub-repo/hello-multiarch:latest --push .
—provenance=false 는 출처 정보 기록 안한다는 뜻이고 —sbom=false 는 소프트웨어 보안 스캔용 메타데이터 기록 안한다는 뜻이라고 합니다.
이러면 manifest 파일이 깔끔하게 나옵니다.
{ "schemaVersion": 2, "mediaType": "application/vnd.docker.distribution.manifest.list.v2+json", "manifests": [ { "mediaType": "application/vnd.docker.distribution.manifest.v2+json", "size": 502, "digest": "sha256:c533169ea77d7c76de5d0e262e38bec7a878f36ccc0e5e76c9d61121a54312b8", "platform": { "architecture": "amd64", "os": "linux" } }, { "mediaType": "application/vnd.docker.distribution.manifest.v2+json", "size": 502, "digest": "sha256:b0544fd66e7a19c2771720e54b6d6082d7cfe321fe79957230d4d7bc84d5d478", "platform": { "architecture": "arm64", "os": "linux" } } ] }
'클라우드' 카테고리의 다른 글
React+Vite nginx로 GCP VM(우분투)에 수동배포 하는 방법 (0) 2025.05.22 Infisical으로 React 환경변수 적용하기 (0) 2025.05.20 GCP VM에 Infisical docker-compose로 설치 후 팀원 초대 (0) 2025.05.19