こんにちは。小椋です。
「まあ15分ぐらいなら落ちてても実際そこまで困らないけど、基本的には24時間起動していてほしいんだよね……」
という緩めのサービスレベルで稼働しているSPOF気味なサーバー、ありますよね。社内向けのジョブスケジューラーとか、一日に数回なんか集めて分析する奴とか。あんまり表立って言わないだけで、御社にもありますよね?
サービスレベルが緩めだし、ミッションクリティカルでもないので、ただ起動しっぱなしにしてほっとけばいいや……と思いきや、やっぱり止まったら止まったで処置も必要だし、生死確認はちゃんとしないといけないし、そもそも起動しっぱなしなのでお金もかかるし、とか、意外とお金も労力もかかりますよね。
私HDEの社長ですが、サーバ代に関してはかなりケチです!
そういうケースに関しては、場合によってはEC2のAutoScaling Groupで管理すると節約ついでに横着できるよ、というダーティーな話を紹介したいと思います。
Auto Scalingとは何か
EC2のAuto Scalingは、"Launch Configuration"と"Auto Scaling Group"の二つの設定で挙動を制御します。
"Launch Configuration" とは、「こういうインスタンスをたくさんたちあげたいよ」の「こういうインスタンス」を定義する設定です。
"Auto Scaling Group"とは、「このLaunch Configurationをとりあえずはじめ10台たちあげたいよ、こういう時に台数を減らしたり、増やしたりしたいよ」の「とりあえずはじめ10台」「こういう時」を定義する設定です。
本来は、例えば突然のスパイクに備えて自動的にWebサーバーフロントエンドを増減したり、ジョブが溜まってきたらワーカーを自動的にたくさん起動したり、ということに使うわけですが、発想を転換すると、冒頭のような24時間稼働させたいサーバーを安価に、かつ横着に実現することができます。
スポットインスタンス1台しか所属しないAuto Scaling Groupの活用
Auto Scaling Groupを作成すると、常にユーザーが指定した台数のインスタンスが起動している状態を勝手に維持してくれます。これはどういうことかというと、
- EC2のhealth checkに失敗し、unhealthyになったインスタンスがいる場合、healthyな台数が揃うように勝手に差し替えてくれる
- 仮にインスタンスが手動または外的要因でterminateされた場合、台数が揃うように勝手に起動してくれる
ということです。
さらに、Auto Scaling GroupのLaunch Configurationでは、スポットインスタンスを指定することができます。スポットインスタンスは、変動価格制のインスタンスで、たいていの時間帯は通常のインスタンスよりも圧倒的に低い価格で起動可能な代わりに、需給が逼迫すると値段が高騰し、もしあらかじめユーザーが指しておいた指値を上回ると突然terminateされる上、stopは存在せず、terminateしかできない、という実に個性的で魅力的なインスタンスです。
参考までに最近の価格表を上に貼りましたが、安いですよね。この例だと、うまく活用するとコストが1/5ぐらいになっちゃいかねません。
圧倒的じゃないか……!(※ただし勝手にterminateする)
さて、そんなわけでAuto Scaling Groupと、スポットインスタンスを組み合わせて、「スポットインスタンス1台だけが所属するAuto Scaling Group」を作ると、「必ずスポットインスタンスが1台起動している状態」を勝手に維持してくれる仕組みを作ることができます。
すなわち……
- 普段はオンデマンドインスタンスよりだいぶ安い値段でインスタンスを起動しっぱなしにできる
- 時価が指値を上回った場合、インスタンスはいったんterminateされるが、その後あらためて起動しようとしてくれる。しばらくして値段が下がれば起動する。
- 仮になんらかの障害でインスタンスが不調になっても、勝手に差し替えてくれる
ということで、安い、手がかからない、といいことづくめかも!
Launch Configuration のイメージ
Auto Scaling Group のイメージ
課題もある
……いいことばかりというわけでもなく、この構成を取るためにはそれなりの準備が必要です。
以下に、ありそうな疑問と、よくある解決法を挙げておきます。
- Q: そもそもAMIはどうするのか?
- A1: まず一回普通のインスタンスを立ち上げて環境を作り、テンプレートとなるAMIを作りましょう。
- A2: user data(Launch Configで指定できる、インスタンス起動時に実行されるスクリプト)で鬼頑張りましょう。
- Q: 固定的なDNS名が必要です。
- A1: IAMロールを割り当てて、Route53で、起動時に自分で自分をDNS登録するようなスクリプトをuser dataに書きましょう。
- A2: いっそDynamic DNSを使いましょう。
- Q: ステートフルなサーバーです。死んだインスタンスのデータを新しいサーバーに引き継ぎたいです。
- A1: 特定のEBSをマウントするようなスクリプトをuser dataに書きましょう。データはそのEBSに置くようにしましょう。ただしAZが片方に固定されてしまうことに注意。
- A2: 死ぬ前にS3に書きましょう。上がってきた奴はS3から取りましょう。
- Q: EC2のhealth checkでは物足りないです。もっとハイレイヤなhealth checkをしたいです。
- A1: インスタンス内で自前のヘルスチェックスクリプトを動かし、異常を検知したら自分をterminateしましょう。Auto Scalingが新しいインスタンスを上げてくれます。
- A2: Auto Scaling GroupにELBを追加すると、HTTPベースでhealth checkできます。少しお金はかかりますが。
このようにちょっとした工夫は必要ですが、うまく使いたいシーンにハマれば手間もお金も節約できていいですよ!
実際のユースケース
当社では、ログを収集したり統計を取ったりするサーバーの一部をこの方法で運用しています。
個人的な利用シーンとしては、僕はこの方法を使って、家庭用マインクラフトサーバーを安価に運用してます。ゲームをやりたい時には息子がWeb上の専用UIからAuto Scaling GroupのDesired Capacityを0台から1台にします。しばらくゲームに動きが無いと勝手にCapacityが1台から0台に戻るように工夫しています。名前解決にはDynamic DNSを使っています。Auto Scalingとスポットインスタンスで家族も円満!