ITお絵かき修行

3歩歩いても忘れないために

CodeBuildのIPガチャを回避するお話

CodePipelineからCodeBuildを呼び出してDockerイメージを作成しデプロイする際、DockerHubの匿名ユーザによるAPI呼び出し制限に引っかかってビルドエラーが頻発する現象が発生しました。

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

クラスメソッド様のブログを参照して『DockerIDを取得しユーザー認証する設定』を実施しました。しかしDockerクソ雑魚勢の私にはハードルが高く色々詰まってしまったので、1から設定する手順をここに残します。
“Too Many Requests.” でビルドが失敗する…。AWS CodeBuild で IP ガチャを回避するために Docker Hub ログインしよう!という話 | Developers.IO

目次


前提
・CodeBuildを使用したECSのビルド環境がすでに存在している
・CodeBuildが使用するRoleに適切な権限が付与されている
→SSM、KMS、ECS、CodeBuildの各種権限が付与されていれば問題ないと思います。私はかなり強めの権限で実施したので、権限を絞っているとうまくいかない可能性はあります。
・CodePipelineを利用していなくても問題ありません

1.DockerIDの取得

(1)DockerHubよりDockerIDを取得

Docker Hub

ID・メールアドレス・パスワードを設定します。
Docker IDの命名規約ですが、下記の制限があります。

  • 長さは4文字以上30文字以下
  • 数字および英小文字で構成する

しかし現在(2020/11/25)実際に入力する際に大文字でも入力でき、発行されるIDが小文字に変換された状態で発行されます。(IDに対する入力チェックがないです。。)
なのでDockerIDは上記制約に従ったIDを設定して下さい。IDが間違っているとDockerHubの認証時に下記のエラーメッセージが出力されます。

Error response from daemon: Get https://registry-1.docker.io/v2/: unauthorized: incorrect username or password
(2)ID発行後にメール検証

「[Docker Hub] Please confirm your email address」の様な件名のメールが、入力したメールアドレス宛に届くので、verifyします。
DockerHubへのログインをしたいだけなので、ここまででDockerHubの作業は完了です。IDとパスワードは次以降の手順で使用します。

2.CodeBuildへの環境変数追加およびパラメータストアへID・パスワードの格納

クラスメソッド様のブログではSecretManagerを使用されていましたが、私はお金をかけたくなかったのでParameterStore(SecureString)を使用しました。
ParameterStore(SecureString)は、CloudFormationでの作成に対応していないのでマネコンより作成します。
(※手順では画面の操作を指示しています。今後画面の配置が変わる可能性はありますが、実施したい内容は変わりません。また本手順ではCodeBuildコンソールから作成していますが、SSMから作っても問題ないはずです)

(1)CodeBuildの更新(前半)

a.CodeBuildのビルドプロジェクト画面を開く(※ビルド履歴が並んでいる画面)
b.右上「編集」より「環境」を選択
c.『AWS CodeBuild にこのサービスロールの編集を許可し、このビルドプロジェクトでの使用を可能にする』のチェックを外し、下の「追加設定」を開く (※チェックを外さないと保存できません。。)

(2)SystemsManager ParameterStoreにてパラメータの作成(SecureString)

a.「パラメータの作成」を押下し、「名前」「値」を設定します。私は下記の値を設定しました。
※クロスアカウントで実施される方はKMSを変更したほうがいいと思います。それ以外の方はデフォルトキーの方が何かと問題にならないと思います。

名前
DOCKERHUB_USER [DockerID]
DOCKERHUB_PASS [DockerIDに対応するパスワード]

b.パラメータを作成すると下記のようになります。パラメータ名の先頭に『/CodeBuild』が付与されます。

ParameterStoreにおけるパラメータ名
/CodeBuild/DOCKERHUB_USER [DockerID]
/CodeBuild/DOCKERHUB_PASS [DockerIDに対応するパスワード]

■ParameterStoreの様子
f:id:hhhhhskw:20201125175504j:plain

(3)CodeBuildの更新(後半)

a.パラメータが作成されると、名前のない環境変数が作成されているので、環境変数の名前をそれぞれ入力したうえでページ下部の「環境の更新」を押下します。
私は環境変数名もパラメータ名に合わせたので、結果として下記のような設定値となりました。

CodeBuild環境変数 ParameterStoreにおけるパラメータ名
DOCKERHUB_USER /CodeBuild/DOCKERHUB_USER [DockerID]
DOCKERHUB_PASS /CodeBuild/DOCKERHUB_PASS [DockerIDに対応するパスワード]

■パラメータの設定状態(CodeBuild)
f:id:hhhhhskw:20201125172100j:plain
環境変数の設定状態(CodeBuild)
f:id:hhhhhskw:20201125172103j:plain

3.CodePipelineの修正(※実施しません)

本手順では実施しません。最初はCodePipelineから渡そうとしていましたが、過度に複雑になりそうだったのでやめました。
ただCodePipelineのパラメータで一元管理したい等の何らかの事情がある場合は、CLIからの更新でパラメータを追加すれば可能だと思います。

4.buildspec.ymlの修正

buildspec.ymlのpre_buildにコマンドを追加します。(下の末尾2行です)
--password-stdinオプションを使わないと警告が出るので下記としています。

phases:
  pre_build:
    commands:
      - DEFAULT=`pwd`
      - echo Logging in to Amazon ECR...
      - aws --version
      - $([※ECSへのログイン])

      - echo Logging in to Docker Hub...
      - echo $DOCKERHUB_PASS | docker login -u $DOCKERHUB_USER --password-stdin

5.実行

Pipelineを流し直して、CodeBuildを実行します。基本的にはうまくいくはずです。
失敗した場合は権限周りやアカウント周りを疑った方がいいと思います。パラメータの置換はうまくいっている場合が多いです(経験上)。
ユーザー認証するようになってからは「toomanyrequests」のエラーは出力されていません。
f:id:hhhhhskw:20201125175855j:plain

6.CodeBuildトラブルシュート

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

CodeBuildの環境変数に値が設定されていない場合に発生します。
DockerHubへのアクセスで発生した場合は、credential等の問題ではないです。
CodeBuildの環境、ビルド結果等に環境変数が設定されていることを確認してください。
参考:Solved: Piplenes: docker login can not perform an interact...


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

ユーザー情報が間違っています。環境変数は正しく設定されている場合が多いので、メールのアクティベーションなど実施漏れがないかを確認したほうがいいと思います。

7.さいごに

  • CodeBuildはハマりどころが多くよく泣かされています(よね)
  • 以前10回以上ビルドに失敗し1時間ドブに捨てたことがあるので、本手順で皆様の時間が救えれば幸いです
  • ソシャゲもAWSもガチャ運なさ過ぎることがわかったのでFGO引退します


■公式・先人の知恵など
CodeBuild のビルド仕様に関するリファレンス - AWS CodeBuild
CodeBuild の Docker サンプル - AWS CodeBuild
docker login | Docker Documentation

Solved: Piplenes: docker login can not perform an interact...
Docker IDの取得方法 — Docker を用いた HPCI ログイン
“Too Many Requests.” でビルドが失敗する…。AWS CodeBuild で IP ガチャを回避するために Docker Hub ログインしよう!という話 | Developers.IO
AWS CodeBuildでビルド時に環境変数を設定する | Hack Notes