Node.js Application to AWS ECS Fargate with GitHub Actions

Node.js Application to AWS ECS Fargate with GitHub Actions

In this article, we will walk you through the process of automating the deployment of a Node.js application to AWS ECS Fargate using GitHub Actions. This workflow streamlines the development and deployment process, making it easier to release updates to your application.

In this article, we will walk you through the process of automating the deployment of a Node.js application to AWS ECS Fargate using GitHub Actions. This workflow streamlines the development and deployment process, making it easier to release updates to your application.

GitHub Actions

GitHub Actions is a powerful automation platform provided by GitHub, the popular version control and collaboration platform. It enables you to automate your software development workflows directly within your GitHub repository. With GitHub Actions, you can create custom workflows to build, test, and deploy your code whenever specific events occur, such as pushes to a repository, pull requests, or issues being opened.

Key features of GitHub Actions include:

  • Event-Driven Automation: You can trigger actions in response to events in your GitHub repository, making it easy to automate tasks like building and deploying code.

  • Custom Workflows: Create tailored workflows by defining steps that can run tasks, tests, and deployment processes.

  • Extensive Marketplace: GitHub Actions offers a wide range of pre-built actions and workflows available in the GitHub Marketplace, making it easy to integrate with various services and technologies.

  • Secrets Management: You can securely store and manage sensitive information like API keys and access tokens using GitHub Secrets.

AWS ECS Fargate

AWS Elastic Container Service (ECS) Fargate is a serverless container orchestration service offered by Amazon Web Services (AWS). It allows you to run Docker containers without managing the underlying infrastructure. ECS Fargate is particularly useful for deploying containerized applications, such as microservices, web applications, and batch jobs.

Key features of AWS ECS Fargate include:

  • Serverless Computing: You don’t need to provision or manage virtual machines; AWS takes care of the infrastructure for you.

  • Scalability: ECS Fargate can automatically scale the number of containers running your application based on defined criteria.

  • Cost Efficiency: You only pay for the resources you use, making it cost-effective for both small and large-scale applications.

  • Easy Integration: ECS Fargate integrates seamlessly with other AWS services, such as Elastic Load Balancing, Amazon RDS, and AWS Identity and Access Management (IAM).

  • Security and Isolation: AWS ensures security and isolation of containers, making it suitable for hosting production applications.

Advantages of Automating Deployment with GitHub Actions and ECS Fargate

Now that we’ve covered the basics, let’s explore the advantages of automating your Node.js application deployment using GitHub Actions and AWS ECS Fargate:

  1. Streamlined Workflow: GitHub Actions allows you to create a custom deployment workflow tailored to your application’s needs. This workflow streamlines the process of building, testing, and deploying your code, reducing the potential for manual errors.

  2. Consistency: Automated deployments ensure that each new version of your application is deployed consistently, regardless of the developer responsible. This consistency is crucial for maintaining the integrity of your application.

  3. Cost Efficiency: ECS Fargate’s serverless nature means you only pay for the container resources you use. Combined with GitHub Actions’ free tier for public repositories, this approach can be cost-efficient for many development teams.

  4. Scalability: ECS Fargate can scale your application based on predefined criteria, ensuring it can handle changes in traffic and demand. This scalability can improve your application’s performance and availability.

  5. Security: AWS provides robust security features, and ECS Fargate benefits from AWS’s security posture. You can control access, permissions, and security settings using AWS Identity and Access Management (IAM).

  6. Continuous Integration/Continuous Deployment (CI/CD): GitHub Actions can be integrated into a CI/CD pipeline, enabling you to automatically build and deploy changes as they are pushed to your repository. This leads to faster release cycles and quicker response to issues.

Prerequisites

Before you start the deployment process, ensure that you have the following:

  1. AWS Account: You need an AWS account. If you don’t have one, you can sign up for an account on the AWS website.

  2. Node.js Application: Create a Node.js application or use an existing one. Make sure your application has a Dockerfile for containerization.

  3. GitHub Repository: Create a new GitHub repository for your Node.js application.

  4. Set up an ECS Fargate cluster and a task definition for your Node.js application.

  5. Create an ECR (Elastic Container Registry) repository to store your Docker images.

Steps

Step-1: Create the ECR repository to store the docker image

  1. Open the Amazon ECR console at https://console.aws.amazon.com/ecr/.

  2. Choose Get Started.

  3. For Visibility settings, choose Private or Public according to your need

  4. For Repository name, specify a name for the repository.

  5. For Tag immutability, choose the tag mutability setting for the repository. Repositories configured with immutable tags will prevent image tags from being overwritten.

  6. For Scan on push, choose the image scanning setting for the repository. Repositories configured to scan on push will start an image scan whenever an image is pushed, otherwise image scans need to be started manually.

  7. For KMS encryption, choose whether to enable server-side encryption using AWS KMS keys stored in the AWS Key Management Service service.

  8. Choose Create repository.

Step-2: Create the AWS ECS Fargate serverless Cluster

  1. Open the console at https://console.aws.amazon.com/ecs/v2.

  2. From the navigation bar, select the Region to use.

  3. In the navigation pane, choose Clusters.

  4. On the Clusters page, choose Create Cluster.

  5. Under Cluster configuration, configure the following: For Cluster name, enter a unique name. (Optional) To have the namespace used for Service Connect be different from the cluster name, for Namespace, enter a unique name.

  6. Under Infrastructure, choose AWS Fargate (serverless), there you will also get the option to select External instances using ECS Anywhere and Amazon EC2 instances.

  7. (Optional) To turn on Container Insights, expand Monitoring, and then turn on Use Container Insights.

  8. (Optional) To help identify your cluster, expand Tags, and then configure your tags. Choose Add tag and do the following: For Key, enter the key name. For Value, enter the key value.

  9. Choose Create.

Step-3: Create ECS task definition role

  1. On the navigation pane https://console.aws.amazon.com/iam/, choose Roles.

  2. Choose Create role.

  3. Under the Trusted Entity Type choose AWS Service.

  4. Under Use case, search for Elastic Container Service, then choose Elastic Container Service Task, then choose Next: Permissions.

  5. In the search box, enter the name of the policy ECS. Then select the box to the left of the policy named AmazonECSTaskExecutionRolePolicy.

  6. In Role details, for the role name, enter a descriptive name, such as ECSTaskExecutionRole and some description.

  7. Choose Next: Tags.

  8. Choose Next: Review.

  9. Choose Create role.

Step-4 Create a Task Definition in ECS

  1. Open the console at https://console.aws.amazon.com/ecs/v2.

  2. In the navigation pane, choose Task definitions.

  3. On the Create new task definition menu, choose Create new task definition.

  4. For Task definition family, specify a unique name for the task definition.

  5. For Launch type, choose the application environment. The console default is AWS Fargate (which is serverless). Amazon ECS uses this value to perform validation to ensure that the task definition parameters are valid for the infrastructure type.

  6. For Operating system/Architecture, choose the operating system and CPU architecture for the task. To run your task on a 64-bit ARM architecture, choose Linux/ARM64. To run your AWS Fargate tasks on Windows containers, choose a supported Windows operating system.

  7. For Task size, choose the CPU and memory values to reserve for the task. The CPU value is specified as vCPUs and memory is specified as GB.

  8. (Optional) Expand the Task roles section to configure the AWS Identity and Access Management (IAM) roles for the task: For Task role, choose the IAM role to assign to the task. A task IAM role provides permissions for the containers in a task to call AWS API operations. For Task execution role, choose the role.

  9. For each container to define in your task definition, complete the following steps. For Name, enter a name for the container. For Image URI, enter the image repo URI to use to start a container. For Essential container, if your task definition has two or more containers defined, you can specify whether the container should be considered essential. When a container is marked as Essential, if that container stops, then the task is stopped. Each task definition must contain at least one essential container. A port mapping allows the container to access ports on the host to send or receive traffic. Under Port mappings, do one of the following: When you use the awsvpc network mode, for Container port and Protocol, choose the port mapping to use for the container. When you use the bridge network mode, for Container port and Protocol, choose the port mapping to use for the container. Choose Add more port mappings to specify additional container port mappings.

  10. (Optional) Expand the Tags section to add tags, as key-value pairs, to the task definition. Choose Add tag, and then do the following: For Key, enter the key name. For Value, enter the key value.

  11. Choose Create to register the task definition.

Step-5: Create an Application Load Balancer and Target Group

To configure your target group

  1. Open the Amazon EC2 console at https://console.aws.amazon.com/ec2/.

  2. In the navigation pane, under Load Balancing, choose Target Groups.

  3. Choose Create target group.

  4. Under Basic configuration, keep the Target type as IP addresses.

  5. For Target group name, enter a name for the new target group.

  6. Keep the default protocol (HTTP) and port (3000).

  7. Keep the IP address type as IPv4.

  8. Select the VPC containing your instances. Keep the protocol version as HTTP1.

  9. For Health checks, keep the default settings.

  10. Choose Next.

  11. On the Register targets page, complete the following steps. This is an optional step for creating the load balancer. However, right now we do not have any targets to attach, so we leave it by default and can add targets afterwards.For Available instances, select one or more instances.Keep the default port 80, and choose Include as pending below.

  12. Choose Create target group.

To create a Application Load Balancer

  1. Open the Amazon EC2 console at https://console.aws.amazon.com/ec2/.

  2. On the navigation bar, choose a Region for your load balancer. Be sure to choose the same Region that you used for your EC2 instances.

  3. In the navigation pane, under Load Balancing, choose Load Balancers.

  4. Choose Create Load Balancer.

  5. For Application Load Balancer, choose Create.

  6. For Load balancer name, enter a name for your load balancer. For example, Nodejs-app-lb.

  7. For Scheme and IP address type, keep the default values.

  8. For Network mapping, select the VPC that you used for your ECS Fargate. Select at least two Availability Zones and one subnet per zone. For each Availability Zone that you used to launch your ECS Fargate, select the Availability Zone and then select one public subnet for that Availability Zone.

  9. For Security groups, we select the default security group for the VPC that you selected in the previous step. You can choose a different security group instead. The security group must include rules that allow the load balancer to communicate with registered targets on both the listener port and the health check port.

  10. For Listeners and routing, keep the default protocol and port, and select your target group from the list. This configures a listener that accepts HTTP traffic on port 80 and forwards traffic to the selected target group by default.

  11. (Optional) Add a tag to categorize your load balancer. Tag keys must be unique for each load balancer. Allowed characters are letters, spaces, numbers (in UTF-8), and the following special characters: + - = . _ : / @. Do not use leading or trailing spaces. Tag values are case-sensitive.

  12. Review your configuration, and choose Create load balancer. A few default attributes are applied to your load balancer during creation. You can view and edit them after creating the load balancer.

Right now we do not have any targets to attach, so we leave it by default and can add targets afterwards.

Step-6: Create the service in the ECS cluster

  1. Open the console at https://console.aws.amazon.com/ecs/v2.

  2. In the navigation page, choose Clusters.

  3. On the Clusters page, choose the cluster to create the service in.

  4. From the Services tab, choose Create.

  5. Under Deployment configuration, specify how your application is deployed.For Application type, choose Service.For Task definition, choose the task definition family and revision to use.For Service name, enter a name for your service. For example nodejs-app-service.For Desired tasks, enter the number of tasks to launch and maintain in the service.

  6. (Optional) To help identify your service and tasks, expand the Tags section, and then configure your tags.To have Amazon ECS automatically tag all newly launched tasks with the cluster name and the task definition tags, select Turn on Amazon ECS managed tags, and then select Task definitions.To have Amazon ECS automatically tag all newly launched tasks with the cluster name and the service tags, select Turn on Amazon ECS managed tags, and then select Service.

  7. Add or remove a tag.Choose Add tag, and then do the following:For Key, enter the key name.For Value, enter the key value.

Now our task will fail as there is no image present in the ECR Repository.

Step-7: Build the Node.JS app docker image through the GitHub Action and push it to ECR

Create a Secret in the GitHub Repository for the Access key and a Secret key.

In your GitHub repository, go to “Settings” > “Secrets” and add secrets for your AWS access keys and any other sensitive information needed for deployment.

Create the Task Definition file in the GitHub Repository.

Define an ECS task using a JSON file (e.g., nodejs-app-def-revision1.json) specifying the container image, ports, and other configuration details.

Create the workflow file for GitHub Action.

Create a GitHub Actions workflow YAML file (e.g., nodejs-app-workflow.yml) in the github/workflows directory.

Define your workflow to automate the deployment process. This involves steps to build the Docker image, push it to ECR, change the Task Definition with lastest image, and deploy it to ECS Fargate. Here’s a simplified example:

Link for my GitHub Repository: github.com/shub6059/Nodejs-app

Here is the complete code for the workflow file.

name: CICD

on:

push:

branches:

- main

jobs:

build-and-deploy:

runs-on: [ ubuntu-latest ]

steps:

- name: Checkout source

uses: actions/checkout@v3

- name: Configure AWS credentials

uses: aws-actions/configure-aws-credentials@v3

with:

aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY }}

aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}

aws-region: <your-aws-region>

- name: Login to Amazon ECR

id: login-ecr

uses: aws-actions/amazon-ecr-login@v1

with:

mask-password: 'true'

- name: Build, tag, and push image to Amazon ECR

id: build-image

env:

ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}

IMAGE_TAG: ${{ github.sha }}

REPOSITORY: <your-ecr-repo>

run: |

docker build -t $ECR_REGISTRY/$REPOSITORY:$IMAGE_TAG .

docker push $ECR_REGISTRY/$REPOSITORY:$IMAGE_TAG

echo "image=$ECR_REGISTRY/$REPOSITORY:$IMAGE_TAG" >> $GITHUB_OUTPUT

- name: Fill in the new image ID in the Amazon ECS task definition

id: task-def

uses: aws-actions/amazon-ecs-render-task-definition@v1

with:

task-definition: nodejs-app-task-definition.json

container-name: <your-container-name>

image: ${{ steps.build-image.outputs.image }}

- name: Deploy Amazon ECS task definition

uses: aws-actions/amazon-ecs-deploy-task-definition@v1

with:

task-definition: ${{ steps.task-def.outputs.task-definition }}

service: <your-service>

cluster: <your-cluster>

wait-for-service-stability: true

Replace placeholders like <your-aws-region>, <your-container-name>, <your-ecr-repo>, <your-cluster>, and <your-service> with your AWS-specific values.

Push to GitHub

Commit and push the GitHub Actions workflow file (nodejs-app-workflow.yml) and your Node.js application code to your GitHub repository.

Push the changes to the main branch or the feature branch you have created, I’m pushing the changes to the main branch only.

Verify Deployment

Once the workflow is triggered (e.g., on a push to the main branch), check the Actions tab in your GitHub repository to monitor the deployment process.

Once workflow is successful go to your task configuration in the aws console.

Copy the Application Load Balancer URL and paste in a browser to test if application is working.

We have successfully deployed the Nodejs app in ECS fargate.