Auto Scaling のライフサイクルフックの使い方 ── インスタンスの終了前にデータの退避を済ませる

目次

概要

Auto Scaling グループのインスタンスは、スケールインやヘルスチェックの失敗で、Auto Scaling の判断で終了されます。インスタンスの EBS にあるログやデータを終了前に S3 へコピーしたいのに、コピーが終わる前にインスタンスが消えてしまう、ということが起こります。

このとき使うのが ライフサイクルフック です。終了時のライフサイクルフックをグループに付けておくと、終了が決まったインスタンスはすぐには終了されず、Terminating:Wait という待機状態で止まります。その間にデータの退避などの処理を行い、終わったら complete-lifecycle-action で「終了を進めてよい」と知らせます。

この記事では、ライフサイクルフックの状態遷移、ハートビートタイムアウトとデフォルトの結果(CONTINUE / ABANDON)、待機中の処理の動かし方を整理します。実践では、Auto Scaling グループに終了時のライフサイクルフックを付けて台数を 0 に減らし、インスタンスが Terminating:Wait で待つことを確かめてから、CloudShell から complete-lifecycle-action を送って終了させます。

終了時のライフサイクルフック ── Terminating:Wait の間に処理を済ませる
終了時のライフサイクルフック ── Terminating:Wait の間に処理を済ませる
クラウドおさる

当番を交代させるとき、いきなり帰らせると引き継ぎ帳が残らぬのでござる。「帰る前に一声かけてから」と決めておくのが、今日のライフサイクルフックでござるよ。

この記事のメリット

  • 終了時のライフサイクルフックで、インスタンスが Terminating:Wait に入る流れを説明できるようになる
  • ハートビートタイムアウトとデフォルトの結果(CONTINUE / ABANDON)の意味が分かる
  • complete-lifecycle-action と record-lifecycle-action-heartbeat の使い分けが分かる
  • 「終了前に処理を済ませたい」要件に、終了保護などの別の機能ではなくライフサイクルフックを選ぶ理由が分かる

執筆者とキャラクター紹介

執筆者:土肥(とひ)

株式会社ジェニュインの代表であり元エンジニア。これまでオンプレミスと AWS 環境のインフラ業務を担当。AWS 認定資格の学習で得た知識を、ハンズオンとともに解説するのが得意。直近では新人の教育も行っており、これから技術を学ぶ方が納得できる解説を心がけています。基礎編・Cloud Practitioner の記事では、解説役としても登場します。

土肥

クラウドおさる

クラウドおさる

はじめましてでござる。弊猿はクラウドおさる。IT インフラが異常に発達した猿山から、雲に乗って地上の AWS を学びに降りてきたのでござる。

クラウドおさる

基礎編や Cloud Practitioner の記事では、とひさんに素朴な疑問をぶつける役でござるな。Security - Specialty などの記事では、要所でワンポイントや注意点をひとこと添えるでござる。

クラウドおさる

猿山にもデータセンターや監視当番があって、地上で起きることはだいたい猿山にも同じ仕組みがあるのでござる。例え話がつい猿山に寄るのは、弊猿の癖でござる。

技術解説

インスタンスのライフサイクルとフック

Auto Scaling グループのインスタンスは、起動から終了まで決まった状態をたどります。スケールイン(希望する容量の縮小、動的スケーリング、スケジュール)で終了するインスタンスが決まると、そのインスタンスは Terminating に移り、InService には戻れなくなります。

終了時のライフサイクルフック(ライフサイクルの移行が「インスタンスの終了」、autoscaling:EC2_INSTANCE_TERMINATING)があると、Terminating と Terminated の間に待機の状態が入ります。

状態内容
InServiceグループの一員として動いている
Terminating終了が決まった。ロードバランサーを使っていれば、ここで登録が解除される
Terminating:Waitライフサイクルフックの待機中。インスタンスはまだ動いていて、ここで終了前の処理を行う
Terminating:Proceedライフサイクルアクションが完了し、終了に進む
Terminated終了した

起動時のライフサイクルフック(autoscaling:EC2_INSTANCE_LAUNCHING)もあり、こちらは Pending:Wait で待ってからソフトウェアの導入などを済ませ、InService に入れます。

起動時と終了時の状態遷移 ── フックは「Wait」を差し込む
起動時と終了時の状態遷移 ── フックは「Wait」を差し込む

ハートビートタイムアウトとデフォルトの結果

ライフサイクルフックには、待機をいつまで続けるかと、時間切れのときにどうするかを設定します。

設定内容
ハートビートのタイムアウト待機する時間。既定は 3600 秒(1 時間)。コンソールでは 30〜7200 秒で指定する。終了時のフックは、必要な処理に合わせた短い値(30〜120 秒)が推奨されている
デフォルトの結果タイムアウトしたときの結果。「続行(CONTINUE)」か「中止(ABANDON)」
グローバルタイムアウトハートビートで延長しても、48 時間かハートビートタイムアウトの 100 倍の、短いほうを超えて待機することはできない

CONTINUE と ABANDON の違いは、起動時と終了時で効き方が変わります。

結果起動時のフック終了時のフック
CONTINUEインスタンスを InService にする残りのフックを続けたうえで終了する
ABANDONインスタンスを終了する残りのフックを止めて終了する

既定では、終了時のフックはどちらの結果でもインスタンスは終了します。終了時のフックはベストエフォートで、タイムアウトや中止のときも、Auto Scaling はそのままインスタンスの終了に進みます。フックだけでは、終了そのものを取りやめることはできません。

なお、インスタンスライフサイクルポリシーで TerminateHookAbandon のときにインスタンスを保持するよう設定しておくと、ABANDON で完了したインスタンスは終了せずに保持状態へ移ります。保持されたインスタンスは手で調べたあと、TerminateInstanceInAutoScalingGroup で終了させます。

クラウドおさる

終了時のフックだけなら、ABANDON を返しても当番は帰ってしまうのでござる。「終了を止める」のではなく「帰る前に時間をもらう」仕組みだと覚えておくでござるぞ。

待機中の処理を動かす方法

ライフサイクルフック自体は、インスタンスを待たせるだけです。待機中に何をするかは自分で用意し、終わったらライフサイクルアクションを完了させます。

方法内容
EventBridge のルールライフサイクルアクションのイベント(終了時は EC2 Instance-terminate Lifecycle Action)を受けて、Lambda 関数や Systems Manager の Automation を動かす。推奨されている方法
SNS・SQS・Lambda への通知フックの通知先にトピック・キュー・関数を指定し、受け取った側で処理する(SQS の FIFO キューは使えない)
インスタンス上のスクリプトインスタンスメタデータの autoscaling/target-lifecycle-state(移行先の状態)をポーリングし、Terminated に向かっていると分かったら処理する

処理が終わったら、次のどちらかの API を呼びます。

API(CLI)用途
complete-lifecycle-action結果(CONTINUE / ABANDON)を返して待機を終える。インスタンス ID か、ライフサイクルアクショントークンで対象を指定する
record-lifecycle-action-heartbeatタイムアウトまでの時間を最初から数え直し、待機を延ばす。たとえばタイムアウト 1 時間で 30 分後に呼ぶと、合計 90 分待てる
クラウドおさる

退避が長引きそうなら「まだ引き継ぎ中でござる」と一声(ハートビート)かければ、待ってもらえるのでござる。ただし声をかけ続けても、上限(グローバルタイムアウト)より先には延ばせぬでござるな。

似た機能との違い

「インスタンスが勝手に消えないようにしたい」という要件には、似た機能がいくつかあります。終了前に処理を済ませたいなら、ライフサイクルフックが目的に合います。

機能何をするか終了前の処理に使えるか
ライフサイクルフック(終了時)終了の前に待機時間を作り、処理が終わったら終了を進める使える
インスタンスのスケールイン保護スケールインで終了されるインスタンスの候補から外す使えない。ヘルスチェックの失敗による置き換えは止めない
EC2 の終了保護(DisableApiTermination)コンソール・CLI・API からの手動の終了を拒否する使えない。Auto Scaling による終了は止めない。処理の時間を作る仕組みでもない
スタンバイ状態インスタンスを一時的にグループのサービスから外す使えない。手動でサービスから外す操作で、終了前の処理の時間を作る仕組みではない
新卒・未経験の方へ
クラウドおさる

AWS を仕事にしたい方へ ── 新卒・未経験から

この記事を書いているのは、AWS の設計・構築を仕事にしている現役エンジニアです。運営元の株式会社ジェニュインでは、新卒・未経験の方も募集しています。異業種や文系からインフラエンジニアになり活躍しているメンバーもいます。

  • ✓システム開発・WEB エンジニア / インフラ構築などの職種で、未経験から応募できます
  • ✓未経験から入社した社員の声を含む社員アンケートを掲載
  • ✓応募フォームから 1 分で応募できます

実践

ハンズオンガイド8 ステップ画面 4 枚

コンソールの横に開いて、チェックしながら進めましょう。

ガイドを開く

別タブで開きます。チェックはこのブラウザに保存されます。

Auto Scaling グループ soa-lifecycle-asg に、終了時のライフサイクルフック soa-terminate-hook を付けます。希望する容量を 0 に減らし、インスタンスが Terminating:Wait で待つことを確かめてから、CloudShell でハートビートと complete-lifecycle-action を送って終了させます。ここでは退避処理の代わりに、待機中のインスタンスの状態を確かめる操作を行います。

前提条件

  • リージョン: ap-northeast-1(東京)
  • 以下のリソースが作成済みであること

まだ用意していない場合は、「作り方の参考」の記事の手順で作れます。リソース名は、この記事の名前に読み替えてください。

リソース種別リソース名内容作り方の参考
起動テンプレートsoa-lifecycle-templateAmazon Linux 2023・t3.microEC2 Auto Scaling で落ちても自動で戻る Web サーバーを作る
Auto Scaling グループsoa-lifecycle-asgsoa-lab-vpc のパブリックサブネット(1a・1c)。最小 0・希望 1・最大 1。インスタンス 1 台が InService同上 ※ロードバランサーは付けない

作成するリソース一覧

リソース種別リソース名用途
ライフサイクルフックsoa-terminate-hookインスタンスの終了前に待機させる

手順 1: 終了時のライフサイクルフックを作る

AWS マネジメントコンソールにログインし、リージョンが ap-northeast-1(東京)であることを確認します。上部の検索バーに EC2 と入力し、「EC2」を選択します。

左側ナビゲーションの「Auto Scaling」→「Auto Scaling グループ」を選択し、soa-lifecycle-asg を開きます。「インスタンス管理」タブを選択し、インスタンスが 1 台 InService になっていることを確認します。

同じタブの「ライフサイクルフック」のセクションで「ライフサイクルフックを作成する」をクリックし、以下を設定します。

  • ライフサイクルフック名: soa-terminate-hook
  • ライフサイクル移行: 「インスタンス終了」
  • ハートビートタイムアウト: 600 秒(既定値は 3600 秒。手順を確かめやすいよう短めにしています)
  • デフォルトの結果: 「CONTINUE」(既定値は ABANDON なので変更します)

その他の項目はデフォルトのままにして、「作成」をクリックします。

ライフサイクルフックの作成画面(soa-terminate-hook・インスタンス終了・タイムアウト 600 秒・CONTINUE)
ライフサイクルフックの作成画面(soa-terminate-hook・インスタンス終了・タイムアウト 600 秒・CONTINUE)

手順 2: 希望する容量を 0 にする

「詳細」タブを選択し、「グループの詳細」の「編集」をクリックします。

  • 希望する容量: 0

最小容量・最大容量はそのままにして、「更新」をクリックします。グループのステータスが「容量の更新」になり、インスタンスを 1 台終了しようとします。

手順 3: Terminating:Wait で待っていることを確かめる

「インスタンス管理」タブを選択します。インスタンスの「ライフサイクル」が Terminating:Wait になっています(表示が変わらない場合は、更新ボタンで一覧を読み込み直します)。

インスタンス管理タブ(ライフサイクルが Terminating:Wait のインスタンス)
インスタンス管理タブ(ライフサイクルが Terminating:Wait のインスタンス)

左側ナビゲーションの「インスタンス」→「インスタンス」を開くと、このインスタンスはまだ「実行中」です。終了は決まっていますが、フックの待機中なので、インスタンス上で退避などの処理を動かせる状態です。

手順 4: CloudShell で待機中のインスタンスを確かめ、待機を延ばす

上部のツールバーの CloudShell アイコンをクリックして AWS CloudShell を開き、次のコマンドで待機中のインスタンスを確認します。

aws autoscaling describe-auto-scaling-instances \
  --query "AutoScalingInstances[?AutoScalingGroupName=='soa-lifecycle-asg'].[InstanceId,LifecycleState]" \
  --output table

インスタンス ID と、Terminating:Wait の状態が表示されます。表示されたインスタンス ID を変数に入れ、ハートビートを送って待機を延ばします。

INSTANCE_ID=<表示されたインスタンス ID>
aws autoscaling record-lifecycle-action-heartbeat \
  --lifecycle-hook-name soa-terminate-hook \
  --auto-scaling-group-name soa-lifecycle-asg \
  --instance-id $INSTANCE_ID

何も表示されなければ成功です。タイムアウトまでの 600 秒が、ここから数え直されます。

CloudShell の実行結果(describe-auto-scaling-instances で Terminating:Wait を確認し、ハートビートを送った状態)
CloudShell の実行結果(describe-auto-scaling-instances で Terminating:Wait を確認し、ハートビートを送った状態)
クラウドおさる

実際の運用では、ここで EBS のデータを S3 へコピーするのでござる。その処理を EventBridge から Lambda や Automation で動かせば、人が CloudShell に張り付かなくても済むでござるな。

手順 5: ライフサイクルアクションを完了する

退避が終わったものとして、complete-lifecycle-action で CONTINUE を返します。

aws autoscaling complete-lifecycle-action \
  --lifecycle-action-result CONTINUE \
  --lifecycle-hook-name soa-terminate-hook \
  --auto-scaling-group-name soa-lifecycle-asg \
  --instance-id $INSTANCE_ID

続けて、状態を確認します。

aws autoscaling describe-auto-scaling-instances --instance-ids $INSTANCE_ID \
  --query "AutoScalingInstances[].[InstanceId,LifecycleState]" --output table

Terminating:Proceed が表示されます(すでに終了していれば、何も表示されません)。

手順 6: 終了したことを確かめる

EC2 のコンソールに戻り、soa-lifecycle-asg の「アクティビティ」タブを選択します。「アクティビティ履歴」の最新の行で、インスタンスの終了(Terminating EC2 instance: i-...)のステータスが「成功」になっていることを確認します。開始時刻から終了時刻までの間が、フックで待機していた時間です。

アクティビティ履歴(インスタンスの終了が成功し、開始から終了までフックの待機時間が空いている状態)
アクティビティ履歴(インスタンスの終了が成功し、開始から終了までフックの待機時間が空いている状態)

「インスタンス管理」タブを開くと、インスタンスはグループから無くなっています。

クラウドおさる

「消える前に何かを済ませたい」と言われたら、待たせる仕組みと、済んだことを知らせる API の組み合わせを思い出すのでござる。終了保護のように、終了そのものを止めるものと取り違えぬようにするでござるな。

まとめ

困りごと使うもの
終了前にログやデータを退避したい終了時のライフサイクルフック(Terminating:Wait で待つ)
処理が終わったら終了を進めたいcomplete-lifecycle-action(CONTINUE / ABANDON)
処理がタイムアウトに間に合わないrecord-lifecycle-action-heartbeat で待機を延ばす
起動後、ソフトウェアの導入を終えてからサービスに入れたい起動時のライフサイクルフック(Pending:Wait)
  • 終了時のフックがあると、インスタンスは Terminating → Terminating:Wait → Terminating:Proceed → Terminated とたどる
  • ハートビートタイムアウトの既定は 1 時間。時間切れのときはデフォルトの結果(CONTINUE / ABANDON)で進む
  • 既定では、終了時のフックは CONTINUE でも ABANDON でもインスタンスは終了する。ABANDON のときに保持したいなら、インスタンスライフサイクルポリシーを組み合わせる
  • 待機はハートビートで延ばせるが、48 時間かタイムアウトの 100 倍の短いほうが上限
  • EC2 の終了保護(DisableApiTermination)は Auto Scaling による終了を止めない。スケールイン保護も、終了前の処理の時間を作る仕組みではない

参照先

キャリア相談
クラウドおさる

独学の先に、AWS の仕事がある ── ジュニアおさるのキャリア相談

CLF には受かったけれど、次に何をすればいいのか分からない。独学で AWS を学ぶジュニアおさるの相談に、株式会社ジェニュイン代表の土肥が答えています。

  • ✓資格はゴールか、CLF の次に何から手を付けるか
  • ✓EC2 の次に作ってみる構成と、IaC・コスト管理
  • ✓実務経験ゼロでも、面接で話せる「これまで」の作り方
新卒・未経験の方へ
クラウドおさる

AWS を仕事にしたい方へ ── 新卒・未経験から

この記事を書いているのは、AWS の設計・構築を仕事にしている現役エンジニアです。運営元の株式会社ジェニュインでは、新卒・未経験の方も募集しています。異業種や文系からインフラエンジニアになり活躍しているメンバーもいます。

  • ✓システム開発・WEB エンジニア / インフラ構築などの職種で、未経験から応募できます
  • ✓未経験から入社した社員の声を含む社員アンケートを掲載
  • ✓応募フォームから 1 分で応募できます

この記事が気に入ったら
フォローしてね!

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

株式会社ジェニュイン(https://genuine-pt.jp)の代表取締役.

2018年〜インフラエンジニアとしてキャリアをスタートし、オンプレミスのネットワーク・サーバ環境で3年半、クラウド環境で4年半の8年間エンジニアとして従事。
2021年に佐藤氏の創業した株式会社Luxyを引き継ぎ、代表に就任。
その後アガルートグループ内の株式会社ジェニュインと合併。
合併後同社代表に就任。

目次