CDK自体はいじったことがあったのだが、APIリファレンスの追い方をちょっと前に整理したものをここに保存。
後は、サンプルがどうもVPCを新規に作るものが多いような気がするので「既存のサブネットを使う」コードを保存しておきたかったという思いもある。
数年後に忘れても思い出せますように。
自分のためのメモだが、ついでに初学者の人のヒントになれば嬉しい。
記事の目的
- APIリファレンスの読み方
- そのほかサンプルやテスト方法などについて参考リンクのメモ
- ALB + EC2 を既存サブネットに起動するコードメモ
APIリファレンスの見方
importの書き方
リファレンスの細かい見方はここが参考になった。
例として、ApplicationLoadBalancerの場合には以下のようにタイプが書いてある。
aws-cdk-lib » aws_elasticloadbalancingv2 » ApplicationLoadBalancer
この場合importの仕方と使い方はアンダーバー(_)をハイフン(-)に変えて以下のようになる。
import * as elbv2 from "aws-cdk-lib/aws-elasticloadbalancingv2";
...
const alb = new elbv2.ApplicationLoadBalancer(this, "ALB", {
...
このimportの書き方は以下のページなどで使われている書き方である。
他にもimportの書き方は複数あり、以下のページではClassic importとBarrel importの2通りを紹介している。
それぞれ以下。
Classic import
import { Stack, App, aws_s3 as s3 } from 'aws-cdk-lib';
...
new s3.Bucket(stack, 'TestBucket');
Barrel import
import { Bucket } from 'aws-cdk-lib/aws-s3';
...
new Bucket(stack, 'TestBucket');
また、上記含めた色々なimport方法を比較してくれている記事もあった。好きな方法で書けば良い。
リファレンスの追い方
「ALB作成時に既存のサブネットを指定したい」という状況を例にとってみていく。
ApplicationLoadBalancerのページを見る
vpcSubnetsプロパティはSubnetSelectionというタイプなので、SubnetSelectionタイプでどうやってサブネットを指定できるのか、プロパティを見る。
SubnetSelectionでサブネットを指定できそうなのはsubnetsプロパティで、これはISubnet[]タイプである。そこでさらにISubnetのリファレンスを見ると以下のようなメソッドから取得できることがわかる。
Obtainable from Subnet.fromSubnetAttributes(), Subnet.fromSubnetId()
なので、こんな感じで既存サブネットを指定したSubnetSelectionを取得できる(fromSubnetAttributesとfromSubnetIdの使い分けはパッとわからなかったので置いておく)
import * as ec2 from "aws-cdk-lib/aws-ec2";
const subnetIds = [
{
"subnetId":"subnet-xxxxx",
"az":"ap-northeast-1a"
},
{
"subnetId":"subnet-yyyyy",
"az":"ap-northeast-1b"
}
]
const subnets: ec2.SubnetSelection = {
subnets:subnetIds.map(subnet => {
// fromSubnetAttributesはISubnetタイプを返す
return ec2.Subnet.fromSubnetAttributes(this, "subnet-"+subnet.subnetId, {
"subnetId":subnet.subnetId,
"availabilityZone": subnet.az
})
})
}
バージョン管理について
CDK固有のものではない情報も多いがこれを機にメモ。
- CDKバージョンを上げたいときはaws-cdkだけではなく、
package.json
のaws-cdk-libを見る必要がある。 - グローバルでcdkをインストールするとバージョンの不整合が起こりうるので、
npm install aws-cdk
でローカルインストールしてnpx cdk
で使うのがバージョンの管理はしやすそう - 以下のコマンドで、全部のパッケージを最新にできる。この記事がバージョン管理について考察してくれている
npm install npm-check-updates
npx ncm -u
npm install
コンストラクタの作り方
この辺りが参考になりそう(読んだわけではない)。
-
AWS CDK の3種類の Construct を使ってデプロイしてみた scopeでthisを指定する時以外の参考になりそう
L2コンストラクトで対応していないプロパティを変えるエスケープハッチ
L1コンストラクトを取り出してそのプロパティを変更する。
// Get the CloudFormation resource
const cfnBucket = bucket.node.defaultChild as s3.CfnBucket;
// Change its properties
cfnBucket.analyticsConfiguration = [
{
id: 'Config',
// ...
}
];
テスト方法
aws-cdk-lib/assertions
ライブラリを使って単体テストができそう
サンプル
-
https://github.com/aws-samples
色々なサンプルが置いてあるレポジトリだが、cdk + 使いたいサービス名で検索するとCDKアプリケーションもあったりする -
AWS Solutions Constructs
CDKチームではないがAWSの人が開発しているらしい。「API Gateway + Lambda」とか「Fargate + SQS」とか、2サービスくらいを組み合わせてまとめたものが多そう。単品でこれを作るのは面倒だよね、というレベルのものはないが、シンプルが故にパーツとしては使いやすそう。 -
https://cdkpatterns.com/
CDKサンプルをオープンソースで公開するプロジェクトのよう
例えば以下のLambda + RDS (RDS Proxy)など、しっかりした構成のサンプル
https://github.com/cdk-patterns/serverless/tree/main/the-rds-proxy/typescript
ALB + EC2 を既存サブネットに起動するコード例
やはりどこかに雛形を置いておきたいためこの記事に入れる。
あとデフォルトでALB作ろうとすると同じAZにノード二つ配置しようとしてエラーになる気がする。
import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
import * as ec2 from "aws-cdk-lib/aws-ec2";
import * as elbv2 from "aws-cdk-lib/aws-elasticloadbalancingv2";
import * as elbv2target from 'aws-cdk-lib/aws-elasticloadbalancingv2-targets';
import * as asg from 'aws-cdk-lib/aws-autoscaling';
// 既存のVPCとサブネットを指定する
// ALBはinternet facingで80ポートフルオープン
// **EC2インスタンスはSSHポートを開けていないのでそこは追記する**
// ALBにアクセスすると固定文字列が返されるだけのシンプルなApacheサーバー
//既存VPCを選択
const VPCID = "vpc-aaa";
// 既存のパブリックサブネットとそのID。AZは別のサブネットを選ぶこと。
const subnetIds = [
{
"subnetId": "subnet-xxxxx",
"az": "ap-northeast-1a"
},
{
"subnetId": "subnet-yyyyy",
"az": "ap-northeast-1b"
}
]
//既存キーペア名
const ec2KeyPairName = "<EC2インスタンス接続用の既存キーペアの名前>";
export class Albwithec2Stack extends cdk.Stack {
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
// 既存のVPC, subnetを取得
const vpc = ec2.Vpc.fromLookup(this, 'Vpc', { vpcId: VPCID })
const subnets: ec2.SubnetSelection = {
subnets: subnetIds.map(subnet => {
return ec2.Subnet.fromSubnetAttributes(this, "subnet-" + subnet.subnetId, {
"subnetId": subnet.subnetId,
"availabilityZone": subnet.az
})
})
}
// ALBを作成
//// SG for ALB
const sgForAlb = new ec2.SecurityGroup(this, "vpcForAlb", {
vpc,
description: "SG for ALB. created by CDK"
})
sgForAlb.addIngressRule(ec2.Peer.anyIpv4(), ec2.Port.tcp(80))
//// ALB
const alb = new elbv2.ApplicationLoadBalancer(this, "ALB", {
vpc,
vpcSubnets: subnets,
internetFacing: true,
securityGroup: sgForAlb
});
// EC2インスタンス用のSG
const sgForEc2 = new ec2.SecurityGroup(this, "vpcForEc2", {
vpc,
description: "SG for EC2. created by CDK"
})
sgForEc2.addIngressRule(ec2.Peer.securityGroupId(sgForAlb.securityGroupId), ec2.Port.tcp(80))
// SSH用に22番ポートを開けるルールも書く
// sgForEc2.addIngressRule(ec2.Peer.prefixList(prefixListId), ec2.Port.tcp(22))
// sgForEc2.addIngressRule(ec2.Peer.ipv4("172.0.0.0/8"), ec2.Port.tcp(22))
// ターゲットグループ作成
const targetGroup = new elbv2.ApplicationTargetGroup(this, "TargetGroup", {
vpc,
port: 80,
targetType: elbv2.TargetType.INSTANCE,
});
// リスナーを作成してALBにアタッチ
alb.addListener("Listener", {
port: 80,
defaultTargetGroups: [targetGroup]
});
//autoscaling
////起動テンプレート
const userData = ec2.UserData.forLinux();
userData.addCommands(
"sudo dnf install httpd -y",
'sudo echo "test page" |sudo tee /var/www/html/index.html',
"sudo service httpd restart"
);
const launchTemplate = new ec2.LaunchTemplate(this, 'LaunchTemplate', {
launchTemplateName: "ec2LaunchTemplateByCdk",
machineImage: ec2.MachineImage.latestAmazonLinux2023(),
instanceType: ec2.InstanceType.of(
ec2.InstanceClass.T2,
ec2.InstanceSize.MICRO
),
securityGroup: sgForEc2,
keyPair: ec2.KeyPair.fromKeyPairName(this, "keyPair", ec2KeyPairName),
userData
});
//起動テンプレートを指定してオートスケーリンググループ作成 & ターゲットグループにアタッチ
const autoScalingGroup = new asg.AutoScalingGroup(this, "AutoScalingGroup", {
vpc,
autoScalingGroupName: "asgByCdk",
launchTemplate,
vpcSubnets: subnets
});
autoScalingGroup.attachToApplicationTargetGroup(targetGroup)
}
}