11
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ZOZOAdvent Calendar 2024

Day 3

CloudFormationのGit同期を自動で作成する(複数のAWSアカウントにも対応)

Posted at

CloudFormation(CFn)のGit同期とは、GitリポジトリにPushしたらスタックが自動で更新される便利な機能です。プルリクエストに変更内容がコメントされる点も素晴らしいです。

image.png

ただし、公式では「マネジメントコンソールでスタックごとにGit同期を設定する方法」しか紹介されておらず、スタックが多い場合はかなり絶望的でした。

そこで本記事では「Gitリポジトリにファイルを追加したら、自動でスタックとGit同期が作成される状態を作る方法」を解説します。

TL;DR

先にゴールを紹介します。この記事では最終的に

aws cloudformation create-stack \
  --stack-name "スタック名" \
  --template-body "file://初期化用ファイル.yaml" # 何かファイルがないとスタックは作れない

で空のスタックを作成し、そのあと

aws codeconnections create-sync-configuration \
  --branch "ブランチ名" \
  --resource-name "スタック名" \
  --config-file "デプロイファイル.yaml" \
  --repository-link-id "REPOSITORY_LINK_ID" \
  --role-arn "IAM RoleのARN" \
  --pull-request-comment ENABLED \
  --sync-type CFN_STACK_SYNC

でGit同期を作成します。

さらにGitHub Actionsを用いて、新規追加されたファイルに対して上記コマンドを実行します。

事前準備 GitHubとAWSを連携する

これだけはどうしても自動化できません :bow:

まずはGitHubとAWSを接続します(GitLabやBitbucketも接続できます)

AWSマネジメントコンソールで CodeBuild > 接続 > 接続を作成

接続の一覧画面

画面に従ってGitHub Appをインストールします。接続名はGitHubのユーザー名(またはOrganization名)をおすすめします。

接続名を入力

GitHub Appのインストール

完了後に表示されるARNはこのあとすぐ使います。

接続の作成が完了

次にAWS CLIでリポジトリリンクを作成します(マネジメントコンソールからは作れません1

リポジトリリンクを作成する
aws codeconnections create-repository-link \
  --connection-arn "今作った接続のARN" \
  --owner-id "GitHubのユーザー名(またはOrganization名)" \
  --repository-name "GitHubのリポジトリ名"

出力されたリポジトリリンクIDは手元に保存してください。

リポジトリリンクIDの例
f919f952-e050-4b24-XXXX-XXXX494d49d6

準備は以上です。

なお、今回は違いますが、Gitリポジトリが2つ以上ある場合は次のようにします。

  • GitHub Appのインストール時に全てのリポジトリを指定する
    • GitHub > Settings > Applications であとから追加することも可能
    • リポジトリを制限せずにインストールするのもOK
  • 1つのリポジトリにつき1つのリポジトリリンクを作成する
    • aws codeconnections list-repository-linksで一覧を見られる

1. テンプレートとデプロイファイルを作る

Git同期を使う場合、いつものテンプレートに加えてデプロイファイルを作ります

まずは「焼肉プロジェクト」の本番環境のIAMユーザーのファイルを作ります。

デプロイファイル yakiniku-iam.yaml
template-file-path: iam.yaml # テンプレートのパス

parameters:
  env: prd
  project: yakiniku
テンプレート iam.yaml
AWSTemplateFormatVersion: 2010-09-09

Parameters:
  env:
    Type: String
  project:
    Type: String

Resources:
  IAMUser:
    Type: AWS::IAM::User
    Properties:
      UserName: !Sub ${env}-${project}-user

次にテンプレートを使いまわして「寿司プロジェクト」のIAMユーザーのファイルを作ります。

デプロイファイル sushi-iam.yaml
template-file-path: iam.yaml

parameters:
  env: prd
  project: sushi # ここだけ変えました!

今回は本番環境(prd)と事前環境(stg)の2つのAWSアカウントがある想定で、次のようなディレクトリ構成にしてみました。

ディレクトリ構成
├── cfn-deployments # デプロイファイル
│   ├── prd
│   │   ├── sushi-iam.yaml
│   │   ├── sushi-log.yaml
│   │   ├── yakiniku-iam.yaml
│   │   └── yakiniku-log.yaml
│   └── stg
│       ├── yakiniku-iam.yaml
│       └── yakiniku-log.yaml
└── cfn-templates
    ├── iam.yaml # IAMユーザーのテンプレート
    └── log.yaml # CloudWatchロググループのテンプレート

これらのファイルはこのあと使います。

2. 初期化用のCloudFormationテンプレートを作る

Git同期を設定するには先にスタックを作る必要があります2

空のスタックを作るために、次のようなテンプレートを準備しておきます(参考

initial-template.yaml
AWSTemplateFormatVersion: 2010-09-09

Resources:
  NullResource:
    Type: AWS::CloudFormation::WaitConditionHandle

3. スクリプトを作る

まずは「Gitリポジトリに新規追加されたファイルを一覧にする処理」が必要です。

作成だけに対応する場合(削除はしない場合)は次のように実装できます。

create-git-sync.sh(一部抜粋)
DIR="対象のディレクトリ"

# リモートのスタック一覧(削除済みは除く)(数が多い場合はページングが必要)
remote="$(aws cloudformation list-stacks --query 'StackSummaries[?StackStatus!=`DELETE_COMPLETE`].[StackName]' --output text | sort)"

# ローカルのファイル一覧
local="$(find "$DIR" -name '*.yaml' -exec basename {} .yaml \; | sort)"

# 差分(=新規作成されたファイル一覧)
diff="$(join -v2 <(echo "$remote") <(echo "$local"))"

これをfor文で回し、スタックとGit同期を作成します。なお、デプロイファイルのファイル名をスタック名にしています。

create-git-sync.sh(一部抜粋)
for stack_name in $diff; do

  echo "NEW STACK: $stack_name"

  # スタックの作成
  aws cloudformation create-stack \
    --stack-name "$stack_name" \
    --template-body file://initial-template.yaml

  # Git同期の作成
  aws codeconnections create-sync-configuration \
    --branch "ブランチ名" \
    --resource-name "$stack_name" \
    --config-file "$DIR/$stack_name.yaml" \
    --repository-link-id "事前準備で作成したリポジトリリンクID" \
    --role-arn "CloudFormationで使用するIAMロールのARN" \
    --pull-request-comment ENABLED \
    --sync-type CFN_STACK_SYNC

done

スクリプトの全体はGitHubでご確認ください。

4. スクリプトをGitHub Actionsで動かす

作成したスクリプトをGitHub Actions(GHA)で動かします。

今回はprdstgの2つのAWSアカウントを使うので、Jobは2並列で動かします。

.github/workflows/main.yaml(一部抜粋)
jobs:
  create-git-sync:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        conf:
          - account: AWS_ACCOUNT_ID_PRD
            branch: main
            dir: cfn-deployments/prd # デプロイファイルのディレクトリ(prd)
            link-id: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
          - account: AWS_ACCOUNT_ID_STG
            branch: main
            dir: cfn-deployments/stg # デプロイファイルのディレクトリ(stg)
            link-id: YYYYYYYY-YYYY-YYYY-YYYY-YYYYYYYYYYYY

次のようなステップを作り、先ほどのスクリプトを動かします。

.github/workflows/main.yaml(一部抜粋)
      - name: create-git-sync
        env:
          BRANCH: ${{ matrix.conf.branch }}
          DIR: ${{ matrix.conf.dir }}
          LINK_ID: ${{ matrix.conf.link-id }}
          ROLE_ARN: arn:aws:iam::${{ secrets[matrix.conf.account] }}:role/my-cloudformation-role
        run: |
          ./create-git-sync.sh "$BRANCH" "$DIR" "$LINK_ID" "$ROLE_ARN"

ワークフローの全体はGitHubでご確認ください。

これで実装は完了です!

結果

リポジトリにファイルを追加すると、自動でスタックとGit同期が作られるようになりました:tada:

作成されたスタック一覧

また、プルリクエストを作るとGitHub Appがスタックの変更内容をコメントしてくれます!(Git同期の作成時に--pull-request-comment ENABLEDを付けたからです)

コメント

ソースコード

作成したファイルは下記で公開しています。

最後までお読みいただきありがとうございました。よろしければ「いいね」もお願いします!

  1. 正確には、CloudFormationのGit同期を作成するときの画面では作ることができます。ただしこの段階ではスタックを作りたくないのでAWS CLIで作業しています

  2. 公式ドキュメントを参照。変更セットだけを作成した状態(REVIEW_IN_PROGRESS)では設定できない点に注意してください

11
0
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
11
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?