Blogical

AWS/Salesforceを中心に様々な情報を配信していきます(/・ω・)/

初めての AWS CDK 入門~ TypeScript 編~

こんにちは、ロジカル・アーツの井川です。

今日は、AWS CDK について紹介していきたいと思います。

AWS CDKとは?

The AWS Cloud Development Kit (略称: AWS CDK) は、CloudFormation を使ってプロビジョニングするためのオープンソースソフトウェア、開発フレームワークです。 AWS CDK を活用することで、AWSリソースをコードで操作することができ、まとめてデプロイすることが可能です。 Infrastructure as Code (IaC) という単語が浸透して数年は経っていると思いますが、YAMLJSONなどではなく、普段開発で使用している言語でプロビジョニング・デプロイが出来る為、これが浸透すれば開発者にとってインフラが本当に手軽なものになるのではないかと思います。

CloudFormation との違い

CloudFormation ではJSONYAMLを使って定義しています。しかし AWS CDK では高級言語を使用することができます。現在サポートに対応している言語とそのバージョンは下記の通りです。

実際に触ってみる

今回は AWS の公式ページ AWS Cloud9 の AWS CDK サンプル を参考に進めていきたいと思います。

作業環境

私が行う環境は以下の通りです。

項目 説明
PC OS Windows 10 Professional
ブラウザ Chrome
IDE Cloud9
ミドルウェア Amazon Linux 2
リージョン Tokyo (ap-northeast-1)
言語 TypeScript

留意事項

私の環境では、下記を前提として進めていきます。

  • AWS アカウントがある
  • AWS Cloud9 EC2 開発環境がある

ステップ 1: 必要なツールをインストールする

それでは触っていきましょう。

ステップ 1.1: Node Version Manager (nvm) をインストールする

まずは Cloud9 を最新の状態にし、 nvm がインストールされているか確認を行います。

$ sudo yum -y update
...
Complete!

$ nvm --version 
0.31.7

きちんとインストールされていますね。

ステップ 1.2: Node.js をインストールする

nvm の確認が出来たらNode.js のインストールを行っていきましょう。Node.js は公式が指定しているバージョンの v8.12.0 を使用します。

$ node --version
v10.17.0

$ nvm install v8.12.0    // 指定のバージョンをインストールする
...
Now using node v8.12.0 (npm v6.4.1)

$ nvm alias default 8.12.0    // エイリアスで使用するバージョンを指定する
default -> 8.12.0 (-> v8.12.0)

ステップ 1.3: TypeScript をインストールする

バージョンを確認してから、TypeScript が入っていないようであればインストールを行います。

$ tsc --version
bash: tsc: command not found

$ npm install -g typescript
...
+ typescript@3.7.5
added 1 package from 1 contributor in 1.495s

$ tsc --version
Version 3.7.5

ステップ 1.4: AWS CDK をインストールする

AWS CDK もバージョンを確認してから入っていないようであればインストールを行っていきます。

$ cdk --version
bash: cdk: command not found

$ npm install -g aws-cdk
...
+ aws-cdk@1.21.1
added 237 packages from 227 contributors in 8.771s

$ cdk --version
1.21.1 (build 842cc5f)

インストールに成功したので、AWS CDK のバージョン番号とビルド番号が表示されていますね。

ステップ 2: コードを追加する

インストールが一通り完了したら、TypeScript ベースのサンプルプロジェクトを作っていきましょう。 このスタックでは、Amazon SNS トピックと Amazon SQS キューを AWS アカウントに作成し、キューをトピックにサブスクライブします。

ステップ 2.1: ディレクトリの作成・切り替え

$ mkdir ~/environment/hello-cdk
$ ls
hello-cdk 

$ cd ~/environment/hello-cdk
~/environment/hello-cdk $

ステップ 2.2: プロジェクト作成

今開いている hello-cdk をプロジェクトのルートディレクトリとして設定します。

$ cdk init sample-app --language typescript

上記コマンドのオプションの補足です。

下記の通り表示されれば、CDK TypeScript project が作成されています。

...
# Welcome to your CDK TypeScript project!

You should explore the contents of this project. It demonstrates a CDK app with an instance of a stack (`HelloCdkStack`)
which contains an Amazon SQS queue that is subscribed to an Amazon SNS topic.

The `cdk.json` file tells the CDK Toolkit how to execute your app.
...

ステップ 2.3: ファイル構成

sample-app の初期ファイル構成は下記の通りです。

$ ls -a
.  ..  bin  cdk.json  .git  .gitignore  jest.config.js  lib  node_modules  .npmignore  package.json  package-lock.json  README.md  test  tsconfig.json

一部について補足説明をします。

項目 種類 説明
.git / .gitignore 隠しサブディレクトリ / 隠しファイル Git等のソース管理ツールとの互換性を持つ
lib サブディレクト AWS CDK スタック用のコードが含まれる (hello-cdk-stack.ts)
bin サブディレクト AWS CDK アプリケーション用のエントリポイントが含まれる (hello-cdk.ts)
node_modules サブディレクト アプリケーションに必要なパッケージが含まれる
.npmignore 隠しファイル ビルド時に使用しない種類のサブディレクトリやファイルが含まれる
cdk.json ファイル このファイルの情報を使用すると cdk コマンドが実行しやすくなる
package-lock.json ファイル このファイルの情報を使用すると npm はビルドや実行に伴うエラーを減らすことが出来る
package.json ファイル このファイルの情報を使用すると npm コマンドの実行が容易になる
README.md ファイル npmAWS CDK で実行できるコマンドのリストがある
tsconfig.json ファイル このファイルの情報を使用すると tsc コマンドの実行が容易になり、エラーも減る可能性がある

ステップ 2.4: lib/hello-cdk-stack.ts ファイルを開き、次のコードを参照する

import sns = require('@aws-cdk/aws-sns');
import sqs = require('@aws-cdk/aws-sqs');
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);

    const queue = new sqs.Queue(this, 'HelloCdkQueue', {
      visibilityTimeoutSec: 300
    });

    const topic = new sns.Topic(this, 'HelloCdkTopic');

    topic.subscribeQueue(queue);
  }
}

コードについて補足説明させていただきます。(誤りがあればご指摘下さい)

  • export class HelloCdkStack extends cdk.Stack {

cdk.Stack を継承して Class: HelloCdkStack を新たに作っています。 ここでいう Stack とは、CloudFormationスタックと同じものです。AWS CDK は CloudFormation を使ってスタックを作るので制限事項なども基本的に同じです。

  • const queue = new sqs.Queue(this, 'HelloCdkQueue', {

新たにSQSのキュー HelloCdkQueue を作成しています。

  • const topic = new sns.Topic(this, 'HelloCdkTopic');

新たにSNSのトピック HelloCdkTopic を作成しています。

  • topic.subscribeQueue(queue);

先ほど作ったSNSトピックは、SQSキューにサブスクライブしています。

ステップ 2.5: 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();

ステップ 2.6: TypeScript コンパイラーを実行

$ npm run build

> hello-cdk@0.1.0 build /home/ec2-user/environment/hello-cdk
> tsc

上記コマンドでコーディングエラーをチェックします。これによって、ファイル bin/hello-cdk.d.ts / lib/hello-cdk-stack.d.ts は型定義ファイル( d.ts )が生成されます。また、 ts ファイルを js ファイルにトランスパイルしています。

下記のように構成されれば成功しています。

f:id:logicalarts:20200121131238p:plain
hello-cdk ファイル構成

ステップ 3: コードを実行する

bin/hello-cdk.js ファイル内のコードをベースにCloudFormationテンプレートを AWS CDK で作成しデプロイします。

ステップ 3.1: CloudFormationテンプレートを AWS CDK で作成

$ cdk synth HelloCdkStack
Resources:
  HelloCdkQueueB56C77B9:
    Type: AWS::SQS::Queue
    Properties:
      VisibilityTimeout: 300
    Metadata:
      aws:cdk:path: HelloCdkStack/HelloCdkQueue/Resource
  HelloCdkQueuePolicy027FC30A:
    Type: AWS::SQS::QueuePolicy
    Properties:
      PolicyDocument:
        Statement:
          - Action: sqs:SendMessage
            Condition:
              ArnEquals:
                aws:SourceArn:
...

ターミナル上で cdk synth HelloCdkStack を実行すると、上記のようなYAMLファイルが生成されます。これは、CloudFormation スタックテンプレートの Resources セクションが表示されています。ここでは長くなるため、大部分を省略させて頂きました。

ステップ 3.2: Bootstrap のインストール

初めて AWS CDK をアカウントもしくはリージョン、環境にデプロイする場合は、ブートストラップスタックをインストールする必要があります。このインストールによって、様々なオペレーションを実行する為のリソースが使用可能になります。

$ cdk bootstrap
   Bootstrapping environment aws://xxxxxxxxxxxxx/ap-northeast-1...
CDKToolkit: creating CloudFormation changeset...
   Environment aws://xxxxxxxxxxxx/ap-northeast-1 bootstrapped (no changes).

xxxxxxxxxxxx にはAWS アカウントIDが入ります。

ステップ 3.3: AWS CDK のデプロイ

全ての準備が整いましたのでデプロイしていきましょう。

$ cdk deploy HelloCdkStack
This deployment will make potentially sensitive changes according to your current security approval level (--require-approval broadening).
Please confirm you intend to make the following modifications:

IAM Statement Changes
┌───┬──────────────────────┬────────┬─────────────────┬───────────────────────────┬──────────────────────────────────────────────────────┐
│   │ Resource             │ Effect │ Action          │ Principal                 │ Condition                                            │
├───┼──────────────────────┼────────┼─────────────────┼───────────────────────────┼──────────────────────────────────────────────────────┤
│ + │ ${HelloCdkQueue.Arn} │ Allow  │ sqs:SendMessage │ Service:sns.amazonaws.com │ "ArnEquals": {                                       │
│   │                      │        │                 │                           │   "aws:SourceArn": "${HelloCdkTopic}"                │
│   │                      │        │                 │                           │ }                                                    │
└───┴──────────────────────┴────────┴─────────────────┴───────────────────────────┴──────────────────────────────────────────────────────┘
(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

セキュリティに関する確認が出ます。これはCloudFormation のデプロイ前にも出る、IAMの変更に対する確認ですね。今回は問題ないので y と入力して、デプロイを進めましょう。

HelloCdkStack: deploying...
HelloCdkStack: creating CloudFormation changeset...
 0/6 | 04:52:40 | CREATE_IN_PROGRESS   | AWS::SNS::Topic        | HelloCdkTopic (HelloCdkTopic1F583424) 
 0/6 | 04:52:41 | CREATE_IN_PROGRESS   | AWS::CDK::Metadata     | CDKMetadata 
 0/6 | 04:52:41 | CREATE_IN_PROGRESS   | AWS::SQS::Queue        | HelloCdkQueue (HelloCdkQueueB56C77B9) 
 0/6 | 04:52:41 | CREATE_IN_PROGRESS   | AWS::SNS::Topic        | HelloCdkTopic (HelloCdkTopic1F583424) Resource creation Initiated
 0/6 | 04:52:41 | CREATE_IN_PROGRESS   | AWS::SQS::Queue        | HelloCdkQueue (HelloCdkQueueB56C77B9) Resource creation Initiated
 0/6 | 04:52:42 | CREATE_IN_PROGRESS   | AWS::CDK::Metadata     | CDKMetadata Resource creation Initiated
 1/6 | 04:52:42 | CREATE_COMPLETE      | AWS::SQS::Queue        | HelloCdkQueue (HelloCdkQueueB56C77B9) 
 2/6 | 04:52:43 | CREATE_COMPLETE      | AWS::CDK::Metadata     | CDKMetadata 
 3/6 | 04:52:52 | CREATE_COMPLETE      | AWS::SNS::Topic        | HelloCdkTopic (HelloCdkTopic1F583424) 
 3/6 | 04:52:54 | CREATE_IN_PROGRESS   | AWS::SQS::QueuePolicy  | HelloCdkQueue/Policy (HelloCdkQueuePolicy027FC30A) 
 3/6 | 04:52:54 | CREATE_IN_PROGRESS   | AWS::SNS::Subscription | HelloCdkQueue/HelloCdkStackHelloCdkTopic850E0FBD (HelloCdkQueueHelloCdkStackHelloCdkTopic850E0FBD36A066B9) 
 3/6 | 04:52:55 | CREATE_IN_PROGRESS   | AWS::SQS::QueuePolicy  | HelloCdkQueue/Policy (HelloCdkQueuePolicy027FC30A) Resource creation Initiated
 4/6 | 04:52:55 | CREATE_COMPLETE      | AWS::SQS::QueuePolicy  | HelloCdkQueue/Policy (HelloCdkQueuePolicy027FC30A) 
 4/6 | 04:52:55 | CREATE_IN_PROGRESS   | AWS::SNS::Subscription | HelloCdkQueue/HelloCdkStackHelloCdkTopic850E0FBD (HelloCdkQueueHelloCdkStackHelloCdkTopic850E0FBD36A066B9) Resource creation Initiated
 5/6 | 04:52:55 | CREATE_COMPLETE      | AWS::SNS::Subscription | HelloCdkQueue/HelloCdkStackHelloCdkTopic850E0FBD (HelloCdkQueueHelloCdkStackHelloCdkTopic850E0FBD36A066B9) 
 6/6 | 04:52:57 | CREATE_COMPLETE      | AWS::CloudFormation::Stack | HelloCdkStack  

   HelloCdkStack

Stack ARN:
arn:aws:cloudformation:ap-northeast-1:xxxxxxxxxxxx:stack/HelloCdkStack/d4f771e0-3c09-11ea-a7

無事デプロイが成功すると上記のような Stack ARN が表示されます。

ステップ 4: リソースを確認する

実際にデプロイされているか確認していきましょう。

ステップ 4.1: SQS / SNS を確認する

f:id:logicalarts:20200121140905p:plain
SQS

f:id:logicalarts:20200121140534p:plain
SNS サブスクリプション画面

SQS / SNS それぞれが問題なく、デプロイされていますね。SNSトピックもSQSキューをサブスクライブするようきちんと設定されています。

ステップ 4.2: サブスクライブを確認する

リソースの有無が確認できたので、実際に動作するか確認していきましょう。まずは、下記のコマンドで、デプロイされたSNSトピックのARNを確認します。

$ aws sns list-topics --output table --query 'Topics[*].TopicArn'
----------------------------------------------------------------------------------------------
|                                         ListTopics                                         |
+--------------------------------------------------------------------------------------------+
|  arn:aws:sns:ap-northeast-1:xxxxxxxxxxxx:HelloCdkStack-HelloCdkTopic1F583424-R1YO356YX6LE  |
+--------------------------------------------------------------------------------------------+

Listの中にある、HelloCdkStack... のトピックを抜き出していきましょう。そして、下記コマンドの --topic-arn の後に貼り付け、実行すると、メッセージが発行されます。

$ aws sns publish --subject "Hello from the AWS CDK" --message "This is a message from the AWS CDK." --topic-arn arn:aws:sns:ap-northeast-1:xxxxxxxxxxxx:HelloCdkStack-HelloCdkTopic1F583424-R1YO356YX6LE
{
    "MessageId": "442e3ac6-36be-5d54-bc31-6c66ba4d2e46"
}

はい、問題なさそうですね。上記のようになれば完了です。

ステップ 5: リソースの削除

最後に、AWS CDK で作成したリソースを削除してみましょう。

$ cdk destroy HelloCdkStack
Are you sure you want to delete: HelloCdkStack (y/n)? y

上記コマンドを実行すると、「本当に削除しますか?」とアラートが出るので、 y を入力し、進めましょう。

   0 | 05:28:43 | DELETE_IN_PROGRESS   | AWS::CloudFormation::Stack | HelloCdkStack User Initiated
   0 | 05:28:45 | DELETE_IN_PROGRESS   | AWS::SNS::Subscription | HelloCdkQueue/HelloCdkStackHelloCdkTopic850E0FBD (HelloCdkQueueHelloCdkStackHelloCdkTopic850E0FBD36A066B9) 
   0 | 05:28:45 | DELETE_IN_PROGRESS   | AWS::SQS::QueuePolicy  | HelloCdkQueue/Policy (HelloCdkQueuePolicy027FC30A) 
   0 | 05:28:45 | DELETE_IN_PROGRESS   | AWS::CDK::Metadata     | CDKMetadata 
   1 | 05:28:46 | DELETE_COMPLETE      | AWS::SQS::QueuePolicy  | HelloCdkQueue/Policy (HelloCdkQueuePolicy027FC30A) 
   2 | 05:28:46 | DELETE_COMPLETE      | AWS::SNS::Subscription | HelloCdkQueue/HelloCdkStackHelloCdkTopic850E0FBD (HelloCdkQueueHelloCdkStackHelloCdkTopic850E0FBD36A066B9) 
   2 | 05:28:46 | DELETE_IN_PROGRESS   | AWS::SQS::Queue        | HelloCdkQueue (HelloCdkQueueB56C77B9) 
   3 | 05:28:46 | DELETE_COMPLETE      | AWS::CDK::Metadata     | CDKMetadata 
   3 | 05:28:47 | DELETE_IN_PROGRESS   | AWS::SNS::Topic        | HelloCdkTopic (HelloCdkTopic1F583424) 
   4 | 05:28:47 | DELETE_COMPLETE      | AWS::SNS::Topic        | HelloCdkTopic (HelloCdkTopic1F583424) 
  4 Currently in progress: HelloCdkStack, HelloCdkQueueB56C77B9

   HelloCdkStack: destroyed

以上で、削除完了です。

まとめ

長くなりましたが、いかがでしたでしょうか。私も AWS CDK を検証の段階でしたので、まとめるのに苦慮しました。説明に不備や誤りがありましたらご指摘ください。また、不明点があれば、元サイト もおすすめです。とても丁寧にまとめられていて理解が浅い私でも進めやすかったです。

所感として、AWS CDK が出てきてまた一段と IaC が進化するのだなと実感しています。どんどん新しいことが出てきますが、取捨選択を意識して使いこなしていきたいですね。

参考サイト

GitHub - aws/aws-cdk: The AWS Cloud Development Kit is a framework for defining cloud infrastructure in code

https://docs.aws.amazon.com/cdk/latest/guide/home.html

【コードでインフラ定義】CDKという異次元体験をさくっとやるのに便利なAWS公式Workshopの紹介 | Developers.IO

https://docs.aws.amazon.com/cdk/latest/guide/getting_started.html

私は Infrastructure as Code をわかっていなかった - メソッド屋のブログ

https://docs.aws.amazon.com/ja_jp/cdk/latest/guide/stacks.html

私がTypeScriptについて勘違いしていたこと、そしてその理由 | POSTD