Deploy ECS Fargate API With ALB: A Terraform Guide

by Alex Johnson 51 views

In this comprehensive guide, we'll walk through the process of deploying an ECS Fargate API service behind an Application Load Balancer (ALB) using Terraform. This setup is crucial for creating scalable, resilient, and easily maintainable applications. We will cover everything from defining a reusable Terraform module to configuring health checks and ensuring proper network access.

Summary

Our primary goal is to create an ECS Fargate service that runs the CloudPulse API, fronted by an internet-facing Application Load Balancer (ALB). The ECS service will reside in the private subnets of an existing VPC, while the ALB will be placed in the public subnets. Health checks will be configured on the /health endpoint to ensure the API's availability and responsiveness.

Goals

  • Define a reusable Terraform module for the CloudPulse API service on ECS Fargate.
  • Front the service with an Application Load Balancer (ALB) in public subnets.
  • Run ECS tasks in private subnets using the existing VPC module outputs.
  • Send container logs to CloudWatch Logs for monitoring and debugging.
  • Make the container image configurable (no hardcoded ECR URI) to promote flexibility and reusability.

Deliverables

To achieve these goals, we will create the following:

  • infra/modules/ecs_api/:
    • main.tf: This file will contain the main Terraform configuration for the ECS Fargate service.
    • variables.tf: This file will define the input variables for the module.
    • outputs.tf: This file will define the output values of the module.
  • infra/envs/dev/main.tf updated to call:
    • existing vpc module
    • new ecs_api module

Architecture

The architecture of our deployment will consist of the following components:

  • ECS Fargate cluster and service: This will manage the deployment and scaling of our containerized application.
  • Task definition for cloudpulse-api container:
    • CPU/memory: small (e.g., 256 / 512) to optimize resource utilization.
    • Container port: 8080 for the API to listen on.
    • Health check path: /health for ALB to monitor the API's health.
    • Logs to CloudWatch Logs for centralized logging.
  • ALB:
    • Internet-facing to allow public access.
    • Listens on port 80 for incoming HTTP requests.
    • Target group with IP targets and health checks on /health.
    • Security group allowing HTTP from the internet.
  • ECS tasks:
    • Placed in private subnets for enhanced security.
    • Security group allows inbound from ALB security group only.
    • Outbound access via NAT gateway for external calls (HTTPS, etc.).

Acceptance Criteria

To ensure our deployment meets the required standards, we will verify the following:

  • terraform plan in infra/envs/dev shows ECS + ALB resources and no errors.
  • ECS tasks are placed in private subnets.
  • ALB is placed in public subnets.
  • Target group health checks use /health on the API port.
  • Module exposes:
    • ALB DNS name for accessing the API.
    • ECS service name/ARN (for reference).
  • Container image is provided via a variable (no hardcoded ECR URI).

Step-by-Step Implementation

1. Define the ECS API Module

First, we'll create a reusable Terraform module for the CloudPulse API service. This involves creating the necessary files (main.tf, variables.tf, and outputs.tf) within the infra/modules/ecs_api/ directory.

infra/modules/ecs_api/main.tf

This file contains the core logic for creating the ECS cluster, task definition, service, and ALB. It also sets up the necessary security groups and CloudWatch Logs configuration. Let's dive deeper into each of these components.

  • ECS Cluster: The ECS cluster is the foundation for running our containerized applications. We define the cluster with a name and configure any necessary settings, such as container insights for monitoring.
  • Task Definition: The task definition specifies the container image, CPU and memory requirements, port mappings, and health check configuration. This is where we define the cloudpulse-api container and set the /health endpoint for health checks.
  • ECS Service: The ECS service manages the deployment and scaling of our tasks. It ensures that the desired number of tasks are running and integrates with the ALB for load balancing. We configure the service to use the task definition and place tasks in the private subnets.
  • Application Load Balancer (ALB): The ALB acts as the entry point for incoming traffic. We configure it to listen on port 80 and forward requests to the ECS tasks. The ALB also performs health checks on the /health endpoint to ensure that only healthy tasks receive traffic.
  • Security Groups: Security groups control the inbound and outbound traffic to our resources. We create security groups for the ALB and ECS tasks, allowing HTTP traffic from the internet to the ALB and restricting traffic to the ECS tasks to only come from the ALB.
  • CloudWatch Logs: CloudWatch Logs provides a centralized logging solution for our containers. We configure the task definition to send logs to CloudWatch Logs, making it easier to monitor and debug our application.

infra/modules/ecs_api/variables.tf

This file defines the input variables for the module. These variables allow us to customize the deployment without modifying the core module code. Some key variables include:

  • vpc_id: The ID of the existing VPC.
  • public_subnet_ids: A list of public subnet IDs for the ALB.
  • private_subnet_ids: A list of private subnet IDs for the ECS tasks.
  • container_image: The URI of the container image to deploy.
  • cpu: The amount of CPU to allocate to each task.
  • memory: The amount of memory to allocate to each task.
  • desired_count: The number of tasks to run.

infra/modules/ecs_api/outputs.tf

This file defines the output values of the module. These outputs provide information about the deployed resources, such as the ALB DNS name and ECS service ARN. These outputs can be used by other Terraform modules or scripts.

  • alb_dns_name: The DNS name of the Application Load Balancer.
  • ecs_service_name: The name of the ECS service.
  • ecs_service_arn: The ARN of the ECS service.

2. Update infra/envs/dev/main.tf

Next, we need to update the infra/envs/dev/main.tf file to call the new ecs_api module and pass in the necessary variables. This involves retrieving the VPC module outputs and configuring the container image, CPU, memory, and desired task count.

  • Retrieve VPC Outputs: Use the terraform_remote_state data source to retrieve the VPC ID, public subnet IDs, and private subnet IDs from the existing VPC module.
  • Call the ecs_api Module: Add a module block to call the ecs_api module and pass in the retrieved VPC outputs, container image URI, CPU, memory, and desired task count.

3. Configure Security Groups

Ensure that the security groups are configured correctly to allow traffic to flow between the ALB and ECS tasks. The ALB security group should allow HTTP traffic from the internet, while the ECS task security group should allow inbound traffic only from the ALB security group.

  • ALB Security Group: Allow HTTP (port 80) traffic from the internet.
  • ECS Task Security Group: Allow inbound traffic from the ALB security group on port 8080.

4. Deploy with Terraform

Finally, we can deploy our infrastructure using Terraform. Run terraform init to initialize the Terraform environment, followed by terraform plan to review the changes, and terraform apply to apply the changes.

  • terraform init: Initializes the Terraform environment and downloads the necessary providers and modules.
  • terraform plan: Generates an execution plan, showing the changes that Terraform will make to your infrastructure.
  • terraform apply: Applies the changes defined in the execution plan, creating the ECS Fargate service and ALB.

5. Verify the Deployment

After the deployment is complete, verify that the ECS tasks are running in the private subnets, the ALB is in the public subnets, and the target group health checks are passing on the /health endpoint. You can also check the CloudWatch Logs to ensure that the container logs are being captured.

  • ECS Tasks in Private Subnets: Verify that the ECS tasks are running in the private subnets by checking the ECS console or using the AWS CLI.
  • ALB in Public Subnets: Verify that the ALB is in the public subnets by checking the ALB configuration in the EC2 console.
  • Health Checks Passing: Verify that the target group health checks are passing on the /health endpoint by checking the ALB target group configuration in the EC2 console.
  • CloudWatch Logs: Verify that the container logs are being captured in CloudWatch Logs by checking the CloudWatch console.

Conclusion

By following these steps, you can successfully deploy an ECS Fargate API service behind an Application Load Balancer using Terraform. This setup provides a scalable, resilient, and easily maintainable infrastructure for your applications. Remember to monitor your application's performance and logs to ensure it is running smoothly.

For more information on ECS Fargate and Application Load Balancers, check out the official AWS documentation. This documentation provides in-depth information and best practices for using these services.