DEV Community

Tanvir Ahmed
Tanvir Ahmed

Posted on

Best Practices for ECS Deployment Using Terraform

Deploying ECS services using Terraform allows you to maintain a modular, reusable, and parameter-driven infrastructure. In this guide, we will focus on creating and reusing ECS task definitions, configuring services, and integrating other AWS components effectively with Terraform.

Problem Statement

Creating a robust ECS deployment often involves repetitive configurations and complex setups. By utilizing Terraform, you can:

  • Simplify the creation of reusable ECS task definitions.
  • Pass dynamic variables to tasks and services.
  • Seamlessly integrate with other AWS services like Secrets Manager and CloudWatch.

Terraform-Based ECS Deployment

Key Components

  1. ECS Task Definitions

    • Define container settings (CPU, memory, image, etc.).
    • Use variables to make definitions reusable across multiple services.
  2. ECS Services

    • Manage the number of tasks, scaling policies, and integration with ALBs.
  3. AWS Services Integration

    • Connect to Secrets Manager for sensitive data.
    • Enable CloudWatch logging and metrics.

Step 1: Reusable Task Definition

Define a parameterized task definition in Terraform:

resource "aws_ecs_task_definition" "app" {
  family                   = var.task_family
  container_definitions    = jsonencode([
    {
      name              = "${var.container_name}"
      image             = "${var.container_image}"
      cpu               = var.cpu
      memory            = var.memory
      essential         = true
      environment       = var.environment_variables
      logConfiguration  = {
        logDriver = "awslogs"
        options   = {
          "awslogs-group"         = var.log_group
          "awslogs-region"        = var.region
          "awslogs-stream-prefix" = var.log_stream_prefix
        }
      }
    }
  ])
  requires_compatibilities = ["FARGATE"]
  network_mode             = "awsvpc"
  execution_role_arn       = aws_iam_role.ecs_task_execution.arn
  task_role_arn            = aws_iam_role.ecs_task.arn
  cpu                      = var.task_cpu
  memory                   = var.task_memory
}

Enter fullscreen mode Exit fullscreen mode

Variables for Flexibility

Define variables to make the task definition reusable:

variable "task_family" {}
variable "container_name" {}
variable "container_image" {}
variable "cpu" {}
variable "memory" {}
variable "environment_variables" { type = list(map(string)) }
variable "log_group" {}
variable "region" {}
variable "log_stream_prefix" {}
variable "task_cpu" {}
variable "task_memory" {}
Enter fullscreen mode Exit fullscreen mode

Step 2: Configuring ECS Service

Define a service resource and pass the task definition dynamically:

resource "aws_ecs_service" "app" {
  name            = var.service_name
  cluster         = aws_ecs_cluster.main.id
  task_definition = aws_ecs_task_definition.app.arn

  desired_count   = var.desired_count
  launch_type     = "FARGATE"

  network_configuration {
    subnets         = var.subnets
    security_groups = [aws_security_group.app.id]
    assign_public_ip = true
  }

  load_balancer {
    target_group_arn = aws_lb_target_group.app.arn
    container_name   = var.container_name
    container_port   = var.container_port
  }

  depends_on = [aws_lb_listener.frontend]
}
Enter fullscreen mode Exit fullscreen mode

Step 3: Parameterized Variables for ECS Service

Define variables for the service:

variable "service_name" {}
variable "desired_count" {}
variable "subnets" { type = list(string) }
variable "container_port" {}`

### Step 4: Secrets Manager Integration

To securely manage environment variables:

`resource "aws_secretsmanager_secret" "app_secret" {
  name = var.secret_name
}

resource "aws_secretsmanager_secret_version" "app_secret_version" {
  secret_id     = aws_secretsmanager_secret.app_secret.id
  secret_string = jsonencode(var.secret_values)
}

variable "secret_name" {}
variable "secret_values" { type = map(string) }
Enter fullscreen mode Exit fullscreen mode

Pass secrets as environment variables in the task definition:

environment = [
  {
    name = "SECRET_KEY"
    valueFrom = aws_secretsmanager_secret.app_secret.arn
  }
]
Enter fullscreen mode Exit fullscreen mode

Step 5: Outputs for Reusability

Define outputs for task definition and service:

output "task_definition_arn" {
  value = aws_ecs_task_definition.app.arn
}

output "service_name" {
  value = aws_ecs_service.app.name
}
Enter fullscreen mode Exit fullscreen mode

Best Practices

  1. Use Modules: Organize your Terraform code into reusable modules.

  2. Version Locking: Use version constraints for Terraform providers.

  3. State Management: Use remote state storage (e.g., S3 with DynamoDB locking).

  4. Parameter Store: Integrate with SSM Parameter Store for dynamic configurations.

Conclusion

By parameterizing ECS task definitions and services in Terraform, you can create a scalable, reusable, and efficient infrastructure. This approach not only reduces duplication but also enhances the flexibility of your deployments, enabling rapid adaptation to new requirements.

Hostinger image

Get n8n VPS hosting 3x cheaper than a cloud solution

Get fast, easy, secure n8n VPS hosting from $4.99/mo at Hostinger. Automate any workflow using a pre-installed n8n application and no-code customization.

Start now

Top comments (0)

Qodo Takeover

Introducing Qodo Gen 1.0: Transform Your Workflow with Agentic AI

Rather than just generating snippets, our agents understand your entire project context, can make decisions, use tools, and carry out tasks autonomously.

Read full post