Package: cdk-fargate-patterns
cdk-fargate-patternsCDK patterns for serverless container with AWS FargateDualAlbFargateServiceInspired byVijay Menonfrom theAWS blog postintroduced in 2019,DualAlbFargateServiceallows you to create one or many fargate services with both internet-facing ALB and internal ALB associated with all services. With this pattern, fargate services will be allowed to intercommunicat via internal ALB while external inbound traffic will be spread across the same service tasks through internet-facing ALB.The sample below will create 3 fargate services associated with both external and internal ALBs. The internal ALB will have an alias(internal.svc.local) auto-configured from Route 53 so services can interconnect through the private ALB endpoint.# Example automatically generated from non-compiling source. May contain errors.DualAlbFargateService(stack,"Service",spot=True,# FARGATE_SPOT only clustertasks=[{"task":order_task,"desired_count":2,"external":{"port":443,"certificate":certificate},"internal":{"port":80},# customize the service autoscaling policy"scaling_policy":{"max_capacity":20,"request_per_target":1000,"target_cpu_utilization":50}},{"task":customer_task,"desired_count":2,"internal":{"port":8080}},{"task":product_task,"desired_count":2,"internal":{"port":9090}},{"task":task,"desired_count":1,"internal":{"port":50051,"certificate":[cert]},"external":{"port":50051,"certificate":[cert]},"protocol_version":elbv2.ApplicationProtocolVersion.GRPC,"health_check":{"healthy_grpc_codes":"12"}}],route53_ops={"zone_name":"svc.local","external_elb_record_name":"external","internal_elb_record_name":"internal"})DualNlbFargateServiceSimilar toDualAlbFargateService, you are allowed to deploy multiple container services with AWS Fargate as well as external NLB and internal NLB.To allowed ingress traffic, you will need to explicitly add ingress rules on theconnections:# Example automatically generated from non-compiling source. May contain errors.nlb_service=DualNlbFargateService(stack,"NLBService",tasks=[...])# we need this to allow ingress traffic from public internet only for the order servicenlb_service.service[0].connections.allow_from_any_ipv4(ec2.Port.tcp(8080))# allow from VPCnlb_service.service.for_each(s=>{s.connections.allowFrom(ec2.Peer.ipv4(nlbService.vpc.vpcCidrBlock),ec2.Port.tcp(8080));})ALB Listener Rules SupportTo share the ALB listener with multiple services, useforwardConditionsto specify custom rules.The sample below defines three services sharing a single extneral listener on HTTPS(TCP 443) with different host names while
interconnecting internally with different listeners on the internal ALB.# Example automatically generated from non-compiling source. May contain errors.DualAlbFargateService(stack,"ALBService",spot=True,# FARGATE_SPOT only clusterenable_execute_command=True,tasks=[{"task":order_task,"desired_count":2,"internal":{"port":80},"external":{"port":443,"certificate":[cert],"forward_conditions":[elbv2.ListenerCondition.host_headers(["order.example.com"])]}},{"task":customer_task,"desired_count":1,"external":{"port":443,"certificate":[cert],"forward_conditions":[elbv2.ListenerCondition.host_headers(["customer.example.com"])]},"internal":{"port":8080}},{"task":product_task,"desired_count":1,"external":{"port":443,"certificate":[cert],"forward_conditions":[elbv2.ListenerCondition.host_headers(["product.example.com"])]},"internal":{"port":9090}}])Fargate Spot SupportBy enabling thespotproperty, 100% fargate spot tasks will be provisioned to help you save up to 70%. Check more details aboutFargate Spot. This is a handy catch-all flag to force all tasks to beFARGATE_SPOTonly.To specify mixed strategy with partialFARGATEand partialFARGATE_SPOT, specify thecapacityProviderStrategyfor individual tasks like.# Example automatically generated from non-compiling source. May contain errors.DualAlbFargateService(stack,"Service",tasks=[{"task":customer_task,"internal":{"port":8080},"desired_count":2,"capacity_provider_strategy":[{"capacity_provider":"FARGATE","base":1,"weight":1},{"capacity_provider":"FARGATE_SPOT","base":0,"weight":3}]}])The custom capacity provider strategy will be applied ifcapacityProviderStretegyis specified, otherwise, 100% spot will be used whenspot: true. The default policy is 100% Fargate on-demand.Fargate Spot Termination HandlingBy default, if fargate spot capacity is available in the cluster, a fargate spot termination handler Lambda function will be created with proper IAM role policies to handle the termination event to ensure we deregister the fargate spot task from target groups gracefully. While it's a recommended feature, you may opt out withspotTerminationHandler: false.# Example automatically generated from non-compiling source. May contain errors.DualAlbFargateService(stack,"Service",spot=True,# FARGATE_SPOT only clusterspot_termination_handler=False,...)ECS ExecSimply turn on theenableExecuteCommandproperty to enable theECS Execsupport for all services.ECS deployment circuit breakerECS deployment circuit breaker automatically rolls back unhealthy service deployments without the need for manual intervention. By default this feature is enabled, you can opt out withcircuitBreaker: false. Read thedocummentationorblog postfor more details.Internal, External or BothSpecify theinternalorexternalproperty to expose your service internally, externally or both.Thecertificateproperty impliesHTTPSprotocol.# Example automatically generated from non-compiling source. May contain errors.DualAlbFargateService(stack,"Service",tasks=[{"task":task1,"internal":{"port":8080}},{"task":task2,"external":{"port":8081}},{"task":task3,"external":{"port":443,"certificate":my_acm_cert},"internal":{"port":8888}}])VPC SubnetsBy default, all tasks will be deployed in the private subnets. You will need the NAT gateway for the default route associated with the private subnets to ensure the task can successfully pull the container images.However, you are allowed to specifyvpcSubnetsto customize the subnet selection.To deploy all tasks in public subnets, one per AZ:# Example automatically generated from non-compiling source. May contain errors.DualAlbFargateService(stack,"Service",vpc_subnets={"subnet_type":ec2.SubnetType.PUBLIC,"one_per_az":True},...)This will implicitly enable theauto assign public IPfor each fargate task so the task can successfully pull the container images from external registry. However, the ingress traffic will still be balanced via the external ALB.To deploy all tasks in specific subnets:# Example automatically generated from non-compiling source. May contain errors.DualAlbFargateService(stack,"Service",vpc_subnets={"subnets":[ec2.Subnet.from_subnet_id(stack,"sub-1a","subnet-0e9460dbcfc4cf6ee"),ec2.Subnet.from_subnet_id(stack,"sub-1b","subnet-0562f666bdf5c29af"),ec2.Subnet.from_subnet_id(stack,"sub-1c","subnet-00ab15c0022872f06")]},...)Import an existing Cluster!!! Before using an existingECS Cluster, please make sure you have the following:see :Adding Fargate capacity providers to an existing cluster# Example automatically generated from non-compiling source. May contain errors.vpc=ec2.Vpc.from_lookup(stack,"defVpc",is_default=True)sg=ec2.SecurityGroup(stack,"demo-sg",vpc=vpc)exist_cluster=ecs.Cluster.from_cluster_attributes(stack,"existCluster",security_groups=[sg],cluster_name="existCluster",vpc=vpc)DualAlbFargateService(stack,"Service",enable_execute_command=True,cluster=exist_cluster,tasks=[{"task":nginx,"desired_count":1,"external":{"port":80},"capacity_provider_strategy":[{"capacity_provider":"FARGATE_SPOT","weight":1}]}])Sample ApplicationThis repository comes with a sample applicaiton with 3 services in Golang. On deployment, theOrderservice will be exposed externally on external ALB port80and all requests to theOrderservice will trigger sub-requests internally to another other two services(productandcustomer) through the internal ALB and eventually aggregate the response back to the client.DeployTo deploy the sample application in you default VPC://installfirst
$yarninstall
//compilethetstojs
$yarnbuild
$npxcdk--applib/integ.default.js-cuse_default_vpc=1diff
$npxcdk--applib/integ.default.js-cuse_default_vpc=1deployTo deploy with HTTPS-only with existing ACM certificate in your default VPC:$npxcdk--applib/integ.default.jsdeploy-cuse_default_vpc=1-cACM_CERT_ARN=<YOUR_ACM_CERT_ARN>On deployment complete, you will see the external ALB endpoint in the CDK output.cURLthe external HTTP endpoint and you should be able to see the aggregated response.$curlhttp://demo-Servi-EH1OINYDWDU9-1397122594.ap-northeast-1.elb.amazonaws.com
or
$curlhttps://<YOUR_CUSTOM_DOMAIN_NAME>{"service":"order","version":"1.0"}{"service":"product","version":"1.0"}{"service":"customer","version":"1.0"}WordPressUse theWordPressconstruct to create a serverlessWordPressservice with AWS Fargate, Amazon EFS filesystem and Aurora serverless database. All credentials auto generated from theAWS Secret Managerand securely inject the credentials into the serverless container with the auto generated IAM task execution role.# Example automatically generated from non-compiling source. May contain errors.WordPress(stack,"WP",aurora_serverless=True,spot=True,enable_execute_command=True)LaravelTheLaravlconstruct is provided as a high-level abstraction that allows you to create a modern Laravel environment running onAWS FargateandAmazon Aurora Serverless. Here comes two variants as the reference:laravel-bitnami- based onbitnami/laravelwithartisanrunning as the built-in web server.laravel-nginx-php-fpm- laravel with nginx and php-fpm maintained byErnest Chiang.Simply pointcodeto your local Laravel codebase and it takes care everything else for you.Samples# Example automatically generated from non-compiling source. May contain errors.## laravel-bitnami#Laravel(stack,"LaravelBitnamiDemo",aurora_serverless=True,spot=True,enable_execute_command=True,code=path.join(__dirname,"../services/laravel-bitnami"),container_port=3000,loadbalancer={"port":80})## laravel-nginx-php-fpm#Laravel(stack,"LaravelNginxDemo",aurora_serverless=True,spot=True,enable_execute_command=True,code=path.join(__dirname,"../services/laravel-nginx-php-fpm"),loadbalancer={"port":80})Seeinteg.laravel.tsfor the full code sample.Local development and testingThedocker-compose.ymlis provided with all sample services in the repository. To bring up all services locally, run:$cdservices
$dockercomposeupUsecURLto test locally:curl http://localhostResponse:{"service":"order","version":"1.0"}
{"service":"product","version":"1.0"}
{"service":"customer","version":"1.0"}FAQQ: What is the difference betweencdk-fargate-patternsandaws-ecs-patterns?A:aws-ecs-patternscomes with a few patterns around Amazon ECS with AWS Fargate or AWS EC2 and focuses on some scenarios with single service and single ELB likeApplicationLoadBalancedFargateServiceandNetworkLoadBalancedFargateService. However,cdk-fargate-patternsis trying to explore use cases on modern application which usually comes with multiple container services grouped as a deployment with inter-service connectivity as well as ingress traffic from external internet by seperating the internal ELB from the external one.Contributors ✨Thanks goes to these wonderful people (emoji key):Neil Kuan🎨💻⚠️💡Ernest Chiang🤔⚠️💻💡Clarence💡💻paper5487🐛Peter Larsson🤔LeoChien-SC🐛This project follows theall-contributorsspecification. Contributions of any kind welcome!