CDKを試してみる

[AWS クラウド開発キット (CDK) – TypeScript と Python 用がご利用可能に](https://aws.amazon.com/jp/blogs/news/aws-cloud-development-kit-cdk-typescript-and-python-are-now-generally-available)

これを触ってみます。

早速、嵌りました。グローバルにインストールするのが屋だったので、ローカルに```npm install aws-cdk```でインストールすると、```cdk```が使えませんでした(なんで？)。仕方なくグローバルインストール。

```
C:\Users\User\aws\cdk>npm install -g aws-cdk
C:\Users\User\AppData\Roaming\npm\cdk -> C:\Users\User\AppData\Roaming\npm\node_modules\aws-cdk\bin\cdk

> core-js@2.6.10 postinstall C:\Users\User\AppData\Roaming\npm\node_modules\aws-cdk\node_modules\core-js
> node postinstall || echo "ignore"

Thank you for using core-js ( https://github.com/zloirock/core-js ) for polyfilling JavaScript standard library!

The project needs your help! Please consider supporting of core-js on Open Collective or Patreon:
> https://opencollective.com/core-js
> https://www.patreon.com/zloirock

Also, the author of core-js ( https://github.com/zloirock ) is looking for a good job -)

+ aws-cdk@1.14.0
added 237 packages from 218 contributors in 23.957s

C:\Users\User\aws\cdk>
```

コマンドの確認します。

```
C:\Users\User\aws\cdk>cdk
Usage: cdk -a <cdk-app> COMMAND

Commands:
  cdk list [STACKS..]             Lists all stacks in the app      [aliases: ls]
  cdk synthesize [STACKS..]       Synthesizes and prints the CloudFormation
                                  template for this stack       [aliases: synth]
  cdk bootstrap [ENVIRONMENTS..]  Deploys the CDK toolkit stack into an AWS
                                  environment
  cdk deploy [STACKS..]           Deploys the stack(s) named STACKS into your
                                  AWS account
  cdk destroy [STACKS..]          Destroy the stack(s) named STACKS
  cdk diff [STACKS..]             Compares the specified stack with the deployed
                                  stack or a local template file, and returns
                                  with status 1 if any difference is found
  cdk metadata [STACK]            Returns all metadata associated with this
                                  stack
  cdk init [TEMPLATE]             Create a new, empty CDK project from a
                                  template. Invoked without TEMPLATE, the app
                                  template will be used.
  cdk context                     Manage cached context values
  cdk docs                        Opens the reference documentation in a browser
                                                                  [aliases: doc]
  cdk doctor                      Check your set-up for potential problems

Options:
  --app, -a             REQUIRED: command-line for executing your app or a cloud
                        assembly directory (e.g. "node bin/my-app.js")  [string]
  --context, -c         Add contextual string parameter (KEY=VALUE)      [array]
  --plugin, -p          Name or path of a node package that extend the CDK
                        features. Can be specified multiple times        [array]
  --trace               Print trace for stack warnings                 [boolean]
  --strict              Do not construct stacks with warnings          [boolean]
  --ignore-errors       Ignores synthesis errors, which will likely produce an
                        invalid output                [boolean] [default: false]
  --json, -j            Use JSON output instead of YAML when templates are
                        printed to STDOUT             [boolean] [default: false]
  --verbose, -v         Show debug logs               [boolean] [default: false]
  --profile             Use the indicated AWS profile as the default environment
                                                                        [string]
  --proxy               Use the indicated proxy. Will read from HTTPS_PROXY
                        environment variable if not specified.          [string]
  --ec2creds, -i        Force trying to fetch EC2 instance credentials. Default:
                        guess EC2 instance status.                     [boolean]
  --version-reporting   Include the "AWS::CDK::Metadata" resource in synthesized
                        templates (enabled by default)                 [boolean]
  --path-metadata       Include "aws:cdk:path" CloudFormation metadata for each
                        resource (enabled by default)  [boolean] [default: true]
  --asset-metadata      Include "aws:asset:*" CloudFormation metadata for
                        resources that user assets (enabled by default)
                                                       [boolean] [default: true]
  --role-arn, -r        ARN of Role to use when invoking CloudFormation [string]
  --toolkit-stack-name  The name of the CDK toolkit stack               [string]
  --staging             Copy assets to the output directory (use --no-staging to
                        disable, needed for local debugging the source files
                        with SAM CLI)                  [boolean] [default: true]
  --output, -o          Emits the synthesized cloud assembly into a directory
                        (default: cdk.out)                              [string]
  --no-color            Removes colors and other style from console output
                                                      [boolean] [default: false]
  --version             Show version number                            [boolean]
  -h, --help            Show help                                      [boolean]

If your app has a single stack, there is no need to specify the stack name

If one of cdk.json or ~/.cdk.json exists, options specified there will be used
as defaults. Settings in cdk.json take precedence.


C:\Users\User\aws\cdk>
```

初期化を行います。言語は```typescript```にしました(フォルダの名前を```cdk```->```cdk01```に変えています)。


```
C:\Users\User\aws>cd cdk01

C:\Users\User\aws\cdk01>cdk init app --language=typescript
Applying project template app for typescript
Initializing a new git repository...
warning: LF will be replaced by CRLF in .gitignore.
The file will have its original line endings in your working directory.
warning: LF will be replaced by CRLF in .npmignore.
The file will have its original line endings in your working directory.
warning: LF will be replaced by CRLF in README.md.
The file will have its original line endings in your working directory.
warning: LF will be replaced by CRLF in bin/cdk01.ts.
The file will have its original line endings in your working directory.
warning: LF will be replaced by CRLF in cdk.json.
The file will have its original line endings in your working directory.
warning: LF will be replaced by CRLF in jest.config.js.
The file will have its original line endings in your working directory.
warning: LF will be replaced by CRLF in lib/cdk01-stack.ts.
The file will have its original line endings in your working directory.
warning: LF will be replaced by CRLF in package.json.
The file will have its original line endings in your working directory.
warning: LF will be replaced by CRLF in test/cdk01.test.ts.
The file will have its original line endings in your working directory.
warning: LF will be replaced by CRLF in tsconfig.json.
The file will have its original line endings in your working directory.
Executing npm install...
npm WARN deprecated left-pad@1.3.0: use String.prototype.padStart()
npm notice created a lockfile as package-lock.json. You should commit this file.
npm WARN cdk01@0.1.0 No repository field.
npm WARN cdk01@0.1.0 No license field.
npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@1.2.9 (node_modules\fsevents):
npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for fsevents@1.2.9: wanted {"os":"darwin","arch":"any"} (current: {"os":"win32","arch":"x64"})

# Useful commands

 * `npm run build`   compile typescript to js
 * `npm run watch`   watch for changes and compile
 * `npm run test`    perform the jest unit tests
 * `cdk deploy`      deploy this stack to your default AWS account/region
 * `cdk diff`        compare deployed stack with current state
 * `cdk synth`       emits the synthesized CloudFormation template


C:\Users\User\aws\cdk01>cdk init app --language=typescript
```

プロジェクトの構造の確認します（init直後ではなく、手でフォルダやファイルの追加があります）。

長いので```gist```に貼っています。
[CDK project structure](https://gist.github.com/b1a747ae29cfc4b28a2cca7e5e723456)


```init```後の```lib\cdk01-stack.ts```ファイルを確認します。```// The code that defines your stack goes here```とある場所にコードを書いてくようです。

```ts
import cdk = require('@aws-cdk/core');
export class Cdk01Stack extends cdk.Stack {
  constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    // The code that defines your stack goes here
  }
}
```

サンプルのコードを追加します。

```
import cdk = require('@aws-cdk/core');

export class Cdk01Stack extends cdk.Stack {
  constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    // The code that defines your stack goes here

    const myVpc = new ec2.Vpc(this, "MyVPC");

    const myCluster = new ecs.Cluster(this, "MyCluster", {
      vpc: myVpc
    });

    const myQueueProcessingService = new ecs_patterns.QueueProcessingFargateService(
      this, "MyQueueProcessingService", {
        cluster: myCluster,
        memoryLimitMiB: 512,
        image: ecs.ContainerImage.fromAsset("my-queue-consumer")
      });

    const myFunction = new lambda.Function(
      this, "MyFrontendFunction", {
        runtime: lambda.Runtime.NODEJS_10_X,
        timeout: Duration.seconds(3),
        handler: "index.handler",
        code: lambda.Code.asset("my-front-end"),
        environment: {
          QUEUE_NAME: myQueueProcessingService.sqsQueue.queueName
        }
      });

    myQueueProcessingService.sqsQueue.grantSendMessages(myFunction);

    const myApi = new apigateway.LambdaRestApi(
      this, "MyFrontendApi", {
        handler: myFunction
      });

  }
}
```

デプロイするつもりはないので、```cdk synth```を使って、```cloud formation```のファイルを生成します。
が、さっそくコンパイルエラーです。

```
C:\Users\User\aws\cdk01>cdk synth
⨯ Unable to compile TypeScript:
lib/cdk01-stack.ts:9:23 - error TS2304: Cannot find name 'ec2'.

9     const myVpc = new ec2.Vpc(this, "MyVPC");
                        ~~~
lib/cdk01-stack.ts:11:27 - error TS2304: Cannot find name 'ecs'.

11     const myCluster = new ecs.Cluster(this, "MyCluster", {
                             ~~~
lib/cdk01-stack.ts:15:42 - error TS2304: Cannot find name 'ecs_patterns'.

15     const myQueueProcessingService = new ecs_patterns.QueueProcessingFargateService(
                                            ~~~~~~~~~~~~
lib/cdk01-stack.ts:19:16 - error TS2304: Cannot find name 'ecs'.

19         image: ecs.ContainerImage.fromAsset("my-queue-consumer")
                  ~~~
lib/cdk01-stack.ts:22:28 - error TS2304: Cannot find name 'lambda'.

22     const myFunction = new lambda.Function(
                              ~~~~~~
lib/cdk01-stack.ts:24:18 - error TS2304: Cannot find name 'lambda'.

24         runtime: lambda.Runtime.NODEJS_10_X,
                    ~~~~~~
lib/cdk01-stack.ts:25:18 - error TS2304: Cannot find name 'Duration'.

25         timeout: Duration.seconds(3),
                    ~~~~~~~~
lib/cdk01-stack.ts:27:15 - error TS2304: Cannot find name 'lambda'.

27         code: lambda.Code.asset("my-front-end"),
                 ~~~~~~
lib/cdk01-stack.ts:35:23 - error TS2304: Cannot find name 'apigateway'.

35     const myApi = new apigateway.LambdaRestApi(
                         ~~~~~~~~~~

Subprocess exited with error 1
```

必要なモジュールが足りないようです。地道にモジュールを追加します。```npm i```の```i```はinstallのiのようです。

```
C:\Users\User\aws\cdk01>npm i @aws-cdk/aws-ecs
npm WARN cdk01@0.1.0 No repository field.
npm WARN cdk01@0.1.0 No license field.
npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@1.2.9 (node_modules\fsevents):
npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for fsevents@1.2.9: wanted {"os":"darwin","arch":"any"} (current: {"os":"win32","arch":"x64"})

+ @aws-cdk/aws-ecs@1.14.0
added 30 packages from 4 contributors and audited 1762575 packages in 26.75s
found 0 vulnerabilities
```

ファイルに```import```を追加します。（```TypeScript```のモジュール```Duration```の追加がわからなかったので、コメントアウトがあります。誰か教えて！）

```
import cdk = require('@aws-cdk/core');
import ec2 = require('@aws-cdk/aws-ec2');
import ecs = require('@aws-cdk/aws-ecs');
import lambda = require('@aws-cdk/aws-lambda');
import ecs_patterns = require('@aws-cdk/aws-ecs-patterns');
import apigateway = require('@aws-cdk/aws-apigateway');

export class Cdk01Stack extends cdk.Stack {
  constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    // The code that defines your stack goes here

    const myVpc = new ec2.Vpc(this, "MyVPC");

    const myCluster = new ecs.Cluster(this, "MyCluster", {
      vpc: myVpc
    });

    const myQueueProcessingService = new ecs_patterns.QueueProcessingFargateService(
      this, "MyQueueProcessingService", {
        cluster: myCluster,
        memoryLimitMiB: 512,
        image: ecs.ContainerImage.fromAsset("my-queue-consumer")
      });

    const myFunction = new lambda.Function(
      this, "MyFrontendFunction", {
        runtime: lambda.Runtime.NODEJS_10_X,
        // timeout: Duration.seconds(3),
        handler: "index.handler",
        code: lambda.Code.asset("my-front-end"),
        environment: {
          QUEUE_NAME: myQueueProcessingService.sqsQueue.queueName
        }
      });

    myQueueProcessingService.sqsQueue.grantSendMessages(myFunction);

    const myApi = new apigateway.LambdaRestApi(
      this, "MyFrontendApi", {
        handler: myFunction
      });

  }
}
```

キューの作成でエラーになるので、フォルダを追加します。

```
C:\Users\User\aws\cdk01>cdk synth
Cannot find image directory at C:\Users\User\aws\cdk01\my-queue-consumer
Subprocess exited with error 1

C:\Users\User\aws\cdk01>mkdir my-queue-consumer
```

再度チャレンジ

```
C:\Users\User\aws\cdk01>cdk synth
No 'Dockerfile' found in C:\Users\User\aws\cdk01\my-queue-consumer
Subprocess exited with error 1
```

Dockerfileがないとのこと。なので、適当につくる。

再度チャレンジ

```
C:\Users\User\aws\cdk01>cdk synth
ENOENT: no such file or directory, stat 'C:\Users\User\aws\cdk01\my-front-end'
Subprocess exited with error 1

C:\Users\User\aws\cdk01>mkdir my-queue-consumer
```

また、フォルダがないとのこと。とりあえず作る。```my-front-end```でなんでフォルダが必要なのだろう？

再度チャレンジ

```
C:\Users\User\aws\cdk01>cdk synth
Resources:
  MyVPCAFB07A31:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: 10.0.0.0/16
      EnableDnsHostnames: true
      EnableDnsSupport: true
      InstanceTenancy: default
      Tags:
        - Key: Name
          Value: Cdk01Stack/MyVPC

以下省略
```

[生成されたファイル](https://gist.github.com/naoto-ogawa/cb9cb73573947f4da5b9bfb1cf11c30e)