Capistrano & RVM - Czego nie przegapić przy konfiguracji?

Capistrano & RVM - Czego nie przegapić przy konfiguracji?

Michał Paprot

Twórcy aplikacji często dużo czasu poświęcają na cykliczny deployment ich najnowszej wersji. Z reguły polega on na pobraniu najnowszej wersji aplikacji, migracji bazy danych, kompilacji styli i skryptów JS oraz restarcie serwera aplikacyjnego. Od ponad 10 lat Capistrano umożliwia im to nie zawsze łatwe zadanie.

Capistrano służy do automatyzacji powtarzających się procedur, głównie na zdalnych maszynach. Łączy się do nich i wykonuje odpowiednie komendy, zdefiniowane w konfiguracji projektu lub dostępne w obszernej bazie rozszerzeń dostępnych w RubyGems.

Dzięki temu możemy automatyzować na przykład deployment aplikacji stworzonych w Ruby on Rails, ich diagnozę, aktualizację certyfikatów SSL bądź całych systemów z rodziny UNIX.

Dzisiaj dowiemy się, jak umożliwić Capistrano 3 deploy aplikacji stworzonych w Railsach, korzystającej z RVM-a (>= 1.0).

Pierwszym krokiem jest doinstalowanie gem-a który instaluje RVM-a-a dla konkretnego deployu:

// Gemfile
gem 'rvm1-capistrano3', require: false

Ten gem zainstaluje i skonfiguruje RVM-a, działa bezproblemowo dla Railsów, przynajmniej od czwórki wzwyż. Po doinstalowaniu gema, wymagamy go w Capfile’u:

// Capfile
require 'rvm1/capistrano3'

a następnie “dogrywamy” go do procedury deploymentu:

// config/deploy/production.rb
before 'deploy', 'rvm1:install:rvm'
before 'deploy', 'rvm1:install:ruby'

Tutaj może pojawić się problem braku Bundlera w gemsecie świeżo utworzonym przez RVMa. Ręczna instalacja go w każdej nowo deployowanej aplikacji mocno kontrastuje z RVM-em robiącym wszystko za nas. Możemy ten problem rozwiązać na dwa sposoby:

  • Wyzwalać instalację Bundlera poprzez gem install bundler przy każdym deployu:

      namespace :deploy do
        task :install_bundler do
          on roles(:app) do
            within File.join(
                     fetch(:deploy_to),
                     'releases',
                     capture(
                       "ls #{File.join(fetch(:deploy_to), 'releases')}"
                     ).split("\n").sort.last
                   ) do
              execute :rvm, :'.', :do, :gem, :install, :bundler
            end
          end
        end
      end
    
  • Lub wymusić w RVM-ie instalację Bundlera dla każdego nowego gemsetu:

      namespace :deploy do
        task :rvm_force_bundler do
          on roles(:app) do
            execute "grep -qF '^bundler' ~/.rvm/gemsets/global.gems
                     || echo 'bundler' >> ~/.rvm/gemsets/global.gems"
          end
        end
      end
    

Mogłoby się wydawać, że drugi sposób jest bardziej jednorazowy – niestety, gem wprowadzający wsparcie RVM-a za każdym deploymentem czyści config RVMa w którym można zdefiniować instalowane gemy. Rozwiązać można to poprzez wyzwalanie komendy dopisującej Bundlera do listy przy każdym deployu. Praktycznie, wychodzi na to samo.

Ważne jest by w repozytorium projektu były pliki .ruby-version i .ruby-gemset i by zawierały odpowiednią treść.

Od teraz po użyciu cap production deploy (gdzie production to nasz stage), Capistrano będzie używał RVM-a dla tego projektu.

Moim zdaniem Capistrano jest naprawdę zaawansowanym narzędziem, które śmiało mogę uznać za niezbędnik każdego twórcy aplikacji - a także administratora.

To pierwszy z serii postów na jego temat - już niebawem przedstawię Wam kolejną porcję informacji, o których mogliście jeszcze nie mieć pojęcia.

Bazowane na witrynach Capistrano i rvm1-capistrano3.
Logo Capistrano stworzone przez Tom Clements, Lee Hambley. Opublikowane na licencji MIT.