fu3ak1's tech days

何事もシンプルに。主にAWS関連の記事を書いています

Docker Hub の Rate Limitに引っかかったのでdocker loginで対策した

AWSのcodebuildで、docker buildが失敗するようになりその対応をしたので備忘録です。

Docker Hub の Rate Limitとは

英語になりますがこちらに記載があります。

www.docker.com

The rate limits will be progressively lowered to a final state of 100 container image requests per six hours for anonymous usage, and 200 container image requests per six hours for free Docker accounts. Image requests exceeding these limits will be denied until the six hour window elapses.

ざっくり私の翻訳

rate limits を徐々に低くしていって、最終的には匿名ユーザーは100 image リクエスト/6時間、free Dockerユーザーには200 image リクエスト/6時間にするから!それ超えたら6時間拒否するからね!

ちなみに現状では以下のlimitとなっているようです。

f:id:fu3ak1:20201120235605p:plain

これを見た私の感想は、「フーン、まぁそんなにたくさんimage リクエストなんてしないし大丈夫だろ、うちはそんなたくさんCICDする組織じゃないし( ̄σ・ ̄*)」という感じでした。

エラーに遭遇、原因判明

そんな気持ちのままAWSのCodeBuild(CodePipeline経由)でdocker buildを行っていると、以下のエラーが・・

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

!?まだ5回くらいしかbuildしていないのに?

少し考えて原因がわかりました。

匿名ユーザーのリクエストのカウントがIPアドレス単位なので、CodeBuildのIPアドレスでカウントされるということでした。

勝手に頭の中で以下のようにユーザー単位でカウントされると思い込んでしまっていたのですが、、

f:id:fu3ak1:20201121000423p:plain

実際は以下のようなイメージですね。IPを共有するので、初めてdocker buildを行う場合でもほかのユーザーの影響を受けてエラーになる可能性があります。

※実際はCodeBuildのIPアドレスは複数ありますが、共有するというイメージで1つで書いています。

f:id:fu3ak1:20201122104635p:plain

対策

対策は以下のようにいくつか考えられます。

  • ECRに定期的にイメージをコピーしておく。
  • CodeBuildをVPC内で実行させ、共用ではなくElastic IPなど固定のIPアドレス経由でDocker Hubにアクセスする
  • Docker Hubユーザーを作成してログイン処理を行う

今回は手間が一番かからなそうなログイン処理を実装することにしました。手順をまとめておきます。

Docker Hub ユーザーの作成

Free Planでユーザーを作成します。メールアドレスが必要です。

Docker Hubのページから、Sign Upします。

f:id:fu3ak1:20201121001631p:plain

画面の指示に従っていけばユーザーの作成が完了します。

作成、ログイン後、アクセストークンを発行します。パスワードでログイン処理も可能なのですが、トークンのほうが無効化できたり、プロジェクトごとで分けれるといった利点があるため今回はトークンにしました。

右上のユーザー名>Account Settingsを選択

f:id:fu3ak1:20201121002300p:plain

左側のメニューからSecurityを選択し、右側のNew Access Tokenをクリックします。

f:id:fu3ak1:20201121002529p:plain

Descriptionが必須のため、任意の文字を入力してCreateします。

f:id:fu3ak1:20201121002658p:plain

Tokenが表示されるのでコピーしておきます。Closeするともう表示できなくなるため注意です。

f:id:fu3ak1:20201121002923p:plain

SSM Parameter Storeへログイン情報格納

ログイン情報を作成できたので、AWS側で使用します。Codebuildで使用するbuildspec.ymlにログイン情報を直接記載するのはセキュリティ的によろしくないので、Systems ManagerのParameter Storeを使用します。 他にはSecrets Managerという選択肢もあるのですが、今回はローテーションを考慮しないかつ無料であるParameter Storeを使用します。

AWS Systems Manager>パラメータストア>パラメータを作成の順で選択します。

まずはdockerhub-userを作成します。(名前は任意でOKです)

f:id:fu3ak1:20201122102504p:plain

情報を秘匿化したいため、安全な文字列を選択します。暗号化に使用するキーの指定が必要ですが、今回はAWS管理のデフォルトのものを使用します。

f:id:fu3ak1:20201122100131p:plain

値にユーザー名を入力して作成します。

f:id:fu3ak1:20201122100451p:plain

dockerhub-tokenも同じように作成します。

f:id:fu3ak1:20201122102626p:plain

buildspec.ymlの修正

ログイン情報が格納できたので、buildspecに記載しているdocker buildの部分を修正します。

※Codebuildの仕様はこちらを参考にしてください。

以下のように、envのところにparameter-storeのところに作成したパラメータストアのKey名を書いておきます。

env:
  parameter-store:
    DOCKER_USER: dockerhub-user
    DOCKER_TOKEN: dockerhub-token

pre_buildフェーズのところで、ecrのみログインしていたところを、dockerhubにもログインするよう追記します。

「echo $DOCKER_TOKEN・・」の行です。パスワードとユーザー名は先ほどenvに記載したパラメータストアから取得しています。

  pre_build:
    commands:
      - aws ecr get-login-password --region $AWS_DEFAULT_REGION | docker login --username AWS --password-stdin $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com
      - echo $DOCKER_TOKEN | docker login -u $DOCKER_USER --password-stdin

CodeBuildを実行してログを見てみると、以下の通りログインに成功していることが見れます。

[Container] 2020/11/20 14:34:30 Running command echo $DOCKER_TOKEN | docker login -u $DOCKER_USER --password-stdin
WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store

Login Succeeded

[Container] 2020/11/20 14:34:32 Phase complete: PRE_BUILD State: SUCCEEDED

ログは割愛しますがdocker buildも無事成功しています。

これで作成したユーザーで200回/6時間まではlimitに引っかからないでしょう。

まとめ、感想

同じように失敗して困った方、なにかの参考になれば幸いです。

200回/6時間の制限はこの対策を行った後もあるため、多くのdocker buildを行う方は注意が必要ですね。

また今後は別の対策として、AWSのECRのパブリック化するようなので、今後はそちらも活用できるかもしれません。

aws.amazon.com