Search code examples
amazon-web-servicesterraformterraform-provider-aws

AWS list of container_definitions using Terraform


I'm trying to deploy an aws_ecs_task_definition with multiple container_defintions in Terraform. I have a variable like this, which I use also for other resources creation:

variable "entity_map" {
  type = map(object({
    name = string,
    port = number,
    image = string,
    type = string,
    ec2_enabled = bool
    ...
  }))
  default = {
    "entity1" = {
      name = "e1",
      port = 1651, 
      image = "link_to_image1"
      type = "B",
      ec2_enabled = true,
      ...
    },
    "entity2" = {
      name = "e2",
      port = 1655,
      image = "link_to_image2",
      type = "S", 
      ec2_enabled = true,
      ...
    },
    ...
  }
}

What I would like to do is iterate through each object (entity1, entity2, ...) and create as many container_definition inside the task definitions.

What I tried to do is to use dynamic block with the for_each approach but this gives me errors. For example

resource "aws_ecs_task_definition" "example" {
  family                   = "example-task"
  network_mode             = "awsvpc"
  requires_compatibilities = ["FARGATE"]

  execution_role_arn = aws_iam_role.ecs_execution_role.arn

  dynamic "container_definitions" {
    for_each = var.entity_map
    content {
      name  = each.value.name
      image = each.value.image
      portMappings {
        containerPort = each.value.port
        hostPort      = each.value.port
      }
    }
  }
...

The error is:

│ 210: dynamic "container_definitions" { │ │ Blocks of type "container_definitions" are not expected here.


Solution

  • There are a few issues here:

    • container_definitions is a parameter, and not a block.
    • The value of container_definitions should be a JSON format string.
    • The variable type of var.entity_map is a map(object(...)), but the resource expects list(object(...)).
    • The object type is not in the expected structure for the resource/API inputs.

    Fixing all of these issues results in:

    variable "entity_map" {
      type = list(object({
        name = string,
        portMappings = list(object{
          containerPort = number
          hostPort      = number
        })
        port = number,
        image = string
      }))
      default = [
        {
          name = "e1",
          portMappings = [{
            containerPort = 1651
            hostPort      = 1651
          }]
          image = "link_to_image1"
        },
        {
          name = "e2",
          portMappings = [{
            containerPort = 1655
            hostPort      = 1655
          }]
          image = "link_to_image2"
        },
        ...
      ]
    }
    
    resource "aws_ecs_task_definition" "example" {
      family                   = "example-task"
      network_mode             = "awsvpc"
      requires_compatibilities = ["FARGATE"]
    
      execution_role_arn = aws_iam_role.ecs_execution_role.arn
    
      container_definitions = jsonencode(var.entity_map)
      ...
    }