Deploying applications to ECS Fargate with AWS CDK
What is ECS fargate?
ECS stands for Elastic Container Service and is an AWS product that allows you to quickly deploy and run docker containers. It can be used to either run tasks intermittently or to replace the standard instance server setup traditionally used. In this article we will be looking at deploying a traditional express API to ECS, but if you are interested in deploying individual tasks check my previous article here.
What is AWS CDK?
CDK stands for Cloud Development Kit and essentially provides the ability to dynamically create Cloud Formation templates with the coding language of your choice, providing greater functionality then just using the default static JSON/YML options.
The image below gives an overview of what we are going to create using CDK.
Virtual Private Cloud (VPC) - used to provision resources with a virtual private network to provide greater control over access and security of resources. This section will essentially create the following:
- Private subnets - to block internet access
- Public subnets - allows internet access
- Security groups - allows you to provide connections between resources in the VPC, e.g. allow the load balancer to access Fargate containers
This section provisions all the resources needed to allow someone outside the VPC to connect to the API via a secured domain name.
- Application load balancer - balances traffic between ECS instances and provides a static IP address for Cloudfront to target
- Cloudfront with WAF for caching and extra security
- Route53 and Certificate manager for creating a nice SSL domain
Application Load Balancer
ECS Fargate is serverless which means the containers don't have a static IP address for the load balancer to target. Instead, we create something called a target group. The containers get deployed to this group which makes their IP address discoverable by the load balancer. In this section we create the following resources:
- A Target group for containers to be deployed to
- A Health check used to ensure the container was deployed correctly
- A listener for any requests on port 443 (HTTPS)
This final section creates all the resources in ECS and connects them to the application load balancer. It creates the following resources:
- An ECS cluster for all containers to be deployed in
- A Service responsible for deploying ECS tasks (with autoscaling based on resources)
- Fargate task definitions to store the configuration for spinning up ECS containers and defines the amount of resource each task can use
- An IAM role assumed by the containers to give role-based access to other AWS resources
Phew, that's everything! Now all that's left to do is to deploy all this using the CDK. So that was quite a lot of configuration one might argue, so what's the benefit of using CDK to deploy stacks like this?
While this is a lot of configuration, if you were to do this same stack with a Cloudformation YML template it would be around 500 lines long! The full stack here is approximately 200 lines long which is far more manageable.
If you were to try to deploy this stack without CDK or Cloud formation you would need to create over 30 resources within the AWS console remembering at each stage how to connect one to the other. This becomes an issue when potentially months later you come back to make a change and need to spend time figuring out how everything works. The code for a CDK stack can therefore also act as documentation of the project's architecture.
Secondly, CDK is using standard programming to build the stack meaning you can add extra layers of functionality. Add custom validation on resources or even load dynamic variables into your stack from external sources.
Lastly, when you deploy with CDK or Cloud formation your deployments are much safer. If one part of the process fails AWS rolls back all the changes to the stack reducing downtime to a minimum (normally none at all).
This article was getting a little long so I didn't include the database as shown in the diagram. In this repository, though, you can check out the full stack where I have included an RDS database deployment. I have also parametrised a lot of the configuration to make the stack more re-usable across projects.