⚙️

CodeBuildでECRのみでDocker Download Rate Limitを回避する

2021/11/03に公開

Docker download rate limit

2021年現在、CodeBuildでDokcer pullを伴う処理(イメージのビルドとか)をさせていると高確率で下記のエラーに遭遇します。

toomanyrequests: You have reached your pull rate limit. You may increase the limit by authenticating and upgrading: https://www.docker.com/increase-rate-limit

2020年の終わり頃から、Docker社はDocker hubアカウントを使わないユーザーがDocker pullするときに制限を設けるようになったんですよね。
この制限はIPアドレス単位でまとめられていて、すこしずつ制限を厳しくしていっているようで最終的には6時間に100イメージ程度のpullが上限になる予定のようです。

にしては制限かかるの早くない?

実のところ、CodeBuildはIPアドレスをかなり使い回す設計になっているようで他のユーザーがpullした分もちゃんと上記の制限に入ってきます..。
なので自分のアカウントで初めてpullしたとしても初回からrate limitにかかることが多いです。

回避策

だいたい下記2つのどちらかになるはずです。

  • pullする前にDockerhubアカウントでログインする
  • ベースになるイメージをECRにミラーリングしておき、そこから利用する。

前者はDockerhubアカウントでログインしたらアカウント単位で制限がかかるので回避できるというやり方です。
このやり方は他の方々が散々語られていると思うので省きます。

今回語るのはECRに前もってイメージを送っておく方法です。
ぶっちゃけDockerhubアカウントでログインした方が早いですが...

ECRのみでイメージを構築する

本来rate limitを回避するならDockerhubアカウントを使ったほうが早いですが、
組織的な都合で専用のDockerhubアカウントを作成できないなどのケースではこちらが選択されます。
またDockerhubアカウント自体も今後制限が厳しくなる可能性も十分あるので、そこまで考慮するならこちらのやり方も候補に上がる方と思います。

やり方としては使用するイメージをECRにpushしてそれを使うだけなのですが、問題はその持ってくる方法ですね。Docker pullされる場合

  • ローカルに既に対象イメージがあるか探す
  • Dockerhubにイメージがあるか探す

といった手順を取るので極論、下記のように直接ECRリポジトリを設定すれば完了なのですが。

# FROM nginx:1.16 Dockerhubからpullする
FROM {アカウントID}.dkr.ecr.ap-northeast-1.amazonaws.com/{イメージ名} # 直接ECRからpullする

この場合開発者は必ずECRにアクセスする権限がないとベースイメージを取得できないことになってしまいます。複数人での開発の際は支障が出る可能性が高いでしょう。
それに既存のDockerfileに手を入れるのも野暮です。
インフラの問題はインフラで片付けたいところなので、これは避けた上で行います。

ベースイメージをECRにプッシュする

まずコンソールでもterraformでも良いのでECRリポジトリを作成してください。

resource "aws_ecr_repository" "nginx" {
  name                 = "nginx"
}

次に手元のローカル端末で公式からベースイメージをpullします。

docker pull nginx:1.16  

作成したECRリポジトリに先程のイメージをそのままpushします。

docker tag  {アカウントID}.dkr.ecr.ap-northeast-1.amazonaws.com/nginx:latest  nginx:1.16
docker push {アカウントID}.dkr.ecr.ap-northeast-1.amazonaws.com/nginx:latest

これでECRイメージの準備はOK。

Docker tagを使ってベースイメージを騙す

CodeBuildのymlを下記のようにすれば解決です。

version: 0.2
phases:
  pre_build:
    commands:
      - $(aws ecr get-login --no-include-email)
      - docker pull {アカウントID}.dkr.ecr.ap-northeast-1.amazonaws.com/nginx:latest 
      - docker tag {アカウントID}.dkr.ecr.ap-northeast-1.amazonaws.com/nginx:latest nginx:1.16 

要はベースイメージを使うより先に前もってECRからイメージをpullし、
docker tagコマンドで本来使う予定だったベースイメージと同じ名前を付与してやるだけです。

これならベースイメージがローカルにあるものと判定されますので、CodeBuild上ではDockerhubへの接続は行われずECRから取得したイメージを使用してくれます。

体感値としてCodebuildは他のCICDサービスと比較してもrate limitに引っかかるので回避策は必須です。特別な理由がなければdockerhubアカウントを作成しましょう。

Discussion