【问题标题】:Using file function with Terraform workspace将文件功能与 Terraform 工作区一起使用
【发布时间】:2021-09-24 07:45:01
【问题描述】:

我有一个正在 Terraform 中创建的资源。在资源中有一个使用 JSON 文件读取值的属性。我正在从一个单独的 JSON 文件中读取这些值,并希望与我的 Terraform 工作区一起声明该属性。以下是我的资源和错误消息。如果可以将 terraform 工作空间集成到文件功能中,那么任何有关如何实现这一点的见解都会有所帮助。

地形资源

resource "aws_ecs_task_definition" "task_definition" {


family                   = "${var.application_name}-${var.application_environment[var.region]}"
  execution_role_arn       = aws_iam_role.ecs_role.arn
  network_mode             = "awsvpc"
  cpu                      = "256"
  memory                   = "512"
  requires_compatibilities = ["FARGATE"]
  container_definitions    = file("scripts/ecs/${terraform.workspace}.json")
}

地形错误

Error: ECS Task Definition container_definitions is invalid: Error decoding JSON: json: cannot unmarshal object into Go value of type []*ecs.ContainerDefinition

on ecs.tf line 26, in resource "aws_ecs_task_definition" "task_definition":
  26:   container_definitions    = file("scripts/ecs/${terraform.workspace}.json")

我希望以这种方式处理它,因为我设置了多个 Terraform 工作区,并希望尽可能保持我的 TF 脚本相同。

容器定义

{


"executionRoleArn": "arn:aws:iam::xxxxxxxxxxxx:role/ecsTaskExecutionRole",
  "containerDefinitions": [
    {
      "logConfiguration": {
        "logDriver": "awslogs",
        "options": {
          "awslogs-group": "/ecs/fargate-devstage",
          "awslogs-region": "us-east-2",
          "awslogs-stream-prefix": "ecs"
        }
      },
      "entryPoint": [
        "[\"sh\"",
        "\"/tmp/init.sh\"]"
      ],
      "portMappings": [
        {
          "hostPort": 9003,
          "protocol": "tcp",
          "containerPort": 9003
        }
      ],
      "cpu": 0,
      "environment": [],
      "mountPoints": [],
      "volumesFrom": [],
      "image": "xxxxxxxxxxxx.dkr.ecr.us-east-2.amazonaws.com/fargate:latest",
      "essential": true,
      "name": "fargate"
    }
  ],
  "placementConstraints": [],
  "memory": "1024",
  "compatibilities": [
    "EC2",
    "FARGATE"
  ],
  "taskDefinitionArn": "arn:aws:ecs:us-east-2:xxxxxxxxxxxx:task-definition/fargate-devstage:45",
  "family": "fargate-devstage",
  "requiresAttributes": [
    {
      "name": "com.amazonaws.ecs.capability.logging-driver.awslogs"
    },
    {
      "name": "ecs.capability.execution-role-awslogs"
    },
    {
      "name": "com.amazonaws.ecs.capability.ecr-auth"
    },
    {
      "name": "com.amazonaws.ecs.capability.docker-remote-api.1.19"
    },
    {
      "name": "ecs.capability.execution-role-ecr-pull"
    },
    {
      "name": "com.amazonaws.ecs.capability.docker-remote-api.1.18"
    },
    {
      "name": "ecs.capability.task-eni"
    }
  ],
  "requiresCompatibilities": [
    "FARGATE"
  ],
  "networkMode": "awsvpc",
  "cpu": "512",
  "revision": 45,
  "status": "ACTIVE",
  "volumes": []
}

【问题讨论】:

  • 如果它无法打开文件,我预计会出现不同的错误。听起来它无法解析文件。你确定这是一个有效的容器定义吗?如果您在没有工作空间插值的情况下暂时对路径进行硬编码,它会起作用吗?您也可以尝试使用local_file 数据源而不是registry.terraform.io/providers/hashicorp/local/latest/docs/…
  • 完全同意错误消息暗示 JSON 结构未被识别为对 ECS 容器定义有效。请在问题中提供示例 JSON。
  • 是的,实际上我确实通过硬编码尝试过。我的容器定义文件有错误。
  • 我已经添加了它抱怨的容器定义json文件。
  • 不幸的是,AWS 提供商在这里只是传递了看起来像是来自 Go 的 JSON 库的原始错误消息,而不是 JSON/ECS 术语中的内容,但我同意这似乎是提供商拒绝文件中已成功加载的 JSON,而不是实际加载文件的错误。

标签: amazon-web-services terraform amazon-ecs ecs-taskdefinition


【解决方案1】:

您必须在container_definitions 中提供仅容器定义,而不是整个任务定义。所以你的 json 会是这样的:

 [
    {
      "logConfiguration": {
        "logDriver": "awslogs",
        "options": {
          "awslogs-group": "/ecs/fargate-devstage",
          "awslogs-region": "us-east-2",
          "awslogs-stream-prefix": "ecs"
        }
      },
      "entryPoint": [
        "[\"sh\"",
        "\"/tmp/init.sh\"]"
      ],
      "portMappings": [
        {
          "hostPort": 9003,
          "protocol": "tcp",
          "containerPort": 9003
        }
      ],
      "cpu": 0,
      "environment": [],
      "mountPoints": [],
      "volumesFrom": [],
      "image": "xxxxxxxxxxxx.dkr.ecr.us-east-2.amazonaws.com/fargate:latest",
      "essential": true,
      "name": "fargate"
    }
  ]

所有其他与任务相关的东西,例如任务执行角色、cpu、内存等都必须直接在aws_ecs_task_definition资源中提供,而不是在container_definitions中。

【讨论】:

    【解决方案2】:

    有很多方法可以解决这个问题,但我认为最好的方法是使用 template_file 数据源和变量替换

    这是一个如何使用它的示例

    data "template_file" "task_definiton" {
      template = file("${path.module}/files/task_definition.json")
    
      vars = {
        region                             = var.region
        secrets_manager_arn                = module.xxxx.secrets_manager_version_arn
        container_memory                   = var.container_memory
        memory_reservation                 = var.container_memory_reservation
        container_cpu                      = var.container_cpu
      }
    }
    
    resource "aws_ecs_task_definition" "task" {
      family                   = "${var.environment}-${var.app_name}"
      execution_role_arn       = aws_iam_role.ecs_task_role.arn
      network_mode             = "awsvpc"
      requires_compatibilities = ["FARGATE"]
      cpu                      = var.fargate_ec2_cpu
      memory                   = var.fargate_ec2_memory
      task_role_arn            = aws_iam_role.ecs_task_role.arn
      container_definitions    = data.template_file.task_definiton.rendered
    }
    

    注意数据源是如何与 rendered 方法一起使用的,以便您检索带有插值变量的实际文件输出

    data.template_file.task_definiton.rendered
    

    关于模板格式和模板文件的更多信息,您可以参考 terraform 的官方文档https://registry.terraform.io/providers/hashicorp/template/latest/docs/data-sources/file

    编辑 1: 我还必须说,如果您想采用这种方法,您必须定义模板所需的变量和 用于工作区的 terraform 资源。

    【讨论】:

      猜你喜欢
      • 2017-02-21
      • 1970-01-01
      • 2018-12-10
      • 2010-10-26
      • 2021-10-13
      • 2021-04-04
      • 2020-12-13
      • 2017-01-16
      • 1970-01-01
      相关资源
      最近更新 更多