On our rails and worker servers at flinc, we recently migrated the ruby version management from rvm to chruby.

Besides the usual arguments against rvm, like preferring unpatched cd commands, there was another reason:

The fnichol’s chef rvm cookbook has some issues.

Issues I experienced using the rvm cookbook

rvm::user_install

The rvm::user_install recipe fails, because it’s trying to find rvm in a wrong path (the global one). This can be fixed by setting a symlink before installing rvm

link '/bin/rvm' do
  to '/home/vagrant/.rvm/bin/rvm'
end

include_recipe 'rvm::user_install'

rvm_ruby '1.9.3' do
  user 'vagrant'
end

file '/bin/rvm' do
  action :delete
end

rvm_gem

The rvm_gem LWRP doesn’t chown the target directly correctly (needs to belong to the user), when using user_install). It needs to be fixed with a manual chown

rvm_gem 'bundler' do
  user 'vagrant'
  ruby_string '1.9.3@mygemset'
end

directory '/home/vagrant/.rvm' do
  owner vagrant
  group vagrant
  recursive true
end

bash defunct processes (zombies)

Some LWRP/recipe in fnichols cookbook leave zombies behind, shown when having a look at the ps tree. Those zombies where occurring on every server where the fnichol rvm cookbook was used.

$ ps axfu
root      8887  0.1  1.1 153668 60756 ?        Sl   Jul07   8:33 chef-client
root     30498  0.5  0.0      0     0 ?        Z    16:05   0:00  \_ [bash] <defunct>
root     30545  0.7  0.0      0     0 ?        Z    16:05   0:00  \_ [bash] <defunct>
root     30634  0.7  0.0      0     0 ?        Z    16:05   0:00  \_ [bash] <defunct>
root     30757  0.6  0.0      0     0 ?        Z    16:05   0:00  \_ [bash] <defunct>
root     30897  0.8  0.0      0     0 ?        Z    16:05   0:00  \_ [bash] <defunct>
root     31149  0.7  0.0      0     0 ?        Z    16:05   0:00  \_ [bash] <defunct>
root     31236  0.8  0.0      0     0 ?        Z    16:05   0:00  \_ [bash] <defunct>
root     31359  0.7  0.0      0     0 ?        Z    16:05   0:00  \_ [bash] <defunct>
root     31499  1.0  0.0      0     0 ?        Z    16:05   0:00  \_ [bash] <defunct>
root     31622  0.9  0.0      0     0 ?        Z    16:05   0:00  \_ [bash] <defunct>
root     31745  0.8  0.0      0     0 ?        Z    16:05   0:00  \_ [bash] <defunct>

As great as a tool as rvm is on your workstation machine, on a (production) server, you usually do not need multiple ruby versions and gemsets, but a clean and stable environment.

Migrating to chruby

The new setup is using fnichol’s ruby-build cookook, as well as the chruby cookbook from Atlanta.

For system processes (like chef-client), I think it’s a good idea to stick to the systems ruby (therefore setting it as a default), while the application uses chruby to select its ruby version. This is how the chruby chef recipe in my wrapper looks like:

# install ruby_build
include_recipe 'ruby_build'

# build and install ruby
ruby_build_ruby node['app-rails']['ruby-string'] do
  prefix_path "/opt/rubies/#{node['app-rails']['ruby-string']}"
end


# install chruby
node.default['chruby']['default'] = 'system'
include_recipe 'chruby'


# install bundler
gem_package 'bundler' do
  gem_binary "/opt/rubies/#{node['app-rails']['ruby-string']}/bin/gem"
end

migrating rvm wrapper to chruby-exec

For starting up services or tasks like “bundle install”, you can use chruby-exec, which works just as smooth as an rvm wrapper.

chruby-exec 1.9.3-p448 -- bundle install