如何用Terraform创建ECS任务定义新版本而非新任务定义
问题描述
我有一个运行多任务的AWS ECS集群,这些任务均为旧任务的修订版本,仅Docker命令中的路径存在差异。希望通过Terraform自动化流程:基于现有任务创建新版本,并在现有集群中运行采用最新任务修订版的新任务。但当前每次运行脚本都会创建新的任务定义,还误以为会创建新ECS集群,不清楚问题出在哪里。
提供的Terraform代码(main.tf)
# Provider configuration provider "aws" { region = "ap-northeast-1" } # Read input.yaml file data "local_file" "input" { filename = "input.yaml" } # Parse input.yaml file locals { input_data = yamldecode(data.local_file.input.content) } # Retrieve existing ECS task definition data "aws_ecs_task_definition" "existing_task" { task_definition = "modbus-simulator-fargate-task" } # Create new ECS task definition based on existing one with modifications resource "aws_ecs_task_definition" "modbus_simulator" { family = data.aws_ecs_task_definition.existing_task.family task_role_arn = data.aws_ecs_task_definition.existing_task.task_role_arn execution_role_arn = data.aws_ecs_task_definition.existing_task.execution_role_arn network_mode = data.aws_ecs_task_definition.existing_task.network_mode requires_compatibilities = ["FARGATE"] # Add FARGATE here cpu = 1024 # Specify CPU here memory = 3072 # Specify memory here container_definitions = jsonencode([ { "name": "client-server-simulator", "image": "337039605624.dkr.ecr.ap-northeast-1.amazonaws.com/client-server-simulator:26-june-2024", "cpu": 0, "portMappings": [ { "name": "client-server-simulator-80-tcp", "containerPort": 80, "hostPort": 80, "protocol": "tcp", "appProtocol": "http" } ], "essential": true, "command": [ "--s3-path", local.input_data[0].s3_path, "--modbus-ip", local.input_data[0].modbus_ip, "--modbus-port", local.input_data[0].modbus_port, "--interval", local.input_data[0].interval, "--edge-id", local.input_data[0].edge_id, "--location", local.input_data[0].location, "--company", local.input_data[0].company ], "environment": [], "mountPoints": [], "volumesFrom": [], "logConfiguration": { "logDriver": "awslogs", "options": { "awslogs-group": "/ecs/modbus-simulator-fargate-task", "awslogs-create-group": "true", "awslogs-region": "ap-northeast-1", "awslogs-stream-prefix": "ecs" } }, "systemControls": [] } ]) } # Update ECS service to use the new task definition revision resource "aws_ecs_service" "modbus_simulator_service" { name = "modbus-simulator-service" cluster = "modbus-simulator-cluster" # use the existing cluster task_definition = aws_ecs_task_definition.modbus_simulator.arn desired_count = 1 # Update only if there's a change in the task definition lifecycle { ignore_changes = [task_definition] } }
编辑补充
.tfstate文件创建并存储在本地系统中,已查阅相关仓库提供的示例。
问题排查与解决步骤
1. 关于“重复创建ECS集群”的澄清
你的代码中没有定义aws_ecs_cluster资源,Terraform不会创建新集群。aws_ecs_service直接指定了现有集群名称modbus-simulator-cluster,所以集群不会被Terraform管控,更不会重复创建。你提到的“创建新集群”大概率是误解,或者之前的脚本包含集群创建逻辑。
2. 任务定义重复创建的原因与优化
(1)正常的修订版生成(符合ECS设计)
AWS ECS任务定义是不可修改的,任何变更(比如command中的参数变化)都会生成新的修订版,这是ECS的原生设计。如果是因为input.yaml中的参数每次运行都有变化,那么生成新修订版是预期行为。
(2)不必要重复创建的修复
如果是无意义的重复创建,检查以下两点:
- 硬编码属性导致的差异:你当前硬编码了
requires_compatibilities、cpu、memory,没有复用现有任务的属性,可能导致即使原任务这些属性不变,Terraform也会因为本地配置与远程不一致而创建新修订版。改为从数据源读取:requires_compatibilities = data.aws_ecs_task_definition.existing_task.requires_compatibilities cpu = data.aws_ecs_task_definition.existing_task.cpu memory = data.aws_ecs_task_definition.existing_task.memory input.yaml意外变更:确保每次运行时input.yaml的内容没有被意外修改(比如换行符、空格差异),否则会触发container_definitions更新,导致新修订版生成。
3. ECS服务无法更新到最新任务定义的问题
你配置了lifecycle.ignore_changes = [task_definition],这会让Terraform忽略任务定义ARN的变化,阻止服务自动更新到新的修订版,和你“运行最新任务修订版”的需求完全相反。直接移除这段配置:
# 移除以下代码块 # lifecycle { # ignore_changes = [task_definition] # }
移除后,当任务定义生成新修订版时,Terraform会自动更新ECS服务,滚动部署最新版本的任务。
4. 本地tfstate的注意事项
本地存储tfstate时,必须保证每次运行Terraform都使用同一个tfstate文件:
- 不要删除、复制或移动tfstate文件,否则Terraform会认为是全新环境,重新创建所有管控的资源。
- 如果是多人协作场景,建议改用远程状态存储(如AWS S3配合DynamoDB锁),避免状态冲突。
内容的提问来源于stack exchange,提问作者Arnav Gupta

