ワークフローについて
あるGitHubリポジトリにおいて、以下のようなワークフローを組んで運用しています。
name: CI pipeline
on:
push:
branches:
- master
pull_request:
branches:
- master
permissions:
contents: read
checks: write
jobs:
test:
if: github.event_name == 'pull_request'
runs-on: ubuntu-latest
container: public.ecr.aws/docker/library/maven:XXXXXXXX
steps:
- name: Checkout Repository
uses: actions/checkout@v3
- name: mvn test
env:
TZ: "Asia/Tokyo"
run: mvn -f server/pom.xml test
- name: Publish Test Report
uses: mikepenz/action-junit-report@v3
with:
report_paths: server/target/surefire-reports/TEST-*.xml
jar-topic-branch:
if: github.event_name == 'pull_request'
.
.
jar-master:
if: github.event_name == 'push' && github.ref_name == 'master'
.
.
トピックブランチでPRを作成した際にはtestとjar-topic-branchが、masterブランチにマージした際にはjar-masterが走ります。
ここで生成されたjarファイルを使ってアプリのデプロイを行っています。
エラー発生と原因特定
ある日PRを作成し、「テスト通ったかな?」とGitHub Actionsタブを開くと、複数のジョブでエラーが発生した痕跡がありました。確認したところ、私がトリガーしたジョブも失敗しています。
ログを見てみると、
/usr/bin/docker pull public.ecr.aws/docker/library/maven:XXXXXXXX
Error response from daemon: error from registry: Data limit exceeded
Error: Docker pull failed with exit code 1
実行環境のコンテナイメージをECR Publicからpullする際に上限に引っかかった、という感じでしょうか。
AWS ECR Publicの使用量上限
AWSのフルマネージドコンテナレジストリです。
パブリックレジストリからイメージを転送する際には、転送するデータ量に対して課金されます。
AWS認証をせず匿名で使用する場合、月間500GBまで利用可能。
AWS認証を行って使用する場合、月間5TBまで無料で利用可能で、その後は有料枠となるそうです。
このワークフローはAWS認証なしで使用していたので、月間500GBまでのData limitに到達してしまったようです。
月間500GBの匿名利用枠はIPアドレス単位で制限されるため、GitHub Actionsのホストランナー(共有IP環境)全体のリクエストが合算され、上限に達する場合があります。
必ずしも自組織だけで500GB使わなくても制限がかかる可能性があるということですね。
解決策
AWS認証を設定することで月間5TBの無料枠が適用され、制限を回避できます。
以下に、実際の手順をまとめました。
1. AWSアカウントにRoleを作る
今回は、仮に 000000000000 アカウントに GitHubActionsEcrRole を作るとします。
今回作成するIAMロールは、本番環境などの重要リソースがあるAWSアカウントから切り離された、開発用やCI共通用の別アカウントに作成する方が安全だと考えられます。
-
IDプロバイダの作成
プロバイダ名「token.actions.githubusercontent.com」のものが存在する場合は新規作成は不要です。
もしなければ、「プロバイダーを追加」から以下の内容で登録します。
プロバイダタイプ:OpenID Connect/ プロバイダの URL:https://token.actions.githubusercontent.com/ Audience:sts.amazonaws.com -
Role/Policyの作成
「信頼されたエンティティタイプ」で ウェブID を選択して作成します。
1.で作成したIDプロバイダと、お使いのGitHub組織/リポジトリの名前を入力。
アタッチするポリシーはAmazonElasticContainerRegistryPublicReadOnlyを指定します。
2. GitHubActionsワークフローに認証ステップを作成する
.
.
jobs:
test:
if: github.event_name == 'pull_request'
runs-on: ubuntu-latest
permissions:
contents: read
checks: write
id-token: write
steps:
- name: Checkout Repository
uses: actions/checkout@v3
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::000000000000:role/GitHubActionsEcrRole
aws-region: us-east-1
- name: Login to Amazon ECR Public
uses: aws-actions/amazon-ecr-login@v2
with:
registry-type: public
- name: mvn test
env:
TZ: "Asia/Tokyo"
run: |
docker run --rm \
--volume "$GITHUB_WORKSPACE:/workspace" \
--workdir /workspace \
--env TZ \
public.ecr.aws/docker/library/maven:XXXXXXXX \
mvn -f server/pom.xml test
- name: Publish Test Report
uses: mikepenz/action-junit-report@v3
with:
report_paths: server/target/surefire-reports/TEST-*.xml
.
.
主な変更点
- permissions を追加:
id-token: write権限を追加するため。最小権限のため、トップレベルには追加せず、OIDCを使用するジョブにのみ与えるようにしています - steps 内に
Configure AWS credentialsとLogin to Amazon ECR Publicを追加 - ジョブレベルの
container:から、steps内でのdocker runに変更
ジョブレベルのcontainer:はsteps実行前にpullされます。そのためsteps内で認証を行っても間に合わず、無認証扱いのままエラーとなってしまいます
結果
上記の対応を行ったことで、無事にワークフローが通るようになりました🎉
なお、Pull Requestをトリガーとして実行されるGitHub Actionsは、該当トピックブランチの設定ファイル(workflow.ymlなど)を参照して実行されます。
そのため今回も、このワークフローへの変更をmasterにマージすることなく、試験的に実行することができました。
日常的に稼働しているワークフローですが、今回のエラーをきっかけに見直したことで、ECRの仕様を学習するいい機会にもなりました。今後もメンテナンスを怠らないように努めていきたいと思います。