일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- Scrum
- adaptive life cycle
- Project
- Crawling
- tensorflow
- 자바스크립트
- python
- AWS
- 다나와
- keras
- Agile
- 프로젝트
- data
- Method
- matplotlib
- data analyze
- javascript
- pandas
- webcrawling
- angular
- DANAWA
- analyzing
- 애자일
- visualizing
- ECS
- 크롤링
- opencv
- instance
- algorithm
- TypeScript
- Today
- Total
LiJell's 성장기
Efficient Multi-Architecture and Multi-Region Container Deployment with Amazon ECS and EC2 Spot Instances 본문
Efficient Multi-Architecture and Multi-Region Container Deployment with Amazon ECS and EC2 Spot Instances
All_is_LiJell 2024. 1. 22. 14:49Building Multi-architecture Container Images and Deploying for Multi-Region in parallel way
개요
저는 ECS EC2 spot instance 가용성과 안정성 확보를 위해서 amd64
와 arm64
모두 사용중입니다. 따라서, container도 multi-architecture 빌드가 필요했습니다. 저는 이미지 빌드 최적화와 여러 regions에 동시 배포를 위해 manifest list
를 활용했습니다. 결과적으로 Github Action matrix를 통해 빠르게 각 regions에 이미지 push와 배포할 수 있습니다.
ps) if you need a English version, you can check out following link
Container Image
- file system
- config
- meta data
Container 구성
크게 layer
*과 manifest
*로 이루어지는데요.
Layer
은 이미지의 일부분이고, 소프트웨어, 라이브러리, 그리고 설정파일 등을 말한다. 그리고 Manifest
는 컨테이너 이미지 구조와 동작 방식을 정의한다. 즉, 이미지를 구성하는 레이어들과 그 이미지의 런타임 특성* 및 구성*을 지정합니다.
도커 같은 경우 컨테이너 이미지 포멧은 Docker Image Specification 과 Image Manifest Specification을 통해서 정의됩니다. 컨테이너 기술에 대한 표준화는 OCI ( OPEN CONTAINER INITIATIVE )를 따릅니다.
- 런타임 특성*: 컨테이너가 사용하는 포트, 환경 변수, 실행할 명령어와 매개변수, 볼륨 마운트, 리소스 제한 등을 말하는데요. Container runtime과는 다른 개념입니다.
- 구성*: 실행할 명령어, 작업 디렉토리 등을 말합니다.
Container pull & push
Container 이미지를 pull하거나 push할 때 크게 두가지 일이 일어납니다. 예를들어, image를 처음 pull하게되면, 첫번째로 manifest
를 image repository와 tag기반으로 받아온 후, manifest를 이용해서 layers를 모아 container file system
을 구성합니다.
Deep Dive into Manifest
manifest는 docker inspect <image>
명령어로 확인할 수 있습니다. 로컬에 있는 이미지를 확인해 보시면, Architecture와 OS등이 명시되어 있는걸 볼 수 있습니다.
기존에는 아마존 ECR에 이미지를 배포할 때, 플랫폼이나 운영 체제 특성을 이미지 태그에 명시해야 했습니다. 예를 들어, 동일한 소스로부터 빌드한 플랫폼별 이미지들을 각각의 이미지 저장소에 별도로 저장했었는데요, 그 결과 container이 실행될 환경에 맞는 올바른 버전의 이미지를 명시적으로 참조하여 가져왔어야 했습니다.
예를 들어, {aws-account-id}.dkr.ecr.{aws-region}.amazonaws.com/my-image-linux-arm64:2.7
과 같이 특정 OS나 아키텍처를 명시하는 것이 필요했었습니다.
하지만 요즘은 manifest list
나 image index
로 불리는 것을 이용해서 더이상 그럴 필요가 없어졌습니다.
Manifest list
Manifest list
는 Docker Image Manifest Specification에서 V2 image manifest (schema version 2) 때 부터 지원하기 시작했습니다.
Manifest list
는 다른 architecture, OS , 그리고 platform attributes를 가지는 각 이미지의 manifests
를 nested 형태로 가질 수 있게 해줍니다. 따라서, {aws-account-id}.dkr.ecr.{aws-region}.amazonaws.com/my-image:2.7
와 같은 형태로 arm64
또는 amd64
등 세부 태그 없이도 이미지를 호출이 가능하게 됩니다.
위 그림과 같이, Container engine이 이미지를 registry에서 pull 할 때 compute environment에 맞는 layer들을 manifest list
의 value에 따라 찾아서 불러와주기 때문입니다. 쉽게 생각하면, 예전에는 단독주택이였는데, 이제 아파트가 된거죠. 결과적으로 manifest list
를 이용하면, 배포 CI/CD pipeline과 ECR repository management 모두 더 간단해집니다.
Manifest list를 위해서는 빌드할 때 약간의 추가 작업이 필요한데요, 그 내용은 아래에서 확인해 보시죠.
Working with multi-architecture images in Amazon ECR
Single Region
사실 multi-architecture images를 빌드 후 한가지 region ECR에만 push하면 된다면 아래와 같은 방법으로 간단하게 해결 할 수 있습니다.
- CLI
docker buildx build --platform linux/amd64,linux/arm64
- Github Action
- name: Build and push
uses: docker/build-push-action@v5
with:
context: .
platforms: linux/amd64,linux/arm64
push: true
tags: user/app:latest
위 방법들은 알아서 manifest list를 생성해주기 때문에 ECR에 push된 이미지의 Artifact type을 확인해보시면 Image Index
를 확인할 수 있습니다.
Multi-Region
Multi-region은 조금 까다롭습니다. buildx
에서 multi-platform은 --load
를 지원하지 않고 --push
는 한가지 region만 가능하기 때문이였습니다 (beta version에서 multi-platform load를 지원이 가능하다는 얘기도 있습니다). 그렇다고 각 region마다 빌드를 따로 하기엔 너무 비효율적이라 생각했습니다.
따라서 제가 결정한 방법은 manifest list
를 활용하는 것이였습니다.
아래 과정은 병렬(parallel)하게 진행됐습니다.
linux/amd64
,linux/arm64
를 parallel하게 빌드 후 runner에--load
를 합니다.- 각 region에 이미지를 push합니다.
- 두 이미지의 manifest를 묶어줄 manifest list를 생성해줍니다.
- manifest list에 annotate으로 어떤 architecture이 어떤 이미지인지를 명시해줍니다.
- manifest list를 push해 줍니다.
- ECR을 확인해 보시면
Image Index
를 확인 할 수 있습니다.
- 예시:
저는 Github Action을 통해서 진행했지만, 예시는 AWS Blog에서 제공해주는 내용을 보여드리겠습니다.
일단 ECR에 이미지를 push 하기 위해서는 ECR private registry에 로그인을 해야겠죠?
$ AWS_ACCOUNT_ID=*aws-account-id* $ AWS_REGION=*aws-region*
$ aws ecr get-login-password --region ${AWS_REGION} | \ docker login --username AWS --password-stdin \ ${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com/hello Login Succeeded
이미지 빌드 후 각 platform에 맞게 tag를 붙여주세요
$ for i in amd64 arm64; do for> docker tag hello:${i} ${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com/hello:${i} for> done
이미지를 확인하면 아래 처럼 보이게 됩니다.
$ docker images | grep hello REPOSITORY TAG IMAGE ID CREATED SIZE {aws-account-id}.dkr.ecr.{aws-region}.amazonaws.com/hello arm64 8d2063eddc5e 4 minutes ago 7.19MB hello arm64 8d2063eddc5e 4 minutes ago 7.19MB {aws-account-id}.dkr.ecr.{aws-region}.amazonaws.com/hello amd64 cbfda9e83a41 4 minutes ago 7.59MB hello amd64 cbfda9e83a41 4 minutes ago 7.59MB
태그를 붙인 각 이미지를 ECR에 push해 주세요
$ for i in amd64 arm64; do for> docker push ${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com/hello:${i} for> done
푸쉬된 이미지를
aws ecr
command로 아래와 같이 확인 할 수 있습니다.$ aws ecr --region ${AWS_REGION} describe-images --repository-name hello { "imageDetails": [ { "registryId": "aws-account-id", "repositoryName": "hello", "imageDigest":"sha256:b50bd7f7..5a0dc770", "imageTags": [ "amd64" ], "imageSizeInBytes": 3954211, "imagePushedAt": "2020-04-24T17:24:11-04:00" }, { "registryId": "aws-account-id", "repositoryName": "hello", "imageDigest": "sha256:2f333a8b..27fc2172", "imageTags": [ "arm64" ], "imageSizeInBytes": 3702268, "imagePushedAt": "2020-04-24T17:24:25-04:00" } ] }
이 시점에서 각 architecture-specific tags에 따라서 이미지를 pull할 수 있습니다. 하지만 좀 더 간단하게 이미지를 pull하기 위해서
manifest list
를 생성 후 Amazon ECR에 푸쉬해 봅시다.docker manifest create
command로manifest list
를 생성해줍니다.$ docker manifest create ${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com/hello \ ${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com/hello:amd64 \ ${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com/hello:arm64 Created manifest list {aws-account-id}.dkr.ecr.{aws-region}.amazonaws.com/hello:latest
mainfest는 default로
latest
tag로 정해지지만, 각자 원하는 tag를 붙일 수 있습니다. 저 같은 경우${{env.ECR_REGISTRY}}/${{matrix.ecr_repository}}:${{env.ENV}}-${{github.run_number}}-${{matrix.platform}}
로 Github Action에서 정해줬습니다.Manifest Annotate
Manifest list
가 어떤 image가 어떤 architecture을 위한건지 명시해줍니다. 저는amd64
에 대해서도 동일하게 진행했습니다.$ docker manifest annotate --arch arm64 ${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com/hello \ ${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com/hello:arm64
Manifest를 push하기 전에 mapping이 잘 됐는지 검증을 한번 해볼까요?
platform.architecture
values를 확인하시면 됩니다.$ docker manifest inspect ${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com/hello { "schemaVersion": 2, "mediaType": "application/vnd.docker.distribution.manifest.list.v2+json", "manifests": [ { "mediaType": "application/vnd.docker.distribution.manifest.v2+json", "size": 528, "digest": "sha256:b50bd7f7..5a0dc770", "platform": { "architecture": "amd64", "os": "linux" } }, { "mediaType": "application/vnd.docker.distribution.manifest.v2+json", "size": 528, "digest": "sha256:2f333a8b..27fc2172", "platform": { "architecture": "arm64", "os": "linux" } } ] }
Manifeset List Push to ECR
검증이 완료되면 생성한 Manifest List를 ECR에 push해줍니다.$ docker manifest push ${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com/hello sha256:bd7a61a6ea3c366c0e58d70233900f0c761d6051da0ad8cbaa19011f873c37bc
이제 ECR Registry를 확인하시면 push한 image의 Artifact type
이 Image Index
인것을 확인할 수 있습니다!!
이 이미지로 이제 배포만 진행하면 돼요!
결과
우리는 container의 구성과 ECR에 push&pull할 때의 로직을 간단히 훑어보고, multi-architecture 이미지를 빌드 후 multi-region에 parallel하게 push하는 방법을 중점적으로 확인해 봤습니다. 그 중에서도 manifest list
를 이용하는 방법을 함께 해봤는데요, 도움이 됐었으면 좋겠네요!
'Cloud' 카테고리의 다른 글
AWS ECS Managed Termination Protection 옵션 사용시 주의할 점 (0) | 2024.03.13 |
---|---|
Amazon ECS managed instance draining (0) | 2024.01.31 |
ECS EC2 Spot instance scaling 속도 개선 방법 (2) | 2023.12.29 |
EC2 Auto Scaling Multiple Launch Templates (0) | 2023.12.29 |
S3 Cache-Control (0) | 2023.10.13 |