While we’re supposed to create docker(y) images and deploy these to the cloud, I’m still comfortable deploying and maintaining quite a range of applications using Capistrano (this builds on the battle tested server management process that I outlined more than 7 years ago). But Capistrano and its plugins are typically aimed at performing application level tasks, and not so much about configuring the environment.
I typically install ruby using rbenv
. To deploy ruby apps using rbenv a Capistrano plugin exist (capistrano/rbenv) but it is missing the commands to install and/or update the ruby installation.
This snippet presented here adds a few commands:
cap rbenv:install
# installs rbenvcap rbenv:update
# updates rbenv & installs the desired ruby versionAdditionally it reimplements the cap rbenv:validate
method, as by default it prevents running any capistrano task when the ruby version doesn’t match.
# Capistrano deploy fragment that adds rbenv:install, rbenv:update and reimplements rbenv:validate with a non-exiting warning.
#
# this assumes "capistrano/rbenv" is `require`d in Capfile
#
set :rbenv_ruby, File.read(File.expand_path("../.ruby-version", __dir__)).strip
Rake::Task["rbenv:validate"].clear_actions
namespace :rbenv do
desc "Install rbenv"
task :install do
on roles(:setup) do
begin
execute "git clone https://github.com/rbenv/rbenv.git ~/.rbenv"
rescue SSHKit::Command::Failed
puts "rbenv already installed, updating..."
execute "cd ~/.rbenv && git pull"
end
# execute "~/.rbenv/bin/rbenv init"
execute "mkdir -p ~/.rbenv/plugins"
begin
execute "git clone https://github.com/rbenv/ruby-build.git ~/.rbenv/plugins/ruby-build"
rescue SSHKit::Command::Failed
puts "rbenv/ruby-build plugin already installed, updating..."
execute "cd ~/.rbenv/plugins/ruby-build && git pull"
end
execute "~/.rbenv/bin/rbenv install -s #{fetch(:rbenv_ruby)}"
execute "~/.rbenv/bin/rbenv global #{fetch(:rbenv_ruby)}"
execute "~/.rbenv/bin/rbenv local #{fetch(:rbenv_ruby)}"
execute "export PATH=\"$HOME/.rbenv/bin:$PATH\" && eval \"$(rbenv init -)\" && ruby -v"
execute "export PATH=\"$HOME/.rbenv/bin:$PATH\" && eval \"$(rbenv init -)\" && gem install bundler --no-document"
if fetch(:rbenv_ruby).nil?
puts "\nPlease uncomment the line `# set :rbenv_ruby, File.read('.ruby-version').strip` to enable capistrano rbenv"
end
execute :echo, "'export PATH=\"$HOME/.rbenv/bin:$PATH\"'", ">>", "~/.bashrc"
execute :echo, "'eval \"$(rbenv init -)\"'", ">>", "~/.bashrc"
end
end
task :validate do
on release_roles(fetch(:rbenv_roles)) do |host|
rbenv_ruby = fetch(:rbenv_ruby)
if rbenv_ruby.nil?
info 'rbenv: rbenv_ruby is not set; ruby version will be defined by the remote hosts via rbenv'
end
# don't check the rbenv_ruby_dir if :rbenv_ruby is not set (it will always fail)
unless rbenv_ruby.nil? || (test "[ -d #{fetch(:rbenv_ruby_dir)} ]") || ARGV.include?("rbenv:install")
warn "rbenv: #{rbenv_ruby} is not installed or not found in #{fetch(:rbenv_ruby_dir)} on #{host}"
exit 1
end
end
end
desc "update ruby"
task :update do
on roles(:app), in: :sequence do
execute "git -C ~/.rbenv/plugins/ruby-build pull"
execute "RBENV_ROOT=~/.rbenv ~/.rbenv/bin/rbenv install #{fetch(:rbenv_ruby)} -s -k"
execute "RBENV_ROOT=~/.rbenv ~/.rbenv/bin/rbenv global #{fetch(:rbenv_ruby)}"
execute "RBENV_ROOT=~/.rbenv RBENV_VERSION=#{fetch(:rbenv_ruby)} ~/.rbenv/bin/rbenv exec gem install -N bundler"
end
end
end
Enjoyed this? Follow me on Mastodon or add the RSS, euh ATOM feed to your feed reader.
Dit artikel van murblog van Maarten Brouwers (murb) is in licentie gegeven volgens een Creative Commons Naamsvermelding 3.0 Nederland licentie .