Déploiement de Rails 2 et Rails 3 avec les gemsets de RVM

Publié dans: 

Utiliser Ruby on Rails en environnement entreprise impose parfois de faire cohabiter Rails 2 et Rails 3 ensemble sur le même serveur. Ceci est aussi valable sur une machine de développement pour des raisons de test ou d'essai de différentes versions par exemple.

Le problème majeur avec une configuration pareille est que Rails 2 et Rails 3 nécessitent chacun ses propres gem (dépendances Ruby), qui peuvent malheureusement faire conflit.

Chaque Rails dépend d'un même gem par exemple mais chacun dans une version différente, pour garantir une compatibilité totale.
Installer un seul gem ou mettre à jour une ancienne version de ce gem créera un conflit menant à des erreurs d'exécution sur l'un des projets.

Pour surmonter ces obstacles de déploiement qui risquent d'abimer une de vos applications Rails, nous profiterons du fameux RVM (Ruby Version Manager) et de ses gemsets.

Commençons déjà par RVM qui est devenu un outil indispensable pour les développeurs Rails puisqu'il permet d'installer et gérer sur le même système différentes versions de Ruby.

Plus encore, avec RVM, on pourra créer pour chaque projet un environnement totalement indépendant qui inclut une version précise de l'interpréteur Ruby et des dépendances gem requises par le projet, tout ceci grâce aux Gemsets.

L'exemple que je vais décrire est tiré d'un cas concret où j'ai eu à installer 2 instances du gestionnaire de projet Redmine: une sous sa version 0.8.7 (fonctionnant sur Rails 2) et une nouvelle sous 2.0.1 (qui requiert Rails 3).

Bien entendu, je suppose que RVM est installé et que je vais déployer mes 2 applications avec Ruby Entreprise Edition et sous Phusion Passenger (comme module Apache) qui sont déjà configurés.
A titre d'information, Ruby EE et Passenger forment le couple idéal pour l'hébergement d'applications Web sur des serveurs!

Voici donc notre ruby actuel et par défaut:

 

Création des gemsets:

Commençons par créer le gemset spécifique au 1er projet. Notre projet appelé "projet1", nous appellerons le gemset du même nom pour l'identifier plus facilement.

$ rvm gemset create projet1

 

Les fichiers .rvmrc:
Ensuite, nous créons le fichier .rvmrc, le fichier clé des gemsets, similaire à un .bashrc pour Linux mais pour charger un environnement RVM spécifique avec un ruby et un gemset choisis.
 

$ cd ~/rails_apps/projet1/
$ rvm --rvmrc --create use ree-1.8.7-2012.02@projet1

A chaque fois que RVM rencontre le .rvmrc, il s'occupe de charger la bonne version de ruby et d'utiliser le bon lot de gems.
Même en ligne de commande, à chaque fois que l'on est dans le répertoire du projet, on appellera le bon ruby avec le bon gemset.

Faisons de même pour le 2ème projet avec la création d'un autre gemset et d'un .rvmrc dans le répertoire ~/rails_apps/projet2/
Et le tour est joué. Un gemset spécifique à chaque projet. Pas de conflit de dépendances et une gestion aisée des environnements.


Pour finir, il ne reste plus qu'à indiquer à Passenger le chemin d'accès des gem de chaque projet:

 

Pour Rails 3:
Ajoutez le nouveau fichier setup_load_paths.rb dans le répertoire config/ de votre application avec le contenu suivant:

  # config/setup_load_paths.rb
  
  if ENV['MY_RUBY_HOME'] && ENV['MY_RUBY_HOME'].include?('rvm')
    begin
      rvm_path     = File.dirname(File.dirname(ENV['MY_RUBY_HOME']))
      rvm_lib_path = File.join(rvm_path, 'lib')
      $LOAD_PATH.unshift rvm_lib_path
      require 'rvm'
      RVM.use_from_path! File.dirname(File.dirname(__FILE__))
    rescue LoadError
      # RVM is unavailable at this point.
      raise "RVM ruby lib is currently unavailable."
    end
  end

  ENV['BUNDLE_GEMFILE'] = File.expand_path('../Gemfile', File.dirname(__FILE__))
  require 'bundler/setup'

Vous pouvez désormais installer vos dépendances facilement et automatiquement avec Bundler d'une seule commande.

Notez bien que dans mon cas, je n'ai pas eu à créer ce fichier sous Rails 3, mais uniquement sous Rails 2 que nous allons voir tout de suite.

 

Pour Rails 2:
De même pour votre application Rails 2, créez sous votre répertoire config/ le fichier setup_load_paths.rb en indiquant à RVM qu'il doit utiliser notre gemset avec Ruby EE:

if ENV['MY_RUBY_HOME'] && ENV['MY_RUBY_HOME'].include?('rvm')
  begin
    rvm_path     = File.dirname(File.dirname(ENV['MY_RUBY_HOME']))
    rvm_lib_path = File.join(rvm_path, 'lib')
    require 'rvm'
    RVM.use!('ree-1.8.7-2012.02@projet2')    
  rescue LoadError
    # RVM is unavailable at this point.
    raise "RVM ruby lib is currently unavailable."
  end
end


Vous pourrez alors installer vos gems un à un avec la manière traditionnelle avec la commande gem install.

Il ne reste plus qu'a configurer 2 virtualhosts pour exposer vos applications avec Apache Passenger. Je vous recommande cette page qui y est consacrée.

Bon déploiement avec RVM et Passenger!