プロキシを使わずにRuby-1.9/2.1混在環境も作れる、Apache2+Passenger4+rbenvを用いた混在環境の作り方
Passenger 3.x で複数のRubyバージョンを使い分けるには、とてもトリッキーな対応が必要でした。
ところがPassenger 4.0.0 より公式に複数のRubyバージョンに対応しました。つまり、同一筐体のApacheで動く他アプリケーションへ影響を与えることなく、気軽にアプリ毎に使うRubyバージョンを変更できるようになります。
これまでの手法
mod_proxyを用いて、必要なRubyバージョン毎に単体起動させたpassengerにTCP/Socketでプロキシするというものでした。なぜなら、読み込むモジュールだけでなく、グローバル値として指定するPassengerRoot
やPassengerRuby
の設定が衝突するためです。
- Phusion Passenger & running multiple Ruby versions – Phusion Corporate Blog
http://blog.phusion.nl/2010/09/21/phusion-passenger-running-multiple-ruby-versions/
これからの手法
Phusion Passenger 4.0 beta 1 is here – Phusion Corporate Blogにて、次のように言及されています。
Passenger 4.0.0 よりモジュール本体とRubyとの依存が無くなり、複数のRubyバージョンおよびJRubyに対応しました。新しく追加されたオプションPassengerDefaultRuby
がグローバル値として適用され、PassengerRuby
をアプリケーション毎など、個別に指定できるようになりました。
これらはVirtualHost、Directory、Locationと.htaccessといったどのディレクティブでも設定できます。
使い方
これよりVirtualHosts毎に別のRubyでアプリケーションを動かすサンプルを紹介します。
step1. rbenvのインストール
公式ドキュメントを参考にインストールします
https://github.com/sstephenson/rbenv#installation
step2. passengerのインストール
rbenvで切り替えた各Rubyにてそれぞれインストールを行います。
# rootで実行 gem install passenger passenger-install-apache2-module
step3. Apacheへ設定ファイルを投入
少なくとも3つの設定(LoadModule, PassengerRoot, PassengerDefaultRuby)を次のいずれかのファイルに書き込みます。 LoadModuleで指定できる.soファイルは、各バージョンのRubyにて実行したgem install passengerでインストールされた場所に存在します。しかしどうやら、どちらのRubyにインストールされたものを指定しても構わないようです。
$ cat /etc/httpd.d/conf/passenger.conf LoadModule passenger_module /root/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/passenger-4.0.41/buildout/apache2/mod_passenger.so <IfModule mod_passenger.c> PassengerRoot /root/.rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/passenger-4.0.41 PassengerDefaultRuby /root/.rbenv/versions/2.1.1/bin/ruby </IfModule> Header always unset "X-Powered-By" Header always unset "X-Rack-Cache" Header always unset "X-Content-Digest"
次に、VIrtualHostの設定を行う準備を行います。
各アプリケーションにPassengerRuby
オプションを用いてrubyバイナリの位置を指定します。この値はrbenvコマンドで使うrubyバージョンに切り替えた後に、passenger-config about ruby-command
コマンドを叩くと次のように分かります。
passenger-config about ruby-command passenger-config was invoked through the following Ruby interpreter: Command: /root/.rbenv/versions/1.9.3-p545/bin/ruby Version: ruby 1.9.3p545 (2014-02-24 revision 45159) [x86_64-linux] To use in Apache: PassengerRuby /root/.rbenv/versions/1.9.3-p545/bin/ruby To use in Nginx : passenger_ruby /root/.rbenv/versions/1.9.3-p545/bin/ruby To use with Standalone: /root/.rbenv/versions/1.9.3-p545/bin/ruby /root/.rbenv/versions/1.9.3-p545/lib/ruby/gems/1.9.1/gems/passenger-4.0.41/bin/passenger start
それぞれ調べた値をvirtualhost設定へPassengerRuby
オプションと共に指定します。
$ cat /etc/httpd.d/conf/virtualhosts.conf NameVirtualHost *:80 <VirtualHost *:80> ServerName ruby19.example.jp DocumentRoot /var/www/ruby19.example.jp/public <Directory /var/www/ruby19.example.jp/public> # This relaxes Apache security settings. AllowOverride all # MultiViews must be turned off. Options -MultiViews </Directory> AllowEncodedSlashes on PassengerAllowEncodedSlashes on # ruby19.example.jp では Ruby 1.9.3-p545 を利用する PassengerRuby /root/.rbenv/versions/1.9.3-p545/bin/ruby LimitRequestBody 41943040 </VirtualHost> <VirtualHost *:80> ServerName ruby21.example.jp DocumentRoot /var/www/ruby21.example.jp/public <Directory /var/www/ruby21.example.jp/public> # This relaxes Apache security settings. AllowOverride all # MultiViews must be turned off. Options -MultiViews </Directory> AllowEncodedSlashes on PassengerAllowEncodedSlashes on # ruby21.example.jp では Ruby 2.1.1 を利用する PassengerRuby /root/.rbenv/versions/2.1.1/bin/ruby LimitRequestBody 41943040 </VirtualHost>
step4. 設定の反映
設定を反映させるため、Apacheを再起動します。
# rootで実行 /etc/init.d/httpd restart
これで以上です。
トリッキーな対応無しに複数バージョンの使い分けが出来るようになりましたね。
手元のVagrantでも試せます
本記事で紹介した環境を配布しています。VirtualboxとVagrantが入っている環境であれば、次の手順で試せます。 具体的な構築手順については、provision.shファイルをご覧ください。
$ git clone https://github.com/y-ken/multiple_ruby_version_in_apache_passenger.git
$ cd multiple_ruby_version_in_apache_passenger
$ vagrant up
$ vagrant ssh
- Sample vagrant image to execute multiple versions of ruby in one Apache Passenger
https://github.com/y-ken/multiple_ruby_version_in_apache_passenger
構築完了後にはその端末へvagrant ssh
コマンドでログインし、curlコマンドでサンプルアプリを叩いて結果を見てみましょう。
ruby19.example.jp ではruby-1.9.3-p545が、ruby21.example.jp ではruby-2.1.1がインタプリタとして動いていることが確認できます。
$ curl -s -H "Host: ruby19.example.jp" http://127.0.0.1/ | grep exec_prefix "exec_prefix"=>"/root/.rbenv/versions/1.9.3-p545", $ curl -s -H "Host: ruby21.example.jp" http://127.0.0.1/ | grep exec_prefix "exec_prefix"=>"/root/.rbenv/versions/2.1.1",
まとめ
これでサーバ構成のシンプルさや運用の手間を抑えたまま、年に何度もにリリースされる最新のRubyバージョンでも受け入れられるインフラが作れます。
古いバージョンが必要なアプリケーションはそのままに、どんどん最新のRubyを追いかけていけますね!