This pattern shows how to deploy a containerized Web API as an ECS fargate service, and expose it with a custom domain using Route53
using Amazon.CDK;
using Amazon.CDK.AWS.CertificateManager;
using Amazon.CDK.AWS.EC2;
using Amazon.CDK.AWS.Ecr.Assets;
using Amazon.CDK.AWS.ECS;
using Amazon.CDK.AWS.ECS.Patterns;
using Amazon.CDK.AWS.Route53;
using Amazon.CDK.AWS.Route53.Targets;
using Constructs;
using Microsoft.Extensions.Options;
using System.Collections.Generic;
namespace Route53AlbFargateCdkDotnet
{
public class Route53AlbFargateCdkDotnetStack : Stack
{
internal Route53AlbFargateCdkDotnetStack(Construct scope, string id, IStackProps props = null) : base(scope, id, props)
{
// Replace the value with your domain name
string apiDomainName = "api.YOUR-DOMAIN.com";
// 1. Hosted zone
var hostedZone = new HostedZone(this, "hosted-zone", new HostedZoneProps
{
ZoneName = apiDomainName
});
hostedZone.ApplyRemovalPolicy(RemovalPolicy.RETAIN);
// 2. SSL certificate via ACM
var certificate = new Certificate(this, "certificate", new CertificateProps
{
DomainName = apiDomainName,
Validation = CertificateValidation.FromDns(hostedZone),
});
// 3. VPC with public and private subnets
var vpc = new Vpc(this, "vpc", new VpcProps
{
Cidr = "10.0.0.0/16",
MaxAzs = 3,
SubnetConfiguration = new[]
{
new SubnetConfiguration
{
Name="private",
SubnetType= SubnetType.PRIVATE_ISOLATED,
CidrMask= 24
},
new SubnetConfiguration
{
Name="public",
SubnetType= SubnetType.PUBLIC,
CidrMask= 24
}
}
});
// Create required VPC endpoints to privately retrieve docker images from the ECR repository
// Reference link - https://docs.aws.amazon.com/AmazonECR/latest/userguide/vpc-endpoints.html
// 4.1. VPC endpoint 1
var ecrDockerVpcEndpoint = new InterfaceVpcEndpoint(this, "ecr-dkr-vpc-endpoint", new InterfaceVpcEndpointProps
{
Vpc = vpc,
Service = InterfaceVpcEndpointAwsService.ECR_DOCKER,
PrivateDnsEnabled = true
});
// 4.2. VPC endpoint 2
var ecrVpcEndpoint = new InterfaceVpcEndpoint(this, "ecr-vpc-endpoint", new InterfaceVpcEndpointProps
{
Vpc = vpc,
Service = InterfaceVpcEndpointAwsService.ECR,
PrivateDnsEnabled = true
});
// 4.3. VPC endpoint 3
var cwVpcEndpoint = new InterfaceVpcEndpoint(this, "cloudwatch-vpc-endpoint", new InterfaceVpcEndpointProps
{
Vpc = vpc,
Service = InterfaceVpcEndpointAwsService.CLOUDWATCH,
PrivateDnsEnabled = true
});
// 4.4. VPC endpoint 4
var cwLogsVpcEndpoint = new InterfaceVpcEndpoint(this, "cloudwatch-logs-vpc-endpoint", new InterfaceVpcEndpointProps
{
Vpc = vpc,
Service = InterfaceVpcEndpointAwsService.CLOUDWATCH_LOGS,
PrivateDnsEnabled = true
});
// 4.5. VPC endpoint 5
var s3VpcEndpoint = new GatewayVpcEndpoint(this, "s3-vpc-endpoint", new GatewayVpcEndpointProps
{
Vpc = vpc,
Service = GatewayVpcEndpointAwsService.S3
});
// 5. ECS cluster
var ecsCluster = new Cluster(this, "ecs-cluster", new ClusterProps
{
Vpc = vpc
});
// 6. ECS fargate service frontend by ALB
var albFargateService = new ApplicationLoadBalancedFargateService(this, "sample-api-service", new ApplicationLoadBalancedFargateServiceProps
{
// ----: Networking (Task Subnets) :-----
// By default, public subnets are used if assignPublicIp is set, otherwise the first available one of Private, Isolated, Public, in that order.
Cluster = ecsCluster,
DesiredCount = 1,
Cpu = 1024, // 1024 unit represents 1 vCPU (per task)
MemoryLimitMiB = 2048,
TaskImageOptions = new ApplicationLoadBalancedTaskImageOptions
{
ContainerPort = 80, // container port, automatically assigned to host port via dynamic port mapping
Image = ContainerImage.FromAsset("./src/SampleApplication.API")
},
Certificate = certificate,
DomainName = apiDomainName,
DomainZone = hostedZone,
AssignPublicIp = false
});
albFargateService.TargetGroup.ConfigureHealthCheck(new Amazon.CDK.AWS.ElasticLoadBalancingV2.HealthCheck
{
Path = "/WeatherForecast"
});
}
}
}
git clone https://github.com/aws-samples/serverless-patterns
cd serverless-patterns/route53-alb-fargate-cdk-dotnet