どんな内容?
ずっと気になっていた機能をやっと試してみることができました。
一言で言うと、AWS 上にデプロイされている既存リソースから CloudFromation テンプレートを生成してくれるよ。
OSS で、Former2 と言うものがありますがこれに近いものでしょうか。
ここでは、IaC ジェネレーター と cdk migrate を利用して実現します。
IaC ジェネレーター
概要
CloudFormation IaC ジェネレーターを使用すると、CloudFormation で管理されていないプロビジョニングされた AWS リソースをテンプレートとして生成することができます。
注意事項
クウォータに注意が必要そうです。
名前 | Value |
---|---|
1 回のアカウントスキャンで処理できるリソースの最大数 | 100000 |
1 日あたりのスキャン数 (リソースが 10,000 未満のアカウントの場合) | |
1 日あたりのスキャン数 (リソースが 10,000 以上のアカウントの場合) | 1 |
アカウントあたりの同時に生成されるテンプレートの数 | 5 |
1 回のテンプレート生成で同時にモデル化されるリソースの数 | 5 |
1 つのテンプレートでモデル化できるリソースの合計数 | 500 |
サポートされている AWS リソース
サポートされている AWS リソースは随時追加されていくと思いますが、ドキュメントを確認する必要があります。
1. アカウントのリソースをスキャンする
[IaC ジェネレーター] から、[新しいスキャンを開始]をクリック。
2. CloudFormation テンプレートを作成する
[テンプレート名]を入力。
(オプション)必要に応じて [削除ポリシー]、[置換ポリシーを更新] を変更します。
[削除ポリシー]:スタックが削除された場合にリソースを保持するか削除するか
[置換ポリシーを更新]:スタックが置換された場合にリソースを保持するか削除するか
CloudFormation テンプレート化するリソースを選択。(ここでは、「AWS:EC2:VPC」のみ選択。)
ここでは、先程追加するリソースとして選択した「AWS:EC2:VPC」に関連するリソースを追加するかどうかの画面となります。ひとまずここでは全て指定しました。
テンプレートが作成されました。Ref などもある程度いい感じに生成してくれるようです。
(警告)「一部のオプションのプロパティがテンプレートに含まれていませんでした。リソース用に設定されている場合は、テンプレートをダウンロードしてオプションのプロパティを追加できます」:メッセージ通りサポートされていないプロパティがありそのプロパティを利用している場合は一度テンプレートをダウンロードし自身で編集してあげる必要があります。今回は利用していないプロパティでしたので特に編集は行なわず進みます。
一つ隣の[テンプレートリソース]に移動すると、ここで「論理ID」を編集することもできるようです。今回は特に編集せずこのまま進みます。
3: CloudFormation にインポートする
「スタックにインポート」をクリック。
以降は 画面に従って、CloudFormation スタックをインポートするだけです。
参考
cdk migrate
概要
デプロイされた CloudFormation テンプレートや CloudFormation スタック、IaC の管理外で作成されたリソースを CDK アプリケーションに移行できるよ。
考慮事項
- L1 コンストラクトのみ
- CloudFormation スタックを移行する場合ネストされたテンプレートはサポートされていない
- CloudFormation テンプレートから移行する場合、 CDK CLI は Fn クラスを使用してロジックを CDK アプリに移行しようとする
CloudFormation スタックからの移行
次の CloudFormation テンプレート(vpc.yaml)で、CloudFormation スタック(vpc)がデプロイ済と仮定します。
AWSTemplateFormatVersion: '2010-09-09'
Description: VPC with public and private subnets
Parameters:
VpcCIDR:
Description: CIDR block for the VPC
Type: String
Default: '10.0.0.0/16'
Resources:
MyVPC:
Type: AWS::EC2::VPC
Properties:
CidrBlock: !Ref VpcCIDR
PublicSubnet:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref MyVPC
CidrBlock: '10.0.1.0/24'
MapPublicIpOnLaunch: true
PrivateSubnet:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref MyVPC
CidrBlock: '10.0.2.0/24'
InternetGateway:
Type: AWS::EC2::InternetGateway
AttachGateway:
Type: AWS::EC2::VPCGatewayAttachment
Properties:
VpcId: !Ref MyVPC
InternetGatewayId: !Ref InternetGateway
PublicRouteTable:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref MyVPC
PublicRoute:
Type: AWS::EC2::Route
DependsOn: AttachGateway
Properties:
RouteTableId: !Ref PublicRouteTable
DestinationCidrBlock: '0.0.0.0/0'
GatewayId: !Ref InternetGateway
PublicSubnetRouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref PublicSubnet
RouteTableId: !Ref PublicRouteTable
CloudFormation スタックから移行する場合は、--from-stack オプションを利用します。
cdk migrate --from-stack --stack-name "vpc"
コマンドの実行が完了したら、スタックを確認してみます。
import * as cdk from 'aws-cdk-lib';
import * as ec2 from 'aws-cdk-lib/aws-ec2';
export interface VpcStackProps extends cdk.StackProps {
/**
* CIDR block for the VPC
* @default '10.0.0.0/16'
*/
readonly vpcCidr?: string;
}
/**
* VPC with public and private subnets
*/
export class VpcStack extends cdk.Stack {
public constructor(scope: cdk.App, id: string, props: VpcStackProps = {}) {
super(scope, id, props);
// Applying default props
props = {
...props,
vpcCidr: props.vpcCidr ?? '10.0.0.0/16',
};
// Resources
const internetGateway = new ec2.CfnInternetGateway(this, 'InternetGateway', {
});
const myVpc = new ec2.CfnVPC(this, 'MyVPC', {
cidrBlock: props.vpcCidr!,
});
const attachGateway = new ec2.CfnVPCGatewayAttachment(this, 'AttachGateway', {
vpcId: myVpc.ref,
internetGatewayId: internetGateway.ref,
});
const privateSubnet = new ec2.CfnSubnet(this, 'PrivateSubnet', {
vpcId: myVpc.ref,
cidrBlock: '10.0.2.0/24',
});
const publicRouteTable = new ec2.CfnRouteTable(this, 'PublicRouteTable', {
vpcId: myVpc.ref,
});
const publicSubnet = new ec2.CfnSubnet(this, 'PublicSubnet', {
vpcId: myVpc.ref,
cidrBlock: '10.0.1.0/24',
mapPublicIpOnLaunch: true,
});
const publicRoute = new ec2.CfnRoute(this, 'PublicRoute', {
routeTableId: publicRouteTable.ref,
destinationCidrBlock: '0.0.0.0/0',
gatewayId: internetGateway.ref,
});
publicRoute.addDependency(attachGateway);
const publicSubnetRouteTableAssociation = new ec2.CfnSubnetRouteTableAssociation(this, 'PublicSubnetRouteTableAssociation', {
subnetId: publicSubnet.ref,
routeTableId: publicRouteTable.ref,
});
}
}
確かに L1 コンストラクトですね。
一応変更して cdk でデプロイされるか動作を確認してみました。myVpc に tags を追加して、デプロイしてみます。
const myVpc = new ec2.CfnVPC(this, 'MyVPC', {
cidrBlock: props.vpcCidr!,
tags: [
{
key: 'Name',
value: 'MyVPC'
},
]
});
cdk deploy
CLI で確認すると反映されていることが tags が反映されていることが確認できました。
aws ec2 describe-vpcs --query 'Vpcs[].Tags'
[
[
{
"Key": "aws:cloudformation:stack-name",
"Value": "vpc"
},
{
"Key": "Name",
"Value": "MyVPC"
},
CloudFormation テンプレートからの移行
CloudFormation テンプレートから移行する場合は --from-path を利用します。
cdk migrate --from-path "./vpc.yaml" --stack-name "vpc"
デプロイされたリソースからの移行
デプロイされた AWS リソースから移行するには、 --from-scan を利用します。
--filterを利用しないと、 CDK CLI は AWS 環境全体をスキャンし、IaC ジェネレーターの最大クォータ制限までリソースを移行します。
cdk migrate --from-scan --stack-name "vpc" --filter "type=AWS::EC2::VPC"
参考