👻

[CDK/CFn] ECSでCapacityProviderを更新する

に公開

CDK deploy で ECS Cluster を更新しようとしたところ下記のようなエラーが発生しました。

The specified capacity provider is in use and cannot be removed. (Service: AmazonECS; Status Code: 400; Error Code: ResourceInUseException;

このエラーは、「Capacity Provider の指定が変更されているが、Service が古い Capacity Provider を使っているので変更できない」というエラーです。このエラーを解消するには、AWS API を叩いて全ての Service について Capacity Provider Strategy を更新してあげる必要があります。

状況確認

まず Cluster で現在の Capacity Provider / Default Capacity Provider Strategy を確認します。

$ aws ecs describe-clusters --cluster $CLUSTER_NAME | jq '.clusters[]'
{
  "clusterArn": "arn:aws:ecs:ap-northeast-1:123456789012:cluster/ClusterA",
  "clusterName": "ClusterA",
  "status": "ACTIVE",
  "registeredContainerInstancesCount": 4,
  "runningTasksCount": 5,
  "pendingTasksCount": 0,
  "activeServicesCount": 5,
  "statistics": [],
  "tags": [],
  "settings": [],
  "capacityProviders": [
    "CapacityProviderA",
    "CapacityProviderB"
  ],
  "defaultCapacityProviderStrategy": [
    {
      "capacityProvider": "CapacityProviderA",
      "weight": 1,
      "base": 0
    },
    {
      "capacityProvider": "CapacityProviderB",
      "weight": 0,
      "base": 0
    }
  ]
}

次に、CDK でどんな Capacity Provider / Default Capacity Provider Strategy に変更されようとしたのか確認します。cdk.out/XXX.template.json を確認すると、Cluster の設定が下記のようになっていました。

    "ClusterXYZ": {
      "Type": "AWS::ECS::ClusterCapacityProviderAssociations",
      "Properties": {
        "CapacityProviders": [
          {
            "Ref": "CapacityProviderARef"
          }
        ],
        "Cluster": {
          "Ref": "ClusterARef"
        },
        "DefaultCapacityProviderStrategy": [
          {
            "CapacityProvider": {
              "Ref": "CapacityProviderARef"
            },
            "Weight": 1
          }
        ]
      },
      "Metadata": {
        "aws:cdk:path": "Project/Cluster/Cluster/Cluster"
      }
    },

たしかに、Capacity Provider の指定が 1 つ減っています。

次に、Service のほうの現状も確認してみます。

$ aws ecs describe-services --services="$(aws ecs list-services --cluster $CLUSTER_NAME --query serviceArns)" --cluster $CLUSTER_NAME --query 'services[].{serviceName: serviceName, capacityProviderStrategy: capacityProviderStrategy}'
[
    {
        "serviceName": "ServiceA",
        "capacityProviderStrategy": null
    },
    {
        "serviceName": "ServiceB",
        "capacityProviderStrategy": [
            {
                "capacityProvider": "CapacityProviderA",
                "weight": 1,
                "base": 0
            },
            {
                "capacityProvider": "CapacityProviderB",
                "weight": 0,
                "base": 0
            }
        ]
    },
    {
        "serviceName": "ServiceC",
        "capacityProviderStrategy": null
    },
    {
        "serviceName": "ServiceD",
        "capacityProviderStrategy": null
    },
    {
        "serviceName": "ServiceE",
        "capacityProviderStrategy": null
    }
]

1 つの Service が古い Capacity Provider を Strategy に含んでいますね。

この状態で、put-cluster-capacity-provider を実行すると、cdk deploy のときと同じエラーが出るはずです。

$ aws ecs put-cluster-capacity-providers --cluster ClusterB --capacity-providers '["CapacityProviderA"]' --default-capacity-provider-strategy '[
    {
        "capacityProvider": "CapacityProviderA",
        "weight": 1,
        "base": 0
    }
]'

An error occurred (ResourceInUseException) when calling the PutClusterCapacityProviders operation: The specified capacity provider is in use and cannot be removed.

解決編

全ての Service から古い Capacity Provider の指定を取り除けば(新しい Strategy を設定しなおせば) OK です。

今回は一件だったので、Service Name を指定して AWS CLI で設定しなおしました。

$ aws ecs update-service --cluster $CLUSTER_NAME --service ServiceB --capacity-provider-strategy '[
    {
        "capacityProvider": "CapacityProviderA",
        "weight": 1,
        "base": 0
    }
]' --force-new-deployment

--force-new-deployment を設定しないと Capacity Provider Strategy のアップデートはできません。タスクが再配置されるので注意してください。

全ての Service のアップデートを行えば、cdk deploy がうまくいくようになるはずです。

Discussion