Welcome to new things

[Technical] [Electronic work] [Gadget] [Game] memo writing

I'm starting to think that using CloudFormation from AWS CDK is the right way to go.

I previously tried to handwrite an AWS CloudFormation template and failed....

www.ekwbtblog.com

What I learned at that time was that CloudFormation templates are not the kind that can be written by hand, but rather generated using some kind of tool.

And Amazon provided a tool for that in the form of the AWS CDK, so I used it, and it's soooo useful!

It was so convenient that from now on, I think I'll use AWS CDK for all my AWS resource creation instead of using the console or CLI!

I will note here a brief description of AWS CDK and its basic usage so that you can use AWS CDK quickly and easily when you need it.

What is AWS CDK?

In a nutshell, the AWS CDK (Cloud Development Kit) is a CloudFormation template generator.

You can write a program to output CloudFormation templates in a probram language such as TypeScript.

The output template can also be used to deploy to CloudFormation on AWS CDK.

What does it mean to write a template programmatically?

It is difficult to visualize in words alone, but the programming flow is as follows.

  1. Various AWS resources are defined as classes, and the class of the AWS resource you want to deploy is generated as an object with new.
  2. Objects have a parent-child relationship and build an object tree of resources, with the CloudFormation stack at the top.

This is the end of the user-written probram, and when this probram is executed, the entire constructed object tree is output as a CloudFormation template.

AWS CDK is useful here

I can write concisely.

If you try to create CloudFormation templates by hand, there is a lot of tedious work involved, such as stringing logical names and using functions, but the flexibility of the programming language allows for nice and concise descriptions.

No more mistakes.

When typing resource and parameter names, the editor's completion function can be used to eliminate typos.

Logical errors are also eliminated, since incorrect resource references will result in an error when the program is input or compiled.

Create resources just like a console CLI

When a resource is created in the console or AWS CLI, it is not visible on the surface, but in fact, behind the scenes, necessary parameters are set, permissions are granted, and other necessary resources are created.

If you write the template by hand, you have to write them all yourself, and the gap between what you see from this console/CLI command and the actual template is huge.

However, the AWS CDK allows you to use CloudFormation to create resources with the same ease as using the console CLI, because the AWS CDK will add to the template what is not specified in the program but is actually needed behind the scenes.

Then we will look at how to use it.

AWS CDK Installation

You must have Node.js installed as it is installed via npm.

npm install -g aws-cdk

The CLI command for AWS CDK is cdk.

Work Flow

Application Creation

First, create a folder and create an application.

One app, one folder, and the folder name is the app name.

Set up the app template with AWS CDK CLI commands in the created folder.

mkdir <app-name>
cd <app-name>
cdk init app --language tyescript

development cycle

Write a program based on the template created above, and use the following commands to turn the development cycle around.

# Compiling TypeScript
npm run build 

# Template output and display of differences from templates already deployed in CloudFormation
cdk diff 

# Template output
cdk synth 

# Deploy stack to CloudFormation
cdk deploy 

# Delete stacks deployed in CloudFormation
cdk destory 

The program is executed at the time of the cdk diff and cdk synth commands, and template output is generated. If the program includes console output, it is also output at this time.

The template file is

. /cdk.out/<stack name>.template.json

The file is output as a file.

sample

For example, "S3 bucket with email notification via AWS SNS when a file is uploaded" can be done simply by stating what you want to do, as shown below.

The actual output of the template is several hundred lines, but the program requires only a small amount of writing because it automatically makes appropriate additions behind the scenes as needed.

import * as cdk from '@aws-cdk/core';
import * as s3 from '@aws-cdk/aws-s3';
import * as s3n from '@aws-cdk/aws-s3-notifications';
import * as sns from '@aws-cdk/aws-sns';
import * as snss from '@aws-cdk/aws-sns-subscriptions';

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

        const bucket = new s3.Bucket(this, 'Bucket');
        const topic = new sns.Topic(this, 'Topic');
        topic.addSubscription(new snss.EmailSubscription('foo@bar.com'));
        bucket.addObjectCreatedNotification(new s3n.SnsDestination(topic));
    }
}

const app = new cdk.App();
new MyFirstCdkStack(app, 'dev-MyFirstCdkStack');

Program Structure

As you can see in the sample program, we first create the application, then the stack, and in the constructor of the stack, we generate various AWS resources.

As described later, when the object is created, the first argument is passed as the parent, App->Stack->Resources, which is a tree structure.

construct

The object to be output to the template inherits from the Construct class and is called construct.

Construct is created with new and takes three arguments from left to right: "scope", "id", and "props".

Argument Description

  • scope

    • Indicates the parent construct that created the construct. In most cases, set this here.
  • id

    • Specify the construct's distinguished name
  • props

    • Set the parameters required to create that resource. What parameters are required depends on the class of the resource

logical name

In the CloudFormation template, a logical name is assigned to a resource to identify it, and <scope's id>+<id>+<hash value is the logical name in AWS CDK.

Since this is passed to "scope," when constructs are created in a nested (tree-like) fashion, logical names are defined on a hierarchy like folder paths, so that logical names do not overlap.

However, if the same id is used in the same scope, it will be the same logical name and will be duplicated. (Of course...).

Also, note that in the CloudFormation template, if the logical name changes, it is treated as a different resource, so once deployed to CloudFormation, if the program resource is moved to a different scope, it will be treated as a completely different Note that once deployed to CloudFormation, if the program resource is moved to another scope, it will be treated as a completely different resource from the deployed resource.

stack

Multiple stacks can be generated from a single app, and templates are output for each stack.

The template file is . /cdk.out/<stack id name>.template.json and the stack name when deployed to CloudFormatin is <id name of stack.

As you can see from the fact that the app is passed as the first argument of the stack, the resource is App->Stack->Resources, which is a child of the stack, but the logical name of the resource does not include the id of the app and the stack.

Multiple Stacks

As mentioned earlier, multiple stacks can be generated from an app.

const app = new cdk.App();
new MyFirstCdkStack(app, 'MyFirstCdkStack');
new MySecondCdkStack(app, 'MySecondCdkStack');

The cdk command allows you to see the list of stacks created by the program.

cdk ls

Specifying a stack name with the cdk command can be applied only to the specified stack.

cdk deploy MyFirstCdkStack

reference

Programmers will probably be working with the AWS CDK API reference in hand.

The classes listed in "Constructs" are the constructs of various AWS resources to be added in new.

Click on a construct to see the required parameters (props) and a detailed description of the property methods of that construct.

Although construct can be said to be a resource wrapper for CloudFormation templates, most operations performed on resources are ported to the construct class, so you can build resources almost exclusively from the AWS CDK API reference.

However, when dealing with CloudFormation templates as they are described below, you will need to refer to the CloudFormation template reference.

Perform raw CloudFormation template description

In most cases, a high-level construct such as s3.Bucket is used, but there is also a "Cfn\" construct that corresponds one-to-one with the CloudFormation template, which can be used to directly describe the CloudFormation template CloudFormation templates can also be directly described using this construct.

Cfn\" is pre-populated with the properties that the resource will use, but furthermore, with CfnResource, you can even specify the resource type and property name yourself to describe a completely raw CloudFormation template.

const cfnBucket = new s3.CfnBucket(this, 'Bucket01', {});
const cfnResouce = new cdk.CfnResource(this, 'Bucket02', {
    type: 'AWS::S3::Bucket',
    properties: {},
});

By the way, the AWS CDK does not require

  • Low-level constructs such as "Cfn\" and "CfnResource" are called L1 (Level 1) constructs, which correspond one-to-one with CloudFormation templates and handle CloudFormation templates directly.
  • High-level constructs that encapsulate CloudFormation templates such as "s3.Bucket" and do not directly handle templates are called L2 (Level 2) constructs.

Referencing an existing resource

Existing resources created outside the stack cannot be changed from within the stack, but there are times when you want to refer to them.

Some constructs have a static function named from...() that can be used to create references to existing resources.

For example, to assign an existing group to a new user

const group = iam.Group.fromGroupArn(this, 'group', 'arn:aws:iam::1234:group/group_name')
const user = new iam.User(this, 'user');
user.addToGroup(group);

The output template is as follows, and you can see that AWS CDK has set the group name from the ARN for good.

{
  "Resources": {
    "user2C2B57AE": {
      "Type": "AWS::IAM::User",
      "Properties": {
        "Groups": [
          "group_name"
        ]
      }
    }
  }
}

Conversely, a construct for which no static function is provided means that there is no way to reference it.

Reuse of AWS CDK code

By inheriting from the cdk.Construct class, an original construct can be created to organize a series of resource creation.

export interface customProps {
    custom?: string;
}

export class customConstruct extends cdk.Construct {
    constructor(scope: Construct, id: string, props: customProps = {}){
        super(scope, id);

        const bucket1 = new s3.Bucket(this, 'bucket1');
        const bucket2 = new s3.Bucket(this, 'bucket2');
        const bucket3 = new s3.Bucket(this, 'bucket3');
    }
}

Since the stack is also a construct, it can be said that the stack is also an original construct.

They allow a series of resource creation to be modularized into an original construct that can be reused from other AWS CDK programs.

Divide into production and development

To separate resources for production and development, it seems to be the AWS CDK way to separate them by output stack.

Since it is a program, the code to divide it into stacks can be written in any way, but for portability, I think it would be better to pass values to props without hard-coding environment values.

A sample using props is described. To prevent the added props parameters from being passed to the parent class, the props without the parameters are passed to the constructor of the parent class.

interface stackProps extends cdk.StackProps {
    stage?: string;
}

class MyFirstCdkStack extends cdk.Stack {
    constructor(scope: cdk.Construct, id: string, props: stackProps) {
        const { stage, ..._props } = props;
        super(scope, id, _props);

        const bucket = new s3.Bucket(this, 'Bucket', {
            bucketName: `${stage}-MyFirstCdkBucket`,
        });
    }
}

let stage;
const app = new cdk.App();

// dev stack
stage = 'dev';
new MyFirstCdkStack(app, `${stage}-MyFirstCdkStack`, { stage });

// prod stack
stage = 'prod';
new MyFirstCdkStack(app, `${stage}-MyFirstCdkStack`, { stage });

file upload

When deploying AWS resources, it is sometimes necessary to upload local files, which is convenient because the AWS CDK does it for you instead of requiring you to upload them yourself.

Lambda

If you specify the folder where the source code of the Lambda function is located, it will automatically upload the entire folder.

const lambda = new lambda.Function(this, "lambdaTest", {
     runtime: lambda.Runtime.NODEJS_12_X,
     code: lambda.Code.fromAsset("./src"),
     handler: "app.handler",
});

S3

Specify the folder where the files you want to upload to S3 are located, and the entire folder will be uploaded automatically.

const bucket = new s3.Bucket(this, 'bucketTest');
const s3file = new s3deploy.BucketDeployment(this, 's3FileTest', {
    sources: [s3deploy.Source.asset('./upload')],
    destinationBucket: bucket,
});

Other Notes

make all versions available

The AWS CDK is frequently upgraded, and it is quite common for the versions of the CLI, modules, and modules to differ from each other. Different versions often cause errors, so check frequently to make sure that all versions are the same.

CLI version confirmation

cdk --version

Module version confirmation

cat package.json

# Check only old ones.
npm outdated

CLI Version Upgrade

npm update -g aws-cdk

Upgraded aws-cdk related module version

npm install <モジュール名>

# Batch processing of "aws-cdk" related modules
npm ls --depth=0 --json --dev --prod \
    | jq -r '.dependencies|keys|.[]' \
    | grep aws-cdk \
    | xargs -L 1 npm install

What not to change

The uniqueness of a resource is determined by "stack name + logical name".

And the logical name is determined by "scope+id".

So, once deployed, the

  • Stack name (id of stack)
  • Resource tree hierarchy position (scope)
  • Resource identification name (id)

is changed, it will no longer be considered the same resource, so be very careful when changing it.

No CloudFormation parameters are used.

AWS CDK recommends creating static templates with no parameters.

In general, we recommend against using AWS CloudFormation parameters with the AWS CDK. Unlike context values or environment variables, the usual way to pass values into your AWS CDK apps without hard-coding them, parameter values are not available at synthesis time, and thus cannot be easily used in other parts of your AWS CDK app, particularly for control flow. Since CloudFormation's unit of reuse was the template, parameters were the means of giving it value.

In AWS CDK, they are now constructs and props, and the values are given at the time of construct use, and the style has changed to outputting a FIXed template with the values set individually, so the need to use CloudFormation parameters has diminished.

Load an existing CloudFormation template

If you are attracted to AWS CDK, you will want to handle your existing CloudFormatin templates with AWS CDK as well.

Using cloudformation-include.CfnInclude, you can read an existing CloudFormatin template and generate the resources described in it as an L1 construct.

Editing that construct allows existing CloudFormation templates to be edited on the AWS CDK code.

Is the use of the system not good?

I actually tried cloudformation-include.CfnInclude, but since it generates L1 constructs, it is no different from handling raw CloudFormation templates, and I did not see much advantage in using it.

Perhaps what I am looking for is AWS CDK code that is a rewrite of an existing CloudFormation template using L2 construct.

However, just as CloudFormer, which generates CloudFormation templates from existing resources, was never officially released in the end, I doubt that the ability to generate L2 construct code from existing CloudFormatin templates will ever be available... I don't think we will ever see the ability to generate L2 construct code from existing CloudFormatin templates....

So it would be faster to look at the existing CloudFormatin template and recreate the same one yourself in AWS CDK.

Impressions, etc.

AWS CDK is really well done.

I wish they would have released it with CloudFormation....

When we released CloudFormation, we probably didn't expect the templates to be so complex.

Does this mean that Infrastructure as Code (IaC) is also becoming too complex to be handled by simply describing resources declaratively, and that advanced programming capabilities are required?

I also speculate that, from Amazon's point of view, it would have been better to write IaC in the programming language itself, rather than adding its own programming functions.

www.ekwbtblog.com

www.ekwbtblog.com

www.ekwbtblog.com

www.ekwbtblog.com

www.ekwbtblog.com

www.ekwbtblog.com

www.ekwbtblog.com

www.ekwbtblog.com

www.ekwbtblog.com

www.ekwbtblog.com

www.ekwbtblog.com

www.ekwbtblog.com

www.ekwbtblog.com

www.ekwbtblog.com

www.ekwbtblog.com

www.ekwbtblog.com

www.ekwbtblog.com

www.ekwbtblog.com

www.ekwbtblog.com

www.ekwbtblog.com

www.ekwbtblog.com

www.ekwbtblog.com

www.ekwbtblog.com

www.ekwbtblog.com

www.ekwbtblog.com

www.ekwbtblog.com

www.ekwbtblog.com

www.ekwbtblog.com

www.ekwbtblog.com

www.ekwbtblog.com

www.ekwbtblog.com

www.ekwbtblog.com

www.ekwbtblog.com

www.ekwbtblog.com

www.ekwbtblog.com

www.ekwbtblog.com

www.ekwbtblog.com

www.ekwbtblog.com

www.ekwbtblog.com

www.ekwbtblog.com

www.ekwbtblog.com

www.ekwbtblog.com

www.ekwbtblog.com

www.ekwbtblog.com

www.ekwbtblog.com

www.ekwbtblog.com

www.ekwbtblog.com

www.ekwbtblog.com

www.ekwbtblog.com

www.ekwbtblog.com

www.ekwbtblog.com

www.ekwbtblog.com