Blog tech

Migrer de Capistrano 2 vers 3 dans une application Rails

Rédigé par Numa Claudel | 16 janvier 2015

Aujourd’hui je vous propose de faire une revue des changements nécessaires pour migrer Capistrano de la version 2 vers la 3 dans une application Rails.

Changements à apporter

Tout d’abord il faut mettre à jour le Gemfile pour ajuster les gems et les versions à utiliser:

gem 'capistrano', '~> 2.0'

devient:

gem 'capistrano', '~> 3.0'

Il faut aussi rajouter ces 2 gems:

gem 'capistrano-rails', '~> 1.1', require: false
gem 'capistrano-bundler', '~> 1.1', require: false

puisque Capistrano 3 n’intègre plus Rails et Bundler par défaut. Si vous utilisez Passenger, vous voudrez aussi ajouter capistrano-passenger.

Nous avons aussi les gems correpondantes au gestionnaire de versions de Ruby capistrano-rvm, capistrano-rbenv et capistrano-chruby, qu’il peut être intéressant d’ajouter. Dans mon cas:

gem 'capistrano-rbenv', '~> 2.0', require: false

Il est ensuite conseillé de faire un backup de l’ancienne configuration de Capistrano 2, qui comprend au minimum un Capfile, un config/deploy.rb, et en cas de multi-instances les fichiers compris dans config/deploy/:

mkdir old_cap
mv Capfile old_cap
mv config/deploy.rb old_cap
mv config/deploy/ old_cap

Après un bundle install, nous pouvons utiliser la nouvelle commande d’installation de Capistrano 3:

bundle exec cap install

On retrouve le Capfile à la racine du projet, ainsi que config/deploy.rb et, puisque Capistrano 3 est multi-instances par défaut, config/deploy/staging.rb et config/deploy/production.rb.

Voici le Capfile généré:

# Load DSL and set up stages
require 'capistrano/setup'

# Include default deployment tasks
require 'capistrano/deploy'

# Include tasks from other gems included in your Gemfile
#
# For documentation on these, see for example:
#
#   https://github.com/capistrano/rvm
#   https://github.com/capistrano/rbenv
#   https://github.com/capistrano/chruby
#   https://github.com/capistrano/bundler
#   https://github.com/capistrano/rails
#   https://github.com/capistrano/passenger
#
# require 'capistrano/rvm'
# require 'capistrano/rbenv'
# require 'capistrano/chruby'
# require 'capistrano/bundler'
# require 'capistrano/rails/assets'
# require 'capistrano/rails/migrations'
# require 'capistrano/passenger'

# Load custom tasks from `lib/capistrano/tasks' if you have any defined
Dir.glob('lib/capistrano/tasks/*.rake').each { |r| import r }

Nous pouvons décommenter les parties qui nous intéressent. Déjà capistrano/bundler, capistrano/rails/assets et capistrano/rails/migrations, puis la gem en rapport avec Passenger si vous l’utilisez, ainsi que la gem correspondante à notre gestionnaire de versions de Ruby.

On peut maintenant remettre en place les anciens fichiers de multi-instances au même endroit dans config/deploy/, et “merger” les nouveaux fichiers avec les anciens.

Notez que la tache deploy:restart n’est plus exécutée automatiquement, il faut donc penser à l’appeler:

after 'deploy:publishing', 'deploy:restart'

# ou

namespace :deploy do
  after :publishing, :restart
end

Pour les utilisateurs de Passenger ayant intégrés la gem capistrano-passenger, cet ajout n’est pas nécessaire.

Au niveau des options

Quelques options ont changées, voici certains changements de définitions à noter:

  • il n’est plus nécessaire de définir de taches pour générer les liens symboliques des fichiers partagés entre les versions. Il suffit dorénavant de définir ceci:
set :linked_files, %w{ config/database.yml }
  • de même pour les dossiers partagés, une option linked_dirs est prévue à cet effet
  • l’option repository devient repo_url
  • l’option set :deploy_via, :remote_cache n’est plus nécessaire, car le mode :copy n’est plus présent dans la version 3
  • l’option pty se définie comme les autres: set :pty, true
  • l’option verbose du tableau d’options ssh_options remplace l’option -v de la ligne de commande. Elle peut être utile pour trouver les erreurs lors d’un déploiement.
set :ssh_options, { verbose: :debug }

Syntaxe des taches

Voici quelques exemples de nouveautés apportées par SSHKit:

  • la récupération de variable se fait via fetch(:var_name) et non plus simplement par var_name
  • les taches s’exécutent maintenant dans un block on, qui défini donc cette tache pour un ou plusieurs roles
  • within sert à définir le dossier dans lequel exécuter les commandes
  • pour définir des paramètres à une tache, il y a with
  • exécuter une commande ne se fait plus avec run, mais avec execute

Exemple pour une tache seed:

desc 'Runs rake db:seed'
task :seed => [:set_rails_env] do
  on primary fetch(:migration_role) do
    within release_path do
      with rails_env: fetch(:rails_env) do
        execute :rake, "db:seed"
      end
    end
  end
end

On peut également voir dans le config/deploy.rb généré:

after :restart, :clear_cache do
  on roles(:web), in: :groups, limit: 3, wait: 10 do
    # Here we can do anything such as:
    # within release_path do
    #   execute :rake, 'cache:clear'
    # end
  end
end

Ici on observe les options in, limit et wait qui servent respectivement à:

  • in: pour définir la stratégie d’execution de la commande sur les différents serveurs (options: parallel, groups et sequence)
  • limit: en cas d’utilisation de l’option groups, définit la taille du groupe
  • wait: définit le temps d’attente entre 2 envois d’ordres pour les options groups et sequence

Flow de Capistrano 3

Le “flow” de déploiement de Capistrano 3 est quelque peu simplifié:

deploy:starting    - start a deployment, make sure everything is ready
deploy:started     - started hook (for custom tasks)
deploy:updating    - update server(s) with a new release
deploy:updated     - updated hook
deploy:publishing  - publish the new release
deploy:published   - published hook
deploy:finishing   - finish the deployment, clean up everything
deploy:finished    - finished hook

et voici celui d’un “rollback”:

deploy:starting
deploy:started
deploy:reverting           - revert server(s) to previous release
deploy:reverted            - reverted hook
deploy:publishing
deploy:published
deploy:finishing_rollback  - finish the rollback, clean up everything
deploy:finished

Pour finir

Une fois le “merge” fini, tout devrait fonctionner comme avant mais avec Capistrano 3. Pour vérifier que tout est ok:

bundle exec cap staging deploy:check

Encore une chose, la tâche cap deploy:cold destinée au premier déploiement d’une application, a été retiré de Capistrano version 3. Voici une page donnant quelques options pour ce cas.

Terminons par un petit nettoyage, désinstallons l’ancienne gem Capistrano 2:

gem uninstall capistrano --version '<3.0'

Voilà donc la base des changements à connaître et à apporter pour effectuer cette migration, sur laquelle vous devrez sans aucun doute faire quelques ajustements en fonction de votre projet.

L’équipe Synbioz.

Libres d’être ensemble.