EC2 Spot Instanceの価格変動をターミナルでモニタリングする

というものを作った。こんな感じの。

f:id:sugyan:20160623232900p:plain

Repository : https://github.com/sugyan/spot-price-watcher

背景

TensorFlowを使ったDeep Learningでアイドルの顔識別なんかをずっとやってきたけど、やっぱりCPUマシンだけでやっていくのは厳しいな、と思い、

ということでAmazon EC2にてGPU instanceを使って動かすことにした。

g2.2xlargeインスタンスでTensorFlowを動かせるようにするのは、下記記事なんかを参考にしながらやってみたら何とか出来た。 ソースからビルドする必要があるのは時間かかってつらかったけど…

qiita.com

まぁ1回環境を構築してAMIを作ってしまえばその後は苦労せずに同じ環境を再現できるので便利ですね。

で、g2.2xlargeインスタンスを普通に作ると一番安いUSリージョンでも $0.65 per Hour かかるのだけど、これを出来るだけ節約したい。 今までEC2まともに使ったことなくて今回はじめて知ったのだけど、Spot Instancesというのがある。

スポットインスタンスでは、スポットインスタンスリクエストに入札価格を指定して、支払うことができるインスタンス時間あたりの価格を選択します。入札価格がその時点のスポット価格以上であれば、リクエストが受理されてインスタンスを実行できるようになります。このインスタンスの実行は、お客様がインスタンスを終了した時点と、スポット価格が入札価格を上回った時点のいずれか早い方までとなります。スポット価格は Amazon EC2 によって設定され、スポットインスタンス容量に対する需要と供給に応じて定期的に変動します。

製品の詳細 - Amazon EC2 スポットインスタンス - Amazon EC2 | AWS

これを使って、スポット価格が安い時間帯に実行すれば通常インスタンスよりかなり安く済ませられる。 ここ数日の大雑把な感覚だと、US regionでのg2.2xlargeだと $0.1 - $0.2 per Hour のときがあり、最大7〜8割お得になる計算。

ただこのスポット価格は刻一刻と変化しており、いつどのAvailability Zoneがどんな価格に変化するか分からないし、予測できない(これをDeep Learningで予測する、とかも課題としては面白いかもしれないw けどどんな要素が絡んでいるかもよく分からないしなぁ…)。

スポット価格が自分の入札価格を上回ってしまうとその時点でインスタンスは強制中断されてしまうので 中断されるのがイヤな場合はできるだけ高額の入札価格にしておけば良いのだけど、勿論そのスポット価格の分は課金されることになるわけで。

自分の場合は個人の趣味レベルでやってることだし アイドル顔認識モデルの学習なんかは数千step実行すれば十分で、g2.2xlargeインスタンスを使うとGPUの力で1stepあたり0.6秒弱、だから1時間あれば6000stepは進むのでそれくらいの間だけ動いてくれれば十分だったりする(CPUだと一晩以上かかっていた)。 たとえ最後まで終了する前に強制中断させられても「うーん残念。仕方ない」で割り切って またタイミングを見計らってやり直せばいいし、途中経過はちょいちょい書き出しているので実行中に様子を見つつそのcheckpointファイルを吸い出しておけば無駄になることは少ない。

なので、とにかく何も考えず「一番安くなっているもの」を使ってギリギリの入札価格で使いたい。 AMIさえコピーして転送しておけば使えるのでRegionもどこでも構わない。

で、EC2のWebコンソールからは「価格設定履歴」というのを開いて各Availability Zoneの価格の遷移を見ることができるのだけど、

f:id:sugyan:20160623234609p:plain

これだと

  • 選択しているRegionの中のAvailability Zoneでしか一覧できない
  • 高騰しているものも含めてすべて描画されて縮尺を変更できない
    • 最低価格付近だけを見たいのに…
  • 直近24時間より短い範囲で見られない

とか ちょっと不満があった。 何より、いちいちブラウザ開いてポチポチしないとチェックできないのは面倒。

  • ターミナルからコマンド一発で
  • 複数Regionで横断的に
  • 最低価格のあたりの直近の変動・値だけを見たい

と思ったので、そういうものを作った次第。

実装

まずコマンドラインからスポット価格の履歴を取得するのはAWS CLIで出来るし、

AWS コマンドラインインターフェイス | AWS

各言語から使うSDKも様々なものが公式から提供されている。

AWS のツール | AWS

どれを使うか迷ったけど、

  1. 各Regionから取得するのは並列で処理したい
  2. せっかくだからターミナル上にグラフを描画したい

1.はGoかNodeかな、という感じで 2.でbleesed-contribっていうのが以前話題になったのを思い出し、

https://github.com/yaronn/blessed-contrib

これを使ってみたかったというのと Goでも近いものでtermuiというものが実装されていたようだったけど こちらは複数データのLine Chartが未実装ということだったのでNodeを使うことにした。

最近ぜんぜんマトモにNode触っていなかったのでPromiseとかも初めて使ってみたくらいだったけど、勉強しながら書いてみました。 こういうのも公開されていて本当にありがたいです。

JavaScript Promiseの本

複数Regionから並列で各Availability Zoneの価格設定履歴を取得できれば、あとはそのデータを使って描画するだけ。 blessed-contribのバグも見事に踏んでしまったのでp-r送ったりもした。

せっかくなのでキー操作で縮尺・表示範囲を変えたり 最新データに更新できるようにしたりした。

f:id:sugyan:20160623232910g:plain

とりあえずこんなんで最新の価格と細かい値動きはターミナルから一覧できるようになって、便利。

もうちょっと汎用的に使えるように出来たかもしれないけど 多分こんなの自分しか使わないだろうし、ってことで対象RegionはUSの3つのみにしている(EU, APにもGPUインスタンスはあるけど常時高騰している)し 調べるのはg2.2xlargeの価格だけにしているし、AWS CLIのためのCredentialも既にaws configureとかで設定している前提で作っている。 ちょっと雑。

npmへのpublishは自重しておく。