ヌーラボのインフラ運用最前線 〜イミュータブルを目指して〜 (後編)

このエントリは前後編に分かれています。前編は主に運用フローやそこでの工夫点、後編は実際の運用から得た知見や今後の課題といった内容です。

ヌーラボアカウントのインフラ運用のフローやそれにおける工夫点を述べた前編 に引き続き、この後編では実際の運用から得た知見と、今後の課題について紹介します。

運用して見えてきたもの

私たちの元々の目的は「イミュータブルインフラストラクチャ」を構築する事ではなく、前編で紹介した課題を解決するための運用フローを構築することでした。それを開発のフェーズからコツコツと模索した結果として「イミュータブルインフラストラクチャー」に少しずつ近づいている、というのが正直なところです。
 
前編で紹介した内容は以下の三つに集約されると思います。
  • 入れ替えを前提としたアプリ、インフラ、(モニタリング等の)運用の設計
  • サーバ構成ツールの全面採用と CI の実施 ( Infrastructure as Code 的側面 )
  • サーバ構成、アプリ双方の CI の成果物を組み合わせて稼働環境を立ち上げる仕組み作り
「イミュータブルインフラストラクチャー」という言葉でよく話題にあがるのは、Docker などの軽量コンテナで、勿論これは重要ではありますが、三つ目の稼働環境を高速に立ち上げるための要素技術の一つに過ぎません。上にあげたように、実運用で「イミュータブル」を行おうとすると、やらないと行けない事は他にも沢山あります。
 
ですので、私たちのような小さなチームでは、一歩ずつ取り組む事になると思うのですが、 前編で紹介した事の中では、 AMI の自動生成のための Ansible のゼロベースの実行は、はじめて CI を体験した時と似たような感覚をもたらし、継続的なサービス運用において最初に取り組む価値は大きいと感じています。AMI を生成するかどうかは AWS 特有の問題ではありますが、ゼロベースで設定が通る ( 走る ) ことを定期的に確認する、というのは構成管理ツールを運用する上でのごく当たり前のプラクティスとなる気がします。
 
一方で私たちが、完全にイミュータブルな運用にしていない(出来ない)のは、以下の理由からです。
  • Java アプリケーションなので環境に依存した問題が起こりにくい
  • リリースにかかる時間がインスタンスを新たに準備する時間と比較して短い
まず、Java のアプリケーションは依存関係も含めて全て war としてパッケージングされているので、サーバ環境への依存関係の問題が出るということはこれまでの経験からも稀です。他の言語のアプリケーションに比べ、環境そのものへの依存度が少なく、問題があった場合でもwar を前のバージョンに戻せば以前の状態に簡単にロールバックできる (実際は以前のバージョンを指定して通常通りの “リリース” を行う) ため、環境そのものを大きく切り替えて得られる安心感がそこまで大きくない、ともいえます。
 
二つ目の時間についてですが、インスタンス単位での入れ替えはどうしても AMI の起動時間がネックとなり通常のリリース作業と比べて時間がかかります。現状、1 回のローリングリリースにかかるのが 10 分ほどです。対して生成された AMI から起動しても大体一つのインスタンスを本番に投入するまでに 5 分はかかってしまいます。
 
これからも分かるように、まだ今のツールをベースにした運用だとリリースの度に環境を入れ替えるのはコスト高で、メリットがあまりありません。勿論時間短縮に向けては努力出来る余地もありますし、今後 Docker の検証なども続けていきますが、根本的に変えるにはまだ年単位で時間はかかりそうな予感がしています。
 
ただ、時間という観点では、障害対応のオペレーションに組み込めないかは検討しています。AWS で運用していると、ホスト OS が原因でインスタンスがハングする経験をされて方も多いと思いますが、これまでインスタンスのリブートや stop/start で対応することもありました。そのほうが手軽でかつ問題が解決することも多かったからなのですが、API 経由でのリブートは最悪ハードリブートがかかるまでに 4 分は待たされ、状況にもよりますが、大体復旧には 10 分程度はかかっていました。ですが、5 分程度で入れ替えが出来るのであれば、インスタンス障害発生時には状況にあわせて対応内容変えるのではなく、常に新しいインスタンスを立ち上げるという形にすれば、かかる時間も短く対応フローもシンプルに出来るのでは、と考えています。 

今後の課題 

上であげた起動時間の問題の他にも、今後イミュータブルインフラストラクチャを推し進めるにあたっての課題としては以下の五つを考えています。
  • サーバ構成テストの拡充
  • AMI 作成ツールの確定
  • ホストリストの自動管理
  • モニタリングの向上
  • 複数バージョンのアプリケーションの同居

サーバ構成テストの拡充

まずテストには serverspec を利用していますが、どこまでをテストすべきかはまだ模索しています。現状は
  • プロセスが稼働していること ( サービスとして有効化されていること )
  • 設定ファイルがあること
  • 設定に特定の記述があること
といった基本的なものに留めていますが、モニタリングツールとの住み分けをしながら、より切り替え時の安心を担保できるよう充実させていきたいと考えています。稼働直後の環境にアプリを導入しプロダクションに投下する前にスモークテストも実施したいとも思ってますが、それは serverspec の範囲外とも考えているので、ツール立ても含め検討していきたい所です。

AMI 作成ツールの確定

AMI 作成は、以下のように二つにフェーズを分けています。
 
 
二つに分けた主な理由は時間で、全てのサーバに共通に必要なものはくくり出して base AMI として作成し、その後 Jenkins のパイプラインで各ロールの AMI を作成するようにして各々のジョブの実行時間を短縮しています。ちなみに現状では base AMI の作成に 15-20 分、各ロール毎の AMI の作成に 20-30 分程度です。上図の通りこのフローで利用するツールとして、一長一短があるため Packer と Vagrant を並用しながらどちらに一本化するかを検討していこうと考えています。
 
Packer は、ゼロベースからセキュリティグループの設定、キーペアの追加などをした上で、インスタンスを立ち上げてAMI 作成後にはその辺りを全て綺麗に片付けてくれる ( 失敗した場合も同様 ) なのが、さすがイメージ作成に特化したツールだけあってよく出来ています。Packer は使うまではそのメリットについては眉唾で、自作の boto で書いたツールを使っていたのですが、エラーで落ちたときのケアをちゃんと行うのが面倒なことがわかり、そこで改めて Packer の良さを理解できました。
 
一方 Vagrant は AMI 生成に特化している訳ではないので、初期化時に必要な設定項目は Packer に比べると多くお手軽感は少ないのですが、Vagrant AWS Provider vagrant-serverspec と  vagrant-ami を組み合わせることで「インスタンス起動 → プロビジョニング → テスト → AMI 作成」というフローを簡単に組み上げる事が出来ます。Packer の場合はこのうち「テスト」を組み込むことが簡単には出来なかった為、Vagrant を採択した経緯もあります。また Packer は問題が発生しても問答無用でインスタンスをターミネートしてしまうのですが、Vagrant はそこまで自動化されていないため、かえってデバッグがしやすいといった点もみえてきました。

ホストリストの自動管理

ホストリストの管理については、先にあげた NUCON の資料の通り、ssh config を各ツール間で共有しています。現在の運用ではそこまでホストリストに頻繁な変更はないので手動で管理しています。ただ、今後入れ替えが頻繁に行われるようになれば、ホストリストの自動化は避けて通れないと感じています。fabric については env.hosts などを動的に変更すれば出来ますし、Ansible も Dynamic Inventory の仕組みをもっていますので、そういったアプローチをしていくことになりそうです。

モニタリングの向上

サービスを運用する観点ではモニタリングは欠かせないものですが、まだイミュータブルな運用を前提としたモニタリングはこれからの領域のように思います。これまでのホスト単位での管理というよりは、サーバが入れ替わっても全体の傾向がとらえやすく、かつそれまでの時系列の履歴が途切れない、入れ替え前後のトラッキングがストレス無く出来る方法が求められてくると思います。
 
またログもひとまずは fluentd にて保存する、ところまでに留まっており、それらを集約してサービスの運用・監視に活用するまでには至っていません。ここはツールを含めて今後考えていきたいところです。

複数バージョンのアプリケーションの同居

Google App Engine などではデプロイ毎に URL が付与されますが、同様のことを仕組み的に作れないかと考えています。こちらの記事 でも触れたのですが、ヌーラボサービスではリアルデータを使ってリリース前のアプリを実際に試しています。複数のバージョンが同居できるようになると、複数ブランチを並行して試すといった事もできますし、また Basecamp (旧 37Signals) で行われてるという Rollout リリース のようなことも行いやすくなるのでは、と考えています。第一歩としてはアプリケーションのバージョン毎に AMI を生成するようにして、次にそれが自動的に起動され、Route53 と連動して URL が付与される、といったステップを妄想しているところです ^^;

いかがでしたでしょうか?
 
様々な観点で私たちの現在の取り組みを紹介してきましたが、私自身は大きな方向性として「イミュータブルインフラストラクチャー」に向かっていくであろうことに異論はありません。ただ、私たちのような小さなチームにとって、その時点で利用可能なツールスタックに基づいて現実のサービス運用におけるワークフローをどうインプリするか、どこまでを目指すかといった点と、それにかかるコストと得られるメリットは見極めて進むべき領域だとも考えています。実際、ここで紹介したワークフローを構築して機能させるまでも、それなりにパワーと時間を使っています。
 
そういったインプリ面も含め、まだまだ「イミュータブルインフラストラクチャー」には議論の余地があり、積極的に実運用における経験を共有していくことで新たな知見が得られる領域だと考えてます。ですので、あえてまだ未成熟な部分もありのまま公開しております。是非「そこはこうしたら良いのでは?」「そこの理由はなぜ?」といったコメントをいただけると嬉しく思います!

より良いチームワークを生み出す

チームの創造力を高めるコラボレーションツール

製品をみる