Daniel
Daniel

Reputation: 391

How to sort out multiple versions of Ruby, Passenger and Rack (under Apache)

I have a classic "monolith" server running multiple Ruby-applications under Passenger. According to the Passenger documentation this should work fine, but I've found a few problems that I need help to sort out.

The documentation states:

Passenger may be installed with any Ruby interpreter. Once installed, you can run Passenger's Ruby parts under any Ruby interpreter you want, even if that Ruby interpreter was not the one you originally installed Passenger with.

[---]

Passenger is also capable of running Ruby web applications under any Ruby interpreter you want. So it is not important which Ruby you use to install Passenger: it will work regardless. Please refer to the documentation for the passenger_ruby directive to learn how run different web applications under different Ruby interpreters.

I have installed Passenger and the Apache module using an official package for my SLES distribution. It is a rather old version (5.0.18), but since the distribution is still maintained it is patched to fix any known security vulnerabilities. This Passenger of course is installed under the system Ruby.

I also have multiple other Rubies installed. If I point to a fresh install using the PassengerRuby directive, it complains that passenger is not found. I've realized I need to have Passenger installed under each Ruby interpreter to be able to start the application. (I haven't seen this explained in the documentation.) This poses a problem though. When installing Passenger under my new Ruby, I use rubygems directly, not the RPM. I can try to select the same version as the RPM (5.0.18) but then it would be a non-patched version. I can also just let the gem command pick the latest (most patched) version, but then the application won't start:

App 21959 stderr: /opt/rubies/ruby-2.5.1/lib/ruby/gems/2.5.0/gems/passenger-5.3.0/src/ruby_supportlib/phusion_passenger/loader_shared_helpers.rb:941:in `try_write_file': undefined method `try_write_file' for #<Hash:0x0000560031e58c88> (NoMethodError)
App 21959 stderr:   from /opt/rubies/ruby-2.5.1/lib/ruby/gems/2.5.0/gems/passenger-5.3.0/src/ruby_supportlib/phusion_passenger/loader_shared_helpers.rb:522:in `dump_envvars'
App 21959 stderr:   from /opt/rubies/ruby-2.5.1/lib/ruby/gems/2.5.0/gems/passenger-5.3.0/src/ruby_supportlib/phusion_passenger/loader_shared_helpers.rb:464:in `dump_all_information'
App 21959 stderr:   from /opt/rubies/ruby-2.5.1/lib/ruby/gems/2.5.0/gems/passenger-5.3.0/src/ruby_supportlib/phusion_passenger/loader_shared_helpers.rb:394:in `about_to_abort'
App 21959 stderr:   from /usr/lib64/passenger/5.0.18//helper-scripts/rack-preloader.rb:89:in `rescue in init_passenger'
App 21959 stderr:   from /usr/lib64/passenger/5.0.18//helper-scripts/rack-preloader.rb:72:in `init_passenger'
App 21959 stderr:   from /usr/lib64/passenger/5.0.18//helper-scripts/rack-preloader.rb:152:in `<module:App>'
App 21959 stderr:   from /usr/lib64/passenger/5.0.18//helper-scripts/rack-preloader.rb:29:in `<module:PhusionPassenger>'
App 21959 stderr:   from /usr/lib64/passenger/5.0.18//helper-scripts/rack-preloader.rb:28:in `<main>'

It looks like a helper script from the "main" Passenger hooks into the newer Passenger. And I guess the error is because som API may have changed?

So this is my first problem – does the installed Passenger require each used Ruby interpreter to have it's own installation of the exact same version of Passenger? How do you handle this?

Now let's say I've solved the first step and have compatible Passengers installed. Then I try to start the app again:

App 1407 stdout: 
[ 2018-05-15 21:34:57.4890 1367/7f1eda77b700 App/Implementation.cpp:303 ]: Could not spawn process for application /myApp: An error occured while starting up the preloader.
  Error ID: 5a8f172f
  Error details saved to: /var/run/passenger/passenger-error-XwWBnN.html
  Message from application: You have already activated rack 2.0.5, but your Gemfile requires rack 2.0.3. Prepending `bundle exec` to your command may solve this. (Gem::LoadError)

Turns out that Passenger itself has a dependency on Rack. The gem sucked in the latest version, which was Rack 2.0.5. Passenger loads this version and then executes Bundler setup. But the application is locked to version 2.0.3. Prepending bundle exec to the PassengerRuby directive doesn't solve it, as then Passenger itself won't be available - unless I add it to the Gemfile, which the documentation quite clearly states should not be necessary.

So I can synchronize these versions, but then I will need to synchronize the Rack version across all applications under a specific Ruby interpreter. This greatly reduces the benefit of bundler, it was meant to solve this kind of problems. Or I need to couple my applications to the current deployment method. What is the best (least bad) way to solve this?

Upvotes: 0

Views: 369

Answers (1)

Jussi Hirvi
Jussi Hirvi

Reputation: 735

Can you use RVM? It should help you manage several rubies and gemsets.

In my system I noticed that one Passenger module is enough, just like the documentation says. I installed it with gem install passengerin an otherwise empty gemset.

One confusing thing I noticed is that the PassengerRubydirective (in the case of Apache) for each VirtualHost should point to each app's gemset, not to the gemset where the Passenger module is installed, nor to any generic (anonymous) gemset. Otherwise you will get confusing multitude of overlapping gemsets. The ruby version mentioned in the PassengerRuby does not need to be the same that Passenger was compiled against. Example from my CentOS installation:

PassengerRuby /usr/local/rvm/gems/ruby-2.4.2@gemset-of-my-app/wrappers/ruby

Upvotes: 0

Related Questions