こんにちは。AWS勉強中の @masatomix です。
前回?までAWS CDKをいろいろいじくったところを記事にしていましたが、ひきつづき AWS CDKです。これからAWS CDK / CloudFormationでいろいろ AWSのリソースを作成するサンプルを作っていきたいのですが、なにはともあれ独立したVPCがほしいので、まずはVPCを新規作成するサンプルです。
前提
- AWS CDK で Infrastructure as Code する の記事の環境がそろっていること
やってみる
作りたい環境はこんな感じ。
Availability Zone 3つにまたがるVPCを構築し、各AZにPublic/Private のSubnetを1つずつ。Private SubnetがInternet に出て行くための NAT Gatewayは1つのAZに配置1。
もちろん、NAT Gatewayに割り振るElastic IPやInternet Gateway、各Subnetがネットに出て行くためのRouteTableなども作成しています。
CDKのソースコード
コードです
import { App, CfnParameter, Stack, StackProps } from 'aws-cdk-lib'
import {
CfnEIP,
CfnInternetGateway,
CfnNatGateway,
CfnRoute,
CfnRouteTable,
CfnSubnet,
CfnSubnetRouteTableAssociation,
CfnVPC,
CfnVPCGatewayAttachment,
} from 'aws-cdk-lib/aws-ec2'
import { availabilityZones, getProfile } from './Utils'
// import * as sqs from 'aws-cdk-lib/aws-sqs';
export class VPCStack extends Stack {
public readonly vpc: CfnVPC
public readonly publicSubnets: CfnSubnet[]
public readonly privateSubnets: CfnSubnet[]
constructor(scope: App, id: string, props?: StackProps) {
super(scope, id, props)
// The code that defines your stack goes here
const p = getProfile(this)
const vpcCIDRs = {
vpc: '192.168.0.0/16',
subnets: [
{ public: '192.168.0.0/24', private: '192.168.1.0/24' },
{ public: '192.168.2.0/24', private: '192.168.3.0/24' },
{ public: '192.168.4.0/24', private: '192.168.5.0/24' },
],
}
const subnetCount = vpcCIDRs.subnets.length
// VPC
const vpc = new CfnVPC(this, `MyVPC`, {
cidrBlock: vpcCIDRs.vpc,
tags: [{ key: 'Name', value: `${p.name}-vpc` }],
})
this.vpc = vpc
// Public Subnet
const publicSubnets = vpcCIDRs.subnets.map(
(subnet, index) =>
new CfnSubnet(this, `MyPublicSubnet${index}`, {
vpcId: vpc.ref,
cidrBlock: subnet.public,
availabilityZone: availabilityZones[index],
mapPublicIpOnLaunch: true,
tags: [{ key: 'Name', value: `${p.name}-public-subnet-${index}` }],
}),
)
this.publicSubnets = publicSubnets
// Private Subnet
const privateSubnets = vpcCIDRs.subnets.map(
(subnet, index) =>
new CfnSubnet(this, `MyPrivateSubnet${index}`, {
vpcId: vpc.ref,
cidrBlock: subnet.private,
availabilityZone: availabilityZones[index],
mapPublicIpOnLaunch: false,
tags: [{ key: 'Name', value: `${p.name}-private-subnet-${index}` }],
}),
)
this.privateSubnets = privateSubnets
// Internet Gateway
const igw = new CfnInternetGateway(this, 'MyInternetGateWay', { tags: [{ key: 'Name', value: `${p.name}-igw` }] })
const attachInternetGateway = new CfnVPCGatewayAttachment(this, 'AttachGateway', {
vpcId: vpc.ref,
internetGatewayId: igw.ref,
})
// Public RouteTables
const publicRouteTables = vpcCIDRs.subnets.map(
(subnet, index) =>
new CfnRouteTable(this, `PublicRouteTable${index}`, {
vpcId: vpc.ref,
tags: [{ key: 'Name', value: `${p.name}-public-route-${index}` }],
}),
)
// Private RouteTables
const privateRouteTables = vpcCIDRs.subnets.map(
(subnet, index) =>
new CfnRouteTable(this, `PrivateRouteTable${index}`, {
vpcId: vpc.ref,
tags: [{ key: 'Name', value: `${p.name}-private-route-${index}` }],
}),
)
for (let index = 0; index < subnetCount; index++) {
// 各Public用 RouteTableに Public Subnetを紐付け
new CfnSubnetRouteTableAssociation(this, `PublicSubnetRouteTableAssociation${index}`, {
routeTableId: publicRouteTables[index].ref,
subnetId: publicSubnets[index].ref,
})
// そのRouteTableはInternet Gatewayを紐付ける
new CfnRoute(this, `PublicRouteToIGW${index}`, {
routeTableId: publicRouteTables[index].ref,
destinationCidrBlock: '0.0.0.0/0',
gatewayId: igw.ref,
})
// 各Private用 RouteTableに Private Subnetを紐付け
new CfnSubnetRouteTableAssociation(this, `PrivateSubnetRouteTableAssociation${index}`, {
routeTableId: privateRouteTables[index].ref,
subnetId: privateSubnets[index].ref,
})
}
// // 各Subnetに、NAT GWを置くパタン
// const eips = [...new Array(subnetCount)].map((_: undefined, index: number) => {
// return new CfnEIP(this, `EIPforNatGw${index}`, { domain: 'vpc' })
// })
// const natgws = [...new Array(subnetCount)].map((_: undefined, index: number) => {
// return new CfnNatGateway(this, `MyNAT${index}`, {
// allocationId: eips[index].attrAllocationId,
// subnetId: publicSubnets[index].ref
// })
// })
// for (let i = 0; i < subnetCount; i++) {
// new CfnRoute(this, `RouteToNAT${i}`, {
// routeTableId: privateRouteTables[i].ref,
// destinationCidrBlock: '0.0.0.0/0',
// natGatewayId: natgws[i].ref
// })
// }
// // 各Subnetに、NAT GWを置くパタン
// 1Subnetに、NAT GWを置くパタン
// publicSubnets[0] に、NAT GWを配置して
const eip = new CfnEIP(this, 'EIPforNatGw1', { domain: 'vpc' })
const natgw = new CfnNatGateway(this, `MyNAT1`, {
allocationId: eip.attrAllocationId,
subnetId: publicSubnets[0].ref,
tags: [{ key: 'Name', value: `${p.name}-natgw` }],
})
natgw.addDependency(attachInternetGateway)
// そのNAT GWを各Private SubnetのRouteTableにセットする
for (let i = 0; i < subnetCount; i++) {
new CfnRoute(this, `RouteToNAT${i}`, {
routeTableId: privateRouteTables[i].ref,
destinationCidrBlock: '0.0.0.0/0',
natGatewayId: natgw.ref,
})
}
// 1Subnetに、NAT GWを置くパタン
}
}
#!/usr/bin/env node
import 'source-map-support/register'
import * as cdk from 'aws-cdk-lib'
import { VPCStack } from '../lib/VPCStack'
const app = new cdk.App()
const vpcStack = new VPCStack(app, 'VPCStack')
{
"app": "npx ts-node --prefer-ts-exts bin/cdk-samples.ts",
...
"context": {
...
"dev": {
"name": "dev-20230815"
}
}
}
ちなみに上記の"dev":{"name": "dev-20230815"}
によって
tags: [{ key: 'Name', value: `${p.name}-vpc` }],
などのプレースホルダが
dev-20230815-vpc
に置換されるようにしてあります。
実行してみる
コードを作ったら、では実行してみます。
$ yarn cdk deploy VPCStack
... しばらくかかります
$
ちゃんとできているか一応確認します。
$ aws ec2 describe-vpcs \
--query "Vpcs[*].[(Tags[?Key=='Name'])[0].Value,VpcId,CidrBlock]" \
--filters "Name=tag:Name,Values=dev-20230815-vpc" \
--output table
-----------------------------------------------------------------
| DescribeVpcs |
+------------------+-------------------------+------------------+
| dev-20230815-vpc| vpc-0461b6f7baff8f8d1 | 192.168.0.0/16 |
+------------------+-------------------------+------------------+
$ aws ec2 describe-subnets \
--query "Subnets[*].[(Tags[?Key=='Name'])[0].Value,CidrBlock,SubnetId]" \
--filters "Name=vpc-id, Values=vpc-0461b6f7baff8f8d1" \
--output table
---------------------------------------------------------------------------------
| DescribeSubnets |
+--------------------------------+-----------------+----------------------------+
| dev-20230815-public-subnet-0 | 192.168.0.0/24 | subnet-0ec370f96cfb4e93b |
| dev-20230815-private-subnet-2 | 192.168.5.0/24 | subnet-0f7dcb24813414db1 |
| dev-20230815-private-subnet-1 | 192.168.3.0/24 | subnet-03587fc0cf1fb9ae8 |
| dev-20230815-public-subnet-1 | 192.168.2.0/24 | subnet-0c05e26c010e2fa3c |
| dev-20230815-public-subnet-2 | 192.168.4.0/24 | subnet-0e2cda5c21e1e6370 |
| dev-20230815-private-subnet-0 | 192.168.1.0/24 | subnet-0a5ec4312d172c4b1 |
+--------------------------------+-----------------+----------------------------+
$
ちゃんとできていそうですね。お疲れさまでした!
関連リンク
- https://github.com/masatomix/cdk-samples/tree/vpc_base 今回のソースコード
- AWS CDK で Infrastructure as Code するこれで環境をつくってください。
- AWS のアーキテクチャ図を描きたい ! でもどうすれば良いの ?
- AWS CDKのTIPS集
-
本番構成では各AZに置くべきやつです。 ↩