Fargate上のGitLab起点でCloudFormationを更新するGitOpsを実現したい

# はじめに
この記事はDevOps on AWS大全 実践編の一部です。
DevOps on AWS大全 実践編の一覧は[こちら](https://qiita.com/tech4anyone/items/c27e74f9ae569ced259f)。

この記事ではGitLab起点でCloudFormationを更新するCICDパイプラインのアーキテクチャを決める流れを解説しています。

具体的には以下流れで説明します。

- 解決したい課題の整理
- 今回使うAWSサービスの整理
- アーキテクチャの策定
- 策定したアーキテクチャで達成できたこと

AWSの区分でいう「Level 400 : 複数のサービス、アーキテクチャによる実装でテクノロジーがどのように機能するかを解説するレベル」の内容です。

# この記事を読んでほしい人
- DevOpsエンジニアがアーキテクチャを決めるときにどのような思考フローを踏んでいるか知りたい人
- CloudFormationを更新するCICDパイプラインのアーキテクチャを知りたい人
- AWS Certified DevOps Engineer Professionalを目指している人

# 前回までの流れ
[こちら](https://qiita.com/tech4anyone/items/023eca84a9f7ac6db474)の記事で以下のアーキテクチャを策定しました。
![](https://storage.googleapis.com/zenn-user-upload/b3aec3793ad9-20231228.png)

# 解決したい課題の整理
現在、解決したいと思っている課題は以下になります。
- GitLabにコミットしたCloudFormationテンプレートを使ってGitOpsを実現したい
- CICDパイプラインを実行した後、実行完了までの間はマネジメントコンソールを見たくない

ということで、これをどうやって解決するか考えていきましょう。

# 今回使うAWSサービスの整理
今回使う代表的なAWSサービスの概要とベストプラクティスを以下にまとめました。

## AWS CodeCommit
AWS CodeCommitは、AWSでホストされる完全マネージド型のソースコントロールサービスです。
Gitと互換性があり、プライベートなGitリポジトリを簡単に作成、管理、共有できます。
AWS CodeCommitは、スケーラブルで安全なストレージを提供し、大規模なプロジェクトやチームにも対応できます。
また、AWSの他の開発サービスやツールとも統合されており、開発プロセスを効率化できます。

## AWS CodeBuild
AWS CodeBuildは、AWSでホストされる完全マネージド型のコンティニュアスインテグレーション(CI)サービスでソースコードからテストやビルドを自動的に実行し、アーティファクトを生成します。
AWS CodeBuildは、様々なプログラミング言語やフレームワークに対応しており、カスタムビルド環境も作成できます。
また、AWSの他の開発サービスやツールとも統合されており、デプロイメントプロセスを効率化できます。

## AWS CodePipeline
AWS CodePipelineは、AWSでホストされる完全マネージド型のコンティニュアスデリバリー(CD)サービスでソースコードからデプロイメントまでの一連のステージを定義し、自動的に実行します。
AWS CodePipelineは、様々なソースプロバイダーやビルドプロバイダー、デプロイプロバイダーと統合できます。
また、AWSの他の開発サービスやツールとも統合されており、リリースプロセスを効率化できます。

## Amazon EventBridge
Amazon EventBridgeは、AWSでホストされる完全マネージド型のイベントバスサービスで、アプリケーションやサービスが発生させるイベントを収集し、ルールに基づいてターゲットに配信します。
Amazon EventBridgeは、様々なイベントソースやターゲット、AWSの他の開発サービスやツールとも統合されており、イベント駆動型のアーキテクチャを実現できます。

## ベストプラクティス

| サービス | ベストプラクティス |
| --- | --- |
| AWS CodeCommit | - リポジトリに適切な名前を付ける<br>- ブランチ戦略を明確にする<br>- コードレビューを実施する<br>- コード品質を保つために静的解析やテストを実行する |
| AWS CodeBuild | - ビルドプロジェクトに適切な名前を付ける<br>- ビルド仕様ファイル(buildspec.yml)を使用する<br>- ビルドキャッシュを有効化する<br>- ビルドログを保存する |
| AWS CodePipeline | - パイプラインに適切な名前を付ける<br>- ステージとアクションの順序と依存関係を明確にする<br>- 変更セットや承認アクションを使用してデプロイメントを安全にする<br>- パイプラインの状態をモニタリングする |
| Amazon EventBridge | - イベントバスに適切な名前を付ける<br>- イベントルールに適切な名前と説明を付ける<br>- イベントパターンを使用してイベントをフィルタリングする<br>- イベントターゲットに適切な名前と説明を付ける |


# アーキテクチャの策定
ここからはやりたいことを順番に考えながらアーキテクチャを策定していきます。
## GitLabにコミットしたCloudFormationを起点にCIを実現したい
GitLabにコミットしたCloudFormationを起点にGitOpsを実現するためにはAWSのCodeシリーズをフル活用する必要があります。
この後のCDまで含めるとCodePipelineを作成必要があるので、アーキテクチャにとりあえずCodePipelineを足しました。

![](https://storage.googleapis.com/zenn-user-upload/252a10fa77b9-20231228.png)

CodePipelineでCICDパイプラインの全体を管理していくのでこの後はCodePipelineを拡大して、その中に何を作っていくかを考えます。

まず、CloudFormationに対するCIとは何かをどう定義するかですが、ここでは静的解析を定期的に実行することをCIと定義します。
CloudFormation Stackを作り実際に作った環境が想定した設定になっているかを確認するほうがよりCIっぽいとは思いますが、ここまでやるとテストのためのソースコードをそれなりに作りこむ必要が出てくるため、費用対効果を考え今回は静的解析を採用します。

静的解析には有名どころやAWS謹製のCloudFormation Linter、cfn-python-lint、AWS CloudFormation Guardあたりを利用するとよいでしょう。
これらを活用して静的解析をするためにCodeBuildによるテストステージを追加しました。
静的解析をクリアしたらS3にアーティファクトを出力します。

そして、静的解析の後には環境の変更内容を知るためにCloudFormationのChange Setを生成してほしいと考えました。
そこで、CodeBuildでの静的解析の後にChange Setの作成ステージを追加しましょう。

これらをまとめると以下のようなアーキテクチャになります。
![](https://storage.googleapis.com/zenn-user-upload/0e5502aa700b-20231228.png)

## GitLabにコミットしたCloudFormationを起点にCDを実現したい
ここまでで、静的解析を行ったCloudFormationのChange Setを生成するところまでを実現できました。
そして、ここからCloudFormation Stackを作成します。
しかし、実際にCloudFormation Stackを作成する前にはChange Setの中身を承認者に確認してもらいたくなります。

そのため、CloudFormation Stackを作成する手前に承認フェーズを設けます。

これらをまとめると以下のようなアーキテクチャになります。
![](https://storage.googleapis.com/zenn-user-upload/86a40562ce03-20231228.png)

## GitLabにコミットしたCloudFormationを起点にChatOpsを実現したい
ここまでくるとGitLabを起点に静的解析のCDとChange Setの承認、CloudFormation Stack作成のCDが実現できているのでCICDパイプラインとしてはいったん完成となります。

しかし、実際の開発を考えるとパイプラインの進行状況をマネジメントコンソールでずっと見ていたくはありません。
そこで、マネジメントコンソールを見に行きたくなるタイミング、具体的にはChange Setの作成が終わったタイミングとCloudFormation Stackの作成が終わったタイミングでチャットに通知を飛ばすことにしようと思います。

通知を飛ばす先はすでにGitLabとセットで作成してあるMattermostにしようと思います。
そのため、CodePipelineのイベントを起点にチャットへの通知が駆動するような仕組みを作る必要があります。

こういったときに利用するのがEventBridgeです。
また、今回はチャットへの連携になるのでLambdaでMattermostのWebhookをよんであげる必要もあります、

これらをまとめると以下のようなアーキテクチャになります。
![](https://storage.googleapis.com/zenn-user-upload/67e9a48f68c9-20231228.png)

そして、このパイプラインを全体のアーキテクチャに組み込むと以下のようなアーキテクチャになります。
![](https://storage.googleapis.com/zenn-user-upload/e3ee1edeb117-20231228.png)

# まとめ
本記事ではGitLab起点でCloudFormationを更新するGitOpsを実現する方法をまとめました。

今回策定したアーキテクチャで実現できたのは以下の項目です。
- GitLabにコミットしたCloudFormationを起点に静的解析を実行するCI
- GitLabにコミットしたCloudFormationを起点にCloudFormation Stackを作成するCD
- マネジメントコンソールを確認する必要があるタイミングでチャットに通知を飛ばすChatOps

次回は今回考えたGitOpsをマルチアカウントに拡張する方法を考えてみたいと思います。