2
1

【AWS】CFn用CI/CD環境の作り方(単一リポジトリに複数ファイルが存在する場合)

Last updated at Posted at 2024-03-26

はじめに

CloudFormation をデプロイする際にどのように実行していますか?
私は CloudShell にテンプレファイルを格納してデプロイすることが多いです。

ただ、以下参考記事に記載されているように、
テンプレートをバージョン管理する前提であれば、
リポジトリにあるテンプレートと AWS インフラを同期させるためにパイプラインからの実行が必要になります。

本記事は複数ファイルが格納されているリポジトリである前提の元、
更新した特定ファイルをパイプラインから CloudFormation デプロイするための手順を記載した内容になります。

■ 参考先

結論

以下2パターンの方法で、
複数ファイルが混在するリポジトリのファイル更新を検知することが可能になる。

  • パターン①:CodePipeline*Codebuildを利用
    • Codebuildを利用してリモートリポジトリの HEAD 情報の差分を取得。
      更新有無を検知し特定ファイルのみ CloufFormation デプロイ処理を行うよう設定
  • パターン②:CodePipeline統合CloudFormationを利用

それぞれのメリットとしては以下の通りである。

  • パターン①
    • Codebuildを利用するため、テストツールの挿入が可能。
      また、エラーが発生した場合にもCloudWatchLogsにログが出力できるため調査が容易
  • パターン②
    • 設定が容易だが、テストルールなどのカスタマイズができない

構成の特徴/構成図

構成の特徴

  • 以下のように複数ファイルが存在するリポジトリにて、
    特定ファイルが更新された時に更新ファイルのみCfnデプロイされること。
Repository(Github上のリモートリポジトリ)
├─index.html
├─style.css
├─README.md
├─buildspec.yml
├─00_img
├─src
└─template
  │─CfntemplateA.yaml
  │─CfntemplateB.yaml★本ファイルのみ更新対象としたい
  └─CfntemplateC.yaml

■GithubのGUI
image.png

構成図

image.png

実装方法

パターン①:CodeBuild利用

1.リモートリポジトリの作成

今回は Github のプライベートリポジトリの利用を想定しています。
リポジトリ作成方法は以下リンクを参考とするため、
本記事の記載からは割愛します。
GitHub プライベートリポジトリの作成手順

2.buildspec ファイル作成

buildspec ファイルとは、CodeBuild 実行時に実行するコマンドを記述したファイルとなります。
今回は更新されたファイルのみを検知できるよう以下記述になりました。
また、本ファイル作成後はリポジトリの最上位階層に格納する必要があります。

version: 0.2

env:
  variables:
    AWS_REGION: ap-northeast-1
    CfntemplateA: CfntemplateA.yaml
    CfntemplateB: CfntemplateB.yaml
    CfntemplateC: CfntemplateC.yaml

phases:
  pre_build:
    commands:
      - echo "Checking for files SettingFalgs..."
      - CfntemplateA_UPDATE_FLAG=$(git diff --name-only HEAD~1 HEAD | grep "$CfntemplateA") || echo "$CfntemplateA_UPDATE_FLAG"
      - CfntemplateB_UPDATE_FLAG=$(git diff --name-only HEAD~1 HEAD | grep "$CfntemplateB") || echo "$CfntemplateB_UPDATE_FLAG"
      - CfntemplateC_UPDATE_FLAG=$(git diff --name-only HEAD~1 HEAD | grep "$CfntemplateC") || echo "$CfntemplateC_UPDATE_FLAG"
      - ls ./template/$CfntemplateA
  build:
    commands:
      - if [ -n "$CfntemplateA_UPDATE_FLAG" ]; then aws cloudformation deploy --template-file ./template/$CfntemplateA --stack-name CfntemplateA; echo " $CfntemplateA has been deployed."; fi
      - if [ -n "$CfntemplateB_UPDATE_FLAG" ]; then aws cloudformation deploy --template-file ./template/$CfntemplateB --stack-name CfntemplateB; echo " $CfntemplateB has been deployed."; fi
      - if [ -n "$CfntemplateC_UPDATE_FLAG" ]; then aws cloudformation deploy --template-file ./template/$CfntemplateC --stack-name CfntemplateC; echo " $CfntemplateC has been deployed."; fi

  post_build:
    commands:
      - echo "CloudFormation deployment completed."

env:buildspec.yml 内で共通で利用できる環境変数の設定
pre_build:ビルド実行前に実行するコマンド。主に依存パッケージのインストールやファイル取得など。
CfntemplateA_UPDATE_FLAG=:後段の処理を変数として格納
git diff --name-only HEAD~1 HEAD:「git diff」コマンドにて、コミット差分を検出する。コミットにはコミット単位でハッシュ値(コミットを表す一意の値)が付与される。HEAD は最新のハッシュ値を指定する記述であり、コミット対象となったファイルのみハッシュ値が更新されるため、ファイルが更新されない限り HEAD は同じ値となる。
※「HEAD~1」は最新コミットの 1 つ前のを指す。
※「--name-only」は差分として検出されたファイル名を抜き出す
build:ビルド時に実行するコマンド。
if [ -n "$CfntemplateA_UPDATE_FLAG" ]:対象変数に値が格納されている場合のみ後続の処理を実行
CloudFormation deploy:更新対象テンプレテートファイルを用いて、スタック更新

3.CodePipeline の作成

AWS コンソールより CodePipeline の作成を選択する。
※以下一部設定項目のみピックアップして記載

  • 必須設定はなく各値は任意で設定
  • パイプラインタイプもv1,v2どちらでも良い

2024-03-20_10h39_55.png

3-1.CodePipeline と GitHub リポジトリを紐づけ

以下設定を行い、「Githubに接続する」を選択

  • ソースプロバイダー:Github(バージョン2)

2024-03-20_10h42_19.png

  • 適当な接続名を入力し、「Githubに接続する」を選択する。

image.png

  • 「新しいアプリをインストールする」を選択する。

2024-03-20_10h46_03.png

表示内容に従ってGithubへログイン。
その後リソース取得元のリポジトリを選択し、「Save」を選択する。
2024-03-20_10h47_23.png

githubとの連携が完了したので、
イベントのトリガーとなるリポジトリとブランチを選択する。

  • 出力アーティファクト形式:完全クローン
    • 本オプションはリポジトリのクローンを後続のCodeBuildの実行環境に格納するオプションとなる。
      後続のCodeBuildでgit Cloneコマンドを実行するためこちらを選択

image.png

3-2.CodeBuild の設定

CodeBuildにてデプロイ対象の検知とデプロイを実施する設定を行う。
また、Pipeline設定の流れでCodeBuildの設定を実施。

  • プロバイダーを構築する:AWS CodeBuild
  • 「プロジェクトを作成する」を選択する。
    image.png

CodeBuildに付与するサービスロールは、
IAM関連の権限不足に伴うエラーが発生する可能性があるため、
必要に応じて権限を付与すること。
※最小特権ではないが「IAMFullAccess」を付与すると確実

  • Buildspec:buildspec ファイルを使用する
    • Buildspec 名 - オプショナル:デフォルト(buildspec.yml)

image.png

なお、デプロイステージは導入不要につきスキップとする

動作確認

リモートリポジトリへの Push をトリガーに、
対象ファイルのみ CloudFormatin デプロイが行われているか確認。

  • CfntemplateB.yamlのみ更新し、リモートリポジトリへ Push
$ git diff
diff --git a/template/CfntemplateB.yaml b/template/CfntemplateB.yaml
       Tags:
         - Key: Name
-          Value: !Sub "${SystemName}-${EnviromentId}"
+          Value: !Sub "${SystemName}-${EnviromentId}-aaa"
⇒「CfntemplateB」のみ更新されていることを確認
$ git add .
$ git commit -m ‘[test]テンプレートファイル追加’ -m ‘テスト用テンプレート追加’
$ git push origin main

githubへのプッシュをトリガーにパイプラインの起動を確認
image.png

  • CloudForamtion の画面を確認し、CfntemplateB.yamlのみ更新されていることを確認

image.png
image.png

以上で特定ファイルのみデプロイされたことが確認できました。

パターン②:CodePipeline統合CloudFormationを利用

CodePipeline 統合 CloudFormationとは?

CodePipeline では CodeBuild から CloudFormation をデプロイしなくても、
CodePipeline が CloudFormation をターゲットにしたデプロイ機能を備えている。

ただ、本機能ではデプロイ対象となるファイル/スタックの個別設定が必要になり、
条件(更新の有無)に応じた条件分けが行えない。

AWS CloudFormation アクションをデプロイする

1.リモートリポジトリの作成

パターン①と同様に割愛

2.CodePipeline の作成

AWS コンソールより CodePipeline の作成を選択する。
※以下一部設定項目のみピックアップして記載

  • 必須設定はなく各値は任意で設定
  • パイプラインタイプもv1,v2どちらでも良い

2024-03-20_10h39_55.png

2-1.CodePipeline と GitHub リポジトリを紐づけ

「出力アーティファクト形式:CodePipeline のデフォルト」を選択
パターン①と同様のため割愛

2-2.CodePipeline統合CloudForamtionの設定

デプロイステージより以下の通り設定を行う

  • デプロイプロバイダー:AWS CloudFormation
  • アクションモード:スタックを作成または更新する
  • スタック名:構築/更新したいスタックを選択
  • ソース名:SourceArtifact
    • ソースステージでgitリポジトリをクローンする場合、「SourceArtifact」のルートディレクトリはgitリポジトリのルートディレクトリとなる
  • ファイル名:対象テンプレートファイル名を記載
    • template/CfntemplateB.yaml
  • ロール名:事前にCodePipelineにSTSできる(信頼関係を設定)ロールを用意
    • Cloudforamtionのアクション権限を付与

image.png

2-3.CodePipeline統合CloudForamtionの設定複製

「アクションの追加」を選択して、デプロイしたいテンプレートの数だけ2-2を繰り返し実行する。
2024-03-24_00h27_47.png

今回は「CfntemplateA.yaml」「CfntemplateB.yaml」「CfntemplateC.yaml」を対象に、
デプロイステージ設定を行った。

2024-03-24_00h38_12.png

動作確認

リモートリポジトリへの Push をトリガーに、
対象ファイルのみ CloudFormatin デプロイが行われているか確認。

  • CfntemplateB.yamlのみ更新し、リモートリポジトリへ Push
$ git diff
diff --git a/template/CfntemplateB.yaml b/template/CfntemplateB.yaml
       Tags:
         - Key: Name
-          Value: !Sub "${SystemName}-${EnviromentId}"
+          Value: !Sub "${SystemName}-${EnviromentId}-aaa"
⇒「CfntemplateB」のみ更新されていることを確認
$ git add .
$ git commit -m ‘[test]テンプレートファイル追加’ -m ‘テスト用テンプレート追加’
$ git push origin main

githubへのプッシュをトリガーにパイプラインの起動を確認
image.png

  • CloudForamtion の画面を確認し、CfntemplateB.yamlのみ更新されていることを確認
    2024-03-24_00h23_13.png
    2024-03-24_00h24_57.png

終わりに

今回はリポジトリを更新したら、
自動的にテンプレートがデプロイされる仕組みを作ってみました。
実案件であれば変更セット作成までとして、了承は手動実行が安全だと思います。
本記事が誰かの助けになれば幸いです。

参考

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1