Elastic Container Service (ECS) is an Amazon Web Services (AWS) service that can be used to manage containers, similar to Kubernetes and OpenShift.
Let's say you have the following files on your Terraform server.
├── required_providers.tf
├── elastic_container_services (directory)
│ ├── cluster.tf
│ ├── listener.tf
│ ├── load_balancer.tf
│ ├── provider.tf
│ ├── security_group.tf
│ ├── services.tf
│ ├── subnets.tf
│ ├── target_group.tf
│ ├── task_definitions.tf
│ ├── virtual_private_cloud.tf
required_providers.tf will almost always have this.
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
}
}
}
Let's say provider.tf has the following. In this example, the "default" profile in /home/username/.aws/config and /home/username/.aws/credentials is being used. This assumes you have setup Terraform as described in Amazon Web Services (AWS) - Getting Started with Terraform.
provider "aws" {
alias = "default"
profile = "default"
region = "default"
}
First you will create a cluster. Let's say cluster.tf has the following.
resource "aws_ecs_cluster" "my-ecs-cluster" {
name = "my-ecs-cluster"
}
Next you will create a task definition. A Task Definition is kind of like a Dockerfile or a Kubernetes deployment YAML file, in that it contains keys and values that are used to define how something should be, such as the settings for a container.
Let's say task-definitions.tf includes the following, to create a task definitation for a Flask container which will use FARGATE, meaning this will be serverless with no EC2 instances.
resource "aws_ecs_task_definition" "flask-task-definition" {
family = "flask"
network_mode = "awsvpc"
requires_compatibilities = ["FARGATE"]
cpu = 1024
memory = 2048
container_definitions = jsonencode([
{
name = "flask"
cpu = 10
memory = 512
image: "https://hub.docker.com/r/tiangolo/uwsgi-nginx-flask:python3.11",
portMappings: [
{
containerPort: 80,
hostPort: 80
}
]
}
])
}
We are going to need Virtual Private Cloud ID, so let's do something like this in virtual_private_cloud.tf.
data "aws_vpc" "virtual-private-cloud" {
filter {
name = "tag-key"
values = ["Name"]
}
filter {
name = "tag-value"
values = ["my-vpc"]
}
}
We are also going to need the Virtual Private Cloud Subnet IDs, perhaps something like this in subnets.tf.
data "aws_subnets" "subnets" {
filter {
name = "vpc-id"
values = [data.aws_vpc.virtual-private-cloud.id]
}
}
And security_group.tf.
data "aws_security_group" "default-security-group" {
filter {
name = "group-name"
values = ["default"]
}
filter {
name = "tag:Name"
values = ["default"]
}
}
In this example, the container will be fronted by an Application Load Balancer, so let's do something like this in load_balancer.tf.
resource "aws_lb" "ecs-application-load-balancer" {
name = "ecs-application-load-balancer"
internal = false
load_balancer_type = "application"
enable_deletion_protection = true
security_groups = [data.aws_security_group.default-security-group.id]
subnets = [data.aws_subnets.subnets.ids[0],data.aws_subnets.subnets.ids[1]]
tags = {
Name = "ecs-application-load-balancer"
}
}
And something like this in target_group.tf.
resource "aws_lb_target_group" "ecs-application-load-balancer-target-group" {
name = "ecs-target-group"
port = 80
protocol = "HTTP"
target_type = "ip"
vpc_id = data.virtual-private-cloud.id
tags = {
Name = "ecs-target-group"
}
}
And something like this in listener.tf.
resource "aws_lb_listener" "ecs-application-load-balancer-listener" {
load_balancer_arn = aws_lb.ecs-application-load-balancer.arn
port = 80
protocol = "HTTP"
default_action {
type = "forward"
target_group_arn = aws_lb_target_group.ecs-application-load-balancer-target-group.arn
}
tags = {
Name = "ecs-listener"
}
}
And now you can create a JSON file that will be used to create a service. Perhaps services.tf has something like this.
resource "aws_ecs_service" "my-flask-service" {
name = "my-flask-service"
launch_type = "FARGATE"
cluster = aws_ecs_cluster.my-ecs-cluster.id
task_definition = aws_ecs_task_definition.flask-task-definition.id
desired_count = 1
load_balancer {
target_group_arn = aws_lb_target_group.ecs-application-load-balancer-target-group.arn
container_name = aws_ecs_task_definition.flask-task-definition.id
container_port = 80
}
network_configuration {
subnets = [data.aws_subnets.subnets.ids[0],data.aws_subnets.subnets.ids[1]]
security_groups = [data.aws_security_group.ecs-security-group.id]
assign_public_ip = false
}
}
Did you find this article helpful?
If so, consider buying me a coffee over at