mazyu36の日記

某SIer所属のクラウドエンジニアのブログ

boto3でECSタスクのスケールイン保護を実装する

はじめに

ECSタスクのスケールイン保護をpython(boto3)で検証したので、その時のメモを残す。

背景

とある案件であるイベントが発生すると、その後ユーザーからのリクエストが急増する可能性があるため、事前にECS FargateでAutoScalingの最大値までスケールアウトをしておくということをやりたかった(Auto Scalingのポリシー自体はターゲット追跡ポリシーを使用)。

しかし単にスケールアウトを指示したのみだと、ユーザーからのアクセスが発生し始める前にスケールインが始まってしまい、効果がなかった。

そうしたところでECSタスクのスケールイン保護が発表された。これを元にスケールアウトした後にスケールイン保護をかければ、アクセス負荷が無い時でも一定時間スケールインしないようにできるのでは??ということで検証していた。

aws.amazon.com

前提

スケールイン保護のやり方

上記ブログにも記載があるがスケールイン保護には以下の2つのやり方がある。

  • Amazon ECS エージェントエンドポイントの使用:主にタスクが自分自身でスケールイン保護をかけるときに使用する方法。
  • Amazon ECS API の使用:主にタスク外からスケールイン保護をかけるときに使用する方法。

今回要件的にECSの外のpythonプログラムから実行したいので、後者でboto3を元に実装することにした。

boto3のAPIを確認

update_task_protectionを使用する形になる。

boto3.amazonaws.com

APIを確認すると以下のようになっている。クラスター名とタスクのarnが必要となる。

response = client.update_task_protection(
    cluster='string',
    tasks=[
        'string',
    ],
    protectionEnabled=True|False,
    expiresInMinutes=123
)

実装

流れ

今回スケールアウトを行い、起動したタスクに一定時間スケールイン保護をかけるということをやりたいので、以下の流れで実施する。

  1. スケールアウトを指示
  2. タスクのarnをリストとして取得
  3. スケールイン保護を実施

1. スケールアウトを指示

update_serviceを使用して指定の数にスケールアウトを指示する。

boto3.amazonaws.com

import boto3

client = boto3.client("ecs")

# クラスター名、サービス名、タスクの必要数を指定してスケールアウトを指定
response = client.update_service(
    cluster=cluster_name,
    service=service_name,
    desiredCount=desired_count,
)

2. タスクのarnをリストとして取得

スケールイン保護のAPIにはタスクのarnのリストを渡す必要があるため、list_tasksを使用して取得する。

boto3.amazonaws.com

ただし1の直後に実行すると、早すぎてスケールアウトで追加されるタスクのarnを取得することができない。

そのため若干いまいちだが、update_service実行後30秒程度待機してからlist_tasksを実行すれば問題なく取得できた(タスク数が多いともっと待機時間いるかも)

※他にいいやり方あったら教えてください。

import time

# 30秒待機
time.sleep(30)

# list_tasksで対象のサービスのタスクのarnを取得する
response = client.list_tasks(
    cluster=cluster_name,
    serviceName=service_name,
)

# responseのtaskArnsからタスクのarnのリストを取得可能
ask_arns=response["taskArns"]

3. スケールイン保護を実施

2で取得したタスクのarnのリストを使用してスケールイン保護をかける。

# スケールイン保護を実施
response = client.update_task_protection(
    cluster=cluster_name,
    tasks=task_arns,  # 2で取得したタスクのarnのリスト
    protectionEnabled=True,  # Trueの場合スケールイン保護が有効
    expiresInMinutes=10  # 指定時間(分)スケールイン保護が有効になる。未指定の場合120分になる。
)

上記を元に実行してみたところ、3のexpiresInMinutesが経過するまではスケールインが発動しないよう、保護することができた。

終わりに

以上でスケールアウトさせた後も、指定時間はスケールインが行われないようにECSタスクを保護することができた。

簡単にできたが、タスクのarnのリストじゃなくてサービス名で指定して一括でスケールイン保護かけるができるとより良いと思う。