Bootstrap FreeKB - Amazon Web Services (AWS) Elastic Container Service (ECS) - Create an EC2 Task Definition using Terraform
Amazon Web Services (AWS) Elastic Container Service (ECS) - Create an EC2 Task Definition using Terraform


Let's say you have the following files on your Terraform server.

├── required_providers.tf
├── elastic_container_services (directory)
│   ├── task_defintions (directory)
│   ├── ├── ec2 (directory)
│   ├── ├── ├── provider.tf
│   ├── ├── ├── task_definition.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"
}

 

This assumes you have already:

An ECS deployment can be:

  • EC2 - apps run in EC2 instance
  • FARGATE - serverless (no EC2 instances)

When creating an EC2 instance:

  • You will need to use one of the ECS Optimized image, almost always the most recent ECS Optimized image.
  • The IAM AmazonEC2ContainerServiceforEC2Role will need to be applied to the EC2 Instance.

Thus, you will probably have the following Terraform data and resource blocks to create an EC2 Instance using the ECS Optimized Image and AmazonEC2ContainerServiceforEC2Role.

data "aws_ami" "most-recent-ecs-optimized-image" {
  most_recent = true

  filter {
    name   = "name"
    values = ["amzn-ami*ecs-optimized"]
  }
}

resource "aws_instance" "ecs-ec2-optimized-instance" {
  ami                  = data.aws_ami.most-recent-ecs-optimized-image.id
  instance_type        = "t3.micro"
  subnet_id            = data.aws_subnets.subnets.ids[0]
  iam_instance_profile = "AmazonEC2ContainerServiceforEC2Role"

  tags = {
    Name = "ecs-ec2-optimized-instance"
  }
}

 

task_definitions.tf could have something like this where requires_compatibilities is EC2.

resource "aws_ecs_task_definition" "flask-ec2-task-definition" {
  family                   = "flask"
  network_mode             = "awsvpc"
  requires_compatibilities = ["EC2"]
  cpu                      = 1024
  memory                   = 2048

  container_definitions = jsonencode([
    {
      name = "flask-container"
      cpu       = 10
      memory    = 512
      image: "tiangolo/uwsgi-nginx-flask:python3.11",
      portMappings: [
        {
          containerPort: 3000,
          hostPort: 3000
        }
      ]
    }
  ])
}

 

Or like this, using JSON instead of jsonencode.

resource "aws_ecs_task_definition" "flask-ec2-task-definition" {
  family                   = "flask"
  network_mode             = "awsvpc"
  requires_compatibilities = ["EC2"]
  cpu                      = 1024
  memory                   = 2048

  container_definitions = <<DEFINITION
  [
    {
      "name": "flask-container",
      "cpu": 10,
      "memory": 512,
      "image": "tiangolo/uwsgi-nginx-flask:python3.11",
      "portMappings": [
        {
          "containerPort": 3000,
          "hostPort": 3000
        }
      ]
    }
  ]
  DEFINITION
}

 

You may need to reissue the terraform init command.

~]# terraform init
Initializing the backend...
Initializing modules...
Initializing provider plugins...
Terraform has been successfully initialized!

 

The terraform plan command can be used to see what Terraform will try to do.

~]$ terraform plan
Terraform will perform the following actions:

  # aws_ecs_task_definition.flask-ec2-task-definition will be created
  + resource "aws_ecs_task_definition" "flask-ec2-task-definition" {
      + arn                      = (known after apply)
      + arn_without_revision     = (known after apply)
      + container_definitions    = jsonencode(
            [
              + {
                  + cpu          = 10
                  + image        = "tiangolo/uwsgi-nginx-flask:python3.11"
                  + memory       = 512
                  + name         = "flask"
                  + portMappings = [
                      + {
                          + containerPort = 80
                          + hostPort      = 80
                        },
                    ]
                },
            ]
        )
      + cpu                      = "1024"
      + family                   = "flask"
      + id                       = (known after apply)
      + memory                   = "2048"
      + network_mode             = "awsvpc"
      + requires_compatibilities = [
          + "EC2",
        ]
      + revision                 = (known after apply)
      + skip_destroy             = false
      + tags_all                 = (known after apply)
    }

Plan: 1 to add, 0 to change, 0 to destroy.

 

The terraform apply command can be used to create, update or delete the resource.

terraform apply -auto-approve

 




Did you find this article helpful?

If so, consider buying me a coffee over at Buy Me A Coffee



Comments


Add a Comment


Please enter 16256b in the box below so that we can be sure you are a human.