📝

続・CloudFormationでEC2インスタンスの起動が完了したらスタックの更新を続行する方法

4 min read

先日、
CloudFormationでEC2インスタンスの起動が完了したらスタックの更新を続行する方法
という記事を書いたのですが、その翌日に、
AWS EC2オートスケーリングで新しいインスタンスの準備ができるまでアタッチを待機させるには
という素晴らしい記事を発見しました!
これは合わせ技一本(?)ができるのでは!?
と思い、さっそく上記の発見した記事を参考にやってみました。

概要

  • 基本的な方法は前回書いた記事のまま
  • Auto Scalingグループ内に起動したEC2インスタンスがALBに登録されるまで5分間待機させる
    • Auto Scalingグループのライフサイクルフックを使用する
  • 以下のようなイメージです
  1. CloudFormationスタックへの更新リクエストにより、Auto Scalingグループの置換更新が行われ、まず新しいAuto ScalingグループとEC2インスタンス1台が起動します。ただし、CloudFormation側は、起動したインスタンスから成功シグナルが送信されるまでスタックの更新を一時停止します。
  2. EC2インスタンスの起動をトリガーに、Auto Scalingグループのライフサイクルフックが発火し、5分間はインスタンスの起動を待機します。この間、ALBにも登録されません。
  3. 5分後にインスタンスがALBに登録され、ヘルスチェックスクリプトにより、インスタンス自身のヘルスチェック結果を確認します。
  4. ヘルスチェックに合格したら、cnf-singalでCloudFormation側に成功シグナルを送信します。
  5. 成功シグナルを受信したCloudFormationは、スタックの更新を再開し、古いAuto Scalingグループの削除を行います。ALBからの登録解除もAuto Scalingグループにより自動的に行われます。

待機の必要性

インスタンス起動後のステータスチェックの間は、ALBに登録されてもしばらくunhealthy状態が続いてしまいます。この状態でAuto Scalingグループ側の「ヘルスチェックの猶予期間」を超えてしまうと、ステータスチェック中のインスタンスが終了してしまいます。
なので、ステータスチェックのための時間をある程度与えることで、ALBに登録されてからhealthyになるまでが速くなるはずだと推測しました。

実は結構前にサポートに相談した際に、以下のようなご案内を頂いていました。
Q. ALBに登録されたインスタンスがタイムアウトでunhealthyになることへの対策

AMI起動後に各種ソフトのインストールをせずにあらかじめ可能な限りAMIに含めておくといったことが一つのプラクティスとなりますが、それでも対応できない場合、Auto Scalingのライフサイクルフックの機能を利用していただき、準備が完了し次第、Auto Scalingで利用可能なように設定いただく方法がございます。

また、別のケースで、インスタンス起動時に、

ハードウェアの初期化にもある程度時間がかかる

ということも教えて頂きました。
以上のような理由から、ステータスチェックにはある程度時間を与え、その間はALBへの登録を待機させるという方法がよいと判断しました。
(Auto Scalingグループのヘルスチェックの猶予期間を長くするという方法もあるとは思います)

設定してみた

CloudFormationやヘルスチェックスクリプトは前回の記事をご覧ください。

ライフサイクルフックの作成

今回は以下のようにライフサイクルフックもCloudFormationテンプレートに記述しました。

"LifecycleHookSpecificationList": [
  {
    "DefaultResult": "CONTINUE",
    "HeartbeatTimeout": 300,
    "LifecycleHookName": "LaunchingHook_BeforeRegisterWithAlb",
    "LifecycleTransition": "autoscaling:EC2_INSTANCE_LAUNCHING"
  },
  {
    "DefaultResult": "CONTINUE",
    "HeartbeatTimeout": 1800,
    "LifecycleHookName": "TerminatingHook_CreateImage",
    "LifecycleTransition": "autoscaling:EC2_INSTANCE_TERMINATING"
  }
]

1つ目のLaunchingHook_BeforeRegisterWithAlbが、インスタンス起動時に300秒待機するライフサイクルフックです。
2つ目のTerminatingHook_CreateImageは、インスタンスが意図せず終了した際に、障害調査用のAMIを取得するためのライフサイクルフックです。今回こちらは使用しませんが、こちらで紹介しています。

実行してみる

では、上記のライフサイクルフックを記述したテンプレートでCloudFormationスタックを更新します。
まず新しいAuto Scalingグループが起動し、ライフサイクルフックによってインスタンスの起動が待機状態になりました。

この間、ターゲットグループには古いインスタンスのみが登録されており、新しいインスタンスはまだ登録されていません。

5分経過すると、インスタンスの起動が完了し、がターゲットグループに登録されました。

ヘルスチェックスクリプトにより、unhealthyhealthyになるのを監視します。

healthyになったので、CloudFormationに成功シグナルを送信し、古いグループとインスタンスは削除されます。古いインスタンスはALBからも自動的に登録解除されます。
CloudFormationは後続の更新処理を実施し、スタックの更新を完了させます。

上記のような挙動で、期待通りに更新することができました!
推測通り、新しいインスタンスのヘルスチェックがhealthyになるのも速かったです。

まとめ

今回は
CloudFormationでEC2インスタンスの起動が完了したらスタックの更新を続行する方法

AWS EC2オートスケーリングで新しいインスタンスの準備ができるまでアタッチを待機させるには
の内容を加えて実装してみました。
ライフサイクルフックでALBへの登録も待機できるというのは知らなかったで、すごく勉強になりました!
AWSの環境は作ったら終わりじゃなくて、こうして少しずつアップデートできるのもうれしいです!

今回の内容がどなたかの参考になれば幸いです。

参考資料

AWS EC2オートスケーリングで新しいインスタンスの準備ができるまでアタッチを待機させるには