AWS CDK Pythonで簡単にネットワークインフラとEC2を構築する

とにかく速く、楽に、全自動でAWSのインフラとEC2をセットで構築したい場合、AWS CDKはとても便利なツールです。今回はAWS CDK Pythonを使うやり方を紹介します。

#### 前提
###### 作業環境
- OS: CentOS 7.7.1908
- Python 3.7.1
- NodeJs v13.0.1
- aws config: 設定済

###### AWS環境
- aws keypair: 作成済。名前は'testkey'とします。


#### 構成
- VPCは/21で切る。10.0.0.0/21
- Subnet: Public 1つ (/24)、Private 1つ (/24)
- SecurityGroup: EC2にSSHを使うために、Inbound 22番ポートを開ける

#### 手順

###### CDKをインストール

```console
# npm install -g aws-cdk
```

###### テストプロジェクト tescdkを作成

```console
# mkdir testcdk
# cd testcdk
# cdk init --language python
Applying project template app for python
Initializing a new git repository...
Executing Creating virtualenv...
# Welcome to your CDK Python project!
This is a blank project for Python development with CDK.
The `cdk.json` file tells the CDK Toolkit how to execute your app.
(省略)
## Useful commands
 * `cdk ls`          list all stacks in the app
 * `cdk synth`       emits the synthesized CloudFormation template
 * `cdk deploy`      deploy this stack to your default AWS account/region
 * `cdk diff`        compare deployed stack with current state
 * `cdk docs`        open CDK documentation
Enjoy!
```

###### ディレクトリとファイル構造を確認

```console
# tree
.
|-- .env
|-- README.md
|-- app.py
|-- cdk.json
|-- requirements.txt
|-- setup.py
|-- source.bat
`-- testcdk
    |-- __init__.py
    `-- testcdk_stack.py
```

###### Python 仮想環境を有効化

```console

# source .env/bin/activate
(.env)
```

setup.pyでEC2作成に必要なライブラリを追加

```python:setup.py
(省略)
install_requires=[
        "aws-cdk.core",
        "aws_cdk.aws_ec2",
],
(省略)
```

###### pipのupdateと必要なライブラリをインストール


```console

# pip install -e .
(省略)
Successfully installed attrs-19.3.0 aws-cdk.aws-cloudwatch-1.32.1 aws-cdk.aws-ec2-1.32.1 aws-cdk.aws-events-1.32.1 aws-cdk.aws-iam-1.32.1 aws-cdk.aws-kms-1.32.1 aws-cdk.aws-logs-1.32.1 aws-cdk.aws-s3-1.32.1 aws-cdk.aws-ssm-1.32.1 aws-cdk.core-1.32.1 aws-cdk.cx-api-1.32.1 aws-cdk.region-info-1.32.1 cattrs-1.0.0 constructs-2.0.1 jsii-1.1.0 publication-0.0.3 python-dateutil-2.8.1 six-1.14.0 testcdk typing-extensions-3.7.4.2
```

###### app.pyでデプロイ先のリージョンを指定

```python:app.py
#!/usr/bin/env python3

from aws_cdk import core

from testcdk.testcdk_stack import TestcdkStack


app = core.App()
TestcdkStack(app, "testcdk", env=core.Environment(region="ap-northeast-1"))

app.synth()
```



###### testcdk/testcdk_stack.pyファイルを編集
VPC、SecurityGroup、EC2を作成するスタックを書きます。

```python:testcdk_stack.py
from aws_cdk import (
        core,
        aws_ec2 <=これを追加
)


class TestcdkStack(core.Stack):

    def __init__(self, scope: core.Construct, id: str, **kwargs) -> None:
        super().__init__(scope, id, **kwargs)

        # The code that defines your stack goes here
        # この下にコードを書いて行く

        cidr = '10.0.0.0/21'　#cidr blockを書く

        vpc = aws_ec2.Vpc(
            self,
            id='test-vpc',
            cidr=cidr,
            nat_gateways=1,
            subnet_configuration=[
                aws_ec2.SubnetConfiguration(
                    cidr_mask=24,  # Public Subnetのnetmaskを定義
                    name='public',
                    subnet_type=aws_ec2.SubnetType.PUBLIC,
                ),
                aws_ec2.SubnetConfiguration(
                    cidr_mask=24, # Private Subnetのnetmaskを定義
                    name='private',
                    subnet_type=aws_ec2.SubnetType.PRIVATE,
                ),
            ],
        )

        security_group = aws_ec2.SecurityGroup(
            self,
            id='test-security-group',
            vpc=vpc,
            security_group_name='test-security-group'
        )

        security_group.add_ingress_rule(
            peer=aws_ec2.Peer.ipv4(cidr),
            connection=aws_ec2.Port.tcp(22), # InboundでPort 22を開ける
        )

        image_id = aws_ec2.AmazonLinuxImage(generation=aws_ec2.AmazonLinuxGeneration.AMAZON_LINUX_2).get_image(self).image_id #EC2のimageを指定

        aws_ec2.CfnInstance(
            self,
            id='testec2',
            availability_zone="ap-northeast-1a", # AZを指定
            image_id=image_id,
            instance_type="t3.micro", # Instance Typeを指定
            key_name='testkey', # Key Pairを指定
            security_group_ids=[security_group.security_group_id],
            subnet_id=vpc.private_subnets[0].subnet_id, # 今回はPrivate Subnetを指定
            tags=[{
                "key": "Name",
                "value": "testec2"　# webコンソールで表示する名前を定義
            }]
        )

```

###### cdk synthで出力されるCloudformation用スタックを確認
```console

# cdk synth
Resources:
  testvpc8985080E:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: 10.0.0.0/21
      EnableDnsHostnames: true
      EnableDnsSupport: true
      InstanceTenancy: default
(省略)
```
cdk synthでスタックをyamlに保存することも出来ます。

```console

cdk synth > cdk.yaml
```

###### デプロイ可能なスタック一覧を確認

```
# cdk ls
testcdk
```

###### 作ったスタックtestcdkを指定してデプロイ
```console
# cdk deploy testcdk
testcdk: deploying...
testcdk creating CloudFormation changeset
```

これで指定したAWSアカウントのリージョンでCloudformationが動き、VPCとSubnet、Security Group、EC2が作成されます。


###### 参考
[Getting Started With the AWS CDK](
https://docs.aws.amazon.com/cdk/latest/guide/getting_started.html)