この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
ども、もこ@札幌オフィスです。
最近流行りのAWS CDKを触ってみた際、どんな実装になっているのか気になりコードを追いかけているととても面白くハマってしまったので、CDKのレイヤーについてご紹介してきます!
前提
本記事はTypeScriptを対象にしています。
また、CDKの初期セットアップ、IaCとは?の解説は省略させていただきます。
CDKのレイヤーモデルについて
CDKには大きく分けて二つのレイヤーがあり、よくあるGetting Started記事では高級なレイヤーを利用して簡単にベストプラクティスな構成を取れるように設計されています。
CDKではこのようなAWSによって実装された高級レイヤーのことを L2 Library(AWS Construct Library)
と読んでいたり、ドキュメントでは XXX module
と呼ばれています。
逆に低レイヤーは L1 Library(AWS CloudFormation Resources)
と呼ばれており、 コードから呼び出す場合は CfnXXX
となります。
L1 Libraryを利用する際は生のCloudFormationを書くのと同等のパラメーター設定が必要で、 L2 Libraryは渡された情報を元にL1 Libraryを良い感じに叩く物と考えてくれれば良いと思います。
@aws-cdk/aws-ec2の実装を読む
AWS CDKのEC2周りのリソースは @aws-cdk/aws-ec2
に内封する形で AWS Construct Library
が提供されており、例えば Vpc
を利用するとVPCの他、MutliAZなPublic/Private SubnetにNAT Gatewayまでも作成されます。ベストプラクティスのハッピーセットです。
これは Vpc()
の実装を読めばAWS Construct Libraryがどのような動作をするのかを完全に理解する事ができるので、CDK詳しいマンになりたい方は是非読んでみてください。
やっていることはそこまで難しいことではなく、一般的なCDKのコードを読む勢いで読めます。
https://github.com/aws/aws-cdk/blob/master/packages/%40aws-cdk/aws-ec2/lib/vpc.ts
これを読み進めていくと、あくまで @aws-cdk/aws-ec2
で提供される Vpc
は、渡されたパラメータの通りに CfnVPC(L1 Library)
を利用して実装されている事がわかると思います。
要件がフワッとしている中でベストアーキテクチャを抑えてAWS環境を作りたい場合などはこのようなAWS提供のConstruct Libraryを利用すると数行で素晴らしい環境を構築する事ができます。
ただ、AWS提供のConstruct Libraryとあまりにも乖離したアーキテクチャを構築したいだとか、AWS Construct Libraryのデフォルト設定を覚えたり、調べたりするのが面倒など、いろいろあるかと思います。
そのような場合はConstruct Libraryを自前で実装するか、L1をベタ書きするかになります。
もちろんL1 Libraryのみを利用する目的でCDKを利用するのも全然問題ナシ!
もちろんL1 Libraryの利用だけを目的にCDKを利用することも全く問題無いですし、むしろ生CloudFormationを書くより良いと思います。
生のCloudFormationではIDEにPluguinを入れないとYAML/JSONに補完が効かなかったり、必須パラメーターが無い時に怒ってくれなかったり、ループで記述する事ができない問題が、CDKを利用するだけで解決しますし、デプロイも cdk deploy
だけで済みます。
また、JSDocも書かれているため、実装に困っても簡単にドキュメントを開いて読む事ができます。
L1 Libraryを使ってVPC/Public Subnet/IGW/RouteTableを作る例
CDK歴全然無いですが、5分くらいで実装が終わりました。
TypeScriptの補完がバリバリ効いてくれるので、ストレスフリーで書く事ができます!
import { Stack, Construct, StackProps } from '@aws-cdk/core';
import {
CfnVPC,
CfnSubnet,
CfnInternetGateway,
CfnRouteTable,
CfnRoute,
CfnSubnetRouteTableAssociation, CfnVPCGatewayAttachment
} from "@aws-cdk/aws-ec2";
export class LabStack extends Stack {
constructor(scope: Construct, id: string, props?: StackProps) {
super(scope, id, props);
const vpc = new CfnVPC(this, "lab-vpc", {
cidrBlock: "10.0.0.0/16",
enableDnsHostnames: true,
enableDnsSupport: true,
tags: [ { key: "Name", value: "lab-vpc" } ]
});
const publicSubnet = new CfnSubnet(this, "lab-subnet", {
vpcId: vpc.ref,
cidrBlock: "10.0.0.0/24",
availabilityZone: this.availabilityZones[0],
tags: [ { key: "Name", value: "lab-subnet" } ]
});
const igw = new CfnInternetGateway(this, "lab-igw", {
tags: [ { key: "Name", value: "lab-igw" } ]
});
const igwAttach = new CfnVPCGatewayAttachment(this, "lab-igw-attach", {
vpcId: vpc.ref,
internetGatewayId: igw.ref
});
const publicRouteTable = new CfnRouteTable(this, "lab-public-route", {
vpcId: vpc.ref
});
const igwRoute = new CfnRoute(this, "lab-public-route-igw", {
routeTableId: publicRouteTable.ref,
destinationCidrBlock: "0.0.0.0/0",
gatewayId: igw.ref
});
const association = new CfnSubnetRouteTableAssociation(this, "lab-public-route-association", {
routeTableId: publicRouteTable.ref,
subnetId: publicSubnet.ref
});
}
}
まだ足りねえ!もっとイケてる実装にしたいんだっ!!
公式リポジトリの「AWS Construct Library Design Guidelines」がTypeScript/CDKの良い部分を寄せ合わされていて、実装する際の非常に良い例になっているので、是非目を通してみてください!
https://github.com/aws/aws-cdk/blob/master/DESIGN_GUIDELINES.md
結論
・Terraformで例えるとリソースのベタ書きがL1 Library(AWS CloudFormation Resources)を用いた感じで、 moduleを利用して良い感じに拡張できるようにしたのがL2 Library(Construct Library)。
・勝手にリソース作って欲しくない時は CfnXXX
を使うと従来のCloudFormation / Terraformのように書ける
・再利用したくなったらforで CfnXXX
をループするような実装も取れるが、L2 Library(Construct Library)を自前で実装してあげることもできる。その際は公式の Vpc
Moduleや、「AWS Construct Library Design Guidelines」を参考にすると良い!
・プログラムでインフラを扱えるので、めちゃめちゃ自由度が高い!!!!!!!!!!!!!!
誰かのお役に立ち、CDKユーザーが増えてくれると嬉しいです!以上、もこでしたー
参考
https://docs.aws.amazon.com/cdk/api/latest/docs/aws-construct-library.html