본문 바로가기

Docker

내가 만든 Docker Image가 ARM 아키텍쳐에서 실행되지 않을 때

반응형

개요

  • Ticketing 프로젝트 진행 중, 서버의 업스케일링을 위해서 AMD/linux기반의 아키텍쳐에서 ARM/linux 기반의 아키텍쳐로 마이그레이션 할 일이 생겼습니다. 그런데 Docker Image로 빌드해놓은 Ticketing 어플리케이션이 ARM 아키텍쳐에서 실행되지 않는다는 오류를 발견했습니다.
no matching manifest for linux/arm64/v8 in the manifest list entries

 

현재 상황

  • 현재 Ticketing Application이 배포되는 과정은 다음과 같습니다.
    1. 개발자가 Github main Branch에 Push
    2. Github Actions Script가 실행되어 Spring Build → Docker Image 생성
    3. 생성된 Image를 Docker hub에 업로드
    4. Github Actions Script가 서버에 접속하여 docker Container (재)실행

 

Base Image 확인하기

  • 먼저 Base Image가 ARM에서도 실행이 가능한지 확인해야 했습니다. Ticketing Application의 이미지의 Base Image는 다음과 같습니다.
FROM openjdk:17-jdk-alpine
  • 위 이미지가 어떤 플랫폼을 지원하는지는 아래의 명령어를 통해 확인이 가능했습니다.

 

docker manifest inspect openjdk:17-jdk-alpine

####### 결과
{
   "schemaVersion": 2,
   "mediaType": "application/vnd.docker.distribution.manifest.list.v2+json",
   "manifests": [
      {
         "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
         "size": 951,
         "digest": "sha256:a996cdcc040704ec6badaf5fecf1e144c096e00231a29188596c784bcf858d05",
         "platform": {
            "architecture": "amd64",
            "os": "linux"
         }
      }
   ]
}
  • 위 결과를 보면 알 수 있듯이, amd에 대한 내용만 있고, arm를 지원한다는 내용은 찾을 수 없었습니다.
  • 그럼 AMD말고 ARM에서도 구축이 가능한 Base Image로 변경이 필요했습니다. 이는 Docker hub에 가서 openjdk에서 검색해서 찾을 수 있었습니다.

 

마찬가지로 manifest inspect로 검색했을 때 arm을 지원한다는 것을 알 수 있었습니다.

{
   "schemaVersion": 2,
   "mediaType": "application/vnd.docker.distribution.manifest.list.v2+json",
   "manifests": [
      {
         "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
         "size": 953,
         "digest": "sha256:9a37f2c649301b955c2fd31fb180070404689cacba0f77404dd20afb1d7b8d84",
         "platform": {
            "architecture": "amd64",
            "os": "linux"
         }
      },
      {
         "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
         "size": 953,
         "digest": "sha256:565d3643a78a657ca03e85c110af9579a07e833d6bcc14f475249c521b5c5d74",
         "platform": {
            "architecture": "arm64",
            "os": "linux",
            "variant": "v8"
         }
      }
   ]
}

 

  • 그래서 Ticketing Application의 Base Image를 변경하고, 바로 Docker Hub에 업로드 해보았습니다. 그리고 다시 ARM에서 실행을 해보았을 때..
no matching manifest for linux/arm64/v8 in the manifest list entries

 

  • 마찬가지로 이전과 같은 오류가 나타났습니다. 그래서 ticketing image에 대해서도 manifest를 조회해보니
docker manifest inspect minturtle/min-ticketing:latest
{
   "schemaVersion": 2,
   "mediaType": "application/vnd.oci.image.index.v1+json",
   "manifests": [
      {
         "mediaType": "application/vnd.oci.image.manifest.v1+json",
         "size": 1436,
         "digest": "sha256:0f1674fd9aebb01cef92f41608e499b485e9c9e859cb93f537d1c151e3964322",
         "platform": {
            "architecture": "amd64",
            "os": "linux"
         }
      },
      {
         "mediaType": "application/vnd.oci.image.manifest.v1+json",
         "size": 566,
         "digest": "sha256:cff4f1ad17427bca1f2e09fdaf8683bdcfc20e7d3779eac04bbd8d06d2ba5de8",
         "platform": {
            "architecture": "unknown",
            "os": "unknown"
         }
      }
   ]
}
  • arm이 나와야 할 자리에 unknown이라는 알 수 없는 플랫폼이 포함되어 있었습니다.

빌드 옵션 변경하기

  • 이에 대해 정보를 좀 찾아보니, 아래의 명령어로 ARM64와 AMD64에 대한 이미지를 빌드해야 한다고 합니다.
docker buildx build --platform linux/arm64,linux/amd64 -t my-spring-app .

 

  • 근데 저는 Github Custom Action을 사용했기 때문에(직접 build 명령어를 실행하지 않음) 다음과 같이 Action Script를 바꾸어 주면 된다고 해서 바로 해보았습니다.
- name: Build and push Docker image
  uses: docker/build-push-action@v4
  with:
    context: .
    push: true
    tags: minturtle/min-ticketing:latest
    platforms: linux/arm64,linux/amd64 # 새로 추가됨
  • 그리고 manifest를 다시 조회해 보니, 아래의 결과가 나왔습니다.
{
   "schemaVersion": 2,
   "mediaType": "application/vnd.oci.image.index.v1+json",
   "manifests": [
      {
         "mediaType": "application/vnd.oci.image.manifest.v1+json",
         "size": 1436,
         "digest": "sha256:07e7767c2aec30d6163dfd5ffac6aa3b764fde836e0517138ce8944d3824396d",
         "platform": {
            "architecture": "arm64",
            "os": "linux"
         }
      },
      {
         "mediaType": "application/vnd.oci.image.manifest.v1+json",
         "size": 1436,
         "digest": "sha256:06943e2a9c100838846c2612ed49e14d61129df1c35a78975e49ba44440fd69a",
         "platform": {
            "architecture": "amd64",
            "os": "linux"
         }
      }
   ]
}
  • 이제 정상적으로 arm/linux 플랫폼을 지원하는 것을 알 수 있었고, 실행도 정상적으로 되는 것을 알 수 있었습니다.

 

그럼 Base Image는 안바꿔도 되는 걸까?

  • 근데 궁금한 점이 하나 생겼는데, Image를 빌드할 때 빌드 옵션만 조정하면 되는거라면 굳이 Base Image를 안바꿔도 되는 거 아닐까요? 이에 대해 ChatGPT에게 물어보니 ChatGPT는 아래와 같이 답변했습니다.
만약 
openjdk:17-slim과 같은 AMD 전용 BASE Image로 변경하면, ARM64 아키텍처를 지원하지 않게 됩니다.
  • 라고는 하는데.. ChatGPT의 말만 믿기에는 조금 찝찝하니까 직접 테스트 해보기로 했습니다.
  • 테스트는 이전에 AMD/linux Platform만 제공했던 openjdk:17-jdk-alpine 이미지로 다시 변경해서 테스트 했습니다.

 

  • arm, amd platform에 대한 빌드
docker buildx build --platform linux/arm64,linux/amd64 -t my-spring-app .

##### 결과
[+] Building 0.0s (0/0)                                                                                                                                                                                              docker:default
ERROR: Multi-platform build is not supported for the docker driver.
Switch to a different driver, or turn on the containerd image store, and try again.
Learn more at https://docs.docker.com/go/build-multi-platform/

 

  • arm에 대한 빌드
docker buildx build --platform linux/arm64 -t my-spring-app . 

### 결과
[+] Building 1.2s (3/3) FINISHED                                                                                                                                                                                     docker:default
 => [internal] load .dockerignore                                                                                                                                                                                              0.0s
 => => transferring context: 2B                                                                                                                                                                                                0.0s
 => [internal] load build definition from Dockerfile                                                                                                                                                                           0.0s
 => => transferring dockerfile: 373B                                                                                                                                                                                           0.0s
 => ERROR [internal] load metadata for docker.io/library/openjdk:17-jdk-alpine                                                                                                                                                 1.1s
------
 > [internal] load metadata for docker.io/library/openjdk:17-jdk-alpine:
------
Dockerfile:1
--------------------
   1 | >>> FROM openjdk:17-jdk-alpine
   2 |
   3 |     # gradle 설정으로 plain jar 파일은 생성되지 않습니다.
--------------------
ERROR: failed to solve: openjdk:17-jdk-alpine: no match for platform in manifest sha256:4b6abae565492dbe9e7a894137c966a7485154238902f2f25e9dbd9784383d81: not found

 

 

  • amd에 대한 빌드
docker buildx build --platform linux/amd64 -t my-spring-app .            

### 결과
[+] Building 3.3s (9/9) FINISHED                                                                                                                                                                                     docker:default
 => [internal] load .dockerignore                                                                                                                                                                                              0.0s
 => => transferring context: 2B                                                                                                                                                                                                0.0s 
 => [internal] load build definition from Dockerfile                                                                                                                                                                           0.0s 
 => => transferring dockerfile: 373B                                                                                                                                                                                           0.0s 
 => [internal] load metadata for docker.io/library/openjdk:17-jdk-alpine                                                                                                                                                       1.0s 
 => [1/4] FROM docker.io/library/openjdk:17-jdk-alpine@sha256:4b6abae565492dbe9e7a894137c966a7485154238902f2f25e9dbd9784383d81                                                                                                 0.0s
 => [internal] load build context                                                                                                                                                                                              1.6s 
 => => transferring context: 85.87MB                                                                                                                                                                                           1.6s 
 => CACHED [2/4] WORKDIR /app                                                                                                                                                                                                  0.0s 
 => CACHED [3/4] RUN mkdir -p /app/logs && chmod -R 777 /app/logs                                                                                                                                                              0.0s 
 => [4/4] COPY build/libs/ticketing-0.0.1-SNAPSHOT.jar app.jar                                                                                                                                                                 0.3s
 => exporting to image                                                                                                                                                                                                         0.3s
 => => exporting layers                                                                                                                                                                                                        0.3s 
 => => writing image sha256:cd33bf809c83d0cdb98f26f1d5f32f9807b4b458e45d9e917be23bb7148bba6c                                                                                                                                   0.0s 
 => => naming to docker.io/library/my-spring-app   
  • 결론적으로 BASE Image를 제공하는 platform에 대해서만 빌드가 가능함을 알 수 있었습니다.
반응형