Chef: RVM + Ruby Enterprise Edition as Default Ruby

Creative Commons License Seattle Municipal Archives

The opscode chef bootstrap installs Matz Ruby on the node automatically. There are cookbooks for installing ruby enterprise edition on a node, but they create a separate Ruby “universe” on your box: You will have to be very careful how you install gems to make sure they are used by either the default Ruby or by REE. As this really bothered me, I created a little cookbook which installs Ruby Enterprise Edition as the default Ruby using Ruby Version Manager (RVM) and Chef. This gives me the best of both worlds: REEs stability and speed as well as a sane way of managing gems.

Bootstrap Your Chef Node

First, you need to bootstrap your node using knife:

$ knife bootstrap www.example.com

This will install Ruby on your node and register the node at the chef server. Now you’re ready to run cookbooks on that node.

The rvm_ree_default cookbook

My cookbook consists of a default recipe and one file to be uploaded to your node. Here is the rvm_ree_default/recipes/default.rb:

#
# Cookbook Name:: rvm_ree_default
# Recipe:: default
#
# Copyright 2010, Matthias Marschall
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# see: http://li109-47.members.linode.com/blog/
package "curl"
package "git-core"

include_recipe "build-essential"

%w(libreadline5-dev zlib1g-dev libssl-dev libxml2-dev libxslt1-dev).each do |pkg|
  package pkg
end

bash "install RVM" do
  user "root"
  code "bash < <( curl -L http://bit.ly/rvm-install-system-wide )"
  not_if "rvm --version"
end
cookbook_file "/etc/profile.d/rvm.sh"

bash "install REE in RVM" do
  user "root"
  code "rvm install ree"
  not_if "rvm list | grep ree"
end

bash "make REE the default ruby" do
  user "root"
  code "rvm --default ree"
end

gem_package "chef" # re-install the chef gem into REE to enable subsequent chef-client runs

It installs the prerequisite packages and uses the rvm-install-system-wide script to get RVM installed. To enable RVM in all shells, it puts the rvm.sh into the /etc/profile.d. Then, it uses RVM to install REE and make it the default Ruby on the box. As a last step, it installs the chef gem again as the brand new REE doesn’t yet have it. Now, REE is your default Ruby and all commands like irb, gem, etc. work as expected using REE.

Here is the rvm_ree_default/files/default/rvm.sh

[[ -s "/usr/local/lib/rvm" ]] && . "/usr/local/lib/rvm"  # This loads RVM into a shell session.

Don’t forget to $ knife cookbook upload rvm_ree_default before trying to use it!

Install RVM at Bootstrap Time

The above way helps if you already have chef nodes up and running and want to switch them to REE. If you install a brand new node, you can use a bootstrap template to install REE with RVM as default. Here you go:

bash -c '
if [ ! -f /usr/local/bin/chef-client ]; then
  apt-get update
  apt-get install -y git-core curl
  apt-get install -y build-essential binutils-doc gcc autoconf flex bison
  apt-get install -y libreadline5-dev zlib1g-dev libssl-dev libxml2-dev libxslt1-dev
  bash < <( curl -L http://bit.ly/rvm-install-system-wide )
  (
  cat < /etc/profile.d/rvm.sh
  source /etc/profile
  rvm install ree
  rvm --default ree
  gem install ohai chef --no-rdoc --no-ri --verbose 
  ln -nfs $(which chef-client) /usr/bin/chef-client
fi

mkdir -p /etc/chef

(
cat <<'EOP'

EOP
) > /tmp/validation.pem
awk NF /tmp/validation.pem > /etc/chef/validation.pem
rm /tmp/validation.pem

(
cat <<'EOP'
log_level        :info
log_location     STDOUT
chef_server_url  ""
validation_client_name ""

# Using default node name"

node_name ""
 
EOP
) > /etc/chef/client.rb

(
cat <<'EOP'
 @run_list }.to_json %>
EOP
) > /etc/chef/first-boot.json

chef-client -j /etc/chef/first-boot.json'

The upper part of the script is the interesting one here: First, it installs the required packages, then RVM and then it uses RVM to install Ruby Enterprise Edition and makes it the default ruby.

The symlink to chef-client is only necessary if you want to use sudo (without -i option) to call chef-client (sudo without -i won’t load the enviroment so RVM will not be available for your sudo commands).

To bootstrap your node using the above script, save it in your chef repo under bootstrap/ubuntu10.04-rvm-ree.erb and run

$ knife bootstrap www.example.com -t bootstrap/ubuntu10.04-rvm-ree.erb

No matter whether you want to switch an existing node to Ruby Enterprise Edition or bootstrap your node using it, the Ruby Version Manager helps you keep a clean system. And, it offers you the possibility to smoothly upgrade to another ruby version later or even use separate gem sets for different applications. Does it work for you? Please leave a comment or tweet this post.

15 thoughts on “Chef: RVM + Ruby Enterprise Edition as Default Ruby

  1. I’m having some trouble with your test:

    not_if “rvm –version”

    I get error output like this:

    ERROR: bash[Install RVM] (/srv/chef/cache/cookbooks/modcloth/recipes/default.rb:38:in `from_file’) had an error:
    No such file or directory – rvm –version

    Like

  2. @M yes, we’re using tynt.com to track user interaction with our blog. I’m sorry that it is annoying when copying code but there is no way to avoid that for special parts of the site. We would have to disable it completely, which is not an option right now.

    Like

  3. @Dennis Great job! The separation of the cookbooks is really nice.

    Without the curl and git-core dependencies, it would not install on a minimal ubuntu install as it can be found on quite a few rented servers.

    And for me it was necessary to install the chef gem into the new default ruby.

    Like

  4. When I bootstrap RVM+ree using either knife ec2 server create…, or knife bootstrap… methods, and on chef-client runs where RVM+ree are installed, the process always causes either knife or chef-client to not return:


    node.amazonws.com ree-1.8.7-2010.02 – #installing

    I never get past that successfully. Any hints? Can I be the only one seeing this behavior?

    Like

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.