CodeBuildのDownload Rate Limitエラー対策として、DockerIDを取得しユーザー認証してビルドする


はじめに

CodePipelineのCodeBuildでの工程で、以下のエラーがたびたび発生しました。

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

DockerHubでは、匿名ユーザによるDockerHubからのコンテナイメージの呼び出し回数は、以下のような制限があります。

設定 意味
無料プラン(匿名ユーザー) 100 pull/6時間あたり
無料プラン(認証ユーザー) 200 pull/6時間あたり
Pro 無制限
Team 無制限

匿名ユーザーは、 IP アドレス単位で回数制限がかかるため、CodeBuildからの実行では自分が行った回数に関係なく制限に引っかかってしまうため、今回のようなエラーが出ていました。

そのため、今回は、無料プランの認証ユーザーとして、DockerHubにログインすることで、Buildのエラーになる確率をぐっと減らしたいと思います。
実際の本番環境ですと、有料プランに入るべきですが。。

前提条件

流れ

①DockerHubのアカウント作成
②SystemsManagerでパラメータ作成
③サービスロールにポリシーをアタッチ
④buildspec.ymlの修正
⑤CodeBuildに環境変数を追加

DockerHubのアカウント作成

こちらのリンクからDockerHubアカウントを作成します。
アカウント作成に必要なDockerID・メールアドレス・パスワードを設定します。
DockerIDは、ユーザ名に近い使い方をします。

Codebuildで必要な値は、以下の2つです。

  • DockerID
  • アカウントパスワード

Docker Hub で Two-Factor Authentication(MFA)を有効にしている場合は、アカウントパスワード の代わりにアクセストークンを使用する必要があります。
アカウント設定に移動し、左タブSecurityをクリックし、New Access Tokensをクリックすると、アクセストークンが発行されます。

  • Access Token DescriptionForCodeBuild
  • Access permissionsRead, Write, Delete
    Generateをクリックします。

SystemsManagerでパラメータ作成

以下の2つのパラメータを作成します。

  • DockerID
  • アカウントパスワード

SystemsManagerのマイパラメータに遷移し、パラメータの作成をクリックします。

  • 名前DOCKER_HUB_ID(何でも可)
  • 利用枠標準
  • タイプ安全な文字列
  • KMSキーソース現在のアカウント
  • KMSキーIDalias/aws/ssm
  • DockerIDの値を入れる

パラメータを作成をクリックします。

同様にアカウントパスワード用も作成します。

  • 名前DOCKER_HUB_PASSWORD(何でも可)
  • 利用枠標準
  • タイプ安全な文字列
  • KMSキーソース現在のアカウント
  • KMSキーIDalias/aws/ssm
  • Dockerアカウントのパスワードの値を入れます

サービスロールにポリシーをアタッチ

ビルドプロジェクトがSystems Managerのパラメータストアに保存されているパラメータを参照する場合、ビルドプロジェクトのサービスロールにssm:GetParametersアクションを許可する必要があります。

サービスロールは、CodeBuildコンソールのビルドプロジェクト→編集環境から確認できます。

IAMのコンソールからサービスロールに遷移し、ポリシー名をクリックします。

さらにアクセス許可を追加するをクリックします。

以下の通りに、GetParametersを追加します。
  • サービスSystems Manager
  • アクションGetParameters
  • リソース全てのリソース
    ポリシーの確認をクリックし、変更の保存をクリックすると設定は完了です。

buildspec.ymlの修正

CodePipelineでのBuildステージにおいて、DockerHubにログインし、認証ユーザーとしてイメージをpullするために、以下の一行をbuildspec.ymlに加えます。

echo $DOCKER_PASSWORD | docker login -u $DOCKER_USER --password-stdin

buildspec.yml修正後
version: 0.2

phases:
  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_PASSWORD | docker login -u $DOCKER_USER --password-stdin
  build:
    commands:

CodeBuildに環境変数を追加

Buildステージに環境変数を追加する方法は、以下の2つあります。
・buildspec.ymlに環境変数を追加する。
・CodePipelineのCodeBuildのステージに環境変数を追加する。

方法①buildspec.ymlに環境変数を追加する

以下のenvにパラメータを入れます。

buildspec.ymlに追加後
version: 0.2

+ env:
+  parameter-store:
+    DOCKER_USER: DOCKER_HUB_ID
+    DOCKER_PASSWORD: DOCKER_HUB_PASSWORD

phases:
  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_PASSWORD | docker login -u $DOCKER_USER --password-stdin
    commands:

DOCKER_HUB_IDDOCKER_HUB_PASSWORDは、パラメータストアで設定した名前になります。

方法②CodePipelineのCodeBuildのステージに環境変数を追加する

こちらの方法で行う場合、DOCKER_HUB_IDDOCKER_HUB_PASSWORDの名前は、/CodeBuild/を頭につける必要があるため、あまりおすすめしません。
パラメータストアで作り直します。
DOCKER_HUB_ID/CodeBuild/DOCKER_HUB_ID
DOCKER_HUB_PASSWORD/CodeBuild/DOCKER_HUB_PASSWORD

環境変数の名前タイプを以下のように追加します。
DOCKER_USER/CodeBuild/DOCKER_HUB_IDパラメータ
DOCKER_PASSWORD/CodeBuild/DOCKER_HUB_PASSWORDパラメータ

これによって、環境変数に設定したには、パラメーターストアで設定した値が入ります。

これで、ビルドで失敗する確率がぐっと下がりました。

ビルド時のエラー集①

サービスロールにSystems Managerssm:GetParameters がアタッチされていない場合に発生します。

Phase context status code: Decrypted Variables Error Message: AccessDeniedException: User: arn:aws:sts::xxxxxxxxx:assumed-role/codebuild-wordpress-service-role/AWSCodeBuild-1b8f0170-e973-4b24-8b03-f61cfb95a403 is not authorized to perform: ssm:GetParameters on resource: arn:aws:ssm:ap-northeast-1:xxxxxxxxxx:parameter/

ビルド時のエラー集②

環境変数の値が間違っています。

Phase context status code: Decrypted Variables Error Message: parameter does not exist: 

ビルド時のエラー集③

CodeBuildに環境変数が設定されていない場合に発生します。

Error: Cannot perform an interactive login from a non TTY device

ビルド時のエラー集④

パラメータに設定しているユーザ名かパスワードが間違っています。

Error response from daemon: Get https://registry-1.docker.io/v2/: unauthorized: incorrect username or password

#参考
ビルドプロジェクトの設定の変更 (コンソール)
CodeBuildのIPガチャを回避
Docker Hub の Rate Limitに引っかかったのでdocker loginで対策