3. ECS任务定义深度配置

任务定义(Task Definition)是 ECS 的“部署契约”,它把镜像、端口、环境变量、密钥、日志、资源与依赖关系一次性声明清楚。容器实例只是执行者,真正决定“跑什么、怎么跑、跑多大、依赖谁”的是任务定义。理解它,等于掌握了 ECS 应用交付的配置中枢。

容器镜像与启动命令

镜像通过 image 指定,建议使用带 tag 或 digest 的完整地址,例如 123456789012.dkr.ecr.cn-north-1.amazonaws.com.cn/order-api:1.4.2,避免 latest 导致版本漂移。可用 command 覆盖镜像 ENTRYPOINT 之后的参数,用 entryPoint 覆盖入口点。若镜像来自私有仓库,需在任务定义中声明 repositoryCredentials 或使用 Secrets Manager 注入凭据。

端口映射:host 与 awsvpc 的差异

端口映射由 portMappings 定义,包含 containerPort、hostPort、protocol。在 bridge 模式下,hostPort 为空表示动态映射;在 awsvpc 模式下,容器直接使用 ENI 的 IP,hostPort 通常等于 containerPort。若同一任务内多个容器共享端口,需保证不冲突。ALB 目标组注册的是任务 ENI 的 IP 与 containerPort,因此 awsvpc 模式下端口声明必须与监听规则一致。

环境变量与密钥注入

普通配置用 environment 键值对,例如 SPRING_PROFILES_ACTIVE=prod。敏感信息不要写进环境变量明文,应使用 secrets 引用 Secrets Manager 或 SSM Parameter Store,例如:

"secrets": [
  { "name": "DB_PASSWORD",
    "valueFrom": "arn:aws:secretsmanager:cn-north-1:123456789012:secret:prod/db-abc123:password::" }
]

执行角色(taskRoleArn)决定容器内应用能调用哪些 AWS API;任务执行角色(executionRoleArn)决定 ECS 代理能否拉取镜像、写日志、读取密钥。两者职责不同,切勿混用。

日志驱动

常用 awslogs 驱动,需指定 awslogs-group、awslogs-region、awslogs-stream-prefix。流名称默认为 prefix/容器名/任务ID,便于在 CloudWatch Logs 中按任务检索。若使用 FireLens,可配置 fluentbit 或 fluentd 驱动,把日志转发到 OpenSearch、Kinesis Firehose 等目标。

资源限制与依赖编排

cpu 与 memory 是任务级硬限制,容器级可用 cpu、memory、memoryReservation 细分。Fargate 必须声明任务级 CPU/内存组合,如 0.5 vCPU + 1 GB。依赖关系通过 dependsOn 声明,condition 可取 START、COMPLETE、SUCCESS、HEALTHY。例如 sidecar 需在应用启动前就绪,可让应用容器依赖 sidecar 的 HEALTHY。

ECS 任务定义核心配置关系图 镜像 · 端口 · 环境变量 · 密钥 · 日志 · 资源 · 依赖 Task Definition(任务定义) executionRoleArn 拉镜像 / 写日志 / 读密钥 taskRoleArn 应用调用 AWS API 权限 容器 A:order-api image: order-api:1.4.2 portMappings: 8080 → 8080 environment: PROFILE=prod secrets: DB_PASSWORD logDriver: awslogs cpu: 512 / memory: 1024 容器 B:log-router image: fluent-bit:2.1 logDriver: firelens cpu: 256 / memory: 512 dependsOn: 无 condition: START dependsOn HEALTHY ECR 镜像仓库 拉取 order-api:1.4.2 Secrets Manager prod/db → DB_PASSWORD CloudWatch Logs /ecs/order-api ALB 目标组 注册 ENI IP:8080 执行角色负责“把容器跑起来”,任务角色负责“容器里应用能做什么”;两者权限边界必须分离

一个可参考的任务定义片段

下面示例展示 order-api 与 log-router 两个容器的关键字段,参数为教学示例,实际请按业务调整:

{
  "family": "order-api",
  "executionRoleArn": "arn:aws:iam::123456789012:role/ecsTaskExecutionRole",
  "taskRoleArn": "arn:aws:iam::123456789012:role/orderApiTaskRole",
  "networkMode": "awsvpc",
  "requiresCompatibilities": ["FARGATE"],
  "cpu": "1024",
  "memory": "2048",
  "containerDefinitions": [
    {
      "name": "order-api",
      "image": "123456789012.dkr.ecr.cn-north-1.amazonaws.com.cn/order-api:1.4.2",
      "portMappings": [{ "containerPort": 8080, "protocol": "tcp" }],
      "environment": [{ "name": "SPRING_PROFILES_ACTIVE", "value": "prod" }],
      "secrets": [{ "name": "DB_PASSWORD",
        "valueFrom": "arn:aws:secretsmanager:cn-north-1:123456789012:secret:prod/db-abc123:password::" }],
      "logConfiguration": {
        "logDriver": "awslogs",
        "options": {
          "awslogs-group": "/ecs/order-api",
          "awslogs-region": "cn-north-1",
          "awslogs-stream-prefix": "ecs"
        }
      },
      "dependsOn": [{ "containerName": "log-router", "condition": "HEALTHY" }]
    },
    {
      "name": "log-router",
      "image": "public.ecr.aws/aws-observability/aws-for-fluent-bit:2.31.0",
      "essential": true,
      "logConfiguration": { "logDriver": "awslogs",
        "options": { "awslogs-group": "/ecs/log-router",
          "awslogs-region": "cn-north-1", "awslogs-stream-prefix": "ecs" } }
    }
  ]
}
依赖条件选择建议:仅需容器进程启动用 START;需等待初始化脚本结束用 COMPLETE;需确认退出码为 0 用 SUCCESS;需通过健康检查用 HEALTHY。生产环境优先使用 HEALTHY,避免应用在依赖未就绪时接收流量。
常见排障点:任务角色与执行角色混淆会导致拉镜像失败或密钥读取被拒;awsvpc 模式下 hostPort 与 containerPort 不一致会导致 ALB 健康检查失败;Fargate 未声明任务级 CPU/内存会直接注册失败;日志组不存在时 awslogs 驱动会静默丢弃日志,需提前创建。

把任务定义当作“可版本化的部署契约”来管理:每次变更生成新 revision,配合 CodeDeploy 蓝绿或滚动更新,回滚时只需指向旧 revision。这样镜像、端口、密钥、日志、资源与依赖关系全部可追溯,应用交付才真正可控。