長年にわたって、IIS上でRuby on Railsを実行するための多数のハックや方法がありました。また、(TomcatやJettyを介した) Java、Go、他の言語や環境を実行する方法もあります。iisnodeを使ってIIS上でNode.jsを実行する (英語 / 日本語) 方法がありますが、これはNode.js固有でした。「10の手順でIIS上でRailsを実行する」といったことを言っているブログ ポストを見つけると、「たった10? 13じゃないの?」といった感じになります。「IIS上にRailsをデプロイできます。それは非常に難しく、ドキュメントも多くありません。特別なFastCGI実装が必要です… 地獄にようこそ」と言う人もいます。
もはや、そうではありません。
Azure Websitesは、しばらく前からNode.jsとJava (Tomcat、またはJetty) を正式にサポートしています。これは非常に素晴らしく、IIS上で動作しています。どのようにして? HttpPlatformHandlerのリリース (英語 / 日本語 / 日本語) によって、IIS 8以降を実行しているWindowsでもこれがサポートされるようになりました。Azure Websitesでの、IIS 8以降でJavaを簡単に実行する (英語 / 日本語 / 日本語) 方法の例は、こちらです。
これがRuby on Railsでもうまく動作するかどうか、見てみましょう!
なぜ、HttpPlatformHandler (英語 / 日本語) が興味深いのでしょうか? ドキュメントを確認してみましょう… これは、IISが、Windows上で実行されているものなら何でも簡単にホストできることを意味しています。こういったことは以前から可能でしたが、さまざまなハックやFastCGIのあれやこれやが必要でした。HttpPlatformHandlerで素晴らしいことは、Rails向けではないということです。ポートをリッスンしている任意のプロセス向けなのです。IISのすべての価値と、セルフ ホスティング シナリオの完全な制御の両方を得られます。
HttpPlatformHandlerは、次の2つのことを行う、IIS 8以降向けのIISモジュールです:
- HTTPリスナーのプロセス管理 – これは、HTTPリクエスト向けにポートをリッスンできる任意のプロセスです。たとえば、Tomcat、Jetty、Node.exe、Rubyなど。
- 管理しているプロセスに、リクエストのプロキシします。
誤解のないように言うと、Windows上のRuby on Railsで作業し、WEBrickでRuby on Railsをローカルにホストできますが、Windows上で運用環境を提供しようとする場合は、Linux上でnginxを使うのと同様に、IISや、さらにはTomcatコンテナー上のJRubyを使いたいでしょう。こういったシナリオで、IISはどのような価値を提供するのでしょうか? IISは、静的ファイル ホスティング、リバース プロキシ、複数のアプリ/言語/フレームワークにわたる複雑な認証を提供し、メモリ、CPU、クラッシュなどを確認してプロセスを監視、管理します。
HttpPlatformHandlerによる、IIS 8上でのRuby on Railsの実行
最初に、Ruby on Railsをインストールしていることを確認します。もししている場合は、先に進んでください。
私は、Windows向けの http://railsinstaller.org/ (英語 / 日本語) を使います。Ruby (英語 / 日本語)、Rails (英語 / 日本語)、Bundler (英語 / 日本語)、Sqlite (英語 / 日本語)、TinyTDS (英語 / 日本語) が、そしてSQL Serverのサポートさえもインストールされます。もう1つの優れたWindows上のRailsは、RailsFTW (英語 / 日本語) です。
IISがインストールされていることも確認するために、「Windowsの機能」に進みます。
それから、HttpPlatformHandlerを入手します。Web Platform Installerで入手することもできますし、こちら (x86 / x64) からインストールすることもできます。
これから作成するアプリのためのフォルダーを作成します。私は c:\inetpub\wwwroot\rails に作成しますが、好きな場所に移動できます。
IISマネージャーで自分のフォルダーを右クリックし、「アプリケーションへの変換」を実行します。
そもそもRailsをインストールしていることを確認するために、「gem install rails」を実行します。RailsInstallerでインストールした場合は、Railsをインストール済みです。RubyInstallerでインストールした場合は、これによってRailsがインストールされます。
注: 執筆時点では、Windows上でgemを実行する際にSSLの問題が発生する場合、gemを2.2.3に手動アップデートする必要があります。なぜインストーラーがアップデートを行わないのか、分かりません。私が見た症状は、(gem 2.2.3で修正された)「bundle install」の奇妙なエラーです。
それから、c:\inetpub\wwwroot\rails で「rails new helloworld」を実行しました。結局は、このフォルダーの1つ上に移動することになりました。最初にアプリを作成してから、IISでそのフォルダーをアプリに変換すべきでした。操作の順序が大事ですね?
ここで、ローカルのWEBrickサーバーでRailsが動作できることを確認するためだけに、c:\inetpub\wwwroot\rails で「rails server」を実行します。次のようになります:
ここで、IIS上で作業しましょう
自分のRailsアプリと同じルート フォルダーにweb.configファイルがることを、確認する必要があります。何ですって!? web.configはASP.NET向けですよね? いいえ、違います。これは、任意のIISアプリケーション向けの構成ファイルです。Go、Java、PHP、Rails、Node.js、ASP.NET、何であっても、これが必要となります。IISは、基本的に何でもホストできます。
Hello Worldコントローラーを追加し、そのビューを編集しましょう。「rails generate controller welcome index」を実行してから、app\views\welcome\index.html.erb を編集します。
ルートの http://localhost/ ではなく http://localhost/rails に自分のRailsアプリを配置します。/config.ru を変更して、アプリがサブディレクトリで実行されていることをRails 4に伝える必要がありました。そうしないと、私のルートが準備されません。
Rails.application.config.relative_url_root = '/rails' map Rails.application.config.relative_url_root || "/" do run Rails.application end
次のパスと、引数の中にあるエンコードされた " に注意してください。これが、IISが起動するruby.exeプロセスに渡される引用符で囲まれた引数となるので、これは重要です。また、%HTTP_PLATFORM_PORT% 環境変数参照にも注意してください。これはIISによって渡され、ローカルホストにバインドされたポートになります。
また、自分のRailsアプリに知らせたい環境変数として、foo、barを追加します。たとえば、次のものを追加します:
<environmentVariable name="RAILS_ENV" value="production"/>
…時が来たら、「stdout」を使って標準デバッグ ロギングを追加しますが、混乱を避けたい場合はそれを削除できます。ログを確認したい場合は、IIS_IUSRS がフォルダーに対する書き込みアクセスを持っていることを確認してください。
警告: この最初の例は、可能なことを示しているだけです。小さな組み込みRuby WEBrickサーバーで、運用環境を提供したくはないでしょう。Fabio Akitaがコメントで親切に指摘してくれたので、彼のコメントをここに引用します:
「Railsを使う例で注意すべき点が1つあります。Windows上のRubyで『rails server』を実行すると、これは (単一スレッドの) 単一プロセスを起動します。これは、同時に1つのリクエストにだけ応答できることを意味しています。IISが同時に多数のリクエストを受信し始め、各リクエストが遅い場合、IISは長いキューを生成し、リクエストがタイムアウトし始めます。Linuxでは、Unicorn、Puma、Rainbows、またはPassengerにHTTPリクエストをリバース プロキシするために、nginxを配置します。これらはすべて、複数のRubyプロセスを調整します (Unixでは、フォークの際に各プロセスは親プロセスのメモリを再使用するので (コピー オン ライト メモリ)、複数プロセスは非常に低コストです)。こうして、同時リクエストを処理できます。」
Windows上の運用環境向けには、IISをJRuby、Tomcat、Pumaとともに使いたいでしょう。
JRuby、Trinidad/Tomcat、Pumaを使う例については、スクロールし続けてください! ページの下部にあります。
また、遅いマシンで開発している際に、IISが起動に時間がかかっているRubyプロセスを停止しているのを確認した場合は、startupTimeLimitを大きくする必要があるかもしれません。
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<handlers>
<add name="httpplatformhandler" path="*" verb="*"
modules="httpPlatformHandler"
resourceType="Unspecified" requireAccess="Script" />
</handlers>
<httpPlatform stdoutLogEnabled="true"
stdoutLogFile="rails.log" startupTimeLimit="20"
processPath="c:\RailsInstaller\Ruby2.1.0\bin\ruby.exe"
arguments="&quot;C:\RailsInstaller\Ruby2.1.0\bin\rails& server -p %HTTP_PLATFORM_PORT% -b 127.0.0.1">
<environmentVariables>
<environmentVariable name="foo" value="bar"/>
</environmentVariables>
</httpPlatform>
</system.webServer>
</configuration>
Sysinternals Process Explorerアプリケーション (英語 / 日本語) における、Rubyのスクリーンショットを示します。プロセス ツリーと誰がどのプロセスを開始したかを確認できるように、これを示したかったのです。サービスであるw3wp (これはIIS) と、それが (Railsを実行している) Rubyをホストしていることを確認できます。また、コマンドライン引数にも注意してください。
そして、はいどうぞ。私のWindows 8マシン上のIIS 8上で動作しているRuby on Rails 4です。
web.configの構成値に関して助けてくれた、MicrosoftのRanjith Ramachandra (@ranjithtweets)、Andrew Westgarth (@apwestgarth) に感謝します!
まとめ
まとめると、IISにHttpPlatformHandlerをインストールし、web.configを適切に追加すれば、準備万端です。IISがプロキシするポートを渡して、好きなものを実行します。
アップデート: IIS上のPuma、Trinidad、Tomcat
コメントで指摘されたように、運用環境でWEBrickを使うのは愚かなことです。してはいけません。JRubyが運用環境へ向かう道だと聞きました。1時間で、JRuby (英語 / 日本語)、Trinidad (英語 / 日本語) (およびTomcat)、Pumaをインストールし、IIS上で自分のHello Worldを実行できました。
Trinidadの構成例を示します (しかし、Trinidadは廃れていると聞いています)。「JRuby -S gem install trinidad」を実行しました。
JAVA_HOME環境変数設定に注意してください。また、Java流の「不正なキー サイズ」エラーのため、いくつかのセキュリティ ポリシー ファイルを更新する必要もありました。それ以外は、パスを構成すれば、動作しました。問題が起きた場合は、その問題はパス関連か、または間違ったJavaバージョンをロードしていることでしょう。また、実験の結果、processesPerApplicationsを変更する必要はありません。多数の個別のプロセスを作成する場合、Javaは多くのメモリ (300MB程度) を消費し、システムに悪影響を与える可能性があります。
運用環境での実行で、10倍のパフォーマンスを得られます。
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<handlers>
<add name="httpplatformhandler" path="*" verb="*"
modules="httpPlatformHandler" resourceType="Unspecified"
requireAccess="Script" />
</handlers>
<httpPlatform stdoutLogEnabled="false" processesPerApplication="1"
stdoutLogFile="rails.log" startupTimeLimit="20"
processPath="C:\jruby-1.7.19\bin\jruby.exe"
arguments="-S trinidad --context /jRubyonRails --env production --dir C:\inetpub\wwwroot\jRubyonRails -p %HTTP_PLATFORM_PORT% ">
<environmentVariables>
<environmentVariable name="JAVA_HOME" value="C:Program Files\Java\jre1.8.0_31"/>
</environmentVariables>
</httpPlatform>
</system.webServer>
</configuration>
そして、これは動作します。最小限の努力で、私のノートPCで簡単に1600リクエスト/秒以上を得られました。いくらかのチューニングとより良いマシンで、さらに良いパフォーマンスを得られると確信しています。
それでは、Trindad/Tomcat (英語 / 日本語) の代わりにPuma (英語 / 日本語) を使いましょう。GemfileにPumaを配置し、テストのために「bundle exec puma」を実行しました。これは動作しました。ここで、PumaをIISに組み込みます。また、奇妙なエラーを回避するために、自分のGemfileに「gem ‘jruby-openssl’, :require => false」を追加する必要がありました。
この場合、IISがリバース プロキシ兼プロセス マネージャーなので、基本的に同じでした。
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<handlers>
<add name="httpplatformhandler" path="*" verb="*"
modules="httpPlatformHandler" resourceType="Unspecified"
requireAccess="Script" />
</handlers>
<httpPlatform stdoutLogEnabled="false" processesPerApplication="1"
stdoutLogFile="rails.log" startupTimeLimit="20"
processPath="C:\jruby-1.7.19\bin\jruby.exe"
arguments="-S puma --env production --dir C:\inetpub\wwwroot\jRubyonRails -p %HTTP_PLATFORM_PORT% ">
<environmentVariables>
<environmentVariable name="JAVA_HOME" value="C:\Program Files\Java\jre1.8.0_31"/>
</environmentVariables>
</httpPlatform>
</system.webServer>
</configuration>
1つのprocessPerApplicationだけを使って、簡単に1500リクエスト/秒を得られました。私はPumaやJRubyについて何も知りませんが、もしそのチューニング方法を知っていたら、さらに良いパフォーマンスを得られると推測しています。
IISなしでPuma自体に対してテストし、本質的に同じ結果を確認しました。今回は計測できなかったようにIISのオーバーヘッドは最小限であり、IISのプロセス管理や他の利点を得られます。この種のことでパフォーマンスに問題がある場合、IISが原因である可能性は低いでしょう。
結局のところ、HttpPlatformHandlerは、Windowsで常に必要とされていたリバース プロキシでしょう!
関連リンク
- HttpPlatformHandler構成リファレンス (英語 / 日本語)
- HttpPlatformHandlerフォーラム
- AzureへのカスタムJava Webサイトのアップロード (英語 / 日本語)
関連情報
- Scott Hanselman > Announcing: Running Ruby on Rails on IIS8 (or anything else, really) with the new HttpPlatformHandler (2015/02/09)