- はじめに
- TypeScript 基礎
- CDK プロジェクトの準備
- CDK ディレクトリ構成 確認
- cdk コマンド
- サンプルアプリケーションのクリーンアップ
- cdk diff
- cdk deploy
- VPCをデプロイ
- リソースのクリーンアップ
- 最後に
はじめに
AWS CDK (以下、CDK)に入門したのでその内容を記事にまとめました。
以下の公式 Workshop Studio の記事を参考にしています。
本記事のゴールとしてはCDKで基本的なVPCを作成することです。
前提と必要なもの
実行する環境はCloud9を利用します。
Cloud9のセットアップ方法については今回は省略します。
その他、CDKを実行するために必要なものとしては以下の通り。
- AWS CDK
- Node.js
- NPM
- TypeScript
CDKインストール 確認
Cloud9 で起動したインスタンスにはCDKがデフォルトインストールされています。
## CDK バージョンを確認 cdk --version 2.87.0 (build 9fca790)
Node.js と NPM
CDKはNode.jsのパッケージ(NPM)のうちの一つです。 どちらもTypeScriptでCDKを動作させるために必要不可欠なものです。
## Node.js バージョンを確認 node --version v16.20.1 ## NPM バージョンを確認 npm --version 8.19.4
TypeScript Compiler を最新バージョンにアップグレード
CDKは以下の言語がサポートされていますが、今回はTypeScriptで動作確認します。
- TypeScript
- JavaScript
- Python
- Java
- C#
- Go
Cloud9へデフォルトインストールされているTypeScriptから最新のバージョンへアップグレードします。
## TypeScript 現在のバージョン tsc --version Version 3.7.5 ## npmでアップグレード npm -g upgrade typescript ## アップグレード後のバージョン tsc --version Version 5.1.6
TypeScript 基礎
いきなりCDKでTypeScriptを実行させる前に、TypeScriptの基礎を少し学びます。
プロジェクトの準備
まずは、TypeScriptで動作するプロジェクトの準備を行います。
## ディレクトリを作成 mkdir test-cdk ## カレントディレクトリ移動 cd test-cdk ## npm 初期化 … package.json が出力される npm init -y Wrote to /home/ec2-user/environment/test-cdk/package.json: { "name": "test-cdk", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [], "author": "", "license": "ISC" }
npm 初期化をすることで、package.jsonが自動作成されます。 package.jsonはnpmパッケージに関する設定情報が記述されるファイルです。
nodeパッケージ インストール
実際にパッケージをインストールします。
今回は@types/node ライブラリをインストールします。
@types/node
とはNode.jsの型定義(TypeScriptの型情報)を含むパッケージでTypeScriptをJavaScriptへコンパイルするために必要なものです。
## インストール npm install @types/node ## package.json 確認 cat package.json { "name": "test-cdk", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [], "author": "", "license": "ISC", "dependencies": { "@types/node": "^20.4.5" } }
"dependencies" セクションに @types/node
が追加されていることを確認できます。
TypeScriptの実行
## TypeScript 初期化 … tsconfig.json tsc --init Created a new tsconfig.json with: TS target: es2016 module: commonjs strict: true esModuleInterop: true skipLibCheck: true forceConsistentCasingInFileNames: true
tsc init を実行することで、tsconfig.jsonが自動生成されます。
tsconfig.json を編集
TypeScriptをJavaScritpへコンパイルする際に変換されたJavaScriptを出力するディレクトリを指定します。
## tsconfig.jsonを編集
vim tsconfig.json
- 変更前
// "outDir": "./", /* Redirect output structure to the directory. */
- 変更後
"outDir": "./dist", /* Redirect output structure to the directory. */
TypeScript ファイル作成
実行させるTypeScriptファイルを作成します。
- helloWorld.ts
console.log('Hello, World!');
TypeScript 実行
helloWorld.tsを展開し、 Run をクリックして実行します。
コンパイルが実行されて変換された後に、 Hello, World!
が出力されていることを確認できます。
以上がTypeScriptの基礎です。
Hello Worldを出力しただけですが、TypeScriptがどうやって動作するかについて少し理解できたと思います。
CDK プロジェクトの準備
ここからCDKで実際にVPCのリソースを作成していきます。
## カレントディレクトリ 移動 cd ~/environment/ ## プロジェクトディレクトリ作成 mkdir cdk-workshop ## CDK 初期化 cdk init sample-app --language typescript
CDK ディレクトリ構成 確認
必要なディレクトリなどが自動生成されます。
以下の構成です。
cdk-workshop/ ├── bin/ │ └── cdk-workshop.ts ├── lib/ │ └── cdk-workshop-stack.ts ├── node_modules/ ├── test/ │ └── cdk-workshop.test.ts ├── .git/ ├── cdk.json ├── jest.config.js ├── package.json ├── README.md ├── tsconfig.json ├── .gitignore └── .npmignore
主要なファイルについて説明します。
bin/cdk-workshop.ts
エントリーポイント
という始めに実行されるtsファイルです。
#!/usr/bin/env node import * as cdk from 'aws-cdk-lib'; import { CdkWorkshopStack } from '../lib/cdk-workshop-stack'; const app = new cdk.App(); new CdkWorkshopStack(app, 'CdkWorkshopStack');
lib/cdk-workshop-stackをimportしてインスタンス化しています。 lib/cdk-workshop-staskを確認します。
lib/cdk-workshop-stack.ts
メインスタック
という、リソース定義の要となるtsファイルです。
import { Duration, Stack, StackProps } from 'aws-cdk-lib'; import * as sns from 'aws-cdk-lib/aws-sns'; import * as subs from 'aws-cdk-lib/aws-sns-subscriptions'; import * as sqs from 'aws-cdk-lib/aws-sqs'; import { Construct } from 'constructs'; export class CdkWorkshopStack extends Stack { constructor(scope: Construct, id: string, props?: StackProps) { super(scope, id, props); const queue = new sqs.Queue(this, 'CdkWorkshopQueue', { visibilityTimeout: Duration.seconds(300) }); const topic = new sns.Topic(this, 'CdkWorkshopTopic'); topic.addSubscription(new subs.SqsSubscription(queue)); } }
aws-snsやaws-sqsがimportされています。
サンプルとしてAWS SNSとSQSなどのリソースが作成されます。
ここに作成したいリソースを記述していくのが基本的な使い方となります。もう一つのポイントは
export class CdkWorkshopStack extends Stack {
の記述です。
このexportの記述があることで、bin/cdk-workshop.ts ファイルにimport { CdkWorkshopStack } from '../lib/cdk-workshop-stack';
と記述して呼び出すことができます。
cdk コマンド
cdkコマンドでリソースを作成します。 作成する前にCloudFormationのテンプレートを出力して確認することができます。
cdk synth
cdk synth
とタイプすると、定義したアプリケーションで作成されるリソースがCloudFormationのテンプレートとして出力されます。
cdk synth … Resources: CdkWorkshopQueue50D9D426: Type: AWS::SQS::Queue Properties: VisibilityTimeout: 300 UpdateReplacePolicy: Delete DeletionPolicy: Delete Metadata: aws:cdk:path: CdkWorkshopStack/CdkWorkshopQueue/Resource CdkWorkshopQueuePolicyAF2494A5: Type: AWS::SQS::QueuePolicy Properties: PolicyDocument: Statement: - Action: sqs:SendMessage Condition: ArnEquals: aws:SourceArn: Ref: CdkWorkshopTopicD368A42F Effect: Allow Principal: Service: sns.amazonaws.com Resource: Fn::GetAtt: - CdkWorkshopQueue50D9D426 - Arn Version: "2012-10-17" Queues: - Ref: CdkWorkshopQueue50D9D426 Metadata: aws:cdk:path: CdkWorkshopStack/CdkWorkshopQueue/Policy/Resource CdkWorkshopQueueCdkWorkshopStackCdkWorkshopTopicD7BE96438B5AD106: Type: AWS::SNS::Subscription Properties: Protocol: sqs TopicArn: Ref: CdkWorkshopTopicD368A42F Endpoint: Fn::GetAtt: - CdkWorkshopQueue50D9D426 - Arn DependsOn: - CdkWorkshopQueuePolicyAF2494A5 Metadata: aws:cdk:path: CdkWorkshopStack/CdkWorkshopQueue/CdkWorkshopStackCdkWorkshopTopicD7BE9643/Resource CdkWorkshopTopicD368A42F: Type: AWS::SNS::Topic Metadata: aws:cdk:path: 〜省略〜
tsファイルへ定義しているとおり、SNSやSQSのリソースが作成されることを確認できます。
cdk bootstrap
アプリケーションを初めてデプロイする前に、前段階として cdk bootstrap
を実行する必要があります。
これを実行することで AWS アカウントの指定したリージョンにデプロイできます。
今回はCloud9を実行しているリージョンへ自動的にデプロイされるようになっています。
## cdk bootstrap実行 … デプロイされるAWSアカウントとリージョンが出力される cdk bootstrap ⏳ Bootstrapping environment aws://【アカウント番号】/ap-northeast-1... Trusted accounts for deployment: (none) Trusted accounts for lookup: (none) Using default execution policy of 'arn:aws:iam::aws:policy/AdministratorAccess'. Pass '--cloudformation-execution-policies' to customize. ✨ hotswap deployment skipped - no changes were detected (use --force to override) ✅ Environment aws://【アカウント番号】/ap-northeast-1 bootstrapped (no changes).
cdk deploy
いよいよ、デプロイを実行します。
## デプロイ実行 … cdk deploy ✨ Synthesis time: 13.87s … Please confirm you intend to make the following modifications: IAM Statement Changes ┌───┬──────────────────────┬────────┬──────────────────────┬──────────────────────┬─────────────────────────┐ │ │ Resource │ Effect │ Action │ Principal │ Condition │ ├───┼──────────────────────┼────────┼──────────────────────┼──────────────────────┼─────────────────────────┤ │ + │ ${CdkWorkshopQueue.A │ Allow │ sqs:SendMessage │ Service:sns.amazonaw │ "ArnEquals": { │ │ │ rn} │ │ │ s.com │ "aws:SourceArn": "${C │ │ │ │ │ │ │ dkWorkshopTopic}" │ │ │ │ │ │ │ } │ └───┴──────────────────────┴────────┴──────────────────────┴──────────────────────┴─────────────────────────┘ (NOTE: There may be security-related changes not in this list. See https://github.com/aws/aws-cdk/issues/1299) Do you wish to deploy these changes (y/n)?
警告が表示されますが、 y + Enter して進みます。
途中、CloudFormationのステータスが表示され、定義したリソースが作成されていること確認できます。
## 【y を Enter】 CdkWorkshopStack: deploying... [1/1] CdkWorkshopStack: creating CloudFormation changeset... [███████████████████▎······································] (2/6) 10:10:45 PM | CREATE_IN_PROGRESS | AWS::CloudFormation::Stack | CdkWorkshopStack 10:10:50 PM | CREATE_IN_PROGRESS | AWS::SQS::Queue | CdkWorkshopQueue
完了しました。
✅ CdkWorkshopStack ✨ Deployment time: 92.26s Stack ARN: arn:aws:cloudformation:ap-northeast-1:【アカウント番号】:stack/CdkWorkshopStack/c0742490-2e5c-11ee-ab2b-0ee353da8cf9 ✨ Total time: 106.13s
AWS マネジメントコンソールのCloudFormationの画面から作成されたリソースを確認しましょう。
サンプルアプリケーションのクリーンアップ
サンプルとして生成されたSNSやSQSのリソースは不要なので削除します。
lib/cdk-workshop-stack.ts 編集
cdk-workshop-stack.tsへ定義されているSNSとSQS関連の記述を削除します。
## lib/cdk-workshop-stack.ts 編集 vim lib/cdk-workshop-stack.ts
変更後は以下のような内容になります。
- lib/cdk-workshop-stack.ts
import { Stack, StackProps } from 'aws-cdk-lib'; import { Construct } from 'constructs'; export class CdkWorkshopStack extends Stack { constructor(scope: Construct, id: string, props?: StackProps) { super(scope, id, props); } }
cdk diff
CDKでは、変更をデプロイする前に変更差分を確認することができます。
## 差分を確認 … 変更後の内容が出力される cdk diff Stack CdkWorkshopStack current credentials could not be used to assume 'arn:aws:iam::【アカウント番号】:role/cdk-hnb659fds-lookup-role-【アカウント番号】-ap-northeast-1', but are for the right account. Proceeding anyway. (To get rid of this warning, please upgrade to bootstrap version >= 8) current credentials could not be used to assume 'arn:aws:iam::【アカウント番号】:role/cdk-hnb659fds-deploy-role-【アカウント番号】-ap-northeast-1', but are for the right account. Proceeding anyway. IAM Statement Changes ┌───┬───────────────────────────────────┬────────┬─────────────────┬───────────────────────────────────┬─────────────────────────────────────┐ │ │ Resource │ Effect │ Action │ Principal │ Condition │ ├───┼───────────────────────────────────┼────────┼─────────────────┼───────────────────────────────────┼─────────────────────────────────────┤ │ - │ ${CdkWorkshopQueue.Arn} │ Allow │ sqs:SendMessage │ Service:sns.amazonaws.com │ "ArnEquals": { │ │ │ │ │ │ │ "aws:SourceArn": "${CdkWorkshopTo │ │ │ │ │ │ │ pic}" │ │ │ │ │ │ │ } │ └───┴───────────────────────────────────┴────────┴─────────────────┴───────────────────────────────────┴─────────────────────────────────────┘ (NOTE: There may be security-related changes not in this list. See https://github.com/aws/aws-cdk/issues/1299) Resources [-] AWS::SQS::Queue CdkWorkshopQueue CdkWorkshopQueue50D9D426 destroy [-] AWS::SQS::QueuePolicy CdkWorkshopQueue/Policy CdkWorkshopQueuePolicyAF2494A5 destroy [-] AWS::SNS::Subscription CdkWorkshopQueue/CdkWorkshopStackCdkWorkshopTopicD7BE9643 CdkWorkshopQueueCdkWorkshopStackCdkWorkshopTopicD7BE96438B5AD106 destroy [-] AWS::SNS::Topic CdkWorkshopTopic CdkWorkshopTopicD368A42F destroy
SNSやSQSのリソースが削除されることがわかります。
cdk deploy
それでは変更をデプロイしましょう。
cdk deploy
リソースが削除されていく様子が確認できます。
VPCをデプロイ
VPCをデプロイします。
ドキュメントを参考にしながらコーディングを進めていきます。
まずは、ドキュメントからVPCのリソースを探します。 左側のセクションから、aws-cdk-lib aws_ec2を展開します。
Overviewをクリックします。
Overviewには該当リソースを宣言するために必要な import 文についての記載があります。まずはこれにならって、lib/cdk-workshop-stack.ts へ import文を追記します。
import { Stack, StackProps } from 'aws-cdk-lib'; import { Construct } from 'constructs'; import * as ec2 from 'aws-cdk-lib/aws-ec2'; export class CdkWorkshopStack extends Stack { constructor(scope: Construct, id: string, props?: StackProps) { super(scope, id, props); } }
ちなみに、Cloud9上ではvimでファイルを編集できますが、 左セクションからファイルを選択して編集することで、コードの入力補完やコード生成が自動的に効いてコーディングがしやすくなります。
続いて、実装部分を追記します。 Constructsの中からVpcを選択します。
Exampleへサンプルコードが記載されています。サンプルにならってVPCを宣言します。
- lib/cdk-workshop-stack.ts
import { Stack, StackProps } from 'aws-cdk-lib'; import { Construct } from 'constructs'; import * as ec2 from 'aws-cdk-lib/aws-ec2'; export class CdkWorkshopStack extends Stack { constructor(scope: Construct, id: string, props?: StackProps) { super(scope, id, props); const vpc = new ec2.Vpc(this, "cdk-workshop-vpc", { ipAddresses: ec2.IpAddresses.cidr('10.0.0.0/16') }) } }
具体的に宣言したのはVPCのIPアドレスとVPCの名前だけです。 この状態でどの様なリソースが生成されるか確認してみましょう。
cdk synth
cdk synth … Resources: cdkworkshopvpcB521BF0D: Type: AWS::EC2::VPC Properties: CidrBlock: 10.0.0.0/16 … cdkworkshopvpcPublicSubnet1SubnetA142096B: Type: AWS::EC2::Subnet … CidrBlock: 10.0.0.0/18 … cdkworkshopvpcPublicSubnet1EIP19F89EFE: Type: AWS::EC2::EIP … cdkworkshopvpcPublicSubnet1NATGatewayA3D141A6: Type: AWS::EC2::NatGateway … cdkworkshopvpcPublicSubnet2Subnet93C22F38: Type: AWS::EC2::Subnet … CidrBlock: 10.0.64.0/18 … cdkworkshopvpcPublicSubnet2EIP7B9FC902: Type: AWS::EC2::EIP … cdkworkshopvpcPublicSubnet2NATGatewayE9F4B63A: Type: AWS::EC2::NatGateway … cdkworkshopvpcPrivateSubnet1Subnet90A70C18: Type: AWS::EC2::Subnet … CidrBlock: 10.0.128.0/18 … cdkworkshopvpcPrivateSubnet2SubnetAFC4C1F8: Type: AWS::EC2::Subnet … CidrBlock: 10.0.192.0/18 … cdkworkshopvpcIGW6B581DEB: Type: AWS::EC2::InternetGateway
VPCのリソースを実装しただけなのに以下のリソースが作成されることがわかりました。
- 2AZへまたがったサブネットが4つ(プライベートサブネットx2、パブリックサブネットx2)
- それぞれのAZごとに1つずつEIPを関連付けたNatGateway
- 1つのInternetGateway
これは、Construct Propsを確認することで理解できます。
この Construct Props には、そのリソースを宣言するためのパラメータが記載されています。
先程宣言したipAddressesもここに記載があり、Nameの値の最後に ?
が記述されていることが確認できます。 これはその Construct Props がオプションであることを示しています。
つまり、 ?
が書かれている Construct Props は設定しなくてもリソースを作成することができるということです。
では宣言しない場合はその設定値はどうなるのか。
それは、 Construct Props の各項目ごとの default:…
の部分で確認することができます。
subnetConfigurationに、サブネットのデフォルト値も記載されています。
cdk deploy
実際に確認したリソースが作成されることを確認しましょう。
cdk deploy
リソースのクリーンアップ
最後にCDKのプロジェクトを全て削除します。
AWS CloudFormation コンソールで、 CdkWorkshopStack
のスタックを削除するか、以下のコマンドで削除できます。
## CDK スタックの削除
cdk destroy
Are you sure you want to delete: CdkWorkshopStack (y/n)?
のメッセージが表示されたら、y + Enter でスタックが削除されていくことを確認できます。
スタックが削除できたら、Cloud9の環境自体の削除も忘れず実施してください。
最後に
普段CloudFormationでリソースを作成することが多い私にとっては、以下のような点がCDKのメリットだと思いました。
- synth,diffが便利
- 推奨値としてのデフォルト設定
- 最小の記述で構築できる
- 依存関係を自動的に考慮してくれる
- テストしやすい
このあたりは別途深掘りして記事にまとめたいと思っています。
以上、CDK初心者向けの入門記事でした。 どなたかのお役に立てれば幸いです。