📝

ALBのヘルスチェック結果を確認するPowerShellスクリプトを書いてみた

2021/06/23に公開

CloudFormationからEC2インスタンスを起動する際、ALBのヘルスチェックをクリアするまで後続の処理を止めておきたいというときに作成したスクリプトです。
PowerShellの超初心者が書いた内容ですが、参考になれば幸いです。

スクリプト

HealthCheck.ps1
# UTF8にエンコード
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8

# 起動したEC2インスタンス自身のIDを取得
$data = Invoke-WebRequest http://169.254.169.254/latest/meta-data/instance-id -UseBasicParsing
$id = $data.Content

# ALBによるヘルスチェックの結果を取得
$state = Get-ELB2TargetHealth -TargetGroupArn <ターゲットグループのARN> -Target @{Id = $id} -Select TargetHealthDescriptions.TargetHealth.State
echo $state >> C:\cfn\state.log

# ヘルスチェックをクリアするまで10秒ごとに結果を取得
while ($state -ne "healthy") {
    $state = Get-ELB2TargetHealth -TargetGroupArn <ターゲットグループのARN> -Target @{Id = $id } -Select TargetHealthDescriptions.TargetHealth.State
    Start-Sleep -s 10
    echo $state >> C:\cfn\state.log
}
echo "done" >> C:\cfn\state.log

エンコード

スクリプトの冒頭に
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
を記述することでUTF8にエンコードしています。
ユーザーデータ実行時にUTF8じゃないとエラーが発生したので以下の記事を参考にして記載しました。
cfn-initの実行時に「Unhandled exception during build: ‘utf8’ codec can’t decode byte…」のエラーが出る件について | DevelopersIO

自身のIDを取得

http://169.254.169.254/latest/meta-data/instance-id
上記でインスタンスのメタデータのうち、インスタンスIDを取得しています。
メタデータについて詳しくは以下のドキュメントをご覧下さい。

インスタンスメタデータの取得 - Amazon Elastic Compute Cloud
インスタンスメタデータのカテゴリ - Amazon Elastic Compute Cloud

PowerShellではcurlの代わりにInvoke-WebRequestを使うようなので、これでメタデータのURLにリクエストしています。
また、-UseBasicParsingのオプションは、EC2 Windows Server2019のデフォルトブラウザであるIEからのリクエスト時に付与しないとリクエストが通らなかったので付与しています。
EC2 user-data を使ってNAME Tagを設定する(Windows) | Oji-Cloud

Invoke-WebRequest http://169.254.169.254/latest/meta-data/instance-id -UseBasicParsingにリクエストすると、以下のレスポンスが返ってきます。

StatusCode        : 200
StatusDescription : OK
Content           : i-07a427e54c9465742
RawContent        : HTTP/1.0 200 OK
                    Connection: keep-alive
                    Accept-Ranges: bytes
                    Content-Length: 19
                    Content-Type: text/plain
                    Date: Thu, 15 Apr 2021 08:23:09 GMT
                    Last-Modified: Thu, 15 Apr 2021 08:13:06 GMT
                    Server: ...
Forms             :
Headers           : {[Connection, keep-alive], [Accept-Ranges, bytes], [Content-Length, 19], [Content-Type, text/plain]...}
Images            : {}
InputFields       : {}
Links             : {}
ParsedHtml        :
RawContentLength  : 19

上記のうち、ContentにインスタンスIDが記載されているので、一度レスポンスを$dataに入れてから、$id = $data.ContentでインスタンスIDのみを取得しています。

ALBによるヘルスチェックの結果を取得

Get-ELB2TargetHealthというAPIでヘルスチェックの結果を取得しています。
PowerShellではAWS CLIの代わりにAWS Tools for PowerShellを使用します。
詳しくはこちらをご覧ください。

各種APIについてはAWS Tools for PowerShell Referenceで確認できます。

Get-ELB2TargetHealthについてはこちらで確認できます。

  • -TargetGroupArn
    ALBのターゲットグループのARNです。
    記述例:-TargetGroupArn <ターゲットグループのARN>
  • -Target
    ヘルスチェックの結果を取得するインスタンスを指定できます。
    記述例:@{Id = "i-0bcc62df9872bd0f7" }
    実際のスクリプトでは$id = $data.Contentで取得したインスタンスIDを$idという変数に入れ、@{Id = $id}でインスタンスIDを指定しています。
  • -Select
    レスポンスの値から任意の値を選択して取得します。
    レスポンス内容はAPIにより異なるので、上記のドキュメントを参照してください。
    実際のスクリプトでは-Select TargetHealthDescriptions.TargetHealth.Stateでヘルスチェックの結果の値(healthyunhealthy)のみ取得しています。

ループ処理

while ($state -ne "healthy") {
    $state = Get-ELB2TargetHealth -TargetGroupArn <ターゲットグループのARN> -Target @{Id = $id } -Select TargetHealthDescriptions.TargetHealth.State
    Start-Sleep -s 10
    echo $state >> C:\cfn\state.log
}
  • ($state -ne "healthy")でヘルスチェックをクリアするまでループする。
  • Start-Sleep -s 10で10秒処理を止める→10秒ごとにループする
  • リクエストは前述の内容と同様

echo $state >> C:\cfn\state.log

スクリプトが実行されたかどうかの確認のためにログファイルにヘルスチェックの結果を書き込んでいます。

使用方法

EC2インスタンスのユーザーデータにスクリプトを記述することで、インスタンス起動時にスクリプトが実行されます。
Windowsのユーザーデータについて詳しくはこちらをご覧ください。
また、カスタムAMIからの起動時や再起動時にもユーザーデータを実行する場合はこちらをご覧ください。

ユースケース

  • CloudFormationでの更新時
    CloudFormationからAuto Scalingグループを作成し、Auto Scalingグループ内で起動するEC2インスタンスがALBのヘルスチェックをクリアしたら、CloudFormationの更新を続行します。詳しくはこちらをご覧ください。

まとめ

今回はALBのヘルスチェック結果を確認するPowerShellスクリプトを作成したので紹介しました。
自分自身がPowerShellの超初心者なので、もっとよい記述方法があるかもしれませんが、ひとまず期待する動作は確認できたのでこちらを使用しています。
もっと書けるようになればインスタンス起動時の初期設定も自動でできるので、機会があれば別のスクリプトも作成してみたいと思います。

参考資料

cfn-initの実行時に「Unhandled exception during build: ‘utf8’ codec can’t decode byte…」のエラーが出る件について | DevelopersIO
インスタンスメタデータの取得 - Amazon Elastic Compute Cloud
インスタンスメタデータのカテゴリ - Amazon Elastic Compute Cloud
EC2 user-data を使ってNAME Tagを設定する(Windows) | Oji-Cloud
AWS Tools for PowerShell とは何ですか? - AWS Tools for PowerShell
AWS Tools for PowerShell Reference
ElasticLoadBalancingV2: Get-ELB2TargetHealth Cmdlet | AWS Tools for PowerShell
Windows インスタンスでの起動時のコマンドの実行 - Amazon Elastic Compute Cloud

Discussion