🏃

Goで書いたCDKをGitHub Actionsする

2023/06/02に公開

はじめに

こんにちは、@thousan_da です。

IaCをCI/CDしたかったので、AWS CDKをGitHub Actionsで自動化しました。
仕事ではTerraformとCircleCIを使っているため、これは趣味です。

使ったサービス/技術

  • AWS CDK (Cloud Development Kit)
  • GitHub Actions
  • Go

背景

クラウドを使っていて、リソースを画面からぽちぽち作るのは管理が大変になるので、IaC (Infrastructure as Code) を使っている人は多いと思います。しかしながら、IaCの運用を手作業で行なっているとこれもまたつらいです。

ということで、CDKのCI/CD環境をGitHub Actionsで作ります。

検索してみると、やっぱりCDKはTypeScriptで書いている人が多いですね。でも僕はGoで書きたいので、GoでセットアップしたCDKを使う方法を紹介します (2023年6月現在、GoのCDKはまだDeveloper Previewバージョンです) 。

mainブランチに対してPull Requestを作ったらdiffを表示し、それがマージされたらdeployされるようにしました。

ワークフローの構成

今回作ったワークフローの構成です。

  • ジョブ1: "cdk-diff"
    • インフラの変更差分を可視化するジョブ
    • cdk diff の実行結果を見ることができる
    • Pull Requestの作成/更新をトリガーに実行される
    • diffの出力結果をPull Requestにコメントする
  • ジョブ2: "cdk-deploy"
    • インフラの変更を適用するジョブ
    • cdk deploy を実行する

Actionsの設定ファイル

CDK Diff

name: CDK Workflow

on:
  pull_request:
    branches: [ main ]

jobs:
  cdk-diff:  # Pull Requestのときのみ実行する
    if: ${{ github.event_name == 'pull_request' }}
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code  # ブランチを切り替える
        uses: actions/checkout@v3

      - name: Setup Node.js  # Node.jsをセットアップする
        uses: actions/setup-node@v3
        with:
          node-version: 18

      - name: Setup Go  # Goをセットアップする
        uses: actions/setup-go@v4
        with:
          go-version: '1.20'

      - name: Install dependencies  # 依存ライブラリをインストールする
        run: |
          npm install -g aws-cdk
          go mod tidy

      - name: Configure AWS credentials  # GitHubに保存したAWSのSecretsを取り出して設定する
        uses: aws-actions/configure-aws-credentials@v2
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          aws-region: ap-northeast-1

      - name: CDK Diff  # 存在するリソースと設定の差分を取得する -> 得られた文字列をoutputを使って次のsrepに渡す (複数行に渡るのでヒアドキュメントで書く)
        id: diff
        run: |
          diff=$(cdk diff) || true
          echo "$diff"
          echo "cdk_diff<<EOF" >> $GITHUB_OUTPUT
          echo "$diff" >> $GITHUB_OUTPUT
          echo "EOF" >> $GITHUB_OUTPUT

      - name: Comment PR  # Pull Requestのコメントに上記の差分を書き込む (変更が無い場合は "No changes" とコメントする)
        uses: actions/github-script@v3
        with:
          script: |
            const diff = `${{ steps.diff.outputs.cdk_diff }}`;
            github.issues.createComment({
              issue_number: context.issue.number,
              owner: context.repo.owner,
              repo: context.repo.repo,
              body: diff ? diff : "No changes"
            });

CDK Deploy

name: CDK Workflow

on:
  push:
    branches: [ main ]

jobs:
  cdk-deploy:
    if: ${{ github.event_name == 'push' }}
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v3

      - name: Setup Node.js
        uses: actions/setup-node@v3
        with:
          node-version: 18

      - name: Setup Go
        uses: actions/setup-go@v4
        with:
          go-version: '1.20'

      - name: Install dependencies
        run: |
          npm install -g aws-cdk
          go mod tidy

      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v2
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          aws-region: ap-northeast-1

      - name: Deploy with CDK  # 設定の変更をデプロイする
        run: |
          cdk synth
          cdk deploy --require-approval never

作業手順

  1. CDKプロジェクトを作成する
  2. Actionsを設定する

CDKプロジェクトを作成する

ローカル環境にNode.jsをインストールしていない場合はインストールします。僕はanyenvでインストールしたnodenvでインストールしたNode.jsを使っています。

次に、CDKをインストールしてCDKプロジェクトを作成します。(npmに明るい方は、グローバルインストールを避けたり、npxを使ったりしてもokです)

# CDKをインストールする
$ npm install -g aws-cdk

# CDKプロジェクトを作る
$ mkdir my-cdk
$ cd my-cdk
$ cdk init app --language go

# CDKブートストラップ (そのregionで今まで一度も実行したことが無い場合のみ)
# 参考: https://docs.aws.amazon.com/ja_jp/cdk/v2/guide/bootstrapping.html
$ cdk bootstrap

できたらGitHubのリポジトリを作成してpushします。

Actionsを設定する

まずはGitHubリポジトリにSecretを登録します。AWSのアカウントでaws-access-key-idとaws-secret-access-keyを用意してから、ブラウザで先ほどpushしたリポジトリを開き、この二つを登録します。

Settingsタブ > 左メニューの"Secrets and variables" > "Actions"をクリック

New repository secret をクリックし、上記2つをそれぞれ、AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEYという名前で保存します。

次に、リポジトリに設定ファイルを追加します。mainから作業用ブランチを切り、my-cdk/.github/workflows/main.yaml というファイルを以下の内容で作成し、commitします。(cdk-diffとcdk-deployを一つのファイルにまとめたもの)

このブランチをpushした後、mainに向けてPull Requestを作成するとワークフローが実行されるはずです!

main.yaml
name: CDK Workflow

on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]

jobs:
  cdk-diff:
    if: ${{ github.event_name == 'pull_request' }}
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v3

      - name: Setup Node.js
        uses: actions/setup-node@v3
        with:
          node-version: 18

      - name: Setup Go
        uses: actions/setup-go@v4
        with:
          go-version: '1.20'

      - name: Install dependencies
        run: |
          npm install -g aws-cdk
          go mod tidy

      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v2
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          aws-region: ap-northeast-1

      - name: CDK Diff
        id: diff
        run: |
          diff=$(cdk diff) || true
          echo "$diff"
          echo "cdk_diff<<EOF" >> $GITHUB_OUTPUT
          echo "$diff" >> $GITHUB_OUTPUT
          echo "EOF" >> $GITHUB_OUTPUT

      - name: Comment PR
        uses: actions/github-script@v3
        with:
          script: |
            const diff = `${{ steps.diff.outputs.cdk_diff }}`;
            github.issues.createComment({
              issue_number: context.issue.number,
              owner: context.repo.owner,
              repo: context.repo.repo,
              body: diff ? diff : "No changes"
            });

  cdk-deploy:
    if: ${{ github.event_name == 'push' }}
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v3

      - name: Setup Node.js
        uses: actions/setup-node@v3
        with:
          node-version: 18

      - name: Setup Go
        uses: actions/setup-go@v4
        with:
          go-version: '1.20'

      - name: Install dependencies
        run: |
          npm install -g aws-cdk
          go mod tidy

      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v2
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          aws-region: ap-northeast-1

      - name: Deploy with CDK
        run: |
          cdk synth
          cdk deploy --require-approval never

続いて、my-cdk/my-cdk.goを編集して何かリソースを定義してみて、Pull Requestのコメントに差分が表示されることと、そのPull Requestをマージされたら定義したリソースが作成されることを確認してみてください。

プロジェクトを作成した時点で、リソース定義の例が書いてあるかもしれません。僕が作成した際には、以下のようにSQSキューの例が書かれていました。

func NewMyCdkStack(scope constructs.Construct, id string, props *MyCdkStackProps) awscdk.Stack {
	var sprops awscdk.StackProps
	if props != nil {
		sprops = props.StackProps
	}
	stack := awscdk.NewStack(scope, &id, &sprops)

	// The code that defines your stack goes here

	// example resource
	awssqs.NewQueue(stack, jsii.String("MyCdkQueue"), &awssqs.QueueProps{
		VisibilityTimeout: awscdk.Duration_Seconds(jsii.Number(300)),
	})

	return stack
}

Discussion