Interactive Shells in Capistrano
Capistrano is a very popular deployment tool written in Ruby. If you’ve deployed Ruby or Rails applications, chances are you’ve heard of it even if you haven’t had the chance to use it.
Capistrano was a crucial part of our deployment process at Loco2 long before overhauling our hosting infrastructure with Terraform and Docker.
Having recently left Loco2, I found myself back on a project that uses Capistrano. As powerful as it is, it frustratingly doesn’t include support for interactive shells. Whilst this is by design, it’s a bit annoying if you want to boot a rails console or run another command that allows input from the user.
After doing some Googling I managed to piece together something that calls ssh
directly, allowing us to run a command in an interactive shell:
namespace :rails do
desc "Start a rails console"
task :console do
exec_interactive("rails console")
end
desc "Start a rails dbconsole"
task :dbconsole do
exec_interactive("rails dbconsole")
end
def exec_interactive(command)
host = primary(:web).hostname
env = "RAILS_ENV=#{fetch(:rails_env)}" # add other ENV variables
command = "cd #{release_path}; #{env} bundle exec #{command}"
puts "Running command on #{host}:"
puts " #{command}\n\n"
exec %(ssh #{host} -t "sh -c '#{command}'")
end
end
The primary(:web).hostname
just fetches the hostname for the first/primary web
host. It’s worth mentioning this because it might not be desirable. You could
quite easily fetch all of the remote hosts and provide a menu that allows the
user to select the host they want to connect to. For my purposes though, I just
wanted to run a rails console without having a custom script that fetched
our hostname via the AWS command line tools.
You may want to consider safeguarding production access by adding a warning
message when fetch(:rails_env) == "production"
, or perhaps add
the --sandbox
option to protect your data.
I believe developers should be trusted to have direct access to all live environments, including production. These sorts of small convenience scripts really help to avoid friction when troubleshooting or debugging data issues on non-local environments.