概要
巷で話題の(私だけ?)aws-cdkですが
「実際何がすごいの?」という疑問に自分ならこう答える!
というものを書いていこうかなと。
派生してaws-cdkのL1とL2の違いについても少しだけ書きます。
↑次回書きます。。
書きました
結論
aws-cdkは
①普段利用しているプログラミング言語を使って
②少ないコード量で
③Cfnを利用することができる
からすごい!!
これについて少しずつみていきます。
環境
操作する環境は以下の通りです。
% node -v //Node.jsのバージョン
v14.16.0
% tsc -v //TypeScriptのバージョン
Version 4.5.5
% cdk --version //aws-cdkのバージョン
1.142.0
本題の前に
早速本題に入っていく前にAWS SDKとCloudFormation(Cfn)について触れます。
以前の投稿でも少し触れたのですが
もう少しだけ詳しく。
AWS SDKとは
公式はこのように言っています。
AWS SDK for JavaScript は AWS のサービス用の JavaScript API を提供します。JavaScript API を使用して、Node.js またはブラウザ用のライブラリまたはアプリケーションを構築できます。
つまり、AWSを操作するAPIをプログラミング言語(C++,Go,Java,JavaScript,.NET,Node.js,PHP,Python,Ruby)から叩けるというツールなんですね。
普段使い慣れた言語で直接AWSも触れる、システムに組み込みやすいというのが大きなメリットです。
AWS CLIもaws ...
とコマンドラインからAPIを実行できますが
上記のような高級言語でAPIを扱えるのが非常に便利でイケている点です。
CloudFormationとは
公式はだらだらとわかりにくいので、、簡単にまとめると
テンプレートと言われるyamlやjson形式のファイルを元にAWSのリソースを自動で作成してくれるサービス
というものです。
ちなみにテンプレートファイルの例がこちら
{
"AWSTemplateFormatVersion" : "2010-09-09",
"Description" : "A simple EC2 instance",
"Resources" : {
"MyEC2Instance" : {
"Type" : "AWS::EC2::Instance",
"Properties" : {
"ImageId" : "ami-0ff8a91507f77f867",
"InstanceType" : "t2.micro"
}
}
}
}
ふ〜んと言った感じ。。。
CloudFormationの凄さ
では何がそんなに便利なのか。
主に次の2点なのかなと思います。
①スタック単位で構築できる
インスタンスやサービス単位ではなくスタック単位でリソースを作成してくれるので自分の好きなまとまりごとに更新や削除・構築が可能な点です。
前述のAWS SDKだとAPIを叩くのはサービスごとになるのでコンソールぽちぽちとやっていることは変わらないんですね。(スクリプトで自動化できるなどのメリットはあるものの)
②依存関係を解消してくれる
「SDKのコードをまとめて実行させる」というのはリソース構築という観点からはNGです。
というのもその方法では依存関係を解消できないからです。
AWSリソースを構築するにあたっては依存関係があったりします。
例えばEC2インスタンスはVPCがないと構築出来ません。つまりEC2はVPCに依存しているということです。
ですので、EC2を構築する前にVPCを(もっといえばSubnetも)構築しておかなければいけないということです。
システムが複雑になってくると思わぬところに依存関係が隠れていてそれを手で解消するのはAWSのスペシャリストでも苦労するかもしれません。
(SDKで構築するとこれをdeployのたびにこれをするハメになります)
Cfnは同一スタック内の依存関係を自動で検出してイイカンジに構築してくれるのです。
しかも万一エラーが起きて構築出来なかった場合、ROLLBACKして変更を全て消してくれます。
変なゴミが残ってないかなんて心配は必要ないわけです。
deploy時の不安解消、手間解消がCfnのメリットですね。
補足
SDKはcdkに対して劣っているということではなく、使うシチュエーションが異なるということです。
AWSリソースの構築はcdkが得意ですし、操作(S3にログをプッシュするなど)はSDKの方が合っているかもしれません。
この記事ではAWSリソースの構築ということについてお話ししているのでSDKを軽く扱っています。
aws-cdkとは
長々とAWS SDKとCfnについて書いてきましたが、aws-cdkは両方のメリットを兼ね備えているというイメージです。
①普段利用しているプログラミング言語で開発可能
こちらにあるようにSDKと同様、普段利用している高級言語で扱うことができるのです。(AWS SDKのメリット)
Q: AWS CDK ではどのプログラム言語がサポートされていますか?
AWS CDK は、JavaScript、TypeScript、Python、Java、C# が一般公開されており、開発者プレビューでは Go がサポートされています。将来的にはほかの言語用の AWS CDK バインディングも計画しています。GitHub でお気に入りを投票してください。
②コード量の少なさ
しかもそのコード量は少ないです。
実際に書いてみましょう。
cdkでVPCを作成してみます。
import { Vpc } from "@aws-cdk/aws-ec2";
import * as cdk from "@aws-cdk/core";
export class CdkStack extends cdk.Stack {
constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
+ new Vpc(this, "VPC");
}
}
この一行でVPCが作成できます。
この一行だけでです!!
そして、作成されるCfnのテンプレートがこちら。(長いですが略さず書きますので流し読みしてください)
Resources:
VPCB9E5F0B4:
Type: AWS::EC2::VPC
Properties:
CidrBlock: 10.0.0.0/16
EnableDnsHostnames: true
EnableDnsSupport: true
InstanceTenancy: default
Tags:
- Key: Name
Value: CdkStack/VPC
Metadata:
aws:cdk:path: CdkStack/VPC/Resource
VPCPublicSubnet1SubnetB4246D30:
Type: AWS::EC2::Subnet
Properties:
CidrBlock: 10.0.0.0/19
VpcId:
Ref: VPCB9E5F0B4
AvailabilityZone: ap-northeast-1a
MapPublicIpOnLaunch: true
Tags:
- Key: aws-cdk:subnet-name
Value: Public
- Key: aws-cdk:subnet-type
Value: Public
- Key: Name
Value: CdkStack/VPC/PublicSubnet1
Metadata:
aws:cdk:path: CdkStack/VPC/PublicSubnet1/Subnet
VPCPublicSubnet1RouteTableFEE4B781:
Type: AWS::EC2::RouteTable
Properties:
VpcId:
Ref: VPCB9E5F0B4
Tags:
- Key: Name
Value: CdkStack/VPC/PublicSubnet1
Metadata:
aws:cdk:path: CdkStack/VPC/PublicSubnet1/RouteTable
VPCPublicSubnet1RouteTableAssociation0B0896DC:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId:
Ref: VPCPublicSubnet1RouteTableFEE4B781
SubnetId:
Ref: VPCPublicSubnet1SubnetB4246D30
Metadata:
aws:cdk:path: CdkStack/VPC/PublicSubnet1/RouteTableAssociation
VPCPublicSubnet1DefaultRoute91CEF279:
Type: AWS::EC2::Route
Properties:
RouteTableId:
Ref: VPCPublicSubnet1RouteTableFEE4B781
DestinationCidrBlock: 0.0.0.0/0
GatewayId:
Ref: VPCIGWB7E252D3
DependsOn:
- VPCVPCGW99B986DC
Metadata:
aws:cdk:path: CdkStack/VPC/PublicSubnet1/DefaultRoute
VPCPublicSubnet1EIP6AD938E8:
Type: AWS::EC2::EIP
Properties:
Domain: vpc
Tags:
- Key: Name
Value: CdkStack/VPC/PublicSubnet1
Metadata:
aws:cdk:path: CdkStack/VPC/PublicSubnet1/EIP
VPCPublicSubnet1NATGatewayE0556630:
Type: AWS::EC2::NatGateway
Properties:
SubnetId:
Ref: VPCPublicSubnet1SubnetB4246D30
AllocationId:
Fn::GetAtt:
- VPCPublicSubnet1EIP6AD938E8
- AllocationId
Tags:
- Key: Name
Value: CdkStack/VPC/PublicSubnet1
Metadata:
aws:cdk:path: CdkStack/VPC/PublicSubnet1/NATGateway
VPCPublicSubnet2Subnet74179F39:
Type: AWS::EC2::Subnet
Properties:
CidrBlock: 10.0.32.0/19
VpcId:
Ref: VPCB9E5F0B4
AvailabilityZone: ap-northeast-1c
MapPublicIpOnLaunch: true
Tags:
- Key: aws-cdk:subnet-name
Value: Public
- Key: aws-cdk:subnet-type
Value: Public
- Key: Name
Value: CdkStack/VPC/PublicSubnet2
Metadata:
aws:cdk:path: CdkStack/VPC/PublicSubnet2/Subnet
VPCPublicSubnet2RouteTable6F1A15F1:
Type: AWS::EC2::RouteTable
Properties:
VpcId:
Ref: VPCB9E5F0B4
Tags:
- Key: Name
Value: CdkStack/VPC/PublicSubnet2
Metadata:
aws:cdk:path: CdkStack/VPC/PublicSubnet2/RouteTable
VPCPublicSubnet2RouteTableAssociation5A808732:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId:
Ref: VPCPublicSubnet2RouteTable6F1A15F1
SubnetId:
Ref: VPCPublicSubnet2Subnet74179F39
Metadata:
aws:cdk:path: CdkStack/VPC/PublicSubnet2/RouteTableAssociation
VPCPublicSubnet2DefaultRouteB7481BBA:
Type: AWS::EC2::Route
Properties:
RouteTableId:
Ref: VPCPublicSubnet2RouteTable6F1A15F1
DestinationCidrBlock: 0.0.0.0/0
GatewayId:
Ref: VPCIGWB7E252D3
DependsOn:
- VPCVPCGW99B986DC
Metadata:
aws:cdk:path: CdkStack/VPC/PublicSubnet2/DefaultRoute
VPCPublicSubnet2EIP4947BC00:
Type: AWS::EC2::EIP
Properties:
Domain: vpc
Tags:
- Key: Name
Value: CdkStack/VPC/PublicSubnet2
Metadata:
aws:cdk:path: CdkStack/VPC/PublicSubnet2/EIP
VPCPublicSubnet2NATGateway3C070193:
Type: AWS::EC2::NatGateway
Properties:
SubnetId:
Ref: VPCPublicSubnet2Subnet74179F39
AllocationId:
Fn::GetAtt:
- VPCPublicSubnet2EIP4947BC00
- AllocationId
Tags:
- Key: Name
Value: CdkStack/VPC/PublicSubnet2
Metadata:
aws:cdk:path: CdkStack/VPC/PublicSubnet2/NATGateway
VPCPublicSubnet3Subnet631C5E25:
Type: AWS::EC2::Subnet
Properties:
CidrBlock: 10.0.64.0/19
VpcId:
Ref: VPCB9E5F0B4
AvailabilityZone: ap-northeast-1d
MapPublicIpOnLaunch: true
Tags:
- Key: aws-cdk:subnet-name
Value: Public
- Key: aws-cdk:subnet-type
Value: Public
- Key: Name
Value: CdkStack/VPC/PublicSubnet3
Metadata:
aws:cdk:path: CdkStack/VPC/PublicSubnet3/Subnet
VPCPublicSubnet3RouteTable98AE0E14:
Type: AWS::EC2::RouteTable
Properties:
VpcId:
Ref: VPCB9E5F0B4
Tags:
- Key: Name
Value: CdkStack/VPC/PublicSubnet3
Metadata:
aws:cdk:path: CdkStack/VPC/PublicSubnet3/RouteTable
VPCPublicSubnet3RouteTableAssociation427FE0C6:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId:
Ref: VPCPublicSubnet3RouteTable98AE0E14
SubnetId:
Ref: VPCPublicSubnet3Subnet631C5E25
Metadata:
aws:cdk:path: CdkStack/VPC/PublicSubnet3/RouteTableAssociation
VPCPublicSubnet3DefaultRouteA0D29D46:
Type: AWS::EC2::Route
Properties:
RouteTableId:
Ref: VPCPublicSubnet3RouteTable98AE0E14
DestinationCidrBlock: 0.0.0.0/0
GatewayId:
Ref: VPCIGWB7E252D3
DependsOn:
- VPCVPCGW99B986DC
Metadata:
aws:cdk:path: CdkStack/VPC/PublicSubnet3/DefaultRoute
VPCPublicSubnet3EIPAD4BC883:
Type: AWS::EC2::EIP
Properties:
Domain: vpc
Tags:
- Key: Name
Value: CdkStack/VPC/PublicSubnet3
Metadata:
aws:cdk:path: CdkStack/VPC/PublicSubnet3/EIP
VPCPublicSubnet3NATGatewayD3048F5C:
Type: AWS::EC2::NatGateway
Properties:
SubnetId:
Ref: VPCPublicSubnet3Subnet631C5E25
AllocationId:
Fn::GetAtt:
- VPCPublicSubnet3EIPAD4BC883
- AllocationId
Tags:
- Key: Name
Value: CdkStack/VPC/PublicSubnet3
Metadata:
aws:cdk:path: CdkStack/VPC/PublicSubnet3/NATGateway
VPCPrivateSubnet1Subnet8BCA10E0:
Type: AWS::EC2::Subnet
Properties:
CidrBlock: 10.0.96.0/19
VpcId:
Ref: VPCB9E5F0B4
AvailabilityZone: ap-northeast-1a
MapPublicIpOnLaunch: false
Tags:
- Key: aws-cdk:subnet-name
Value: Private
- Key: aws-cdk:subnet-type
Value: Private
- Key: Name
Value: CdkStack/VPC/PrivateSubnet1
Metadata:
aws:cdk:path: CdkStack/VPC/PrivateSubnet1/Subnet
VPCPrivateSubnet1RouteTableBE8A6027:
Type: AWS::EC2::RouteTable
Properties:
VpcId:
Ref: VPCB9E5F0B4
Tags:
- Key: Name
Value: CdkStack/VPC/PrivateSubnet1
Metadata:
aws:cdk:path: CdkStack/VPC/PrivateSubnet1/RouteTable
VPCPrivateSubnet1RouteTableAssociation347902D1:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId:
Ref: VPCPrivateSubnet1RouteTableBE8A6027
SubnetId:
Ref: VPCPrivateSubnet1Subnet8BCA10E0
Metadata:
aws:cdk:path: CdkStack/VPC/PrivateSubnet1/RouteTableAssociation
VPCPrivateSubnet1DefaultRouteAE1D6490:
Type: AWS::EC2::Route
Properties:
RouteTableId:
Ref: VPCPrivateSubnet1RouteTableBE8A6027
DestinationCidrBlock: 0.0.0.0/0
NatGatewayId:
Ref: VPCPublicSubnet1NATGatewayE0556630
Metadata:
aws:cdk:path: CdkStack/VPC/PrivateSubnet1/DefaultRoute
VPCPrivateSubnet2SubnetCFCDAA7A:
Type: AWS::EC2::Subnet
Properties:
CidrBlock: 10.0.128.0/19
VpcId:
Ref: VPCB9E5F0B4
AvailabilityZone: ap-northeast-1c
MapPublicIpOnLaunch: false
Tags:
- Key: aws-cdk:subnet-name
Value: Private
- Key: aws-cdk:subnet-type
Value: Private
- Key: Name
Value: CdkStack/VPC/PrivateSubnet2
Metadata:
aws:cdk:path: CdkStack/VPC/PrivateSubnet2/Subnet
VPCPrivateSubnet2RouteTable0A19E10E:
Type: AWS::EC2::RouteTable
Properties:
VpcId:
Ref: VPCB9E5F0B4
Tags:
- Key: Name
Value: CdkStack/VPC/PrivateSubnet2
Metadata:
aws:cdk:path: CdkStack/VPC/PrivateSubnet2/RouteTable
VPCPrivateSubnet2RouteTableAssociation0C73D413:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId:
Ref: VPCPrivateSubnet2RouteTable0A19E10E
SubnetId:
Ref: VPCPrivateSubnet2SubnetCFCDAA7A
Metadata:
aws:cdk:path: CdkStack/VPC/PrivateSubnet2/RouteTableAssociation
VPCPrivateSubnet2DefaultRouteF4F5CFD2:
Type: AWS::EC2::Route
Properties:
RouteTableId:
Ref: VPCPrivateSubnet2RouteTable0A19E10E
DestinationCidrBlock: 0.0.0.0/0
NatGatewayId:
Ref: VPCPublicSubnet2NATGateway3C070193
Metadata:
aws:cdk:path: CdkStack/VPC/PrivateSubnet2/DefaultRoute
VPCPrivateSubnet3Subnet3EDCD457:
Type: AWS::EC2::Subnet
Properties:
CidrBlock: 10.0.160.0/19
VpcId:
Ref: VPCB9E5F0B4
AvailabilityZone: ap-northeast-1d
MapPublicIpOnLaunch: false
Tags:
- Key: aws-cdk:subnet-name
Value: Private
- Key: aws-cdk:subnet-type
Value: Private
- Key: Name
Value: CdkStack/VPC/PrivateSubnet3
Metadata:
aws:cdk:path: CdkStack/VPC/PrivateSubnet3/Subnet
VPCPrivateSubnet3RouteTable192186F8:
Type: AWS::EC2::RouteTable
Properties:
VpcId:
Ref: VPCB9E5F0B4
Tags:
- Key: Name
Value: CdkStack/VPC/PrivateSubnet3
Metadata:
aws:cdk:path: CdkStack/VPC/PrivateSubnet3/RouteTable
VPCPrivateSubnet3RouteTableAssociationC28D144E:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId:
Ref: VPCPrivateSubnet3RouteTable192186F8
SubnetId:
Ref: VPCPrivateSubnet3Subnet3EDCD457
Metadata:
aws:cdk:path: CdkStack/VPC/PrivateSubnet3/RouteTableAssociation
VPCPrivateSubnet3DefaultRoute27F311AE:
Type: AWS::EC2::Route
Properties:
RouteTableId:
Ref: VPCPrivateSubnet3RouteTable192186F8
DestinationCidrBlock: 0.0.0.0/0
NatGatewayId:
Ref: VPCPublicSubnet3NATGatewayD3048F5C
Metadata:
aws:cdk:path: CdkStack/VPC/PrivateSubnet3/DefaultRoute
VPCIGWB7E252D3:
Type: AWS::EC2::InternetGateway
Properties:
Tags:
- Key: Name
Value: CdkStack/VPC
Metadata:
aws:cdk:path: CdkStack/VPC/IGW
VPCVPCGW99B986DC:
Type: AWS::EC2::VPCGatewayAttachment
Properties:
VpcId:
Ref: VPCB9E5F0B4
InternetGatewayId:
Ref: VPCIGWB7E252D3
Metadata:
aws:cdk:path: CdkStack/VPC/VPCGW
CDKMetadata:
Type: AWS::CDK::Metadata
Properties:
Analytics: v2:deflate64:H4sIAAAAAAAA/0WPTw+CMAzFP4v3MYQQzxJiDBdDwHAfpcbxZzNbpzGE7y6IyKm/vr42fQEPopDvd0fxsh7UrT+ANsiHggS0LEernQFkiVaWjANiyU2t6sjmJYSQD+UD5kmZJSxzVSehcJXCr3ujXDvCq6g63PRNi63VIAVJrf7mGU5pNpeLoLMgfIk3y4x8TrgdThWhmXg1LJ/8upimKPceFY0jU7pG3lj/GUQ8OEy5GyulZ5wi2SPPl/oBpmTsORQBAAA=
Metadata:
aws:cdk:path: CdkStack/CDKMetadata/Default
Cfnのテンプレートファイルに比べて以下に少ないコード量で(=手軽に)リソースを記述できるか理解してもらえたでしょうか?
これがメリットの2点目です。
③Cfnを利用することができる
aws-cdkはそのデプロイの過程でCfnのテンプレートファイルを生成し、
Cfnを利用してdeployします。
当然、Cfnのメリットを享受できます。
Q: AWS CDK と CloudFormation にはどのような関係がありますか?
AWS CDK は、最新のプログラミング言語のすべての機能を活用して AWS Infrastructure as Code を定義する、デベロッパー中心のツールキットと考えることができます。AWS CDK アプリケーションが実行されると、それらは完全に形成された CloudFormation JSON/YAML テンプレートにコンパイルされ、プロビジョニング用に CloudFormation サービスに送信されます。AWS CDK は CloudFormation を利用しているため、CloudFormation の安全なデプロイ、自動ロールバック、ドリフト検出などのすべての利点がそのまま提供されます。
VPCだけでこの量になるCfnのテンプレートを他のサービスの分も手で書いていけますか?
Cfnを使わずに依存関係を解消しながら簡単にdeployできますか?
この両方の難題に「YES」と答えるToolがaws-cdkなんです。
まとめ
aws-cdkは
①使い慣れた言語でAWSリソースを、(直接APIを実行するわけではないので注意)
②比較的少量のコードで気軽に記述でき
③Cfnを利用して依存関係の解消やエラー時のROLLBACKなどを行える。
というのがaws-cdkの凄さでした。
AWSリソース構築という段においてはaws-cdkはかなり便利で替えの利かないツールなのではと思っています。
特にIaCの文脈でインフラのコード管理を考えた時に避けては通れないツールですね。
もう少し深く(cdkのL1とL2について)書こうと思いましたが
予想より文量が多くなってしまったので次回に回そうと思います。
主にCfnとcdkの関係の話になります。