AWS CDKでVPC、サブネット、EC2を作成してみる

2023.01.11

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

はじめに

AWS上で何らかの検証を行うため、VPCとサブネットを用意し、その中にEC2インスタンスを作成することはしばしばあるかと思います。 これらをパッと作れるよう、以下のような点を考慮しつつAWS CDKで作成してみました。

  • VPC、パブリックサブネット、プライベートサブネットを作成。それぞれのサブネットにEC2インスタンスを作成する。
  • EC2インスタンスにはSession Managerで接続できるようにする。
  • セキュリティグループを作成するが、Ingressは何も許可しない(必要な時に手動で許可する想定)。
  • CDKのbootstrapコマンドで使用するバケット名を指定できるようにする。
  • CDKのToolkitのスタック名を指定できるようにする。
  • CloudFormationスタックに説明を入れる。

以下、作成した時に行ったことやソースについて書きたいと思います。

実装について

前提条件

AWS CDKを実行するにあたり、AWS CLIやNode.js、CDKなど必要なものはローカルにインストール済みであるものとします。 今回使用したCDKのバージョンは「2.56.0」となります。

$ cdk --version
2.56.0 (build 1485f48)

プロジェクト作成

ローカルに作業用のフォルダを作成します。今回は「cdk-vpc-ec2」というフォルダ名としました。

$ mkdir cdk-vpc-ec2
$ cd cdk-vpc-ec2

以下のコマンドを実行してプロジェクトを作成します。

$ cdk init sample-app --language typescript

実装したソース

AWS CDKのソースは以下のようになります。

cdk-vpc-ec2.ts

#!/usr/bin/env node
import * as cdk from 'aws-cdk-lib';
import { CdkVpcEc2Stack } from '../lib/cdk-vpc-ec2-stack';
import { DefaultStackSynthesizer } from 'aws-cdk-lib';

const app = new cdk.App();
new CdkVpcEc2Stack(app, 'CdkVpcEc2Stack', {
    synthesizer: new DefaultStackSynthesizer({
        fileAssetsBucketName: 'cdk-vpc-ec2-assets', // bootstrapのバケット名を指定
    }),
    description: 'This is a cdk-vpc-ec2-sample-stack', // CloudFormationスタックに説明を追加
});

cdk-vpc-ec2-stack.ts

import { Duration, Stack, StackProps } from 'aws-cdk-lib';
import * as s3 from 'aws-cdk-lib/aws-s3';
import * as ec2 from 'aws-cdk-lib/aws-ec2';
import * as iam from 'aws-cdk-lib/aws-iam';
import { CfnOutput } from 'aws-cdk-lib';
import { Construct } from 'constructs';

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

    // バケット
    const bucket = new s3.Bucket(this, 'SampleBucket', {
      blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL,
      encryption: s3.BucketEncryption.S3_MANAGED,
      bucketName: "cdk-vpc-ec2-sample-bucket",
    });

    // VPC
    const vpc = new ec2.Vpc(this, 'SampleVpc', {
      ipAddresses: ec2.IpAddresses.cidr('10.0.0.0/16'),
      vpcName: 'cdk-sample-vpc'
    });

    // セキュリティグループ
    const securityGroup = new ec2.SecurityGroup(this, 'SampleSecurityGroup', {
      vpc: vpc,
      securityGroupName: 'cdk-vpc-ec2-security-group',
    });

    // (Session Mangerを使うための)IAMロール
    const instanceRole = new iam.Role(this, 'SampleRole', {
      assumedBy: new iam.ServicePrincipal('ec2.amazonaws.com'),
      managedPolicies: [
        iam.ManagedPolicy.fromAwsManagedPolicyName(
          "AmazonSSMManagedInstanceCore"
        ),
      ],
      description: 'cdk-vpc-ec2-instance-role',
    });

    // EC2インスタンス作成
    const createInstance = (id: string, name: string, subnet: ec2.SubnetSelection) : ec2.Instance => {
      return new ec2.Instance(this, id, {
        vpc,
        vpcSubnets: subnet,
        instanceType: new ec2.InstanceType(this.node.tryGetContext('instanceType')),
        machineImage: ec2.MachineImage.latestAmazonLinux({
          generation: ec2.AmazonLinuxGeneration.AMAZON_LINUX_2,
        }),
        securityGroup: securityGroup,
        role: instanceRole,
        instanceName: name
      });
    };

    const instance1 = createInstance('SampleInstance1', 'cdk-vpc-ec2-instance1', vpc.selectSubnets({
      subnetType: ec2.SubnetType.PUBLIC
    }));

    const instance2 = createInstance('SampleInstance2', 'cdk-vpc-ec2-instance2', vpc.selectSubnets({
      subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS
    }));

    // CloudFormationに出力
    new CfnOutput(this, 'S3', { value: bucket.bucketName });
    new CfnOutput(this, 'VPC', { value: vpc.vpcId });
    new CfnOutput(this, 'Security Group', { value: securityGroup.securityGroupId });
    new CfnOutput(this, 'EC2Instance1', { value: instance1.instanceId });
    new CfnOutput(this, 'EC2Instance2', { value: instance2.instanceId });
  }
}

cdk.json

{
  (中略)
  "context": {
    (中略。context内に以下をインスタンスタイプの定義を追記)
    "instanceType": "t2.micro"
  }
}

コメントに書いてあるように、bootstrapで使用する任意のバケット名を指定しています。 また作成されるCloudFormationに説明を追加したり、出力値に作成したリソースの名称等を出力するようにしています。

実行したコマンド

bootstrapではバケット名、ToolKitのスタック名を指定しました。以下のようなコマンドとなります。

$ cdk bootstrap \
    --bootstrap-bucket-name cdk-vpc-ec2-assets \
    --toolkit-stack-name cdk-vpc-ec2-toolkit \

diffやdeployなどのコマンドは特に引数などは必要ありません。

$ cdk diff
$ cdk deploy

実行結果

CDKのコマンドを実行するとCloudFormationやリソースが作成されるかと思います。以下に作成されたもののキャプチャの一部を挙げて起きます。

スタックの説明

スタックの出力値

インスタンス

まとめ

個人的にしばしば使うリソースをAWS CDKを使って作ってみました。何かの役にたてば幸いです。

参考サイト