개발

ECR Multi Architecture(amd64/arm64) 이미지 저장하기

데이비드___ 2023. 3. 23. 01:09

목적: ECR에서 Requirements 같이 image가 관리 가능한지 확인, 가능할 경우 방법 및 적용.
단일 tag 안에서 나뉘어 관리되는 것이 docker repo 자체 기능인지, registry 별로 별도 지원해야하는 것인지 확인 필요
단일 tag일 경우, image pull 진행 시 platform 선택이 어떻게 이루어지는 것인지 확인 필요
명시적으로 platform을 지정해야하는지, 지정안했을 경우 어떻게 동작하는지 등

 

 

기존 ECR 문제점 확인


ECR 구조 설명

ECR은 내부적으로 repo아래에 Config 와 Layers로 분리되어 있습니다.

다들 docker push를 하시면서 layer가 하나씩 업로드 되는 상황들을 한번씩 보셨으리라 생각됩니다.

Docker Manifest 확인

 

Docker inspect 명령어를 사용하면 Docker 개발 환경에서의 로컬 이미지의 Manifest 확인 가능

$ docker inspect 2fd81e4837329c8f8f90b1285854dffe4ee3e412af21f1077cfc8318e14ca186

 

ID기준으로 Config 하위에 어려가지 정보들이 있는 것을 확인 가능.

  • Config
  • Architecture
  • OS

 

[
    {
        "Id": "sha256:112222",
        "RepoTags": [
            "2.dkr.ecr.ap-northeast-2.amazonaws.com/ecr-repo-an2-public-st:arm64",
            "2.dkr.ecr.ap-northeast-2.amazonaws.com/ecr-repo-an2-public-st:latest",
            "hello:arm64"
        ],
        "RepoDigests": [
            "22222.dkr.ecr.ap-northeast-2.amazonaws.com/ecr-repo-an2-public-e4121adb241fa518"
        ],
        "Parent": "",
        "Comment": "buildkit.dockerfile.v0",
        "Created": "2023-01-17T01:23:11.125330987Z",
        "Container": "",
        "ContainerConfig": {
            "Hostname": "",
            "Domainname": "",
            "User": "",
            "AttachStdin": false,
            "AttachStdout": false,
            "AttachStderr": false,
            "Tty": false,
            "OpenStdin": false,
            "StdinOnce": false,
            "Env": null,
            "Cmd": null,
            "Image": "",
            "Volumes": null,
            "WorkingDir": "",
            "Entrypoint": null,
            "OnBuild": null,
            "Labels": null
        },
        "DockerVersion": "",
        "Author": "",
        "Config": {
            "Hostname": "",
            "Domainname": "",
            "User": "",
            "AttachStdin": false,
            "AttachStdout": false,
            "AttachStderr": false,
            "ExposedPorts": {
                "8080/tcp": {}
            },
            "Tty": false,
            "OpenStdin": false,
            "StdinOnce": false,
            "Env": [
                "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
            ],
            "Cmd": null,
            "Image": "",
            "Volumes": null,
            "WorkingDir": "/app",
            "Entrypoint": [
                "./hello"
            ],
            "OnBuild": null,
            "Labels": null
        },
        "Architecture": "amd64",
        "Os": "linux",
        "Size": 7192365,
        "VirtualSize": 7192365,
        "GraphDriver": {
            "Data": {
                "LowerDir": "/var/lib/docker/overlay2/pzyhi6eizefv36oopt7tveopg/diff",
                "MergedDir": "/var/lib/docker/overlay2/dwiu7tr71x21s7sf0sruant1b/merged",
                "UpperDir": "/var/lib/docker/overlay2/dwiu7tr71x21s7sf0sruant1b/diff",
                "WorkDir": "/var/lib/docker/overlay2/dwiu7tr71x21s7sf0sruant1b/work"
            },
            "Name": "overlay2"
        },
        "RootFS": {
            "Type": "layers",
            "Layers": [
                "sha256:2",
                "sha256:2"
            ]
        },
        "Metadata": {
            "LastTagTime": "2023-01-17T01:24:13.826609381Z"
        }
    }
]

문제점 확인

  • ECR내부적으로 Config / Layers 로 분리 되어 있음
    • Config 하위에 Architecture 정보가 저장됨
    • 기존 구조에서 여라가지 Architecture를 지원하기 위해서는 별도의 Tag를 생성하여 이미지를 사용(Pull)해야 함
      • /my-image-linux-arm64:2.7 와 같은 태깅 형태가 필요.
      • 1개의 tag에서 Archiectre별로 나눠 주지 못함

ECR Multi Architecture


  • 기존 구조에서 Docker Manifest List가 추가 되어 각각의 Architecture 별로 분리되는 구조.
  • Docker Manifest List가 여러개의 Archtecture Image를 싸고 있는 형태

목표

  • Amd64/ Arm64 이미지를 생성하여 T20-st ECR에 Push하여
  • 하나의 Latest(tag) 버전으로 2개의 Architecture 이미지가 정상 동작하는지 확인

설명

초반 구조에 대해 이야기를 조금 하는데, 그 이후에는 삽질 하는 것들이 나오니 빠른 결과를 보시려면 35분 이후로 이동하셔서 듣는 걸 추천

 

Takeaway

  • 사전 arm64/ amd 64  build한 Output img 필요
  • Architecture별 이미지 Docker (tag / push)하여 ECR에 업로드
# Tag
$ docker tag hello:arm64 1.dkr.ecr.ap-northeast-2.amazonaws.com/ecr-repo-an2-public-st:arm64
$ docker tag hello:amd64 1.dkr.ecr.ap-northeast-2.amazonaws.com/ecr-repo-an2-public-st:amd64
 
# Push
$ docker push 1.dkr.ecr.ap-northeast-2.amazonaws.com/ecr-repo-an2-public-st:arm64
$ docker push 1.dkr.ecr.ap-northeast-2.amazonaws.com/ecr-repo-an2-public-st:arm64
ECR이 제대로 Push 되어 있는지 확인
  • ECR이 제대로 Push 되어 있는지 확인
# ECR Image list
$ aws ecr --region ap-northeast-2 describe-images --repository-name ecr-repo-an2-public-st
  • Docker manifest 생성
# Create Manifest
docker manifest create ${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com/${ECR_REPO_NAME} \
# ${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com/${ECR_REPO_NAME}:${amd64} \
# ${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com/${ECR_REPO_NAME}:${arm64}
 

# Add Annotation
docker manifest annoate --arch arm64 ${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com/${ECR_REPO_NAME} \
# ${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com/${ECR_REPO_NAME}:${arm64}

Manifest 확인

# Manifest Inspection
docker manifest inspect ${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com/${ECR_REPO_NAME}

# Manifest push
docker manifest push ${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com/${ECR_REPO_NAME}

결과


Architecture 별 Docker 실행 및 동작 확인

# Docker run

docker run --platform=linux/arm64 -d -p 8080:8080 2.dkr.ecr.ap-northeast-2.amazonaws.com/ecr-repo-an2-public-st:latest
docker run --platform=linux/amd64 -d -p 8080:8080 2.dkr.ecr.ap-northeast-2.amazonaws.com/ecr-repo-an2-public-st:latest

  • Latest 1개의 Tag로 Architecture 별로 분리되어 Img 사용 가능
  • 실행 관점으로 여러 Architecture를 관리해야 한다면 명시적으로 선언하는 것이 필요하다고 생각 됨
    • 예) --paltform=linux/arm64
  • docker run시에 --platform 옵션을 제외하고 실행시에는
    • Local Machine의 Architecture Dependent하게 실행하고 동작 됨.

 

참조


(공식) AWS multi-architecture container images for amazon ECR
Docker manifest 활용하여 Multi-Architecture DockerHub에 올리기