Welcome to part two in our three part Capistrano 3 tutorial series. If you worked your way through part one then you should be all set to write your first Capistrano deploy script. The deploy script we'll create will be a "bare bones" script which simply moves files from an SVN tag to a folder on your Staging server.
Compared to part one this tutorial instalment is a walk in the park. Enjoy!
Making Capistrano 3 work with non-Rails based projects
Unlike Capistrano 2, Capistrano 3 is not written for default usage with Rails projects. This makes things simpler as we don't have to do anything special for Capistrano to work with our LAMP project.
Let's create a minimal deploy script for our 'Example.com' application. Change into the config
folder within the Example project's deploy script files and edit the deploy.rb
file:
cd /home/deploy/capistrano/example/config/ vi deploy.rb
You should see something along the lines of:
set :application, 'my_app_name' set :repo_url, 'git@example.com:me/my_repo.git' # ask :branch, proc { `git rev-parse --abbrev-ref HEAD`.chomp } # set :deploy_to, '/var/www/my_app' # set :scm, :git # set :format, :pretty # set :log_level, :debug # set :pty, true # set :linked_files, %w{config/database.yml} # set :linked_dirs, %w{bin log tmp/pids tmp/cache tmp/sockets vendor/bundle public/system} # set :default_env, { path: "/opt/ruby/bin:$PATH" } # set :keep_releases, 5 namespace :deploy do desc 'Restart application' task :restart do on roles(:app), in: :sequence, wait: 5 do # Your restart mechanism here, for example: # execute :touch, release_path.join('tmp/restart.txt') end end 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 after :finishing, 'deploy:cleanup' end
We can get rid of a lot of the example and informational lines and fill in some of our known settings:
set :application, 'example' set :repo_url, "svn+ssh://svn.zodiacmedia.co.uk/example" set :ssh_options, { user: 'deploy' } set :scm, :svn set :format, :pretty set :log_level, :debug set :keep_releases, 5 namespace :deploy do after :finishing, 'deploy:cleanup' end
This file contains only the shared settings that are common to all of our deployment environments (Staging and Production). Let's set our Staging specific settings file now.
cd /home/deploy/capistrano/example/config/deploy vi staging.rb
By default this reads:
set :stage, :staging # Simple Role Syntax # ================== # Supports bulk-adding hosts to roles, the primary # server in each group is considered to be the first # unless any hosts have the primary property set. role :app, %w{deploy@example.com} role :web, %w{deploy@example.com} role :db, %w{deploy@example.com} # Extended Server Syntax # ====================== # This can be used to drop a more detailed server # definition into the server list. The second argument # something that quacks like a hash can be used to set # extended properties on the server. server 'example.com', user: 'deploy', roles: %w{web app}, my_property: :my_value # you can set custom ssh options # it's possible to pass any option but you need to keep in mind that net/ssh understand limited list of options # you can see them in [net/ssh documentation](http://net-ssh.github.io/net-ssh/classes/Net/SSH.html#method-c-start) # set it globally # set :ssh_options, { # keys: %w(/home/rlisowski/.ssh/id_rsa), # forward_agent: false, # auth_methods: %w(password) # } # and/or per server # server 'example.com', # user: 'user_name', # roles: %w{web app}, # ssh_options: { # user: 'user_name', # overrides user setting above # keys: %w(/home/user_name/.ssh/id_rsa), # forward_agent: false, # auth_methods: %w(publickey password) # # password: 'please use keys' # } # setting per server overrides global ssh_options # fetch(:default_env).merge!(rails_env: :staging)
Again let's ditch the commented example lines and fill in our specific settings for our Staging deployment server:
set :stage, :staging server 'staging.zodiacmedia.co.uk', roles: %w{web app db}, port: 22 set :deploy_to, '/var/www/staging.example.com'
Note that you need to change port 22 to the appropriate number if you run SSH sessions on a non-standard port.
We're now in a position to do some testing:
cd /home/deploy/capistrano/example cap staging svn:check
This should show you the results of an svn info
query on your target repository. If you run into issues it'll almost certainly be due to SSH permissions. To debug this you can use the tactic of switching to the deploy
user's Linux account and trying to run the svn info
command from that Linux account. For example:
sudo –s su deploy svn info svn+ssh://svn.zodiacmedia.co.uk/example
If you can run the svn info
query ok then continue your debugging by running the same commands Capistrano is trying to run using the same Linux users and relevant servers.
When you run cap staging svn:check
you'll be prompted to enter your SSH key's password. This can get quite tiresome and can be avoided by saving your key to ssh-agent
for the duration of your SSH session as follows:
ssh-agent bash ssh-add
Then type in your SSH key's password.
Getting ready to deploy to Staging
If the deploy_to
folder doesn't exist on your target server create it using:
sudo mkdir -p /var/www/staging.example.com
Then change the folder ownership and permissions as follows:
sudo chown deploy:www-data /var/www/staging.example.com/
Then we need to run cap staging deploy:check
to setup the folder structure needed when deploying. Change directory:
cd /home/deploy/capistrano/example/
And run:
cap staging deploy:check
You should be prompted to enter your SSH key when this command runs unless you've saved in ssh-agent
.
This will create the standard folder structure in the /var/www/staging.example.com
folder which can be seen as follows:
ls -la /var/www/staging.example.com total 16 drwxr-xr-x 4 deploy www-data 4096 Nov 29 09:19 . drwxr-xr-x 12 root root 4096 Nov 29 09:17 .. drwxrwxr-x 6 deploy deploy 4096 Nov 29 16:21 releases drwxrwxr-x 2 deploy deploy 4096 Nov 29 09:19 shared
The releases
folder will go on to contain subfolders where the contents of your codebase will be checked out to. When you actually create a successful release then a symlink with the identifier current
will be added to the /var/www/staging.example.com
folder. This will point to the latest SVN export in the releases
folder. The shared
folder is for placing assets shared across releases (e.g. user uploaded content etc) which will be symlinked to from your current release.
Before we make our first deploy let's refresh our memory on our deploy strategy.
An SVN tag is a release
Previously we outlined how each SVN tag would be a release candidate. To make this viable the svn.rake
file we added to our Capistrano installation earlier prompts us to enter an svn_location
when we run a deploy. This defaults to trunk
but if we wanted to deploy a specific tag then we could enter tags/TAGNAME
where TAGNAME
is replaced by an actual tag name e.g. 1.12 or 0.43 etc. We tend to use incremental numbers for tag names as it's easier to keep track of releases that way.
So let's make our first release.
cap staging deploy
Enter the tag name you want to deploy, et voilà, your one line deploy of code from Subversion to Staging is complete!
We're now in a position where we can move on to the more powerful functionality of Capistrano, creating bespoke tasks in the deploy script for a project. In the next installment in this tutorial series we'll expand on the "bare bones" deploy script we've just created and evolve it into a script for deploying a Drupal powered website.