スポットインスタンス戦略 on Ubuntu — 割り込み対策と自動フェイルオーバー

クラウド

この記事のポイント

  • AWS スポットインスタンスはオンデマンド比でおよそ50〜57%安い(us-east-1 実測・2026-06-15)。ただし「最大90%」級の割引は常時出るわけではありません
  • 実測でわかった一番大事なこと:安いタイプほど割り込まれやすい。最安級の t3.medium は割り込み率 >20%、ほぼ同じ割引の t3.large は <5% でした
  • 割り込みは2分前に spot/termination-time エンドポイントから HTTP 200 で通知されるので、systemd timer でポーリングして graceful shutdown を自動化できます
  • Auto Scaling Group の MixedInstancesPolicycapacity-optimized + ステートレス設計が、止まらない構成の鍵です

結論から言うと、AWS のスポットインスタンスは「安いから選ぶ」ではなく「割り込まれにくさで選ぶ」のが正解です。実際に料金 API を叩いて確かめたところ、割引率がほぼ同じでも割り込み頻度はタイプによって4倍以上違いました。

この記事では、AWS の公開料金データ(ec2.shop API)と、Ubuntu 24.04(Docker公式イメージ)での実コマンド検証をもとに、スポットの料金実態・割り込み通知の検知・自動フェイルオーバー構成までを、手を動かしながら解説します。数字はすべて 2026年6月15日に取得した実測値です。

スポットインスタンスとは

AWS のスポットインスタンスとは、AWS のデータセンターで余っている EC2 キャパシティを格安で使う仕組みです。オンデマンドインスタンスと同じスペックを、条件が良ければ大幅に安く利用できます。

ただしトレードオフがあります。AWS がその容量を必要としたとき、2分間の猶予のあとにインスタンスが強制終了されます(これを「スポットインスタンスの割り込み」と呼びます)。この割り込みさえ対処できれば、Ubuntu でバッチ処理・Webサーバー・CIパイプラインを走らせる際に大きなコスト削減ができます。

AWS公式 EC2スポットインスタンス紹介ページ(mock)
AWS公式 EC2スポットインスタンス紹介ページ(mock)

AWS 公式は「最大90%割引」とうたっていますが、これはあくまで上限値です。次の章で実際の料金 API を叩いて、現実の割引率を確かめてみます。

注意

本記事のコマンドは Ubuntu 24.04 LTS(Docker公式イメージ ubuntu:24.04)で検証しています。AWS CLI のインストール方法・IMDS の仕様は AWS による変更がある場合があります。本番環境に適用する際は AWS 公式ドキュメントも合わせて参照してください。

スポット料金の実態(料金APIから実測)

「どれくらい安いのか」を自分の目で確かめるため、オンデマンド価格とスポット価格、さらに SpotReclaimRate(割り込みの起きやすさの目安)を公開している ec2.shop の料金 API から、2026年6月15日に us-east-1 の主要インスタンスを実測しました。

EC2スポット vs オンデマンド料金と割り込み率(us-east-1実測、2026-06-15)
EC2スポット vs オンデマンド料金と割り込み率(us-east-1実測、2026-06-15)

たとえば t3.medium(2 vCPU / 4 GB)のスポット料金は $0.0179/時間で、オンデマンドの $0.0416/時間と比べて約 57%OFF でした。720〜730時間フル稼働でも月額 $13 前後です。「最大90%」までは届きませんが、半額以下になるのは十分に大きな差です。

ここで実測して初めて見えたのが、「割引率」と「割り込み率」はまったく別物だという事実です。下のグラフは、同じデータを割引率順に並べ、色で割り込み率を表したものです。

割引率と割り込み率の実測(us-east-1、2026-06-15)
割引率と割り込み率の実測(us-east-1、2026-06-15)

注目してほしいのは赤いバーです。最安級の t3.medium(-57.0%)と m5.xlarge(-57.4%)は、割引率が大きい一方で割り込み率が >20%と高い分類でした。逆に、ほぼ同じ割引の t3.large(-50.8%)は割り込み率 <5% と段違いに安定しています。つまり、数ドルの差で「安いけどよく落ちる」インスタンスをわざわざ選んでしまうことが起こり得るのです。

著者アイコン
著者アイコン

正直、最初は「一番安い t3.medium 一択でしょ」と思っていました。でも実測の割り込み率を見て考えを変えました。価格表だけ見て選ぶと、落ちやすいタイプを掴まされます。後述する capacity-optimized 戦略で「安定したプールを自動で選ばせる」のが結局いちばん楽です。

ちなみに同じ計測を東京リージョン(ap-northeast-1)でも行ったところ、割引率はさらに大きく t4g.medium で約75%、t3.medium で約62%でした。日本向けに低遅延で動かしたい場合は東京リージョンのスポットも十分に狙えます。

なお、スポット料金がどう決まるかは AWS 公式の料金ページにも説明があります。価格は需要と供給で変動し、リージョンとインスタンスタイプごとに決まる、という前提を押さえておきましょう。

AWS公式 EC2スポットインスタンス料金ページ(mock)
AWS公式 EC2スポットインスタンス料金ページ(mock)

割り込み通知の仕組みと実測

スポットの最大の不安は「突然止まること」ですが、AWS は割り込みの2分前に必ず通知してくれます。この通知は IMDS(Instance Metadata Service:インスタンス自身のメタデータを返す内部エンドポイント)の特定パスへの HTTP リクエストで確認できます。

仕組みを言葉で説明するより、実際に動かしたほうが早いです。今回は ubuntu:24.04 コンテナの中に IMDS と同じ応答を返すモックサーバーを立て、本番とまったく同じ curl でHTTPステータスを計測しました。

割り込み通知ポーリングの動作検証(モックIMDS / Ubuntu 24.04 実測)
割り込み通知ポーリングの動作検証(モックIMDS / Ubuntu 24.04 実測)

ポイントは、見るのは HTTP ステータスコードだけでいいことです。

  • 404:割り込みの予告なし(平常時はずっとこれ)
  • 200:割り込みが2分以内に発生する(本文に終了予定時刻 2026-06-15T09:12:00Z が入る)

IMDSv2 では、まずトークンを取得し、そのトークンを付けてメタデータにアクセスします。実機でのコマンドは次のとおりです(上の図はこの流れをコンテナ内で実測したものです)。




ubuntu@spot-instance: ~
# Step 1: IMDSv2 トークンを取得(TTL: 6時間)
$ TOKEN=$(curl -s -X PUT \
-H “X-aws-ec2-metadata-token-ttl-seconds: 21600” \
http://169.254.169.254/latest/api/token)

# Step 2: 割り込み通知を確認(ステータスコードだけ取る)
$ curl -s -o /dev/null -w “%{http_code}” \
-H “X-aws-ec2-metadata-token: $TOKEN” \
http://169.254.169.254/latest/meta-data/spot/termination-time
404 ← 404=通知なし、200=割り込み予告

割り込みハンドラを実装する

上記の通知確認を自動化するシェルスクリプトを Ubuntu に配置します。以下のスクリプトは、コンテナ内で bash -n による構文チェックを通過した実動作ファイルです(前章の図の Step4 がその実行結果です)。

①ハンドラスクリプトを作成する




ubuntu@spot-instance: ~
$ sudo nano /usr/local/bin/spot-handler.sh

ファイルの中身は以下のとおりです(構文チェック済み)。




/usr/local/bin/spot-handler.sh
#!/bin/bash
# AWS Spot インスタンス終了通知チェックスクリプト
# systemd timer から 5秒ごとに呼び出される

LOG_TAG=”spot-handler”
APP_SERVICE=”myapp.service” # 停止するサービス名に変更する

# IMDSv2 トークン取得
TOKEN=$(curl -s -X PUT \
-H “X-aws-ec2-metadata-token-ttl-seconds: 21600” \
http://169.254.169.254/latest/api/token 2>/dev/null)

# 終了通知の確認(HTTPステータスだけ見る)
STATUS=$(curl -s -o /dev/null -w “%{http_code}” \
-H “X-aws-ec2-metadata-token: $TOKEN” \
http://169.254.169.254/latest/meta-data/spot/termination-time \
2>/dev/null)

if [ “$STATUS” = “200” ]; then
logger -t “$LOG_TAG” “SPOT TERMINATION NOTICE – graceful shutdown start”
# ALB のターゲットグループから登録解除(drain の猶予を作る)
aws elbv2 deregister-targets –target-group-arn “${TARGET_GROUP_ARN}” \
–targets Id=$(curl -s http://169.254.169.254/latest/meta-data/instance-id \
-H “X-aws-ec2-metadata-token: $TOKEN”) 2>/dev/null || true
sleep 90 # drain time(2分猶予より短く設定する)
systemctl stop “$APP_SERVICE”
logger -t “$LOG_TAG” “Service $APP_SERVICE stopped gracefully”
else
logger -t “$LOG_TAG” “No termination notice (HTTP: $STATUS)”
fi



ubuntu@spot-instance: ~
$ sudo chmod +x /usr/local/bin/spot-handler.sh
# 構文チェック(ubuntu:24.04 で実測)
$ bash -n /usr/local/bin/spot-handler.sh && echo “構文OK”
構文OK

注意

sleep 90 の数値は ALB の「登録解除の遅延(Deregistration delay)」設定に合わせてください。デフォルトは300秒ですが、スポットの2分猶予(120秒)に間に合わせるため 90〜110秒程度に短縮することを推奨します。ALB コンソールの「ターゲットグループ → 属性」から変更できます。

systemd timer でポーリングを自動化する

ハンドラを5秒ごとに自動実行するため、systemd(Linux の起動・サービス管理の仕組み)のサービスとタイマーを作成します。作成した2つのユニットファイルは、コンテナ内で systemd-analyze verify による構文検証を通過済みです(systemd 255 / Ubuntu 24.04)。

手順1:service ユニットファイルを作成する




/etc/systemd/system/spot-termination-handler.service
[Unit]
Description=AWS Spot Termination Handler
After=network.target

[Service]
Type=oneshot
ExecStart=/usr/local/bin/spot-handler.sh
StandardOutput=journal
StandardError=journal

手順2:timer ユニットファイルを作成する




/etc/systemd/system/spot-check.timer
[Unit]
Description=Check Spot Termination Every 5 Seconds

[Timer]
OnBootSec=10
OnUnitActiveSec=5
Unit=spot-termination-handler.service

[Install]
WantedBy=timers.target

手順3:構文検証して有効化する




ubuntu@spot-instance: ~
# ユニットの構文を検証(ubuntu:24.04 / systemd 255 で実測)
$ systemd-analyze verify /etc/systemd/system/spot-check.timer
(エラー出力なし=検証OK)

$ sudo systemctl daemon-reload
$ sudo systemctl enable –now spot-check.timer

# タイマーの動作確認
$ systemctl list-timers spot-check.timer
NEXT LEFT UNIT ACTIVATES
… 22:34:05 JST 4s left spot-check.timer spot-termination-handler.service

# ログの確認方法
$ journalctl -t spot-handler -f
spot-handler[3721]: No termination notice (HTTP: 404)

これで5秒ごとにハンドラが走り、割り込み通知(HTTP 200)を検知すると自動で graceful shutdown が実行されます。全体の流れを図にすると次のようになります。

スポット割り込み通知から graceful shutdown までの流れ(illustrative)
スポット割り込み通知から graceful shutdown までの流れ(illustrative)

自動フェイルオーバー構成を作る

1台のスポットだけでサービスを運用すると、割り込みの瞬間にサービスが止まります。本番運用ではスポットとオンデマンドを混在させる「混在起動構成」が基本戦略です。

スポット+オンデマンド混在の自動フェイルオーバー構成(illustrative)
スポット+オンデマンド混在の自動フェイルオーバー構成(illustrative)

Auto Scaling Group の MixedInstancesPolicy 設定

AWS CLI で Auto Scaling Group を作る際、以下のように MixedInstancesPolicy を指定します。複数のインスタンスタイプを並べておくのが、前半で見た「割り込み率の差」への一番効く対策です。




ubuntu@workstation: ~
$ aws autoscaling create-auto-scaling-group \
–auto-scaling-group-name my-mixed-asg \
–min-size 2 –max-size 6 –desired-capacity 4 \
–mixed-instances-policy ‘{
“InstancesDistribution”: {
“OnDemandBaseCapacity”: 1,
“OnDemandPercentageAboveBaseCapacity”: 0,
“SpotAllocationStrategy”: “capacity-optimized”
},
“LaunchTemplate”: {
“LaunchTemplateSpecification”: {
“LaunchTemplateId”: “lt-0abc123def456”,
“Version”: “$Latest”
},
“Overrides”: [
{“InstanceType”: “c5.xlarge”},
{“InstanceType”: “c6a.xlarge”},
{“InstanceType”: “m5.xlarge”}
]
}
}’ \
–vpc-zone-identifier “subnet-aaa,subnet-bbb,subnet-ccc”

設定のポイントを解説します。

  • OnDemandBaseCapacity: 1:最低1台はオンデマンドを確保。全スポットが割り込まれても1台は残ります
  • OnDemandPercentageAboveBaseCapacity: 0:ベース以外は100%スポットで調達
  • SpotAllocationStrategy: "capacity-optimized"割り込み頻度が最も低いスポットプールを自動で選ぶ。前半で見た「安いけど落ちやすいタイプ」を避けてくれます
  • 複数タイプ(c5.xlarge / c6a.xlarge / m5.xlarge)を指定:調達先プールが分散してさらに安定します

ステートレス設計が必須

フェイルオーバーを実際に動かすには、アプリの状態(ステート)をインスタンス内に持たないことが前提です。

データの種類 保存先 理由
セッション情報 Redis(ElastiCache) インスタンスが変わってもセッションが引き継がれる
アップロードファイル S3 全インスタンスから共通でアクセスできる
データベース RDS / Aurora(マネージド) インスタンスの外に DB を出して依存を切る
アプリログ CloudWatch Logs インスタンス終了後もログが消えない

運用上の注意点とよくある疑問

①「スポットが全台割り込まれたら」どうなる?

Mixed ASG なら OnDemandBaseCapacity で設定したオンデマンド台数が残ります。1台あれば、スポットが全台落ちても ALB 経由でリクエストがその1台に流れ続けます。ただし処理能力は落ちるので、スケールアウトのトリガーを設定しておくことを推奨します。

②どのインスタンスタイプを選ぶべきか

前半の実測でわかったとおり、価格表の安さだけで選ぶのは危険です。t3.mediumm5.xlarge は安い反面、割り込み率 >20% の分類でした。1タイプに固定するより、割り込み率が低めのタイプ(今回は t3.largec6a.xlarge)を含む複数タイプを指定し、capacity-optimized に選ばせるのが最も安定します。

③Ubuntu 24.04 で AWS CLI を使うときの注意点

正直ここは詰まりやすいポイントです。Ubuntu 24.04 LTS では awscli パッケージが apt のリポジトリから提供されていません。実際にコンテナで確認したところ、候補すら出ませんでした。




ubuntu@spot-instance: ~
# ubuntu:24.04 で実測:apt に awscli はあるか
$ apt-cache policy awscli
awscli:
Installed: (none)
Candidate: (none)
← 候補なし。apt では入らない

# 公式インストーラを使う(aarch64 の例)
$ curl “https://awscli.amazonaws.com/awscli-exe-linux-aarch64.zip” -o awscliv2.zip
$ unzip awscliv2.zip && sudo ./aws/install

④スポット接続用の SSH 鍵を作る

スポットはよく作り直すので、踏み台(Bastion)を1台オンデマンドで立て、そこから ed25519 鍵で接続する構成が管理しやすいです。鍵生成は ubuntu:24.04 で実測しました(OpenSSH_9.6p1)。




ubuntu@spot-instance: ~
$ ssh-keygen -t ed25519 -f ~/.ssh/spot_key -C “ubuntu-spot-access”
Generating public/private ed25519 key pair.
Your identification has been saved in ~/.ssh/spot_key
The key fingerprint is:
SHA256:hXL8BjQDVRIA/8z9H59xVd8uDI41C2XP8VEczr6SJio ubuntu-spot-access
# ↑ Ubuntu 24.04 (OpenSSH_9.6p1) での実行結果

⑤sysbench でベンチを取っておく理由

スポットは同じインスタンスタイプでも、割り当てられる物理ハードによって性能が変動することがあります。新しい個体が起動したら sysbench でベンチを取り、極端に遅い個体を即座に置き換える仕組みを入れておくと品質が安定します。下は手元の Docker(ubuntu:24.04)で3回計測した実測例です。

sysbench CPU 実測(Docker ubuntu:24.04、2026-06-15)
sysbench CPU 実測(Docker ubuntu:24.04、2026-06-15)

計測値は 14,410 / 15,419 / 15,382 events/sec(平均15,070、変動幅±3.4%)でした。この数字はあくまで計測ホストのものです。本番 EC2 では環境が異なるため、デプロイ後に必ず自前で計測してください。

まとめ

スポットインスタンス戦略のポイントを整理します。

スポットインスタンス運用のまとめ

  • スポットはオンデマンド比でおよそ50〜57%安い(us-east-1 実測、2026-06-15)。「最大90%」は上限値で常時は出ない
  • 安い=安全ではない。t3.medium は -57%でも割り込み率 >20%、t3.large は -50.8%でも <5% と4倍以上の差がある
  • 割り込みは2分前に spot/termination-time から HTTP 200 で通知される。見るのはステータスコードだけ
  • systemd timer(5秒間隔)+シェルスクリプトで graceful shutdown を自動化できる(ユニットは systemd-analyze verify 済み)
  • ASG の MixedInstancesPolicy + capacity-optimized + 複数タイプ指定で割り込み頻度を最小化する
  • セッションは Redis、ファイルは S3、DB は RDS に逃がすステートレス設計が大前提

本格的にスポット戦略へ進む前に、まずはオンデマンドの小さなインスタンスで AWS に近い操作感に慣れておくのがおすすめです。AWS に環境が近く、東京リージョンも選べる Vultr なら、月 $5〜7 の小さなプランから気軽に始められます。

クラウド上での Ubuntu の基本的なセットアップ手順は、以下の記事も参考にしてください。

コメント

タイトルとURLをコピーしました