Tutorial: Deploy a Node.js with RDS Web Application on AWS ECS Fargate
“In the name of Allah most beneficent and merciful”
AWS ECS Fargate provides a serverless solution for running your docker container in an AWS environment. In this tutorial we will deploy our nodejs application with the help of docker and ECS. So our architecture would like this.
By the end of this demonstration the above picture would become more clear apart from the CICD part which i will cover in another article. So first thing is to have docker and aws cli installed and running on your system. Please make sure of this before moving forward.
ECR:
ECR is the registry where you save your docker images in AWS. So in order to push your application image to the ECR, we need to create a repository inside it. Go to the AWS ECR console and click Create.
Enter the repository name of your choice. One thing to remember is that your AWS account ARN is appended at the start by default. Our local application image will have the same name in order to push it to ECR which is coming up next.
Dockerfile:
In order to make a docker image of your application we need to have a dockerfile inside it. Create one according to your application environment. A sample of a Nodejs web app running node 10.x version has been given below.
One important thing to notice here is that we are using ubuntu image from the AWS public registry instead of docker hub. Because docker hub has a limitation for the number of downloads you can make from it. So after multiple iterations of your build it would give error. So always use the image from the AWS public registry.
Also add a .dockerignore file and append “node_modules” inside it.
Next build the image using the below command
docker build -t 764244323070.dkr.ecr.us-west-2.amazonaws.com/demo-app:1 .
dot at the end of above command represent that our dockerfile is in the same directory where the command is being executed, if you have yours in a different directory and then give its path instead of dot.
Notice that our image has the same name as our repository had in the ECR.
Next we need to push the image to ECR for that first we need to login into the ECR using AWS CLI. Make sure that AWS CLI is installed and configured with your AWS account. Run the below command in order to log into the ECR. Replace the AWS region and account ARN with yours.
aws ecr get-login-password — region us-west-2 | docker login — username AWS — password-stdin 764244323070.dkr.ecr.us-west-2.amazonaws.com
You will see the message “Login Succeeded” for a successful login. Now push the image to ECR using the command:
docker push 764244323070.dkr.ecr.us-west-2.amazonaws.com/demo-app:1
It will take some time depending upon the size of your application image.
Load Balancer:
Next, we need to make a load balancer that will manage and route traffic to our ECS Service Tasks.
Your load balancer would be running in public subnets of your VPC having an internet gateway attached. While the ECS Tasks would be running in private subnets allowing access to the load balancer.
A very important point to remember is that the public subnets of the load balancer and private subnets of ECS tasks should be in the same availability zones. Otherwise, your load balancer won't be able to access the ECS tasks and your tasks would be stopping/starting continuously.
In my case, I have chosen public subnets of us-west-2c and us-west-2d.
Make sure to select the target type as IP. By default Instance option is selected which is used when load balancer is being used with EC2.
Next enter the port on which you want the load balancer to route the traffic. It’s the same port on which your app runs.
Now a catch here is that the default health check path of load balancer is root or ‘/’ and if you have not handled the root route in your application then the health checks of load balancer would fail, making the ECS tasks terminating and starting over and over again.
So make sure to give a valid path for the health check which confirms that your application backend is alive.
Next, click on register targets and leave it as it is for now and click next and your load balancer will be created.
ECS
Now lets jump into setting up the ECS. ECS has four major components as shown in the picture below.
Container Definition: In this, we specify the image to be used. The one we pushed into the ECR.
Task Definition: Task is nothing but a running instance of your container. In its definition, we specify the memory and number of CPUs to allocate to the task.
Service: It serves as the environment for your tasks e.g vpc, subnets, security groups.
Cluster: It's a container for your ECS services, one cluster can have multiple services.
Task Definition
Next, we need to setup up the task definition. Go to the Task Definitions tab and click on Create.
Select Fargate as launch type.
Provide the name and Task Role. This role basically allows your tasks or application to interact with other AWS resources like RDS. In our case, our application uses RDS as a database so we need to provide a role to our task having the permission of RDS.
In our case, I have already made a role for it. You can create your own in a separate tab by going to the IAM console and adding the permissions shown below.
Click on the refresh button on the side of the Task role dropdown and select the role. Task Execution role will be selected by default, leave it as it is.
Next, you need to specify the memory and number of CPUs for your task. Keep it to the minimum as we will be adding the autoscaling to it later in the tutorial. In our case, I have set it to 2GB and 1 vCPU. Please note that you will be charged according to the amount of memory and number of CPUs you provide for your task.
Next click on Add container, here we will specify our ECR repository URI, soft limit for our container which should resemble the memory you allocated to your task previously. Add the port in the port mapping on which your app runs and is exposed in docker.
Click Add and click next and your task definition is all set up. Now with our container and task definition both ready. The next step is to configure the ECS cluster and service which will run our defined ECS Tasks.
Cluster
Go to the AWS ECS console and click on the create cluster. Next, select the template “Networking Only” which is for fargate.
Give a name of your choice but I suggest following a pattern e.g ‘appname-cluster’. Click on create and the cluster is ready.
ECS Service
Go to the clusters tab and select your newly created cluster and under the Services sub-tab, click on Create.
Select the launch type as Fargate.
Select the task definition that you created earlier from the dropdown.
Select the cluster.
Provide a name to your service and the number of tasks you want to be running at all times. In our case, I have given the value 1.
Click next and specify the VPC and subnets keeping the below point in mind.
A very important point to remember is that the public subnets of load balancer and private subnets of ECS tasks should be in same availability zones. Otherwise your load balancer wont be able to access the ECS tasks and your tasks would be stopping/starting continuously.
Select Auto-assign public ip Disabled because we are accessing our application via load balancer.
Select the load balancer from the drop down which you created at the beginning of this guide.
Health check period is set to 15 seconds which means during the cold start of your application the load balancer health checks would be ignored as the app is not ready during this time. It prevents the load balancer to stoping your task finding it unhealthy whereas during this time your app was actually starting up.
Click on the ‘Add to load balancer’ button. Select the listener port 80 and target group from the dropdown.
Click on the Next step to set up the Autoscaling on this service. Provide the minimum number of tasks you want to keep running all the time e.g 1. Desired number of tasks which is also 1 and maximum number of tasks which is actually the limit to which your tasks can autoscale e.g 200.
Select ‘Step Scaling’ in the Scaling policy type.
Next, we need to set up scale out and scale in rules. Give the name for your policy and Select create new alarm. Specify the thresholds for both of your alarms. e,g for scale out alarm, I have set the threshold of avg CPU utilization reaching above or equal to 80% in a consecutive period of 1 minute.
Next, select the actions to perform which in scale out case is to Add 1 task.
Similarly set the scale in policy.
Click next thats it your Application is finally deployed on ECS.
Few more things to do related to the security groups of your ECS service, Load balancer and RDS. Which is to allow load balancer to access the ECS service tasks and allow the ECS service to access the RDS.
First we need to edit the inbound rules for our ECS service security group. Navigate to it and select it.
Add the inbound rule for the security group of your load balancer. Your security group rules would look like shown below.
Next, we need to edit the inbound rule of our RDS security group, add a rule to allow the security group of ECS service to access the RDS.
We are all set your app should be running fine now. Hit the DNS name of your load balancer in the browser and your app should be working fine.
Troubleshooting
If your task is getting stopped by itself then according to my experience there are two major reasons for it.
1- Load balancer health checks are failing either because of the invalid health check path or port. Which makes your target unhealthy and your load balancer scheduler would terminate your task and start a new one and it will keep on doing unless the health check is successful.
2- Your Service security group does not allow the load balancer to access it. For that make sure you have added the rule for load balancer in the ECS service security group. go to the service logs and check for the errors.
For additional details, you can navigate to the ECS service logs where you can find logs for both Running and Stopped tasks.
End:
I hope you find this guide easy to understand as I have highlighted all the issues and catches I faced during this, so that you may not face those same issues. If you have any suggestions or confusion, feel free to comment.
Thanks, peace!