AWS Cloud Development Kit (以下CDK)はプログラミング言語を使用してAWS環境の定義、デプロイができるフレームワークです。CDKのコードは最終的にCloudFormationのテンプレートに変換されてデプロイされるため、宣言型のCloudFormationの持つ冪等性(繰り返し実行しても同じ結果になる)の恩恵を受けつつ、様々なデータ構造や繰り返しなどの制御構造を持つプログラミング言語でインフラストラクチャを記述できるというメリットがあります。2019/1/19時点ではPreviewで、C#/JavaScript/TypeScript/Javaで記述することができます。
前回はCDKのインストールを実施したので今回はTypeScriptを使って公式のTutorialを実施します。
環境
- OS: macOS Sierra (10.12.6)
- AWS CDK: 0.21.0
Node.jsが動く環境であればどの環境でも動作するはずです。
前提条件
以下は予めインストールしておく必要があります。
- Node.js (>= 8.11.x)
- AWS CLI
- git
- AWS CDK
CDKプロジェクトの初期化
CDKプロジェクトをデフォルトテンプレートから初期化します。
プロジェクトフォルダの作成
$ mkdir hello-cdk
$ cd hello-cdk
Tutrialではここでgit init
していますが 、次のcdk init
が空のディレクトリでないと実行できませんでした。またcdk init
を実行すると自動的に.gitフォルダや.gitignoreファイルが作成されます。
プロジェクトの初期化
$ cdk init --language typescript
以下のようなディレクトリ構成となります。
total 208
drwxr-xr-x 13 xxxxx 1896053708 442 1 4 22:10 .
drwxr-xr-x 4 xxxxx 1896053708 136 1 4 22:10 ..
drwxr-xr-x 12 xxxxx 1896053708 408 1 4 22:10 .git
-rw-r--r-- 1 xxxxx 1896053708 25 1 4 22:10 .gitignore
-rw-r--r-- 1 xxxxx 1896053708 13 1 4 22:10 .npmignore
-rw-r--r-- 1 xxxxx 1896053708 320 12 20 22:02 README.md
drwxr-xr-x 3 xxxxx 1896053708 102 1 4 22:10 bin
-rw-r--r-- 1 xxxxx 1896053708 37 1 4 22:10 cdk.json
drwxr-xr-x 3 xxxxx 1896053708 102 1 4 22:10 lib
drwxr-xr-x 239 xxxxx 1896053708 8126 1 4 22:10 node_modules
-rw-r--r-- 1 xxxxx 1896053708 78741 1 4 22:10 package-lock.json
-rw-r--r-- 1 xxxxx 1896053708 345 1 4 22:10 package.json
-rw-r--r-- 1 xxxxx 1896053708 558 12 20 22:02 tsconfig.json
サンプルアプリケーションのビルド
デフォルトテンプレートに含まれるサンプルアプリケーションをビルドします。
サンプルコードの確認
cdk init
を実行した時点で、サンプルコードが出力されています。以下の前者がCDKアプリケーション、後者はCDKアプリケーションでimportしているHelloCdkStackスタックです。ファイルが分かれているのは単純に再利用性を考慮してのことと思われます。
$ cat bin/hello-cdk.ts
#!/usr/bin/env node
import cdk = require('@aws-cdk/cdk');
import { HelloCdkStack } from '../lib/hello-cdk-stack';
const app = new cdk.App();
new HelloCdkStack(app, 'HelloCdkStack');
app.run();
$ cat lib/hello-cdk-stack.ts
import cdk = require('@aws-cdk/cdk');
export class HelloCdkStack extends cdk.Stack {
constructor(parent: cdk.App, name: string, props?: cdk.StackProps) {
super(parent, name, props);
// The code that defines your stack goes here
}
}
tsファイルのビルド
$ npm run build
cdk ls
コマンドでStackをリストするとHelloCdkStackが表示されますが、この時点ではAWS環境には何も展開されていません。
$ cdk ls -l
- name: HelloCdkStack
environment:
name: xxxxxxxxxxxx/ap-northeast-1
account: "xxxxxxxxxxxx"
region: ap-northeast-1
AWSリソースの追加とデプロイ
サンプルスタックにはAWSリソースが定義されていないため、S3バケットを1つ追加します。その後実際にAWS環境にデプロイします。
@aws-cdk/aws-s3パッケージのインストール
$ npm install @aws-cdk/aws-s3
S3バケットの追加
lib/hello-cdk-stack.ts
を編集し、S3バケットをスタックに追加します。
import cdk = require('@aws-cdk/cdk');
import s3 = require('@aws-cdk/aws-s3'); //s3パッケージをimport
export class HelloCdkStack extends cdk.Stack {
constructor(parent: cdk.App, id: string, props?: cdk.StackProps) {
super(parent, id, props);
new s3.Bucket(this, 'MyFirstBucket', { //s3バケットを追加
versioned: true
});
}
}
ビルド
$ npm run build
リソースの確認
CDKによって作成されるCloudFormationスタックのテンプレート(Resources)を確認します。
$ cdk synth HelloCdkStack
Resources:
MyFirstBucketB8884501:
Type: AWS::S3::Bucket
Properties:
VersioningConfiguration:
Status: Enabled
DeletionPolicy: Retain
Metadata:
aws:cdk:path: HelloCdkStack/MyFirstBucket/Resource
CDKMetadata:
Type: AWS::CDK::Metadata
Properties:
Modules: aws-cdk=0.21.0,@aws-cdk/aws-codepipeline-api=0.21.0,@aws-cdk/aws-events=0.21.0,@aws-cdk/aws-iam=0.21.0,@aws-cdk/aws-kms=0.21.0,@aws-cdk/aws-s3=0.21.0,@aws-cdk/aws-s3-notifications=0.21.0,@aws-cdk/cdk=0.21.0,@aws-cdk/cx-api=0.21.0,jsii-runtime=node.js/v10.2.1
S3バケットが定義されています。Logical Nameはs3.Bucket
オブジェクト作成時の引数MyFirstBucket
の後にランダム文字列が追加されたものとなっています。DeletionPolicy: Retain
のためStackを削除してもバケットが残るようになっています。
cdk diff
コマンドを実行すると現状のリソースとの差分が表示されます。
$ cdk diff
Resources
[+] AWS::S3::Bucket MyFirstBucket MyFirstBucketB8884501
スタックのデプロイ
$ cdk deploy
HelloCdkStack: deploying...
HelloCdkStack: creating CloudFormation changeset...
0/3 | 11:19:16 | REVIEW_IN_PROGRESS | AWS::CloudFormation::Stack | HelloCdkStack User Initiated
0/3 | 11:19:21 | CREATE_IN_PROGRESS | AWS::CloudFormation::Stack | HelloCdkStack User Initiated
0/3 | 11:19:26 | CREATE_IN_PROGRESS | AWS::S3::Bucket | MyFirstBucket (MyFirstBucketB8884501)
0/3 | 11:19:26 | CREATE_IN_PROGRESS | AWS::CDK::Metadata | CDKMetadata
0/3 | 11:19:28 | CREATE_IN_PROGRESS | AWS::S3::Bucket | MyFirstBucket (MyFirstBucketB8884501) Resource creation Initiated
0/3 | 11:19:29 | CREATE_IN_PROGRESS | AWS::CDK::Metadata | CDKMetadata Resource creation Initiated
1/3 | 11:19:29 | CREATE_COMPLETE | AWS::CDK::Metadata | CDKMetadata
2/3 | 11:19:48 | CREATE_COMPLETE | AWS::S3::Bucket | MyFirstBucket (MyFirstBucketB8884501)
3/3 | 11:19:50 | CREATE_COMPLETE | AWS::CloudFormation::Stack | HelloCdkStack
✅ HelloCdkStack
Stack ARN:
arn:aws:cloudformation:ap-northeast-1:xxxxxxxxxxxx:stack/HelloCdkStack/4cf8a750-10
90-11e9-a609-0671757157c6
スタックの確認
作成されたスタックを確認します。
$ aws cloudformation describe-stacks \
--stack-name HelloCdkStack
{
"Stacks": [
{
"StackId": "arn:aws:cloudformation:ap-northeast-1:xxxxxxxxxxxx:stack/HelloCdkStack/4cf8a750-1090-11e9-a609-0671757157c6",
"StackName": "HelloCdkStack",
"ChangeSetId": "arn:aws:cloudformation:ap-northeast-1:xxxxxxxxxxxx:changeSet/CDK-0f39e1e5-0f1b-43fc-9a04-c1570dcd75ff/03917ebe-6886-4123-aa06-e7ef0139be3f",
"CreationTime": "2019-01-05T02:19:16.463Z",
"LastUpdatedTime": "2019-01-05T02:19:21.942Z",
"RollbackConfiguration": {},
"StackStatus": "CREATE_COMPLETE",
"DisableRollback": false,
"NotificationARNs": [],
"Capabilities": [
"CAPABILITY_IAM",
"CAPABILITY_NAMED_IAM"
],
"Tags": [],
"EnableTerminationProtection": false,
"DriftInformation": {
"StackDriftStatus": "NOT_CHECKED"
}
}
]
}
作成されたS3バケットのPhysical ID(バケット名)を確認します。
$ aws cloudformation describe-stack-resources \
--stack-name HelloCdkStack \
--query StackResources[?ResourceType==\`AWS::S3::Bucket\`]
[
{
"StackName": "HelloCdkStack",
"StackId": "arn:aws:cloudformation:ap-northeast-1:xxxxxxxxxxxx:stack/HelloCdkStack/4cf8a750-1090-11e9-a609-0671757157c6",
"LogicalResourceId": "MyFirstBucketB8884501",
"PhysicalResourceId": "hellocdkstack-myfirstbucketb8884501-sakucck9x6ae",
"ResourceType": "AWS::S3::Bucket",
"Timestamp": "2019-01-05T02:19:48.651Z",
"ResourceStatus": "CREATE_COMPLETE",
"DriftInformation": {
"StackResourceDriftStatus": "NOT_CHECKED"
}
}
]
hellocdkstack-myfirstbucketb8884501-sakucck9x6ae
となっています。[stack名]-[Logical ID]-[ランダム文字列]のようです。
コード内で指定したS3バケットのバージョニング設定を確認します。
aws s3api get-bucket-versioning \
--bucket "hellocdkstack-myfirstbucketb8884501-sakucck9x6ae"
{
"Status": "Enabled"
}
AWSリソースの変更
次はS3バケットの設定を変更し、差分をデプロイします。
コードの編集
lib/hello-cdk-stack.ts
を編集し、KMS暗号化を有効にします。
new s3.Bucket(this, 'MyFirstBucket', {
versioned: true, //カンマを追加
encryption: s3.BucketEncryption.KmsManaged //追加
});
ビルド
$ npm run build
差分の確認
$ cdk diff
Resources
[~] AWS::S3::Bucket MyFirstBucket MyFirstBucketB8884501
└─ [+] BucketEncryption
└─ {"ServerSideEncryptionConfiguration":[{"ServerSideEncryptionByDefault":{"SSEAlgorithm":"aws:kms"}}]}
スタックのデプロイ
$ cdk deploy
HelloCdkStack: deploying...
HelloCdkStack: creating CloudFormation changeset...
0/2 | 11:48:31 | UPDATE_IN_PROGRESS | AWS::CloudFormation::Stack | HelloCdkStack User Initiated
0/2 | 11:48:37 | UPDATE_IN_PROGRESS | AWS::S3::Bucket | MyFirstBucket (MyFirstBucketB8884501)
1/2 | 11:48:58 | UPDATE_COMPLETE | AWS::S3::Bucket | MyFirstBucket (MyFirstBucketB8884501)
1/2 | 11:49:00 | UPDATE_COMPLETE_CLEA | AWS::CloudFormation::Stack | HelloCdkStack
2/2 | 11:49:01 | UPDATE_COMPLETE | AWS::CloudFormation::Stack | HelloCdkStack
✅ HelloCdkStack
Stack ARN:
arn:aws:cloudformation:ap-northeast-1:xxxxxxxxxxxx:stack/HelloCdkStack/4cf8a750-1090-11e9-a609-0671757157c6
設定の確認
S3バケットの暗号化設定を確認します。
$ aws s3api get-bucket-encryption \
--bucket "hellocdkstack-myfirstbucketb8884501-sakucck9x6ae"
{
"ServerSideEncryptionConfiguration": {
"Rules": [
{
"ApplyServerSideEncryptionByDefault": {
"SSEAlgorithm": "aws:kms"
}
}
]
}
}
スタックの削除
展開されたスタックをAWS環境から削除します。
プロジェクトフォルダでcdk destroy
コマンドを実行します。
$ cdk destroy
Are you sure you want to delete: HelloCdkStack (y/n)? y
HelloCdkStack: destroying...
0 | 12:02:25 | DELETE_IN_PROGRESS | AWS::CloudFormation::Stack | HelloCdkStack User Initiated
0 | 12:02:27 | DELETE_IN_PROGRESS | AWS::CDK::Metadata | CDKMetadata
0 | 12:02:27 | DELETE_SKIPPED | AWS::S3::Bucket | MyFirstBucket (MyFirstBucketB8884501)
1 | 12:02:30 | DELETE_COMPLETE | AWS::CDK::Metadata | CDKMetadata
✅ HelloCdkStack: destroyed
削除されたか確認します。
$ aws cloudformation describe-stacks \
--stack-name "HelloCdkStack"
An error occurred (ValidationError) when calling the DescribeStacks operation: Stack with id HelloCdkStack does not exist
#おまけ
各CDKコマンドでCallされたAWS APIです。今回はCloudTrailから取得しておりソースコードを全て読んだわけではないので漏れはあるかも。予想通りCloudFormationのAPIをCallしていました。cdk diffはソースコードも少し見てみましたがchange setを作っているわけではなく、GetTemplateで既存のテンプレートを取得してローカルとの差分を見ているようです。
CDKコマンド | サービス | アクション |
---|---|---|
cdk init --language typescript | なし | なし |
cdk ls -l | なし | なし |
cdk diff | CloudFormation | GetTemplate |
cdk deploy | CloudFormation | DescribeStackEvents DescribeStacks ExecuteChangeSet DescribeChaneSet CreateChangeSet GetTemplate |
cdk destroy | CloudFormation | DescribeStackEvents DescribeStacks DeleteStack |