この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
はじめに
CX事業本部@札幌の佐藤です。この記事では、AWS CDKのConstructについて説明していきます。
この記事に出てくるサンプルコードは以下のリポジトリにありますので、参考にしてみてください。
https://github.com/briete/aws-cdk-construct-library-sample
前提
AWS CDK Workshopを試した程度の知識を前提にしています。まだやっていないという方、とてもわかりやすいWorkshopなのでぜひやってみてください。
概要
AWS CDKは、基本概念として以下の3つの要素によって構成されています。
App
AWS CDKの最上位層。複数スタックの依存関係などを定義します。
Stack
CloudFormationスタックと1:1で対応します。AWSへのデプロイはこのスタック単位で行います。
Construct
デプロイするAWSリソース。上記のStack層に、Construct Library を使用してAWSリソースを定義していきます。
今回は、この中のConstructについて焦点を当てていきます。
3種類のConstruct
AWS CDKでは、Construct Libraryというライブラリを使ってAWSリソースを作成していきます。このConstruct Libraryには以下の3つの種類があります。
High Level Construct
- Function クラスのように、AWS CDKがCloudFormationの各リソースを抽象化してくれているライブラリです。クラスには、
addEventSource(source)
のような直感的にリソースを定義できる便利なメソッドがあり、CloudFormationを使うよりも簡単に各リソースを定義することができます。 - ほとんどの場合は、こちらを使った方が便利です。
- ただ、すべてのリソースがHigh Level Constructに対応しているわけではなく、
developer preview
となっているリソースなどはまだまだ対応されていない状況です(aws-iot
、aws-greengrass
など)。ただ、AWS CDKは頻繁にアップデートされているため、High Level Constructが提供されるのも時間の問題かと思います。 developer preview
のリソースに関しては、下記のLow Level Constractを使って定義することになります。
Low Level Construct
- CfnFunction クラスのように、High Lebel Constructsより低レベルなライブラリで、CloudFormationの各リソースと1:1の関係になっています。クラスに
Cfn
プレフィックスがついているものがこれに該当します。 - CloudFormationリソースと1:1で対応しているため、もし既存のCloudFormationテンプレートをどうしてもCDKに移行したいなどの要件がある場合は、Low Level Constructを使って、CloudFormationのYAML/JSONを手動でTypeScriptやPythonに変換することもできます。
- 作成しようとしているAWSリソースに、High Level Constructがあるならばそちらを使った方が簡単にリソースを定義できるためオススメです。より細かいパラメーターの設定をしたいなどの要件がある場合にこちらを使えば良いと思います。
Patterns
- aws-ecs-patterns のように、複数のリソースを含む一般的なパターンを定義しているライブラリです。このクラスのコンストラクタに、必要なリソースのインスタンスを渡すだけで、一般的なパターンのインフラ環境を簡単に作成することができます。
High Level Construct、Low Level Construct、Patternでそれぞれデプロイしてみた
実際に、上記の3つのライブラリを使用して、AWSリソースを作成してみたいとおもいます。
環境
項目 | バージョン |
---|---|
macOS | Mojave 10.14.5 |
node | v10.16.0 |
npm | 6.9.0 |
aws-cdk | 1.11.0 (build 4ed4d96) |
CDKプロジェクトと必要なライブラリのインストール
$ mkdir aws-cdk-construct-library-sample
$ cd aws-cdk-construct-library-sample
$ cdk init app --language=typescript
$ npm install --save @aws-cdk/aws-lambda @aws-cdk/aws-apigateway @aws-cdk/aws-iam @aws-cdk/aws-ecs-patterns @aws-cdk/aws-ecs
High Level Constructで実装
まずは、High Level Constructで実装します。Lambda + API Gatewayのリソースを作成します。
サンプル用のLambdaのコード
src/handler/app.ts
export async function handler(event: any) {
return {
statusCode: 200,
body: 'Sample Lambda Response'
}
}
CDKでインフラを定義
lib/aws-cdk-high-level-construct-library-sample-stack.ts
import cdk = require('@aws-cdk/core');
import lambda = require('@aws-cdk/aws-lambda');
import apigateway = require('@aws-cdk/aws-apigateway');
export class AwsCdkHighLevelConstructLibrarySampleStack extends cdk.Stack {
constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
const sampleLambda = new lambda.Function(this, 'sample-lambda', {
code: lambda.Code.asset('src/handler'),
handler: 'app.handler',
runtime: lambda.Runtime.NODEJS_10_X,
});
const api = new apigateway.RestApi(this, 'api', {
restApiName: 'SampleApi'
});
const integration = new apigateway.LambdaIntegration(sampleLambda, {
proxy: true
});
const resource = api.root.addResource('sample');
resource.addMethod('POST', integration);
}
}
Lambda + API Gatewayの構成ならば、High Level Constructを使えば30行ほどで書けてしまいます。
デプロイ
$ cdk deploy AwsCdkHighLevelConstructLibrarySampleStack
動作確認
$ curl -sS -X POST https://XXXXXXXXXXX.execute-api.ap-northeast-1.amazonaws.com/prod/sample
Sample Lambda Response
うまく動いているようです。
Low Level Constructで実装
次に、Low Level ConstructでLambda + APi Gatewayを実装します。こちらの場合は、上記に比べて抽象化がなされていないためCloudFormationと同じように、一つ一つ定義していくことになります。
CDKでインフラを定義
lib/aws-cdk-low-level-construct-library-sample-stack.ts
import cdk = require('@aws-cdk/core');
import lambda = require('@aws-cdk/aws-lambda');
import apigateway = require('@aws-cdk/aws-apigateway');
import iam = require('@aws-cdk/aws-iam');
export class AwsCdkLowLevelConstructLibrarySampleStack extends cdk.Stack {
constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
const region: string = cdk.Stack.of(this).region;
const accountId: string = cdk.Stack.of(this).account;
const lambdaServiceRole = new iam.CfnRole(this, 'sampleLambdaServiceRole', {
assumeRolePolicyDocument: {
"Statement": [
{
"Action": "sts:AssumeRole",
"Effect": "Allow",
"Principal": {
"Service": "lambda.amazonaws.com"
}
}
],
"Version": "2012-10-17"
},
managedPolicyArns: [
"arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
]
});
const lambdaFunction = new lambda.CfnFunction(this, 'SampleLambdaFunction', {
code: {
s3Bucket: "s3bucket",
s3Key: "s3key"
},
handler: "app.handler",
role: lambdaServiceRole.attrArn,
runtime: "nodejs10.x"
});
lambdaFunction.addDependsOn(lambdaServiceRole);
const api = new apigateway.CfnRestApi(this, 'SampleRestApi', {
name: "SampleApi"
});
const cloudwatchRole = new iam.CfnRole(this, 'CloudWatchRole', {
assumeRolePolicyDocument: {
"Statement": [
{
"Action": "sts:AssumeRole",
"Effect": "Allow",
"Principal": {
"Service": "apigateway.amazonaws.com"
}
}
],
"Version": "2012-10-17"
},
managedPolicyArns: [
"arn:aws:iam::aws:policy/service-role/AmazonAPIGatewayPushToCloudWatchLogs"
]
});
const apiAccount = new apigateway.CfnAccount(this, 'SampleApiAccount', {
cloudWatchRoleArn: cloudwatchRole.attrArn
});
apiAccount.addDependsOn(api);
const apiResource = new apigateway.CfnResource(this, 'SampleApiResource', {
parentId: api.attrRootResourceId,
pathPart: "sample",
restApiId: api.ref
});
const apiMethod = new apigateway.CfnMethod(this, 'SampleApiMethod', {
httpMethod: "POST",
resourceId: apiResource.ref,
restApiId: api.ref,
authorizationType: "NONE",
integration: {
integrationHttpMethod: "POST",
type: "AWS_PROXY",
uri: `arn:aws:apigateway:${region}:lambda:path/2015-03-31/functions/${lambdaFunction.attrArn}/invocations`
}
});
const apiDeployment = new apigateway.CfnDeployment(this, 'Deployment', {
restApiId: api.ref
});
apiDeployment.addDependsOn(apiMethod);
apiDeployment.addDependsOn(apiResource);
const apiStage = new apigateway.CfnStage(this, 'SampleStage', {
restApiId: api.ref,
deploymentId: apiDeployment.ref,
stageName: "prod"
});
new lambda.CfnPermission(this, 'SampleLambdaPermission', {
action: "lambda:InvokeFunction",
functionName: lambdaFunction.attrArn,
principal: "apigateway.amazonaws.com",
sourceArn: `arn:aws:execute-api:${region}:${accountId}:${api.ref}/${apiStage.ref}/POST/sample`
});
new lambda.CfnPermission(this, 'TestSamleLambdaPermission', {
action: "lambda:InvokeFunction",
functionName: lambdaFunction.attrArn,
principal: "apigateway.amazonaws.com",
sourceArn: `arn:aws:execute-api:${region}:${accountId}:${api.ref}/test-invoke-stage/POST/sample`
});
}
}
Low Level Constractでは120行ぐらい書かなければいけませんでした。High Level Constructと比べて、コード量は4倍近くになっています。CloudFormationと1:1なので、リソースのARNを直接指定しなければならない場面や、IAMのポリシーを自分でガリガリ書いていく必要があるので、High Level Constractに比べて冗長な記述になってしまいます。
デプロイ
$ cdk deploy AwsCdkLowLevelConstructLibrarySampleStack
動作確認
$ curl -sS -X POST https://XXXXXXXXXXX.execute-api.ap-northeast-1.amazonaws.com/prod/sample
Sample Lambda Response
先ほどと同じく動作しています。
High Level ConstructとLow Level Constructの比較
実際に同じAWSリソースを実装してみて、High Level ConstructとLow Level Constructで、かなり行数が違っていることがわかると思います。High Level Constructでは、AWS CDKが抽象化してくれているので、内部で色々なリソースを作ってくれています。そのため行数を少なく記述できます。リソースごとに細かいパラメータの設定が必要でない限りは、High Level Constructを使用するのがオススメです。
Patterns で実装
High Level Constructの他にも、Patternsというさらに一般的なパターンとして抽象化されているライブラリがあります。現状、AWS CDK公式で提供しているPatternsは以下の2つがあります。
- aws-ecs-patterns
- aws-route53-patterns
今回は、aws-ecs-patterns
ライブラリを使用して、ECS、Fargate、Application Load Balancerのインフラ環境を作ってみます。
CDKでインフラを定義
lib/aws-cdk-patterns-construct-library-sample-stack.ts
import cdk = require('@aws-cdk/core');
import ecs = require('@aws-cdk/aws-ecs');
import ecsPatterns = require('@aws-cdk/aws-ecs-patterns');
export class AwsCdkPatternsConstructLibrarySampleStack extends cdk.Stack {
constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
const cluster = new ecs.Cluster(this, 'SampleCluster', {
clusterName: 'SampleCluster',
});
const taskDefinition = new ecs.FargateTaskDefinition(this, 'TaskDefinition');
const container = taskDefinition.addContainer('SampleContainer', {
image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'),
});
container.addPortMappings({
containerPort: 80
});
const appLoadBalancedFargateService = new ecsPatterns.ApplicationLoadBalancedFargateService(this, 'SampleService', {
cluster: cluster,
memoryLimitMiB: 1024,
cpu: 512,
desiredCount: 1,
taskDefinition: taskDefinition
});
}
}
cdk synthコマンドで、生成されたCloudFormationテンプレートを確認してみます。
$ cdk synth AwsCdkPatternsConstructLibrarySampleStack
Resources:
SampleClusterB4B72990:
Type: AWS::ECS::Cluster
Properties:
ClusterName: SampleCluster
Metadata:
aws:cdk:path: AwsCdkPatternsConstructLibrarySampleStack/SampleCluster/Resource
SampleClusterVpcD1C6ABD9:
Type: AWS::EC2::VPC
Properties:
CidrBlock: 10.0.0.0/16
EnableDnsHostnames: true
EnableDnsSupport: true
InstanceTenancy: default
Tags:
- Key: Name
Value: AwsCdkPatternsConstructLibrarySampleStack/SampleCluster/Vpc
Metadata:
aws:cdk:path: AwsCdkPatternsConstructLibrarySampleStack/SampleCluster/Vpc/Resource
SampleClusterVpcPublicSubnet1SubnetE377A512:
Type: AWS::EC2::Subnet
Properties:
CidrBlock: 10.0.0.0/18
VpcId:
Ref: SampleClusterVpcD1C6ABD9
AvailabilityZone:
Fn::Select:
- 0
- Fn::GetAZs: ""
MapPublicIpOnLaunch: true
Tags:
- Key: Name
Value: AwsCdkPatternsConstructLibrarySampleStack/SampleCluster/Vpc/PublicSubnet1
- Key: aws-cdk:subnet-name
Value: Public
- Key: aws-cdk:subnet-type
Value: Public
Metadata:
aws:cdk:path: AwsCdkPatternsConstructLibrarySampleStack/SampleCluster/Vpc/PublicSubnet1/Subnet
SampleClusterVpcPublicSubnet1RouteTable7114D244:
Type: AWS::EC2::RouteTable
Properties:
VpcId:
Ref: SampleClusterVpcD1C6ABD9
Tags:
- Key: Name
Value: AwsCdkPatternsConstructLibrarySampleStack/SampleCluster/Vpc/PublicSubnet1
Metadata:
aws:cdk:path: AwsCdkPatternsConstructLibrarySampleStack/SampleCluster/Vpc/PublicSubnet1/RouteTable
SampleClusterVpcPublicSubnet1RouteTableAssociation0B5402E3:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId:
Ref: SampleClusterVpcPublicSubnet1RouteTable7114D244
SubnetId:
Ref: SampleClusterVpcPublicSubnet1SubnetE377A512
Metadata:
aws:cdk:path: AwsCdkPatternsConstructLibrarySampleStack/SampleCluster/Vpc/PublicSubnet1/RouteTableAssociation
SampleClusterVpcPublicSubnet1DefaultRoute28A82BC4:
Type: AWS::EC2::Route
Properties:
RouteTableId:
Ref: SampleClusterVpcPublicSubnet1RouteTable7114D244
DestinationCidrBlock: 0.0.0.0/0
GatewayId:
Ref: SampleClusterVpcIGW21649D5C
DependsOn:
- SampleClusterVpcVPCGW39AFB859
Metadata:
aws:cdk:path: AwsCdkPatternsConstructLibrarySampleStack/SampleCluster/Vpc/PublicSubnet1/DefaultRoute
SampleClusterVpcPublicSubnet1EIPD2C3FC83:
Type: AWS::EC2::EIP
Properties:
Domain: vpc
Metadata:
aws:cdk:path: AwsCdkPatternsConstructLibrarySampleStack/SampleCluster/Vpc/PublicSubnet1/EIP
SampleClusterVpcPublicSubnet1NATGateway715FE613:
Type: AWS::EC2::NatGateway
Properties:
AllocationId:
Fn::GetAtt:
- SampleClusterVpcPublicSubnet1EIPD2C3FC83
- AllocationId
SubnetId:
Ref: SampleClusterVpcPublicSubnet1SubnetE377A512
Tags:
- Key: Name
Value: AwsCdkPatternsConstructLibrarySampleStack/SampleCluster/Vpc/PublicSubnet1
Metadata:
aws:cdk:path: AwsCdkPatternsConstructLibrarySampleStack/SampleCluster/Vpc/PublicSubnet1/NATGateway
SampleClusterVpcPublicSubnet2SubnetB88D2B08:
Type: AWS::EC2::Subnet
Properties:
CidrBlock: 10.0.64.0/18
VpcId:
Ref: SampleClusterVpcD1C6ABD9
AvailabilityZone:
Fn::Select:
- 1
- Fn::GetAZs: ""
MapPublicIpOnLaunch: true
Tags:
- Key: Name
Value: AwsCdkPatternsConstructLibrarySampleStack/SampleCluster/Vpc/PublicSubnet2
- Key: aws-cdk:subnet-name
Value: Public
- Key: aws-cdk:subnet-type
Value: Public
Metadata:
aws:cdk:path: AwsCdkPatternsConstructLibrarySampleStack/SampleCluster/Vpc/PublicSubnet2/Subnet
SampleClusterVpcPublicSubnet2RouteTable8A11EEAD:
Type: AWS::EC2::RouteTable
Properties:
VpcId:
Ref: SampleClusterVpcD1C6ABD9
Tags:
- Key: Name
Value: AwsCdkPatternsConstructLibrarySampleStack/SampleCluster/Vpc/PublicSubnet2
Metadata:
aws:cdk:path: AwsCdkPatternsConstructLibrarySampleStack/SampleCluster/Vpc/PublicSubnet2/RouteTable
SampleClusterVpcPublicSubnet2RouteTableAssociation857BF408:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId:
Ref: SampleClusterVpcPublicSubnet2RouteTable8A11EEAD
SubnetId:
Ref: SampleClusterVpcPublicSubnet2SubnetB88D2B08
Metadata:
aws:cdk:path: AwsCdkPatternsConstructLibrarySampleStack/SampleCluster/Vpc/PublicSubnet2/RouteTableAssociation
SampleClusterVpcPublicSubnet2DefaultRouteFD4087CF:
Type: AWS::EC2::Route
Properties:
RouteTableId:
Ref: SampleClusterVpcPublicSubnet2RouteTable8A11EEAD
DestinationCidrBlock: 0.0.0.0/0
GatewayId:
Ref: SampleClusterVpcIGW21649D5C
DependsOn:
- SampleClusterVpcVPCGW39AFB859
Metadata:
aws:cdk:path: AwsCdkPatternsConstructLibrarySampleStack/SampleCluster/Vpc/PublicSubnet2/DefaultRoute
SampleClusterVpcPublicSubnet2EIPCB2281EA:
Type: AWS::EC2::EIP
Properties:
Domain: vpc
Metadata:
aws:cdk:path: AwsCdkPatternsConstructLibrarySampleStack/SampleCluster/Vpc/PublicSubnet2/EIP
SampleClusterVpcPublicSubnet2NATGatewayB385D543:
Type: AWS::EC2::NatGateway
Properties:
AllocationId:
Fn::GetAtt:
- SampleClusterVpcPublicSubnet2EIPCB2281EA
- AllocationId
SubnetId:
Ref: SampleClusterVpcPublicSubnet2SubnetB88D2B08
Tags:
- Key: Name
Value: AwsCdkPatternsConstructLibrarySampleStack/SampleCluster/Vpc/PublicSubnet2
Metadata:
aws:cdk:path: AwsCdkPatternsConstructLibrarySampleStack/SampleCluster/Vpc/PublicSubnet2/NATGateway
SampleClusterVpcPrivateSubnet1Subnet24256A44:
Type: AWS::EC2::Subnet
Properties:
CidrBlock: 10.0.128.0/18
VpcId:
Ref: SampleClusterVpcD1C6ABD9
AvailabilityZone:
Fn::Select:
- 0
- Fn::GetAZs: ""
MapPublicIpOnLaunch: false
Tags:
- Key: Name
Value: AwsCdkPatternsConstructLibrarySampleStack/SampleCluster/Vpc/PrivateSubnet1
- Key: aws-cdk:subnet-name
Value: Private
- Key: aws-cdk:subnet-type
Value: Private
Metadata:
aws:cdk:path: AwsCdkPatternsConstructLibrarySampleStack/SampleCluster/Vpc/PrivateSubnet1/Subnet
SampleClusterVpcPrivateSubnet1RouteTable55080EB4:
Type: AWS::EC2::RouteTable
Properties:
VpcId:
Ref: SampleClusterVpcD1C6ABD9
Tags:
- Key: Name
Value: AwsCdkPatternsConstructLibrarySampleStack/SampleCluster/Vpc/PrivateSubnet1
Metadata:
aws:cdk:path: AwsCdkPatternsConstructLibrarySampleStack/SampleCluster/Vpc/PrivateSubnet1/RouteTable
SampleClusterVpcPrivateSubnet1RouteTableAssociationBC171CD8:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId:
Ref: SampleClusterVpcPrivateSubnet1RouteTable55080EB4
SubnetId:
Ref: SampleClusterVpcPrivateSubnet1Subnet24256A44
Metadata:
aws:cdk:path: AwsCdkPatternsConstructLibrarySampleStack/SampleCluster/Vpc/PrivateSubnet1/RouteTableAssociation
SampleClusterVpcPrivateSubnet1DefaultRouteB1C5B147:
Type: AWS::EC2::Route
Properties:
RouteTableId:
Ref: SampleClusterVpcPrivateSubnet1RouteTable55080EB4
DestinationCidrBlock: 0.0.0.0/0
NatGatewayId:
Ref: SampleClusterVpcPublicSubnet1NATGateway715FE613
Metadata:
aws:cdk:path: AwsCdkPatternsConstructLibrarySampleStack/SampleCluster/Vpc/PrivateSubnet1/DefaultRoute
SampleClusterVpcPrivateSubnet2Subnet25DCB36D:
Type: AWS::EC2::Subnet
Properties:
CidrBlock: 10.0.192.0/18
VpcId:
Ref: SampleClusterVpcD1C6ABD9
AvailabilityZone:
Fn::Select:
- 1
- Fn::GetAZs: ""
MapPublicIpOnLaunch: false
Tags:
- Key: Name
Value: AwsCdkPatternsConstructLibrarySampleStack/SampleCluster/Vpc/PrivateSubnet2
- Key: aws-cdk:subnet-name
Value: Private
- Key: aws-cdk:subnet-type
Value: Private
Metadata:
aws:cdk:path: AwsCdkPatternsConstructLibrarySampleStack/SampleCluster/Vpc/PrivateSubnet2/Subnet
SampleClusterVpcPrivateSubnet2RouteTable35B9289E:
Type: AWS::EC2::RouteTable
Properties:
VpcId:
Ref: SampleClusterVpcD1C6ABD9
Tags:
- Key: Name
Value: AwsCdkPatternsConstructLibrarySampleStack/SampleCluster/Vpc/PrivateSubnet2
Metadata:
aws:cdk:path: AwsCdkPatternsConstructLibrarySampleStack/SampleCluster/Vpc/PrivateSubnet2/RouteTable
SampleClusterVpcPrivateSubnet2RouteTableAssociationC174EB56:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId:
Ref: SampleClusterVpcPrivateSubnet2RouteTable35B9289E
SubnetId:
Ref: SampleClusterVpcPrivateSubnet2Subnet25DCB36D
Metadata:
aws:cdk:path: AwsCdkPatternsConstructLibrarySampleStack/SampleCluster/Vpc/PrivateSubnet2/RouteTableAssociation
SampleClusterVpcPrivateSubnet2DefaultRoute74AE4D72:
Type: AWS::EC2::Route
Properties:
RouteTableId:
Ref: SampleClusterVpcPrivateSubnet2RouteTable35B9289E
DestinationCidrBlock: 0.0.0.0/0
NatGatewayId:
Ref: SampleClusterVpcPublicSubnet2NATGatewayB385D543
Metadata:
aws:cdk:path: AwsCdkPatternsConstructLibrarySampleStack/SampleCluster/Vpc/PrivateSubnet2/DefaultRoute
SampleClusterVpcIGW21649D5C:
Type: AWS::EC2::InternetGateway
Properties:
Tags:
- Key: Name
Value: AwsCdkPatternsConstructLibrarySampleStack/SampleCluster/Vpc
Metadata:
aws:cdk:path: AwsCdkPatternsConstructLibrarySampleStack/SampleCluster/Vpc/IGW
SampleClusterVpcVPCGW39AFB859:
Type: AWS::EC2::VPCGatewayAttachment
Properties:
VpcId:
Ref: SampleClusterVpcD1C6ABD9
InternetGatewayId:
Ref: SampleClusterVpcIGW21649D5C
Metadata:
aws:cdk:path: AwsCdkPatternsConstructLibrarySampleStack/SampleCluster/Vpc/VPCGW
TaskDefinitionTaskRoleFD40A61D:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Statement:
- Action: sts:AssumeRole
Effect: Allow
Principal:
Service: ecs-tasks.amazonaws.com
Version: "2012-10-17"
Metadata:
aws:cdk:path: AwsCdkPatternsConstructLibrarySampleStack/TaskDefinition/TaskRole/Resource
TaskDefinitionB36D86D9:
Type: AWS::ECS::TaskDefinition
Properties:
ContainerDefinitions:
- Essential: true
Image: amazon/amazon-ecs-sample
Name: SampleContainer
PortMappings:
- ContainerPort: 80
Protocol: tcp
Cpu: "256"
Family: AwsCdkPatternsConstructLibrarySampleStackTaskDefinitionDFEE4CCD
Memory: "512"
NetworkMode: awsvpc
RequiresCompatibilities:
- FARGATE
TaskRoleArn:
Fn::GetAtt:
- TaskDefinitionTaskRoleFD40A61D
- Arn
Metadata:
aws:cdk:path: AwsCdkPatternsConstructLibrarySampleStack/TaskDefinition/Resource
SampleServiceLBF4CAFE0D:
Type: AWS::ElasticLoadBalancingV2::LoadBalancer
Properties:
Scheme: internet-facing
SecurityGroups:
- Fn::GetAtt:
- SampleServiceLBSecurityGroup3D8CF0A2
- GroupId
Subnets:
- Ref: SampleClusterVpcPublicSubnet1SubnetE377A512
- Ref: SampleClusterVpcPublicSubnet2SubnetB88D2B08
Type: application
DependsOn:
- SampleClusterVpcPublicSubnet1DefaultRoute28A82BC4
- SampleClusterVpcPublicSubnet2DefaultRouteFD4087CF
Metadata:
aws:cdk:path: AwsCdkPatternsConstructLibrarySampleStack/SampleService/LB/Resource
SampleServiceLBSecurityGroup3D8CF0A2:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: Automatically created Security Group for ELB AwsCdkPatternsConstructLibrarySampleStackSampleServiceLB60DF5B18
SecurityGroupIngress:
- CidrIp: 0.0.0.0/0
Description: Allow from anyone on port 80
FromPort: 80
IpProtocol: tcp
ToPort: 80
VpcId:
Ref: SampleClusterVpcD1C6ABD9
Metadata:
aws:cdk:path: AwsCdkPatternsConstructLibrarySampleStack/SampleService/LB/SecurityGroup/Resource
SampleServiceLBSecurityGrouptoAwsCdkPatternsConstructLibrarySampleStackSampleServiceSecurityGroup3FF4258B809AF497E9:
Type: AWS::EC2::SecurityGroupEgress
Properties:
GroupId:
Fn::GetAtt:
- SampleServiceLBSecurityGroup3D8CF0A2
- GroupId
IpProtocol: tcp
Description: Load balancer to target
DestinationSecurityGroupId:
Fn::GetAtt:
- SampleServiceSecurityGroupF3490F3B
- GroupId
FromPort: 80
ToPort: 80
Metadata:
aws:cdk:path: AwsCdkPatternsConstructLibrarySampleStack/SampleService/LB/SecurityGroup/to AwsCdkPatternsConstructLibrarySampleStackSampleServiceSecurityGroup3FF4258B:80
SampleServiceLBPublicListenerA227ACD3:
Type: AWS::ElasticLoadBalancingV2::Listener
Properties:
DefaultActions:
- TargetGroupArn:
Ref: SampleServiceLBPublicListenerECSGroup1AB7CB78
Type: forward
LoadBalancerArn:
Ref: SampleServiceLBF4CAFE0D
Port: 80
Protocol: HTTP
Metadata:
aws:cdk:path: AwsCdkPatternsConstructLibrarySampleStack/SampleService/LB/PublicListener/Resource
SampleServiceLBPublicListenerECSGroup1AB7CB78:
Type: AWS::ElasticLoadBalancingV2::TargetGroup
Properties:
Port: 80
Protocol: HTTP
TargetType: ip
VpcId:
Ref: SampleClusterVpcD1C6ABD9
Metadata:
aws:cdk:path: AwsCdkPatternsConstructLibrarySampleStack/SampleService/LB/PublicListener/ECSGroup/Resource
SampleService263FFCD0:
Type: AWS::ECS::Service
Properties:
TaskDefinition:
Ref: TaskDefinitionB36D86D9
Cluster:
Ref: SampleClusterB4B72990
DeploymentConfiguration:
MaximumPercent: 200
MinimumHealthyPercent: 50
DesiredCount: 1
EnableECSManagedTags: false
HealthCheckGracePeriodSeconds: 60
LaunchType: FARGATE
LoadBalancers:
- ContainerName: SampleContainer
ContainerPort: 80
TargetGroupArn:
Ref: SampleServiceLBPublicListenerECSGroup1AB7CB78
NetworkConfiguration:
AwsvpcConfiguration:
AssignPublicIp: DISABLED
SecurityGroups:
- Fn::GetAtt:
- SampleServiceSecurityGroupF3490F3B
- GroupId
Subnets:
- Ref: SampleClusterVpcPrivateSubnet1Subnet24256A44
- Ref: SampleClusterVpcPrivateSubnet2Subnet25DCB36D
DependsOn:
- SampleServiceLBPublicListenerECSGroup1AB7CB78
- SampleServiceLBPublicListenerA227ACD3
Metadata:
aws:cdk:path: AwsCdkPatternsConstructLibrarySampleStack/SampleService/Service/Service
SampleServiceSecurityGroupF3490F3B:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: AwsCdkPatternsConstructLibrarySampleStack/SampleService/Service/SecurityGroup
SecurityGroupEgress:
- CidrIp: 0.0.0.0/0
Description: Allow all outbound traffic by default
IpProtocol: "-1"
VpcId:
Ref: SampleClusterVpcD1C6ABD9
Metadata:
aws:cdk:path: AwsCdkPatternsConstructLibrarySampleStack/SampleService/Service/SecurityGroup/Resource
SampleServiceSecurityGroupfromAwsCdkPatternsConstructLibrarySampleStackSampleServiceLBSecurityGroup3BC91F0D80BE55E0A3:
Type: AWS::EC2::SecurityGroupIngress
Properties:
IpProtocol: tcp
Description: Load balancer to target
FromPort: 80
GroupId:
Fn::GetAtt:
- SampleServiceSecurityGroupF3490F3B
- GroupId
SourceSecurityGroupId:
Fn::GetAtt:
- SampleServiceLBSecurityGroup3D8CF0A2
- GroupId
ToPort: 80
Metadata:
aws:cdk:path: AwsCdkPatternsConstructLibrarySampleStack/SampleService/Service/SecurityGroup/from AwsCdkPatternsConstructLibrarySampleStackSampleServiceLBSecurityGroup3BC91F0D:80
CDKMetadata:
Type: AWS::CDK::Metadata
Properties:
Modules: aws-cdk=1.11.0,@aws-cdk/assets=1.11.0,@aws-cdk/aws-apigateway=1.11.0,@aws-cdk/aws-applicationautoscaling=1.11.0,@aws-cdk/aws-autoscaling=1.11.0,@aws-cdk/aws-autoscaling-common=1.11.0,@aws-cdk/aws-autoscaling-hooktargets=1.11.0,@aws-cdk/aws-certificatemanager=1.11.0,@aws-cdk/aws-cloudformation=1.11.0,@aws-cdk/aws-cloudwatch=1.11.0,@aws-cdk/aws-ec2=1.11.0,@aws-cdk/aws-ecr=1.11.0,@aws-cdk/aws-ecr-assets=1.11.0,@aws-cdk/aws-ecs=1.11.0,@aws-cdk/aws-ecs-patterns=1.11.0,@aws-cdk/aws-elasticloadbalancingv2=1.11.0,@aws-cdk/aws-events=1.11.0,@aws-cdk/aws-events-targets=1.11.0,@aws-cdk/aws-iam=1.11.0,@aws-cdk/aws-kms=1.11.0,@aws-cdk/aws-lambda=1.11.0,@aws-cdk/aws-logs=1.11.0,@aws-cdk/aws-route53=1.11.0,@aws-cdk/aws-route53-targets=1.11.0,@aws-cdk/aws-s3=1.11.0,@aws-cdk/aws-s3-assets=1.11.0,@aws-cdk/aws-servicediscovery=1.11.0,@aws-cdk/aws-sns=1.11.0,@aws-cdk/aws-sns-subscriptions=1.11.0,@aws-cdk/aws-sqs=1.11.0,@aws-cdk/aws-ssm=1.11.0,@aws-cdk/core=1.11.0,@aws-cdk/cx-api=1.11.0,@aws-cdk/region-info=1.11.0,jsii-runtime=node.js/v10.16.0
Condition: CDKMetadataAvailable
Outputs:
SampleServiceLoadBalancerDNS54524680:
Value:
Fn::GetAtt:
- SampleServiceLBF4CAFE0D
- DNSName
SampleServiceServiceURLA7529434:
Value:
Fn::Join:
- ""
- - http://
- Fn::GetAtt:
- SampleServiceLBF4CAFE0D
- DNSName
Conditions:
CDKMetadataAvailable:
Fn::Or:
- Fn::Or:
- Fn::Equals:
- Ref: AWS::Region
- ap-east-1
- Fn::Equals:
- Ref: AWS::Region
- ap-northeast-1
- Fn::Equals:
- Ref: AWS::Region
- ap-northeast-2
- Fn::Equals:
- Ref: AWS::Region
- ap-south-1
- Fn::Equals:
- Ref: AWS::Region
- ap-southeast-1
- Fn::Equals:
- Ref: AWS::Region
- ap-southeast-2
- Fn::Equals:
- Ref: AWS::Region
- ca-central-1
- Fn::Equals:
- Ref: AWS::Region
- cn-north-1
- Fn::Equals:
- Ref: AWS::Region
- cn-northwest-1
- Fn::Equals:
- Ref: AWS::Region
- eu-central-1
- Fn::Or:
- Fn::Equals:
- Ref: AWS::Region
- eu-north-1
- Fn::Equals:
- Ref: AWS::Region
- eu-west-1
- Fn::Equals:
- Ref: AWS::Region
- eu-west-2
- Fn::Equals:
- Ref: AWS::Region
- eu-west-3
- Fn::Equals:
- Ref: AWS::Region
- me-south-1
- Fn::Equals:
- Ref: AWS::Region
- sa-east-1
- Fn::Equals:
- Ref: AWS::Region
- us-east-1
- Fn::Equals:
- Ref: AWS::Region
- us-east-2
- Fn::Equals:
- Ref: AWS::Region
- us-west-1
- Fn::Equals:
- Ref: AWS::Region
- us-west-2
たった30行ほどのコードですが、500行越えのCloudFormationテンプレートが出力されました。以下のリソースが作成されているのが確認できます。
- VPC
- Public Subnet
- Private Subnet
- NAT Gateway
- Route Table
- Security Group
- ELB
- ECS Cluster
- ECS Service
- ECS Task Definition
Patternライブラリが、いかにCloudFormationテンプレートを抽象化してくれているかがわかるかと思います。20 ~ 30行ほどのコードであらかじめ定義された一般的なパターンのインフラ環境をデプロイできるというのは、とても強力な機能です。標準のpatternライブラリ自体は2種類とまだ少ないですが、今後のアップデートに期待です。
デプロイ
$ cdk deploy AwsCdkPatternsConstructLibrarySampleStack
動作確認
デプロイできたらCloudFormationの出力タブにELBのURLが出力されているため、それをクリックしてみます。以下のように、ECS、Fargate上で動いているPHPのサンプルアプリケーションが表示されれば成功です。
終わりに
以上、AWS CDKのConstructs Libraryを理解するための記事でした。先日行われていたAWS DevDayでもCDKのセッションがあったりと、CDK界隈が盛り上がってきているなと感じています。本当に便利なのでぜひみなさんも触ってみてください!