이 문제는 약 6개월 전인 2020년 11월 해결한 문제이고 이제는 다양한 해결 방법에 대한 글이 있지만 이 글과 동일한 해결 방법을 제시한 한국어 글은 아직 찾지 못해 포스팅합니다.
저희 회사는 Docker 컨테이너 형태로 Amazon ECS(이하 ECS)에 서비스를 배포하고 있습니다. 만약 누군가가 GitHub의 특정 브랜치에 코드를 푸시 또는 머지하면 아래와 같은 일이 일어납니다.
docker build
명령을 실행해 사전에 작성된 Dockerfile에 따라 Docker 이미지로 빌드합니다.이 일은 모두 CodePipeline 파이프라인에 의해 자동으로 수행됩니다. 그런데 언제부턴가 이 파이프라인이 자꾸 실패하기 시작했습니다.
처음에는 일시적인 오류일 것이라고 생각하고 파이프라인이 실패할 때마다 수동으로 다시 실행해주었습니다. 그러면 일정 확률로 파이프라인이 성공하고, 정상적으로 배포가 되었습니다. 일종의 기술 부채를 만들었던 셈입니다.
그러나 며칠이 지나도 문제는 해결되지 않았습니다. 그 동안 한 번의 배포를 위해 파이프라인이 실패할 때마다 성공할때까지 계속 수동으로 파이프라인을 재실행해줘야 하다 보니 팀원들에게는 하나의 스트레스 요소가 되었습니다.
결국 원인을 파악해서 조치를 취해야겠다는 결론을 내렸고 문제의 원인을 파악하기 시작했습니다. 우선 파이프라인의 어디에서 실패하는지를 알아야 했고, 그 위치는 CodeBuild 빌드였습니다.
하나의 파이프라인은 여러 스테이지로 구성되며 파이프라인에는 CodeBuild 빌드, Jenkins 빌드, CodeDeploy 배포 등 다양한 구성요소가 포함될 수 있습니다.
[Container] 2020/11/20 09:05:12 Entering phase BUILD
[Container] 2020/11/20 09:05:12 Running command docker build -t $REPOSITORY_URI:latest .
Sending build context to Docker daemon 4.656MB
Step 1/8 : FROM node:********
toomanyrequests: You have reached your pull rate limit. You may increase the limit by authenticating and upgrading: https://www.docker.com/increase-rate-limit
[Container] 2020/11/20 09:05:15 Command did not exit successfully docker build -t $REPOSITORY_URI:latest . exit status 1
[Container] 2020/11/20 09:05:15 Phase complete: BUILD State: FAILED
[Container] 2020/11/20 09:05:15 Phase context status code: COMMAND_EXECUTION_ERROR Message: Error while executing command: docker build -t $REPOSITORY_URI:latest .. Reason: exit status 1
CodeBuild의 빌드 로그로부터 빌드가 실패한 원인을 확인할 수 있었습니다. 빌드 과정에서 베이스 이미지를 풀 받으려고 요청할 때 pull rate limit에 도달했다는 응답을 받게 되어 실패한 것이었습니다. 그리고 그동안 잘 작동하던 빌드가 갑자기 이렇게 죽게 된 이유는 Understanding Docker Hub Rate Limiting에서 확인할 수 있었습니다.
On November 20, 2020, rate limits anonymous and free authenticated use of Docker Hub went into effect. Anonymous and Free Docker Hub users are limited to 100 and 200 container image pull requests per six hours.
2020년 11월 20일을 기점으로 익명 사용자는 6시간 동안 100개의 컨테이너 이미지만을 풀 받을 수 있도록 변경된 것이었습니다.
그러면 하루에 100번의 빌드는 성공하는 것일까요? 저희의 빌드 로그에 따르면 그렇지도 않은 것으로 보입니다. 또 횟수와 상관없이 일정 확률로 빌드가 성공할 때도 있습니다. 그 원인은 아래와 같이 추측하고 있습니다.
Docker Hub는 rate limit을 증가시키기 위해서 Docker Pro나 Docker Team 구독으로 업그레이드하라고 합니다.
To increase your pull rate limits you can upgrade your account to a Docker Pro or Team subscription.
그러나 이 방법은 추가 비용이 발생한다는 문제점과, 빌드를 수정해야 한다는 문제가 있습니다. 구체적으로는 AWS Secrets Manager에 로그인 정보를 등록하고 이를 사용해 로그인하도록 buildspec을 수정해야 합니다. 또, 빌드를 위한 베이스 이미지를 가져오기 위해 팀원 한 명 당 매달 7USD를 지불해야 한다는 것은 수지타산에도 맞지 않아보입니다.
다른 방법을 고민하던 중, Docker Hub의 rate limit이 문제의 원인이라면 Docker Hub를 사용하지 않으면 되는 것이 아닌가 하는 생각이 떠올랐습니다. 그렇게 빌드 완료된 이미지를 저장하던 ECR에 빌드에 필요한 베이스 이미지를 올려두면 되겠다는 아이디어가 나왔습니다.
방법은 간단합니다. ECR 로그인을 위해 AWS CLI가 설치 및 설정되어 있어야 합니다.
$ docker pull node:********
$ docker tag node:******** ************.dkr.ecr.ap-northeast-2.amazonaws.com/base/node:********
$ aws ecr get-login-password --region ap-northeast-2 | docker login --username AWS --password-stdin ************.dkr.ecr.ap-northeast-2.amazonaws.com
$ docker push ************.dkr.ecr.ap-northeast-2.amazonaws.com/base/node:********
# FROM node:********
FROM ************.dkr.ecr.ap-northeast-2.amazonaws.com/base/node:********
...
Step 1/8 : FROM ************.dkr.ecr.ap-northeast-2.amazonaws.com/base/node:********
********: Pulling from base/node
이 글을 작성하려고 동일한 해결 방법을 제시한 한국어 포스트가 있는지 찾다가 AWS 블로그 포스트와 영어 포스트를 발견했습니다 AWS 블로그에 작성된 글은 2020년 11월 2일 작성된 것으로 이 글에 소개한 ECR을 사용하는 방법을 포함하여 두 가지 해결 방법을 권장합니다.
- 사용되는 퍼블릭 이미지를 Amazon ECR과 같은 프라이빗 레지스트리로 복사한다.
- 유료 Docker Hub 구독으로 업그레이드한다.
AWS 블로그 포스트에 관심이 있는 분들은 아래 URL을 확인하시기 바랍니다.
Advice for customers dealing with Docker Hub rate limits, and a Coming Soon announcement - AWS Blog