【アップデート】Amazon EC2 Auto Scalingでライフサイクル状態をインスタンスメタデータから取得できるようになりました

2022.03.25

コンサル部のとばち(@toda_kk)です。

Amazon EC2 Auto Scalingで管理しているEC2インスタンスについて、ライフサイクル状態をインスタンスメタデータサービス(IMDS)から取得できるようになりました。

EC2インスタンスのライフサイクルに応じた操作について、従来はAuto Scalingグループのライフサイクルフックを設定した上でEventBridgeなどと組み合わせることで実現可能でした。従来の方法については、下記の記事などが参考になるかと思います。

今回のアップデートによってライフサイクル状態の遷移をEC2インスタンス上から取得できるようになり、インスタンスメタデータサービスをポーリングしておくことで、EventBridgeなどを利用したイベント検知を設定しなくてもライフサイクル状態に応じた特定の操作をEC2インスタンス上から実行できるようになります。

ドキュメントの確認

インスタンスメタデータのカテゴリーのドキュメントに、ライフサイクルの項目 autoscaling/target-lifecycle-state が追加されています。

取得できるステータスの値は、下記の通りです。このうち Warmed: と付くものは、ウォームプールを利用した際の値となります。

  • InService
  • Terminated
  • Detached
  • Standby
  • Warmed:Hibernated
  • Warmed:Running
  • Warmed:Stopped
  • Warmed:Terminated

また、EC2 Auto Scalingのドキュメントにも、インスタンスメタデータからライフサイクル状態を取得する方法についてページが追加されています。

実際に取得する際のコマンドが記載されています。

IMDSv1

curl http://169.254.169.254/latest/meta-data/autoscaling/target-lifecycle-state

IMDSv2

TOKEN=`curl -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600"` \
&& curl -H "X-aws-ec2-metadata-token: $TOKEN" -v http://169.254.169.254/latest/meta-data/autoscaling/target-lifecycle-state

ちなみに上記のURLは、EC2インスタンスがAuto Scalingによって起動している場合にのみ有効なようで、Auto Scalingグループで管理していないEC2インスタンスからリクエストすると404エラーが返ってきました。

Auto Scalingグループで管理していないEC2インスタンスから実行

$ curl http://169.254.169.254/latest/meta-data/autoscaling/target-lifecycle-state
<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
        "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
 <head>
  <title>404 - Not Found</title>
 </head>
 <body>
  <h1>404 - Not Found</h1>
 </body>
</html>

チュートリアルのドキュメントが用意されている

加えて、ユーザーデータを用いてインスタンスメタデータからライフサイクル状態を取得するためのチュートリアルのドキュメントも用意されていました。

チュートリアルでは、下記のスクリプトを実行するユーザーデータを起動テンプレートに設定しておき、Auto Scalingグループで管理するEC2インスタンスが起動した際にホスト名を変更する処理を実行しています。

ユーザーデータ

#!/bin/bash

function get_target_state {
    echo $(curl -s http://169.254.169.254/latest/meta-data/autoscaling/target-lifecycle-state)
}

function get_instance_id {
    echo $(curl -s http://169.254.169.254/latest/meta-data/instance-id)
}

function complete_lifecycle_action {
    instance_id=$(get_instance_id)
    group_name='TestAutoScalingEvent-group'
    region='us-west-2'
 
    echo $instance_id
    echo $region
    echo $(aws autoscaling complete-lifecycle-action \
      --lifecycle-hook-name TestAutoScalingEvent-hook \
      --auto-scaling-group-name $group_name \
      --lifecycle-action-result CONTINUE \
      --instance-id $instance_id \
      --region $region)
}

function main {
    while true
    do
        target_state=$(get_target_state)
        if [ \"$target_state\" = \"InService\" ]; then
            # Change hostname
            export new_hostname="${group_name}-$instance_id"
            hostname $new_hostname
            # Send callback
            complete_lifecycle_action
        fi
        echo $target_state
        sleep 5
    done
}

main

このスクリプトは、下記のような内容となっています。

  • インスタンスメタデータから、インスタンスのライフサイクル状態およびインスタンスIDを取得する
  • ライフサイクルの状態が InService に変わるまで繰り返し取得する
  • ライフサイクルの状態が InService の場合、インスタンスのホスト名を、Auto Scalingグループの名前を先頭に付けたインスタンスIDに変更する
  • AWS CLIで complete-lifecycle-action コマンドを実行してコールバックを送信し、EC2 Auto Scalingに対して起動を継続させるよう通知して、ライフサイクルアクションを完了させる

工夫次第ではライフサイクルに応じたイベント処理がEC2インスタンス上で完結できそう

今回のアップデートによって、工夫次第ではライフサイクルに応じたイベント処理がEC2インスタンス上で完結できるようになりました。

ただし、インスタンスメタデータサービスをポーリングしておく必要があるなど、ある程度の制約はありそうです。

上手くいかない場合には、EventBridgeなどを利用した従来の方法も代替案としてご検討いただくのがよろしいかと思います。

以上、コンサル部のとばち(@toda_kk)でした。