Docker Hub의 Pull Rate Limit 문제 Amazon ECR로 해결하기

JunGu Kang·2021년 5월 30일
0

이 문제는 약 6개월 전인 2020년 11월 해결한 문제이고 이제는 다양한 해결 방법에 대한 글이 있지만 이 글과 동일한 해결 방법을 제시한 한국어 글은 아직 찾지 못해 포스팅합니다.

인트로

저희 회사는 Docker 컨테이너 형태로 Amazon ECS(이하 ECS)에 서비스를 배포하고 있습니다. 만약 누군가가 GitHub의 특정 브랜치에 코드를 푸시 또는 머지하면 아래와 같은 일이 일어납니다.

  1. AWS CodePipeline(이하 CodePiipeline)이 바라보고 있는 브랜치에 변경 사항이 발생했음을 감지하면 파이프라인이 실행됩니다.
  2. AWS CodeBuild(이하 CodeBuild) 빌드가 전달받은 최신 코드를 빌드합니다. 간단히 docker build 명령을 실행해 사전에 작성된 Dockerfile에 따라 Docker 이미지로 빌드합니다.
  3. 빌드된 이미지를 Amazon ECR(이하 ECR) 레지스트리에 푸시합니다.
  4. ECS 작업 정의에 빌드된 최신 이미지가 반영됩니다.
  5. ECS 클러스터는 변경된 작업 정의에 따라 서비스를 업데이트합니다.

이 일은 모두 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번의 빌드는 성공하는 것일까요? 저희의 빌드 로그에 따르면 그렇지도 않은 것으로 보입니다. 또 횟수와 상관없이 일정 확률로 빌드가 성공할 때도 있습니다. 그 원인은 아래와 같이 추측하고 있습니다.

  1. Docker Hub는 인증되지 않은 사용자에 대해 요청 IP를 기반으로 구분하여 rate limit을 적용한다.
  2. 빌드 작업은 무작위로 CodeBuild 인스턴스에 배치된다.
  3. 배치된 인스턴스가 Docker Hub의 rate limit에 도달하였으면 이미지를 풀 받는데 실패하고, 그렇지 않으면 이미지를 풀 받는데 성공한다.

해결 방법

Docker Hub 계정 사용

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를 지불해야 한다는 것은 수지타산에도 맞지 않아보입니다.

ECR 사용

다른 방법을 고민하던 중, Docker Hub의 rate limit이 문제의 원인이라면 Docker Hub를 사용하지 않으면 되는 것이 아닌가 하는 생각이 떠올랐습니다. 그렇게 빌드 완료된 이미지를 저장하던 ECR에 빌드에 필요한 베이스 이미지를 올려두면 되겠다는 아이디어가 나왔습니다.

방법은 간단합니다. ECR 로그인을 위해 AWS CLI가 설치 및 설정되어 있어야 합니다.

  1. 로컬 머신에 필요한 이미지를 풀 받습니다.
$ docker pull node:********
  1. 풀 받은 이미지를 ECR 레지스트리에 푸시하기 위해 태그를 지정합니다. 지정할 태그는 AWS 콘솔에서 확인할 수 있습니다.
$ docker tag node:******** ************.dkr.ecr.ap-northeast-2.amazonaws.com/base/node:********
  1. AWS ECR에 로그인 후 이미지를 푸시합니다. 로그인과 푸시 명령도 AWS 콘솔에서 확인할 수 있습니다.
$ 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:********
  1. 이제 Docker Hub 대신 ECR로부터 베이스 이미지를 풀 받도록 Dockerfile을 수정합니다.
# FROM node:********
FROM ************.dkr.ecr.ap-northeast-2.amazonaws.com/base/node:********
...
  1. 그리고 변경된 Dockerfile을 푸시하면 빌드 과정에서 ECR로부터 베이스 이미지를 풀 받게 되므로 더이상 빌드가 실패하지 않습니다.
Step 1/8 : FROM ************.dkr.ecr.ap-northeast-2.amazonaws.com/base/node:********
********: Pulling from base/node

마치며

이 글을 작성하려고 동일한 해결 방법을 제시한 한국어 포스트가 있는지 찾다가 AWS 블로그 포스트와 영어 포스트를 발견했습니다 AWS 블로그에 작성된 글은 2020년 11월 2일 작성된 것으로 이 글에 소개한 ECR을 사용하는 방법을 포함하여 두 가지 해결 방법을 권장합니다.

  1. 사용되는 퍼블릭 이미지를 Amazon ECR과 같은 프라이빗 레지스트리로 복사한다.
  2. 유료 Docker Hub 구독으로 업그레이드한다.

AWS 블로그 포스트에 관심이 있는 분들은 아래 URL을 확인하시기 바랍니다.

Advice for customers dealing with Docker Hub rate limits, and a Coming Soon announcement - AWS Blog

profile
Backend Engineer

0개의 댓글