Skip to main content
This guide walks you through deploying a working ECS cluster with a Fargate service using the integrated root module. The cluster will run a sample frontend container with Fargate on-demand and Fargate Spot capacity providers.

Prerequisites

  • Terraform >= 1.5.7 installed (install guide)
  • AWS credentials configured in your environment (AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY, or an IAM role via instance profile / SSO)
  • Existing VPC and subnets — you need subnet IDs to place your ECS tasks
Running this configuration creates real AWS resources that incur charges. Run terraform destroy when you no longer need the cluster.

Steps

1

Configure the AWS provider

Create a versions.tf file to pin the provider versions required by the module:
terraform {
  required_version = ">= 1.5.7"

  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = ">= 6.34"
    }
  }
}

provider "aws" {
  region = "us-east-1"
}
2

Deploy an ECS cluster with a Fargate service

Create a main.tf with the integrated root module. This configuration creates a cluster with Fargate on-demand and Fargate Spot capacity providers, and deploys a service with two containers: a FluentBit sidecar for log forwarding and the application container.
module "ecs" {
  source = "terraform-aws-modules/ecs/aws"

  cluster_name = "ecs-integrated"

  cluster_configuration = {
    execute_command_configuration = {
      logging = "OVERRIDE"
      log_configuration = {
        cloud_watch_log_group_name = "/aws/ecs/aws-ec2"
      }
    }
  }

  # Cluster capacity providers
  cluster_capacity_providers = ["FARGATE", "FARGATE_SPOT"]
  default_capacity_provider_strategy = {
    FARGATE = {
      weight = 50
      base   = 20
    }
    FARGATE_SPOT = {
      weight = 50
    }
  }

  services = {
    ecsdemo-frontend = {
      cpu    = 1024
      memory = 4096

      # Container definition(s)
      container_definitions = {

        fluent-bit = {
          cpu       = 512
          memory    = 1024
          essential = true
          image     = "906394416424.dkr.ecr.us-west-2.amazonaws.com/aws-for-fluent-bit:stable"
          firelensConfiguration = {
            type = "fluentbit"
          }
          memoryReservation = 50
        }

        ecs-sample = {
          cpu       = 512
          memory    = 1024
          essential = true
          image     = "public.ecr.aws/aws-containers/ecsdemo-frontend:776fd50"
          portMappings = [
            {
              name          = "ecs-sample"
              containerPort = 80
              protocol      = "tcp"
            }
          ]

          # Example image used requires access to write to root filesystem
          readonlyRootFilesystem = false

          dependsOn = [{
            containerName = "fluent-bit"
            condition     = "START"
          }]

          enable_cloudwatch_logging = false
          logConfiguration = {
            logDriver = "awsfirelens"
            options = {
              Name                    = "firehose"
              region                  = "eu-west-1"
              delivery_stream         = "my-stream"
              log-driver-buffer-limit = "2097152"
            }
          }
          memoryReservation = 100
        }
      }

      service_connect_configuration = {
        namespace = "example"
        service = [{
          client_alias = {
            port     = 80
            dns_name = "ecs-sample"
          }
          port_name      = "ecs-sample"
          discovery_name = "ecs-sample"
        }]
      }

      load_balancer = {
        service = {
          target_group_arn = "arn:aws:elasticloadbalancing:eu-west-1:1234567890:targetgroup/bluegreentarget1/209a844cd01825a4"
          container_name   = "ecs-sample"
          container_port   = 80
        }
      }

      subnet_ids = ["subnet-abcde012", "subnet-bcde012a", "subnet-fghi345a"]

      security_group_ingress_rules = {
        alb_3000 = {
          description                  = "Service port"
          from_port                    = 80
          ip_protocol                  = "tcp"
          referenced_security_group_id = "sg-12345678"
        }
      }
      security_group_egress_rules = {
        all = {
          ip_protocol = "-1"
          cidr_ipv4   = "0.0.0.0/0"
        }
      }
    }
  }

  tags = {
    Environment = "Development"
    Project     = "Example"
  }
}
Replace subnet_ids, target_group_arn, and referenced_security_group_id with real values from your AWS account before applying.
3

Apply and verify

Initialize and apply the configuration:
terraform init
terraform plan
terraform apply
After the apply completes, verify the cluster and service are running in the AWS console under ECS > Clusters, or use the AWS CLI:
aws ecs describe-clusters --clusters ecs-integrated
aws ecs list-services --cluster ecs-integrated

What was created

After a successful apply, you have:
ResourceDescription
ECS clusterNamed ecs-integrated with Fargate and Fargate Spot capacity providers
Capacity provider strategy50/50 weight split between FARGATE (with a base of 20) and FARGATE_SPOT
ECS serviceecsdemo-frontend service with a task definition and two container definitions
Task definitionRegisters the fluent-bit and ecs-sample container definitions with their CPU/memory allocations
CloudWatch log groupCreated by the module for ECS cluster execute command logging
Security groupCreated for the service with the ingress/egress rules you specified
Service IAM roleCreated automatically because the service uses a load balancer target group
Task execution IAM roleGrants ECS permission to pull images and write logs on behalf of your tasks
The service module always ignores changes to desired_count in Terraform to avoid conflicts with application autoscaling. To change the running task count after initial deployment, use the AWS console, CLI, or a separate null_resource with a local-exec provisioner.

Next steps

Fargate guide

Learn how to configure Fargate on-demand and Fargate Spot with mixed capacity provider strategies.

EC2 Auto Scaling

Attach an EC2 Auto Scaling Group as a capacity provider for full compute control.

Logging

Configure CloudWatch logging, FireLens, and FluentBit sidecars for your containers.

Autoscaling

Set up target tracking and scheduled scaling policies for your ECS services.