AWS CDKの新機能”cdk migrate”試してみた
はじめに
AWS CDK v2.100.0で cdk migrate
が追加されました
こんにちは、入社してからCDKを触り始めたばかりのCDK初心者akiraです。
2023年10月7日にAWS CDK v2.100.0がリリースされました。本ブログではリリースされた機能のうち「cdk migrate」について書かせていただきます。
何が出来るのか
現在デプロイされているCFn、ローカルのCFnファイルからCDKのソースを作成することが出来ます。CDKの言語はCDKで利用できる全ての言語をサポートしています。
本検証ではデプロイ済みのCFnリソースをCDKに取り込んでみます。本検証ではCDKの言語はTypescriptで実施します。
本記事はリポジトリにも
CDK migrate is currently experimental and may have breaking changes in the future.
https://github.com/aws/aws-cdk/pull/27325
との記載があるとおり、あくまで現時点での検証となりますのでご了承ください。
その他の注意事項もございますのでお手元で検証する際はリポジトリに記載の注意書きをお読みいただければと思います。
実際にやってみる(デプロイ済みのCFn→CDK)
下準備
テンプレート説明
まずは以下のリソースをAWS上にデプロイします。
構成はVPCの中に1つだけサブネットがあるシンプルなものです。
パラメータを設定した際の扱いが気になったので、リソースのタグとCIDRをパラメータとして渡すテンプレートになっています。
AWSTemplateFormatVersion: "2010-09-09"
Parameters:
PJid:
Type: String
Default: "test"
VPCCIDR:
Type: String
Default: "10.0.0.0/16"
PublicSubnetCIDR:
Type: String
Default: "10.0.10.0/24"
Resources:
# VPC
VPC:
Type: "AWS::EC2::VPC"
Properties:
CidrBlock: !Ref VPCCIDR
EnableDnsSupport: "true"
EnableDnsHostnames: "true"
InstanceTenancy: default
Tags:
- Key: Name
Value: !Sub "${PJid}-vpc"
# InternetGateway
InternetGateway:
Type: "AWS::EC2::InternetGateway"
Properties:
Tags:
- Key: Name
Value: !Sub "${PJid}-igw"
# IGW Attach
InternetGatewayAttachment:
Type: "AWS::EC2::VPCGatewayAttachment"
Properties:
InternetGatewayId: !Ref InternetGateway
VpcId: !Ref VPC
# Public Subnet
PublicSubnet:
Type: "AWS::EC2::Subnet"
Properties:
AvailabilityZone: "ap-northeast-1a"
CidrBlock: !Ref PublicSubnetCIDR
VpcId: !Ref VPC
Tags:
- Key: Name
Value: !Sub "${PJid}-public-subnet-a"
# Public RouteTable
PublicRouteTable:
Type: "AWS::EC2::RouteTable"
Properties:
VpcId: !Ref VPC
Tags:
- Key: Name
Value: !Sub "${PJid}-public-route-a"
# PublicRoute
PublicRoute:
Type: "AWS::EC2::Route"
Properties:
RouteTableId: !Ref PublicRouteTable
DestinationCidrBlock: "0.0.0.0/0"
GatewayId: !Ref InternetGateway
# PublicRouteTable Associate Subnet
PublicSubnetRouteTablessociation:
Type: "AWS::EC2::SubnetRouteTableAssociation"
Properties:
SubnetId: !Ref PublicSubnet
RouteTableId: !Ref PublicRouteTable
デプロイ
デプロイの手順は省略しますが以下のように設定してデプロイします。
スタック名は後ほどのコマンドで利用するのでメモしておきます。
スタック名: cdk-migrate-test
確認
成功を確認後、念のためリソースを見に行きます。
想定通り作成されています
cdk migrateコマンド実行
ここまでで準備は整ったので早速コマンドを実行していきます。
※デプロイしたAWSに対してCDKコマンドが実行できる状態にするまでの手順は割愛いたします。
コマンド実行
CDKのバージョンがv2.100.0であることを確認して実行していきます。
# バージョン確認
cdk --version
デプロイ済みのCFnに対してcdk migrateを実行する際は以下のように指定します
cdk migrate --stack-name {ターゲットのスタック名} --language {CDKの言語} --from-stack
今回は以下のように指定して実行していきます。
cdk migrate --stack-name cdk-migrate-test --language typescript --from-stack
実行後 All done!
まで表示されれば成功です。
cdk migrate --stack-name cdk-migrate-test --language typescript --from-stack
This is an experimental feature. We make no guarantees about the outcome or stability of the functionality.
⏳ Generating CDK app for cdk-migrate-test...
Applying project template app for typescript
Initializing a new git repository...
Executing npm install...
✅ All done!
成功すると、コマンドを実行したディレクトリ配下にCDKのリソースが --stack-name
で指定したスタック名で作成されます。
tree ./cdk-migrate-test
.
├── README.md
├── bin
│ └── cdk-migrate-test.ts
├── cdk.json
├── jest.config.js
├── lib
│ └── cdk-migrate-test-stack.ts
├── node_modules
│ ├── @ampproject
│ │ └── remapping
│ │ ├── LICENSE
│ │ ├── README.md
~~ 以下略 ~~
結果の確認
cdk-migrate-test.ts
、cdk-migrate-test-stack.ts
の中身を見てみます。
#!/usr/bin/env node
import 'source-map-support/register';
import * as cdk from 'aws-cdk-lib';
import { CdkMigrateTestStack } from '../lib/cdk-migrate-test-stack';
const app = new cdk.App();
new CdkMigrateTestStack(app, 'cdk-migrate-test', {
/* If you don't specify 'env', this stack will be environment-agnostic.
* Account/Region-dependent features and context lookups will not work,
* but a single synthesized template can be deployed anywhere. */
/* Uncomment the next line to specialize this stack for the AWS Account
* and Region that are implied by the current CLI configuration. */
// env: { account: process.env.CDK_DEFAULT_ACCOUNT, region: process.env.CDK_DEFAULT_REGION },
/* Uncomment the next line if you know exactly what Account and Region you
* want to deploy the stack to. */
// env: { account: '123456789012', region: 'us-east-1' },
/* For more information, see https://docs.aws.amazon.com/cdk/latest/guide/environments.html */
});
import * as cdk from 'aws-cdk-lib';
import * as ec2 from 'aws-cdk-lib/aws-ec2';
export interface CdkMigrateTestStackProps extends cdk.StackProps {
/**
* @default 'test'
*/
readonly pJid?: string;
/**
* @default '10.0.0.0/16'
*/
readonly vpccidr?: string;
/**
* @default '10.0.10.0/24'
*/
readonly publicSubnetCidr?: string;
}
export class CdkMigrateTestStack extends cdk.Stack {
public constructor(scope: cdk.App, id: string, props: CdkMigrateTestStackProps = {}) {
super(scope, id, props);
// Applying default props
props = {
...props,
pJid: props.pJid ?? 'test',
vpccidr: props.vpccidr ?? '10.0.0.0/16',
publicSubnetCidr: props.publicSubnetCidr ?? '10.0.10.0/24',
};
// Resources
const internetGateway = new ec2.CfnInternetGateway(this, 'InternetGateway', {
tags: [
{
key: 'Name',
value: `${props.pJid!}-igw`,
},
],
});
const vpc = new ec2.CfnVPC(this, 'VPC', {
cidrBlock: props.vpccidr!,
enableDnsSupport: true,
enableDnsHostnames: true,
instanceTenancy: 'default',
tags: [
{
key: 'Name',
value: `${props.pJid!}-vpc`,
},
],
});
if (internetGateway == null) { throw new Error(`A combination of conditions caused 'internetGateway' to be undefined. Fixit.`); }
if (vpc == null) { throw new Error(`A combination of conditions caused 'vpc' to be undefined. Fixit.`); }
const internetGatewayAttachment = new ec2.CfnVPCGatewayAttachment(this, 'InternetGatewayAttachment', {
internetGatewayId: internetGateway.ref,
vpcId: vpc.ref,
});
if (vpc == null) { throw new Error(`A combination of conditions caused 'vpc' to be undefined. Fixit.`); }
const publicRouteTable = new ec2.CfnRouteTable(this, 'PublicRouteTable', {
vpcId: vpc.ref,
tags: [
{
key: 'Name',
value: `${props.pJid!}-public-route-a`,
},
],
});
if (vpc == null) { throw new Error(`A combination of conditions caused 'vpc' to be undefined. Fixit.`); }
const publicSubnet = new ec2.CfnSubnet(this, 'PublicSubnet', {
availabilityZone: 'ap-northeast-1a',
cidrBlock: props.publicSubnetCidr!,
vpcId: vpc.ref,
tags: [
{
key: 'Name',
value: `${props.pJid!}-public-subnet-a`,
},
],
});
if (internetGateway == null) { throw new Error(`A combination of conditions caused 'internetGateway' to be undefined. Fixit.`); }
if (publicRouteTable == null) { throw new Error(`A combination of conditions caused 'publicRouteTable' to be undefined. Fixit.`); }
const publicRoute = new ec2.CfnRoute(this, 'PublicRoute', {
routeTableId: publicRouteTable.ref,
destinationCidrBlock: '0.0.0.0/0',
gatewayId: internetGateway.ref,
});
if (publicRouteTable == null) { throw new Error(`A combination of conditions caused 'publicRouteTable' to be undefined. Fixit.`); }
if (publicSubnet == null) { throw new Error(`A combination of conditions caused 'publicSubnet' to be undefined. Fixit.`); }
const publicSubnetRouteTablessociation = new ec2.CfnSubnetRouteTableAssociation(this, 'PublicSubnetRouteTablessociation', {
subnetId: publicSubnet.ref,
routeTableId: publicRouteTable.ref,
});
}
}
元のCFnでパラメータとしていた部分が CdkMigrateTestStack
のパラメータとして渡せる(8〜16行目付近)ように再現されていることがわかりました!
CDKをデプロイしてみる
作成されたCDKをデプロイしてみる
作成されたCDKに修正の必要がなさそうなのでデプロイしてみます。すると、元はCFnで作成されていたスタックに更新が発生します。
今回のデプロイでは readonly pJid?: string;
の部分に引数を渡さずに実行したため、リソースのNameタグがデフォルト値のtest
に変更されたことがわかります。
編集してデプロイしてみる
CDKで管理できることを確認するためにreadonly pJid?: string;
にcdk-migrate-success
を設定してリソースのタグが変更されるか実行してみます。
#!/usr/bin/env node
import 'source-map-support/register';
import * as cdk from 'aws-cdk-lib';
import { CdkMigrateTestStack } from '../lib/cdk-migrate-test-stack';
const app = new cdk.App();
new CdkMigrateTestStack(app, 'cdk-migrate-test', {
pJid: "cdk-migrate-success" // ★★追加★★
});
特に問題なく更新されました!
リソースの方も問題なく変更されていることがわかります。
まとめ
CFnで管理していたリソースを簡単にCDKに変更し、継続管理できることがわかりました。
冒頭に記載したとおりこれはあくまで experimental
な機能なので、まだ制約事項なども多く本番投入は出来ませんが、正式リリースされれば既存のCFn運用をCDKに乗せ替えることが出来て運用の高度化など多方面に有用な機能であるとワクワクしました。安定版のリリースが待ち遠しく感じたakiraでした。