CodePipelineの同じパイプラインを呼び出すEventBridgeのルールが複数存在する場合の挙動を確認した

2021.08.31

FargateへCI/CDの設定をCodePipelineで行っていました。CodePipelineの設定はCloudFormationで作成した後にマネージメントコンソールから手動で変更、設定追加などして動作検証していました。その中で以下の状況に遭遇しました。

CodeCommitの特定ブランチにPushしました。その後、CodeBuildによるビルドフェーズ(Build)が実行中で成功・失敗とも分からないまま、後続のデプロイフェーズ(Depoly)が実行中です。一体なにをデプロイしようとしているのでしょうか?

どういった設定だとこの状況になるのか、設定した内容をさかのぼって確認しました。

結論

  • CloudWatch Eventsのルール内に重複した内容のイベントルール設定があり、1回のCodeCommitへのPushで2度パイプラインを起動していた。
  • 重複したルールの1つは明示的にCloudFormationで作成したルール。
  • もう片方はマネージメントコンソールから手動でパイプラインを作成したタイミングで自動的に追加されたルール。

イベントを追う

CodeCommitにPushした後、何が起きたのかCloudTrailから確認します。

StartPipelineExecutionのイベントが同時刻に2つあります。なにかのパイプラインが2回呼び出されていることが分かります。

ログを比較

2つのuserNameが存在し、共に同じパイプライン(冒頭のスクリーンショットのパイプライン)を呼び出している事が分かりました。また、invokedByevents.amazons.comということから、CloudWatch Eventsか、EventBridgeから呼ばれていることが分かります。

EventRecord1の抜粋

        "sessionContext": {
            "sessionIssuer": {
                "type": "Role",
                "principalId": "AROAQ4BT4DHFLRQ3GWYT3",
                "arn": "arn:aws:iam::123456789012:role/service-role/sample3-dev-webservice-eventbridge-service-role",
                "accountId": "123456789012",
                "userName": "sample3-dev-webservice-eventbridge-service-role"
            },
            "webIdFederationData": {},
            "attributes": {
                "creationDate": "2021-08-28T00:15:55Z",
                "mfaAuthenticated": "false"
            }
        },
        "invokedBy": "events.amazonaws.com"

EventRecord2の抜粋

        "sessionContext": {
            "sessionIssuer": {
                "type": "Role",
                "principalId": "AROAQ4BT4DHFPWFZ5H3EC",
                "arn": "arn:aws:iam::123456789012:role/service-role/cwe-role-ap-northeast-1-sample3-dev-webservice-pipeline",
                "accountId": "123456789012",
                "userName": "cwe-role-ap-northeast-1-sample3-dev-webservice-pipeline"
            },
            "webIdFederationData": {},
            "attributes": {
                "creationDate": "2021-08-28T00:15:55Z",
                "mfaAuthenticated": "false"
            }
        },
        "invokedBy": "events.amazonaws.com"

CloudWatch Events? EventsBridge?となったときはよくある質問をご確認いただくと分かりやすいかと思います。

Q: Amazon EventBridge は CloudWatch Events とどのように関連していますか?

Amazon EventBridge は、CloudWatch Events をベースに構築された、CloudWatch Events を拡張するサービスです。以降省略...

CloudWatch Eventsか、EventBridgeのルール確認

CodeCommitのイベントを検知してCodePipelineを実行するルールはCloudFormationから明示的にCloudWatch Eventsのルールを作成していました。似たようなルールが存在するはずなので調べます。

sample3-dev-webserice-ruleはCloudFormationで作成したものです。codepipeline-からはじまるルール名が怪しいので確認します。

上の画像の赤枠のルール2つとも以下の同じイベントパターンの設定がされていました。内容は特定のCodeCommitのリポジトリ(sample3-webappservice)の特定ブランチ(main)で特定のイベント(作成または更新)をトリガーとしています。

EventPattern

{
  "source": [
    "aws.codecommit"
  ],
  "detail-type": [
    "CodeCommit Repository State Change"
  ],
  "resources": [
    "arn:aws:codecommit:ap-northeast-1:123456789012:sample3-webappservice"
  ],
  "detail": {
    "event": [
      "referenceCreated",
      "referenceUpdated"
    ],
    "referenceType": [
      "branch"
    ],
    "referenceName": [
      "main"
    ]
  }
}

イベントを検知するとターゲットの設定が同じパイプラインを指定しています。冒頭のビルドフェーズと、デプロイフェーズが実行中のパイプラインのことです。つまり、1回のCodeCommitへのPushで2回同じパイプラインを呼び出します。

ビルドフェーズが実行中にもかかわらず、デプロイフェーズが実行中だったのは、一足先に起動したパイプラインがビルドを終えデプロイに入り、少し遅れて起動したパイプラインがまだビルド中だったためです。

では、codepipeline-からはじまる名前のルールはいつ作成されたのでしょうか?

ルール作成したのは?

マネージメントコンソールからパイプラインを作成すると自動的にCloudWatch Eventsにルール追加が行われます。以下ドキュメントの引用になります。

CodePipeline は、Amazon CloudWatch Events を使用して、CodeCommit ソースリポジトリとブランチの変更や S3 ソースバケットの変更を検出します。

コンソールを使用してパイプラインを作成または編集すると、変更検出リソースが作成されます。

CloudTrailからルール追加のイベント名(PutRule)を検索すると、まずCloudFormationからのPutRuleのログがあります。その後にマネージメントコンソールでCloudFormationで作成したパイプラインの設定変更していました。またPutRuleのログが記録されています。

マネージメントコンソールからパイプラインを作成するときはCloudWatch Eventsのルール設定を意識することはありません。よしなにやってくれる分、ここを知っているとトラブルシュートかなにかで役に立つかもしれません。

おわりに

CodePipelineのCloudFormationをはじめて作成したときに、CodeCommitにPushしてもパイプラインなにも反応しないぞ?どこでフックしてるんだと調べたことがありました。

当初の想像していたのはCodePipelineという枠組みのなかで、CodeCommitのイベントを検知してるのかと思っていました。それは誤りでCodeCommitのイベントをEventBridgeのルールで拾って、CodePipelineの所定のパイプラインを起動させることを知りました。その時はEventBridgeのルールがいつ作成されたいたのかまでは把握していませんでした。今回の一件で再度ドキュメントを読み直す機会があり、CodePipeline起動前の動作について理解が深まりました。

後日追記

マネージドコンソールからパイプラインを見てたら、CloudWatch Eventsで検出するか、CodePipelineで検出するか選べるオプションがありました。推奨はCloudWatch Eventsになっており、あながちCodePipelineで検知すると想像していたのは間違いではありませんでした。