🍣

スポットインスタンスの中断通知を受けてスクリプトを実行する (インスタンスメタデータ編)

2023/06/09に公開

はじめに

スポットインスタンスは中断する可能性があります。
そのため中断通知を受け取ったら何かしらのアクション(バックアップ等)を実行して、中断の影響を少なくする必要があります。

今回はその避難訓練として、インスタンスメタデータから中断通知を受け取り、その通知から簡単なスクリプトを実行させる検証を行いました。

※EventBridge+Lambda編はいずれできたらいいな

検証内容

  • 5秒おきにインスタンスメタデータinstance-actionを確認するシェルスクリプトを動かす
  • 返却されるステータスコードが404であれば、中断通知が来ていないためそのまま続行
  • 返却されるステータスコードが200の際に、instance-actionの内容を一時ファイルに書き込み、s3にコピーする

中断時のバックアップを想定した軽い検証となります。

環境

FISでスポットインスタンスを停止出来る環境を使用します。Terraformで再現可能です。
https://github.com/not75743/FIS-Terminate-SpotInstance

事前準備

s3の準備

ファイル格納用のs3を用意します。
特に言及することはありません。

メタデータinstance-actionの理解

中断通知のありなしで応答する内容が異なります。

中断通知なし

エラーメッセージ、ステータスコード404が返却されます。

$ TOKEN=`curl -s -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" http://169.254.169.254/latest/meta-data/spot/instance-action
<?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>

中断通知あり

中断予定時間、ステータスコード200が返却されます。
この場合2023年6月9日10時27分17秒にスポットインスタンスが中断されます。

$ TOKEN=`curl -s -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" http://169.254.169.254/latest/meta-data/spot/instance-action
{"action":"terminate","time":"2023-06-09T01:27:17Z"}

シェルスクリプトの準備

今回はcronを作成せずに、シェルスクリプトを実行・常駐するスタイルにしました。
(cronで5秒おき実行はできるのかな?)

#!/bin/bash

export s3bucket="testbucket-20230609"

while true; do
  TOKEN=`curl -s -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600"`
  response=$(curl -s -w "%{http_code}" -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/spot/instance-action)

  http_code=${response:(-3)}
  
  if [ "$http_code" == "200" ]; then
    instance_action=${response:0:${#response}-3}
    echo $instance_action > /tmp/instance-action.txt
    aws s3 cp /tmp/instance-action.txt s3://${s3bucket}/
    break
  fi
  sleep 5
done

instance-actionの応答するステータスコードが200であれば、その内容をs3にコピーします。
ステータスコードが404であれば、中断通知が来ていないということで特に何もしません。

準備が出来たらスポットインスタンスでスクリプトを実行します。

$ vi spot-notice.sh
$ chmod 700 spot-notice.sh
$ ./spot-notice.sh

動作確認

FISでスポットインスタンスへ中断通知を送ります。

s3に中断予定時間の書かれたファイルが転送されればOKです


参考

https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/spot-instance-termination-notices.html

Discussion