はじめに
今回は、以下の記事で作成した「単一スタック」のテンプレートを、「クロススタック」に書き換えてデプロイしてみました。
構成はそのまま維持しつつ「責務ごとに分割」することが可能になります。また、役割ごとに分割することで可読性も上がります。
また、再利用性の高さから、実務でもっとも採用されているスタック構成となります。
さっそく実装してみた
以下のような(クロス)スタック構成になります。
App
├── NetworkStack
├── SecurityStack
└── ComputeStack
bin/app.tsを以下のコードで書き換えます。
bin/app.ts
#!/usr/bin/env node
import * as cdk from 'aws-cdk-lib';
import { NetworkStack } from '../lib/network-stack';
import { SecurityStack } from '../lib/security-stack';
import { ComputeStack } from '../lib/compute-stack';
const app = new cdk.App();
// =========================
// Network
// =========================
const network = new NetworkStack(app, 'NetworkStack');
// =========================
// Security
// =========================
const security = new SecurityStack(app, 'SecurityStack', {
vpc: network.vpc,
});
// =========================
// Compute
// =========================
new ComputeStack(app, 'ComputeStack', {
vpc: network.vpc,
securityGroup: security.sg,
});
lib/network-stack.tsを作成します。
lib/network-stack.ts
import * as cdk from 'aws-cdk-lib';
import { Stack, StackProps } from 'aws-cdk-lib';
import * as ec2 from 'aws-cdk-lib/aws-ec2';
import { Construct } from 'constructs';
export class NetworkStack extends Stack {
public readonly vpc: ec2.Vpc;
constructor(scope: Construct, id: string, props?: StackProps) {
super(scope, id, props);
this.vpc = new ec2.Vpc(this, 'Vpc', {
ipAddresses: ec2.IpAddresses.cidr('10.0.0.0/16'),
maxAzs: 1,
subnetConfiguration: [
{
name: 'public-subnet',
subnetType: ec2.SubnetType.PUBLIC,
cidrMask: 24,
},
],
natGateways: 0,
});
}
}
lib/security-stack.tsを作成します。
lib/security-stack.ts
import * as cdk from 'aws-cdk-lib';
import { Stack, StackProps } from 'aws-cdk-lib';
import * as ec2 from 'aws-cdk-lib/aws-ec2';
import { Construct } from 'constructs';
interface SecurityStackProps extends StackProps {
vpc: ec2.Vpc;
}
export class SecurityStack extends Stack {
public readonly sg: ec2.SecurityGroup;
constructor(scope: Construct, id: string, props: SecurityStackProps) {
super(scope, id, props);
this.sg = new ec2.SecurityGroup(this, 'PublicSG', {
vpc: props.vpc,
description: 'Allow HTTP access',
allowAllOutbound: true,
});
this.sg.addIngressRule(
ec2.Peer.anyIpv4(),
ec2.Port.tcp(80),
'Allow HTTP from anywhere'
);
}
}
lib/compute-stack.tsを作成します。
lib/compute-stack.ts
import * as cdk from 'aws-cdk-lib';
import { Stack, StackProps } from 'aws-cdk-lib';
import * as ec2 from 'aws-cdk-lib/aws-ec2';
import { Construct } from 'constructs';
interface ComputeStackProps extends StackProps {
vpc: ec2.Vpc;
securityGroup: ec2.SecurityGroup;
}
export class ComputeStack extends Stack {
constructor(scope: Construct, id: string, props: ComputeStackProps) {
super(scope, id, props);
const instance = new ec2.Instance(this, 'EC2', {
vpc: props.vpc,
vpcSubnets: {
subnetType: ec2.SubnetType.PUBLIC,
},
instanceType: ec2.InstanceType.of(
ec2.InstanceClass.T3,
ec2.InstanceSize.MICRO
),
machineImage: ec2.MachineImage.latestAmazonLinux2023(),
securityGroup: props.securityGroup,
});
instance.addUserData(
'#!/bin/bash',
'dnf update -y',
'dnf install -y httpd',
'systemctl start httpd',
'systemctl enable httpd',
'echo "<h1>Hello from EC2!!!!!</h1>" > /var/www/html/index.html'
);
cdk.Tags.of(instance).add('Name', 'test-ec2');
}
}
デプロイ
一括デプロイ
以下のコマンドを実行します。
zsh
cdk deploy --all
CDKが内部で、
- NetworkStack
- SecurityStack
- ComputeStack
の順に依存関係を自動解決しデプロイします。
個別デプロイ
以下のようにスタック名を指定して個別にデプロイも可能です。
zsh
cdk deploy NetworkStack
cdk deploy SecurityStack
cdk deploy ComputeStack
ただし、依存関係に注意する必要があります。
更新
デプロイと同様のコマンドを実行します(差分があるスタックだけ更新されます)
削除
一括削除
以下のコマンドを実行します。
zsh
cdk destroy --all
CDKが内部で、
- ComputeStack
- SecurityStack
- NetworkStack
の順に依存関係を考慮し削除します。
個別削除
以下のようにスタック名を指定して個別に削除も可能です。
zsh
cdk destroy ComputeStack
cdk destroy SecurityStack
cdk destroy NetworkStack
ただし、この場合も依存関係に注意する必要があります。