用于创建 ECS 服务的 Cloudformation 模板卡在 CREATE_IN_PROGRESS

Cloudformation template for creating ECS service stuck in CREATE_IN_PROGRESS

我正在使用 Cloudformation 创建 AWS ECS 服务。

一切似乎都已成功完成,我可以看到实例已附加到负载均衡器,负载均衡器正在声明该实例健康,如果我点击负载均衡器,我将成功进入我的运行 容器。

查看ECS控制面板,服务已经稳定,一切正常。我还可以看到容器是稳定的,而不是 terminated/re-created。

然而,Cloudformation 模板从未完成,它一直停留在 CREATE_IN_PROGRESS 直到大约 30-60 分钟后,当它回滚时声称服务未稳定。查看 CloudTrail,我可以看到由 ecs-service-scheduler 实例化的多个 RegisterInstancesWithLoadBalancer,所有这些都具有相同的参数,即相同的实例 ID 和负载均衡器。我正在为 ECS 使用标准的 IAM 角色和权限,所以这应该不是权限问题。

有人遇到过类似的问题吗?

我想我遇到了类似的问题。 尝试查看服务模板中的 "DesiredCount" 属性。我认为 CloudFormation 将指示 creation/update 仍在进行中,直到服务达到集群中的 "DesiredCount" 数量。

您的 AWS::ECS::Service 需要注册 TaskDefinition 的完整 ARN(来源:See the answer from ChrisB@AWS on the AWS forums)。关键是使用 完整 ARN 设置您的 TaskDefinition,包括修订 。如果您跳过修订版(下例中的 :123),则会使用最新的修订版,但 CloudFormation 在失败前仍会与 "CREATE_IN_PROGRESS" 共进午餐约一个小时。这是一种方法:

"MyService": {
    "Type": "AWS::ECS::Service",
    "Properties": {
        "Cluster": { "Ref": "ECSClusterArn" },
        "DesiredCount": 1,
        "LoadBalancers": [
            {
                "ContainerName": "myContainer",
                "ContainerPort": "80",
                "LoadBalancerName": "MyELBName"
            }
        ],
        "Role": { "Ref": "EcsElbServiceRoleArn" },
        "TaskDefinition": {
            "Fn::Join": ["", ["arn:aws:ecs:", { "Ref": "AWS::Region" },
            ":", { "Ref": "AWS::AccountId" },
            ":task-definition/my-task-definition-name:123"]]}
        }
    }
}

这是通过 aws cli 和 jq 获取 MyTaskDefinition 最新版本的绝妙方法:

aws ecs list-task-definitions --family-prefix MyTaskDefinition | jq --raw-output .taskDefinitionArns[0][-1:]

无需为 TaskDefinition 注册完整的 ARN,因为当此资源的逻辑 ID 提供给 Ref 内部函数时,Ref returns Amazon 资源名称 (ARN)。

在以下示例中,Ref 函数 returns MyTaskDefinition 任务的 ARN,例如 arn:aws:ecs:us-west-2:123456789012:task/1abf0f6d-a411-4033-b8eb-a4eed3ad252a.

{ "Ref": "MyTaskDefinition" }

来源http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ecs-taskdefinition.html

我发现了另一个会导致此问题的相关场景,我想我会把它放在这里以防其他人 运行 参与其中。如果您定义 TaskDefinition 并使用其 ContainerDefinition 中实际不存在的图像,然后您尝试 运行 将 TaskDefinition 作为服务,您将 运行 进入相同的挂起问题(或至少看起来像相同的问题)。

注意:下面的示例 YAML 块都在同一个 CloudFormation 模板中

作为示例,我创建了这个 Repository:

MyRepository:
    Type: AWS::ECR::Repository

然后我创建了这个 Cluster:

MyCluster:
    Type: AWS::ECS::Cluster

还有这个TaskDefinition(删节):

MyECSTaskDefinition:
    Type: AWS::ECS::TaskDefinition
    Properties:
        # ...
        ContainerDefinitions:
            # ...
              Image: !Join ["", [!Ref "AWS::AccountId", ".dkr.ecr.", !Ref "AWS::Region", ".amazonaws.com/", !Ref MyRepository, ":1"]]
            # ...

有了这些定义,我就去创建一个 Service 这样的:

MyECSServiceDefinition:
    Type: AWS::ECS::Service
    Properties:
        Cluster: !Ref MyCluster
        DesiredCount: 2
        PlacementStrategies:
            - Type: spread
              Field: attribute:ecs.availability-zone
        TaskDefinition: !Ref MyECSTaskDefinition

这一切对我来说似乎都是明智的,但事实证明这有两个问题 written/deployed 导致它挂起。

  1. DesiredCount 设置为 2,这意味着它将实际尝试启动服务并 运行 它,而不仅仅是定义它。如果我将 DesiredCount 设置为 0,则效果很好。
  2. MyECSTaskDefinition 中定义的 Image 尚不存在。我将存储库作为此模板的一部分,但实际上并没有向其推送任何内容。因此,当 MyECSServiceDefinition 尝试启动 2 个实例的 DesiredCount 时,它会挂起,因为图像在存储库中实际上不可用(因为存储库实际上只是在同一模板中创建的)。

因此,目前,解决方案是创建 ServiceDesiredCount 为 0 的 CloudFormation 堆栈,将适当的 Image 上传到存储库,然后更新用于扩展服务的 CloudFormation 堆栈。或者,有一个单独的模板来设置像存储库这样的核心基础设施,将构建上传到那个模板,然后有一个单独的模板到 运行 来设置 Services 自己。

希望对遇到此问题的任何人有所帮助!

任何阻止 ECS 服务定义达到 Desired Count 的东西。一个例子是在附加到实例所用角色的策略中缺少权限。检查实例 ECS 代理日志 (/var/log/ecs/ecs-agent.log.timestamp).

另一个例子: 实例没有足够的可用内存来匹配请求的 Desired Count.. 事件将显示如下内容:

"...服务 myService 无法放置任务,因为没有容器实例满足其所有要求。最接近的匹配容器实例 123456789 可用内存不足..."=20 =]

我遇到了同样的问题。我通过为任务定义增加分配的内存大小来解决。

您运行 的容器不得超过您的 ECS 实例上的可用内存。

为了增加另一种可能性,我曾经 运行 解决过这个问题,其中模板的一切都很好,所需的任务数 = 运行 任务的 #,等等。结果是其中一个底层 EC2 实例卡在接近 100% CPU 状态(但 EC2 将其视为 "healthy")。它阻止 CloudFormation 验证该特定实例。我杀死了坏的 EC2 实例,ECS 启动了一个真正健康的实例。

要添加另一个数据点,我已经看到 AWS::ECS::Service 如果 ECR docker 图像不是 a) 可从 ECR 存储库 [=] 永久卡在 CREATE_IN_PROGRESS 21=]and b) 通过健康检查。

我已经多次尝试使用有效图像哈希但失败的健康检查容器启动 AWS::ECS::Service,然后修复图像并执行各种 "set desired count to zero", "set it back",等等,没有什么 AFAICT 让它解开。

我最终不得不删除堆栈,并从 立即 通过健康检查的图像重新开始。然后就正常了。

超级古怪。