Amazon ECRのレプリケーションイベントをトリガーにAWS CodePipelineを起動してみた
はじめに
こんにちは、コンサルティング部の神野です。
「Amazon ECR(以下ECR)のクロスアカウントレプリケーションをトリガーとして、別アカウントのAWS CodePipeline(以下CodePipeline)を起動したい」ことがあって調査して試してみました!
例えば、開発環境で作成したコンテナイメージをそのまま、検証や本番環境で使用したくレプリケーションして、デプロイしたいケースなどです。
実際に試してみたところ、いくつか押さえておくべきポイントがあったので、今回はその内容を共有させていただきたいと思います。
ECRレプリケーションイベントについて
ECRでは、リージョン間やアカウント間でコンテナイメージを自動的にレプリケーションする機能が提供されています。
このレプリケーションが実行されると、下記のようなイベントが発行されます。
レプリケーションイベントの構造
公式ドキュメントを見ると、レプリケーション時に発行されるイベントは以下のような構造になっています。
{
"version": "0",
"id": "c8b133b1-6029-ee73-e2a1-4f466b8ba999",
"detail-type": "ECR Replication Action",
"source": "aws.ecr",
"account": "123456789012",
"time": "2024-05-08T20:44:54Z",
"region": "us-east-1",
"resources": [
"arn:aws:ecr:us-east-1:123456789012:repository/docker-hub/alpine"
],
"detail": {
"result": "SUCCESS",
"repository-name": "docker-hub/alpine",
"image-digest": "sha256:7f5b2640fe6fb4f46592dfd3410c4a79dac4f89e4782432e0378abcd1234",
"source-account": "123456789012",
"action-type": "REPLICATE",
"source-region": "us-west-2",
"image-tag": "3.17.2"
}
}
このイベントには、リポジトリ名、イメージダイジェスト、イメージタグ、レプリケーション結果などの情報が含まれています。
このイベントをEventBridgeで拾ってCodePipelineを起動させます。
全体の流れとしては下記となります。
EventBridgeルールの設定
基本的な設定パターン
まず、レプリケーションが成功したことを検知する基本的なルールは以下のようになります。
{
"detail-type": ["ECR Replication Action"],
"source": ["aws.ecr"],
"detail": {
"result": ["SUCCESS"],
"repository-name": ["cross-account-sample-image"],
"action-type": ["REPLICATE"]
}
}
この設定では、以下の条件を満たすイベントをキャッチします。
- ECRのレプリケーションアクションである
- 結果が成功(SUCCESS)である
- 特定のリポジトリ名に一致する
- アクションタイプがREPLICATEである
タグを厳密に指定する場合
もし特定のタグ(例えばlatest
タグのみ)をトリガーにしたい場合は、以下のようにimage-tag
を追加します。
{
"detail-type": ["ECR Replication Action"],
"source": ["aws.ecr"],
"detail": {
"result": ["SUCCESS"],
"repository-name": ["cross-account-sample-image"],
"action-type": ["REPLICATE"],
"image-tag": ["latest"]
}
}
この設定により、latest
タグが付与されたイメージがレプリケーションされた場合のみ、CodePipelineが起動されるようになります。
イメージタグ運用による設定の違い
ただ、イメージタグの運用方法によって設定方法が変わってきます。
パターン1: latestタグのような固定タグを使用する場合
latest
タグのような固定タグのみを使用する運用の場合は、上記の基本的な設定で問題なく動作します。
特別な設定は不要で、そのままCodePipelineと連携できます。
パターン2: コミットハッシュ等の動的なタグを使用する場合
Gitのコミットハッシュやビルド番号など、動的に変化するタグを使用している場合は注意が必要です。
何も指定しないと、CodePipelineのソースにはlatest
タグまたは固定のタグが使われてしまいます。
これでは、レプリケーションされた特定のイメージを正しく参照できません。
このような場合、EventBridgeの入力トランスフォーマー機能を使用する必要があります。
入力トランスフォーマー機能の設定
入力トランスフォーマー機能を使うことで、EventBridgeのイベント情報を加工して、CodePipelineに渡すことができます。
入力パスの設定
まず、イベントから必要な情報を抽出するための入力パスを定義します。
{
"imageDigest": "$.detail.image-digest",
}
この設定により、以下の情報を変数として取り出せます。
imageDigest
: イメージのダイジェスト値
入力テンプレートの設定
次に、抽出した情報をCodePipelineに渡す形式に変換します。
{
"sourceRevisions": [
{
"actionName": "cross-account-sample-image-latest",
"revisionType": "IMAGE_DIGEST",
"revisionValue": "<imageDigest>"
}
]
}
ここでのポイントは以下の通りです
actionName
: CodePipelineのソースアクション名を指定しますrevisionType
:IMAGE_DIGEST
を指定することで、特定のイメージを一意に識別しますrevisionValue
: 入力パスで抽出したimageDigest
を動的に挿入します
この設定により、レプリケーションされた特定のイメージダイジェストを持つイメージをソースとして、CodePipelineを起動できるようになります!このパターンを実際に試してみましょう!
実際にやってみる
前提
ECRのクロスアカウントレプリケーションの設定が済んでいる前提として進めていきます。
以下の作業はレプリケーション先のアカウントで進めていきます。
ECRのクロスアカウントレプリケーションの設定は下記を参照いただくとわかりやすいかと思います。
CodePipelineの設定
今回は動的にソースを取得することを確認したいので、あくまでECRをソースとした設定を進めていくところを中心に書いています。ビルドステージ以降は任意の組み合わせで構いません。
- CodePipelineコンソール上で
パイプラインを作成する
を選択
カスタムパイプラインを構築する
を選択
- 任意のパイプライン名を入力して、
次に
を選択
- クロスアカウントレプリケーションの設定を実施しているECRのレポジトリを選択します。また、タグは今回は動的に最新のイメージを取得したいので、空にしています。何も指定しなければ
latest
タグがソースとなります。
- ビルドステージ以降は任意の選択で構いません。今回はCodeBuildを指定しました。
- ビルドステージ以降のステップはスキップしてパイプラインを作成します。
パイプラインを作成すると動的にソースステージのアクション名が付与されるのでメモしておきます。後ほど入力トランスフォーマーの設定をする際に使用します。
次にEventBridgeの設定を進めていきます。
EventBridgeの設定
ECRのレプリケーションイベントを検知してCode Pipelineを実行する、EventBridgeルールを作成します。
-
EventBridgeコンソール上から
ルールを作成
を選択
-
任意のルール名を入力し、ルールタイプは
イベントパターンを持つルール
を選択して、次へ
-
カスタムパターンを選択し下記jsonを入力、repository-nameは今回使用するレポジトリ名にしておきます。レプリケーションが成功した際のイベントを検知するようにします。
{
"detail-type": ["ECR Replication Action"],
"source": ["aws.ecr"],
"detail": {
"result": ["SUCCESS"],
"repository-name": ["<今回使用するレポジトリ名>"],
"action-type": ["REPLICATE"],
}
}
4. AWSのサービスを選択し、ターゲットを選択でCodePipelineを選択します。事前に作成したパイプラインのARNを入力します
- 次に、ターゲット入力を設定で入力トランスフォーマーを選択し、設定します。
- 入力パスとテンプレートはそれぞれ下記を入力します。イメージダイジェストをイベントから取得し、トランスフォーマーでそのダイジェスト値を指定します。
actionName
はソースステージのアクション名を入力しましょう。
{
"imageDigest": "$.detail.image-digest"
}
{
"sourceRevisions": [
{
"actionName": "ソースステージのアクション名を入力",
"revisionType": "IMAGE_DIGEST",
"revisionValue": "<imageDigest>"
}
]
}
7. そのまま次に進めてルールの作成を完了させます。
これで準備が完了です。ソースアカウントでイメージを更新して、ターゲットアカウントでレプリケーションを実行させます。
レプリケーションが完了した時点では下記状態が最新となりました。
ダイジェストが2f8c・・・
から始まるイメージが最新で、latestタグが最新ではない状態です。
一方でCodePipeline側は問題なく起動しているか、また最新のイメージが動的に取得できているか確認してみます。
ソースステージの出力を見てみます。
ダイジェストを見ると最新のイメージとダイジェストが一致していますね!!動的に取得することが成功しました!
まとめ
今回は、クロスアカウントでECRレプリケーションをトリガーにCodePipelineを起動してみました。
EventBridgeとECRの連携はそこまで難しくなくシンプルだなと感じました。
ただ、一部タグ運用によってはEventBridgeの入力トランスフォーマー機能でハッシュ値を明示的に指定する必要があることがポイントですね。
本記事が少しでも参考になったら幸いです!
最後までご覧いただきありがとうございました!