ECRのイメージを更新して、EventBridge経由でGitLabのパイプラインを実行する

以前に[イメージの更新契機でTektonパイプラインを実行する](https://qiita.com/ipppppei/items/d64808f93d1198ade5df)という記事を書いたが、その派生版として、ECR上のイメージを更新してGitLabのパイプラインを実行する、というのを試した時のメモ。


## やること
- ECRにpushする
- pushした契機でEventBridgeを動かす
- EventBridgeが動いた契機でGitLabのパイプラインを実行する

なお、今回使ったGitLabは普段はIPによるアクセス制限を実施しているが、テストのために一時的にアクセス制限を緩和して実施した。
IP制限を実施しようとすると、[AWS IP アドレスの範囲](https://docs.aws.amazon.com/ja_jp/general/latest/gr/aws-ip-ranges.html)に記載されているIPを制限すればいいのかもしれない。EventBridgeのAPI destinationのIP rangeをご存知の方がいたら教えて欲しい。


## GitLabの設定
最初に、対象となるGitLabのパイプラインを動かすProjectを用意する。
今回は[hello-tanzu](https://github.com/tanzu-japan/hello-tanzu)をcloneしたものを用意し、ProjectのCI/CD->Editorからデフォルト値が適用された`.gitlab-ci.yml`を作成した。
![1657257218502.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547981/ef01e895-c432-658f-1940-6c655a9eba10.png)
また、Image Push契機でRunnerを動かすために、Webhookを設定する。CI/CD -> Pipeline triggers -> Expandを選択し、Add triggerでTriggerを追加する。
![1657257533824.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547981/eccf7092-80ce-d214-37ee-1ccc260687a7.png)
追加後、"Use webhook"のところに表示されたURLを保存し、REF_NAMEとTOKEN（"Add trigger"を押した際に作成されたToken）を書き換えてメモ帳なりに控えておく。\
今回、対象プロジェクトのプロジェクトIDが`3`であり、ターゲットは`main`ブランチ、Tokenは`ca85c3d59036cc92b3fbe1df5e3949`であるため、WebhookのURLは以下のようになった。
```
https://gitlab.mygitlab.hoge/api/v4/projects/3/ref/main/trigger/pipeline?token=ca85c3d59036cc92b3fbe1df5e3949
```

## EventBridgeの設定

### イベントパターンの作成
EventBridgeにアクセスし、"Create rule"からEventを作成する。\
Rule typeは"Rule with an event pattern"を選択する。
![1657255399178.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547981/2e375a3d-7117-fc0a-59fd-20a8acd97306.png)
Event sourceに"AWS events or EventBridge partner events"を選択し、Event patternを埋める。(Sample eventのところは無視する)\
設定した項目はこちらとなる。
- Event source：AWS services
- AWS service：ECR
- Event type：ECR Image Action
- Specific action type(s)：PUSH
- Specific result(s)：SUCCESS
- Any repository
- Any image tag
  
 今回はImageのPushに成功したらGitLabのPipelineをキックしたいため、イベント契機をPUSH, SUCCESSに絞っている。（実運用時はrepositoryなども絞るべき）\
 実際に入力した画面は以下となる。
![1657256040859.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547981/4bd16785-aee3-80dd-9e5c-487305aea283.png)
これでイベントパターン（API発行契機）が作成されたので、Nextを押してターゲットの選択に進む。

### ターゲットの選択
どこにイベント通知を送るかを定義する。"Target types"で"EventBridge API destination"を選択し、"API destination"で"Create a new API destination"を選択する。
![1657260695764.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547981/896b2a01-9c34-400d-482d-7f82fd2c4f2f.png)
Nameを適当に設定した後、以下を設定する。
- API destination endpoint：WebhookのURL(https://gitlab.mygitlab.hoge/api/v4/projects/3/ref/main/trigger/pipeline?token=ca85c3d59036cc92b3fbe1df5e3949)
- HTTP method：POST

また、Connectionを作る必要があるが、今回はTokenをURLの中に含んでいるので、中身は適当で問題ない。
- Conncetion："Create a new connection"
- Connection name：GitLabConnection
- Destination type：Other
- Authorization type：API Key
- API key name：hoge
- Value：fuga
- Execution role："Create a new role for this specific resource"

残り、Nextを押して終了となる。

## 動作確認
手元の環境にdocker daemonを入れていないので、imageのpushは[imgpkg](https://carvel.dev/imgpkg/)コマンドで実施する。

ECRの"View push commands"よりdocker loginコマンドをコピーして実行する。
```
aws ecr get-login-password --region us-east-1 | docker login --username AWS --password-stdin xxxxx.dkr.ecr.us-east-1.amazonaws.com
```
適当なImageをpushする。今回は事前に自前のHarborに作成しておいたhello-tanzuのイメージを利用し、それをECRにコピーする。
```
imgpkg copy -i myharbor.hoge/myapp/hello-tanzu --to-repo xxxxx.dkr.ecr.us-east-1.amazonaws.com/hello-tanzu
```
imgpkgコマンドが正常に終了すると、GitLab側でPipeline上にジョブが実行されるのが確認できる。
![1657265402001.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547981/60ac0b8e-2f9f-9f82-a5f3-7bd2fe77102c.png)

## おまけ：TRIGGER_PAYLOAD
GitLabにはEventBridgeから渡ってきた情報が環境変数`TRIGGER_PAYLOAD`という名前で格納される。
今回検証で使った環境での`TRIGGER_PAYLOAD`の中身は以下のようになっている。
```json
{
  "ref": "main",
  "version": "0",
  "id": "3",
  "detail-type": "ECR Image Action",
  "source": "aws.ecr",
  "account": "xxxxx",
  "time": "2022-07-08T07:27:39Z",
  "region": "us-east-1",
  "resources": [],
  "detail": {
    "result": "SUCCESS",
    "repository-name": "hello-tanzu",
    "image-digest": "sha256:0246b1e14ba01b66e90b7485033992635bb820cd25d31319adc1471497fe0a5b",
    "action-type": "PUSH",
    "image-tag": "latest"
  },
  "variables": {}
}
```
イメージのダイジェスト値が含まれるため、ECRのイメージ更新契機でGitLabのジョブがキックされた際、ArgoCDが管理するManifestのイメージのダイジェスト値を上書きすれば自動デプロイも実現できる。