はじめに
実務への応用を効かせようとIaCのCI/CDについて学習を進めるべく、手始めに、AWS CDKとサーバーレスアプリケーション(Lambda ✖︎ API Gateway)を使用した構成を実現しました。
また、AWS Codeシリーズを使用したCI/CDも検討しましたが、cdkに記述する内容が多くなってしまう点と、ミニマムかつシンプルに実装できる点からCI/CDにはGithub Actionsを使用しました。
備忘がてら実装の記録を残します!
今回作成したコードは以下のリポジトリにあげています。
開発環境
- CDK : 2.72.1 (build ddbfac7)
- TypeScript : typescript@4.9.5
Stack
cdkのinitや最初に必要な手順は省略します。
メインとなるappは以下のようになっています。
import { Stack, StackProps } from 'aws-cdk-lib';
import * as lambda from 'aws-cdk-lib/aws-lambda';
import * as apigateway from 'aws-cdk-lib/aws-apigateway';
import { Construct } from 'constructs';
export class CdkGithubActionsStack extends Stack {
constructor(scope: Construct, id: string, props?: StackProps) {
super(scope, id, props);
// The code that defines your stack goes here
// Create a Lambda function with code from the "src/lambda" directory
const hello = new lambda.Function(this, 'HelloHandler', {
runtime: lambda.Runtime.NODEJS_16_X,
code: lambda.Code.fromAsset('src/'),
handler: 'hello.handler',
});
// defines an API Gateway REST API resource backed by our "hello" function.
new apigateway.LambdaRestApi(this, 'GithubActionsEndpoint', {
handler: hello,
endpointTypes: [ apigateway.EndpointType.REGIONAL ],
});
}
}
CI/CD
CI/CDを検討するにあたり、ブランチ戦略を決めます!
今回は、シンプルさを優先してGithub Flow
で実装しました。
(実務ではGit Flow
を使用する場合がほとんどだと思いますが)
ざっくりとパイプラインの流れを説明すると・・・
- mainブランチから機能ブランチを作成し、プッシュ
- github上でpull requestを出すと1つ目のトリガーが起動
- cdkのbuildや単体テスト、スナップショットテストが実行
- mainブランチへのマージトリガーに2つ目のトリガーが起動
- cdkがAWS環境にデプロイされる
パイプラインの実行ファイルを作成し、cdk.yml
に内容を記載
$ mkdir .github/workflows && touch cdk.yml
name: cdk-github-actions
on:
push:
branches:
- main
pull_request:
jobs:
build-test-deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Use Node.js 16.x
uses: actions/setup-node@v1
with:
node-version: 16.x
- name: Setup dependencies
run: npm ci
- name: Build
run: npm run build
- name: Unit tests
if: contains(github.event_name, 'pull_request')
run: npm run test:app
- name: CDK Diff Check
if: contains(github.event_name, 'pull_request')
run: npm run cdk:diff
env:
AWS_DEFAULT_REGION: 'ap-northeast-1'
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
- name: Snapshot tests
if: contains(github.event_name, 'pull_request')
run: npm run test:snapshot -- -u
- name: CDK Deploy
if: contains(github.event_name, 'push')
run: npm run cdk:deploy
env:
AWS_DEFAULT_REGION: 'ap-northeast-1'
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
Snapshot Testing
cdkのテスト方法には、Fine-grained tests
とSnapshot tests
があるが、
ここでは、IaCのCI/CDの実行確認がメインなので、Snapshot Testing
を使用して、テンプレートの差分を確認するだけにとどめたいと思います。
Snapshot Testingは、事前に記録されたスナップショット(今回は CloudFormation のテンプレートにあたる)に対して、テスト実行時の実装から作成した CloudFormation のテンプレートを検証(比較)します。ここで、差分がなければテスト結果OK、差分があればテスト結果NG となります。
import { App } from 'aws-cdk-lib';
import { Template } from 'aws-cdk-lib/assertions';
import { CdkGithubActionsStack } from '../lib/cdk-github-actions-stack';
test('SnapshotTest', () => {
const app = new App();
const stack = new CdkGithubActionsStack(app, 'CdkGithubActionsStack', {});
const template = Template.fromStack(stack);
expect(template.toJSON()).toMatchSnapshot();
});
エラーへの対処
tsの型が合わず、this
でエラーになってしまう
【結論】
-
packge.json
のaws-libのバージョンを揃える必要がある1.
packege.lock.json
の削除
2.packege.json
からバージョンを変更
3.npm install
確認
コードをcommit → push → pull request作成 → merge
し、GithubActionsを確認してみると・・・
それぞれしっかりとパイプラインが実行されています!
さいごに
IaCのCI/CDについて最もシンプルな構成から実現してみました。
次回はより実運用に近くなるよう、開発環境,Staging環境,本番環境
を用意し、複数環境に対するIacのCI/CD方法をやってみたいと思います。
参考
AWS CDK
Github Actions