「NLBのターゲットにALBを作成する構成をサクッと試したい」
NLBのターゲットにはALBを登録することもできます。
やったこと無かったので、試してみました。
せっかくなので、AWS CDKを使って構築してみました。
やってみた
構成図
リソース作成
コードは以下になります。
コードを実行してのリソース作成には、手元の環境で10分ほどかかりました。
作成される構成は上記の図のとおりです。
Webサーバ用のEC2では、ユーザーデータを使ってapacheのインストールとテスト用にindex.htmlを作成しています。
import * as cdk from 'aws-cdk-lib';
import { CfnOutput } from 'aws-cdk-lib';
import * as ec2 from 'aws-cdk-lib/aws-ec2';
import * as elbv2 from 'aws-cdk-lib/aws-elasticloadbalancingv2';
import * as elbv2_tg from 'aws-cdk-lib/aws-elasticloadbalancingv2-targets'
import * as iam from 'aws-cdk-lib/aws-iam';
import { Construct } from 'constructs';
export class NlbAlbTestStack extends cdk.Stack {
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
const natGatewayProvider = ec2.NatProvider.instance({
instanceType: new ec2.InstanceType('t3.small'),
});
const vpc = new ec2.Vpc(this, "Vpc", {
cidr: "10.0.0.0/16",
availabilityZones: [ "ap-northeast-1a", "ap-northeast-1c"],
natGatewayProvider,
natGateways: 1,
subnetConfiguration: [
{
cidrMask: 24,
name: "public",
subnetType: ec2.SubnetType.PUBLIC
},
{
cidrMask: 24,
name: "private",
subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS
},
]
})
// Security Group
const albSg = new ec2.SecurityGroup(this, "alb-sg", {
vpc,
allowAllOutbound: true,
description: "security group for a alb"
})
albSg.connections.allowInternally(ec2.Port.tcp(80))
const webServerSg = new ec2.SecurityGroup(this, "web-server-sg", {
vpc,
allowAllOutbound: true,
description: "security group for a web server"
})
webServerSg.connections.allowFrom(albSg, ec2.Port.tcp(80), 'Allow alb access')
// EC2
const userData = ec2.UserData.forLinux({
shebang: "#!/bin/bash",
})
userData.addCommands(
"yum update -y",
"yum install -y httpd",
"systemctl start httpd",
"systemctl enable httpd",
"echo test > /var/www/html/index.html"
)
const role = iam.Role.fromRoleName(this, "Ec2Role", "AmazonSSMRoleForInstancesQuickSetup")
const machineImage = new ec2.AmazonLinuxImage({
generation: ec2.AmazonLinuxGeneration.AMAZON_LINUX_2,
edition: ec2.AmazonLinuxEdition.STANDARD,
virtualization: ec2.AmazonLinuxVirt.HVM,
storage: ec2.AmazonLinuxStorage.GENERAL_PURPOSE,
});
const webServer = new ec2.Instance(this, "Instance", {
vpc,
instanceType: ec2.InstanceType.of(ec2.InstanceClass.T3, ec2.InstanceSize.MICRO),
machineImage,
vpcSubnets: {
subnets: vpc.privateSubnets
},
role,
userData
})
webServer.addSecurityGroup(webServerSg)
// nat instance作成前にuserdataを実行してしまうとyumでエラーになる
webServer.node.addDependency(vpc)
// ALB(private)
const alb = new elbv2.ApplicationLoadBalancer(this, "Alb", {
internetFacing: false,
vpc,
vpcSubnets: {
subnets: vpc.privateSubnets
}
})
alb.addSecurityGroup(albSg)
const instanceTarget = new elbv2_tg.InstanceTarget(webServer)
const albListener = alb.addListener("AlbHttpListener", {
port: 80,
protocol: elbv2.ApplicationProtocol.HTTP
})
albListener.addTargets("WebServerTarget", {
targets: [ instanceTarget ],
port: 80
})
const albTarget = new elbv2_tg.AlbTarget(alb, 80 )
// NLB(public)
const nlb = new elbv2.NetworkLoadBalancer(this, "Nlb", {
vpc,
internetFacing: true,
vpcSubnets: {
subnets: vpc.publicSubnets
}
})
// ALBが存在しない時点でTargetGroupを作るとエラーになるため
nlb.node.addDependency(alb)
const nlbListener = nlb.addListener("NlbHttpListener", {
port: 80,
protocol: elbv2.Protocol.TCP
})
nlbListener.addTargets("AlbTarget", {
targets: [ albTarget ],
port: 80
})
new CfnOutput(this, "NlbDnsName",{
value: nlb.loadBalancerDnsName
})
}
}
疎通確認
NLBのエンドポイントにcurlをして、Webサーバで表示しているコンテンツを確認します。
NLBのエンドポイントは、CDKのOutputで出しているためCDK実行時にコンソール上からも確認できます。
% curl <NLBのエンドポイント>
test
少しハマったところ
主にリソース作成の依存関係でハマりました。
nat instance作成前にEC2が作成されて、EC2のユーザーデータのyumが動かなかった
業務で利用する場合はVPCのスタックとNLBやALBのスタックは、分割することが多いと思うのであまり発生しないとは思います。
最初は、EC2とVPC関連のリソースを明示的に依存関係を作らずに作成していました。
そのため、EC2でインターネット接続が可能になる前にユーザーデータが実行されてユーザーデータが動かないことがありました。
以下のように依存関係を追加することで、この事象は回避できました。
// nat instance作成前にuserdataを実行してしまうとyumでエラーになる
webServer.node.addDependency(vpc)
ALBが存在しない時点でNLBのターゲットグループを作成してしまう
今回はNLBのターゲットグループでALBを指定しています。
依存関係を明示していないと、CloudFormatino実行時にALBが存在しない旨のエラーがでます。
// ALBが存在しない時点でTargetGroupを作るとエラーになるため
nlb.node.addDependency(alb)
おわりに
AWS CDKでNLB + ALB + EC2の構成を作成してみました。
似たような構成をCDKで作成する際に参考になると嬉しいです。
以上、AWS事業本部の佐藤(@chari7311)でした。