This, and the following entry, are the main focus of this tutorial. Here you will learn how to create a Capistrano project, recipe – for deploying your application code, run tests, stop and restart the NodeJS server; and maintain roles. The assumptions are that git, npm and NodeJS are already installed on target servers, and your code is hosted in a git repository.
This entry is structured around a set of basic questions, followed by answered and code snippets. Snippets below are based on default code generated by an install command.
How to create a Capistrano project?
A Capistrano project can be created, issuing the following command, in a project’s folder:
cap install
It is a good idea to store Capistrano projects in a separate repository, to be able to control access and separate concerns. This dedicated repository could follow a folder structure with a directory per project.
What are Capistrano recipes and tasks?
Capistrano recipes are a set of instructions, that run either local or remote shell commands. Commands can be grouped by tasks – defined by a set of Ruby instructions. The main Capistrano recipe is “deploy”, with some of it’s tasks below:
publishing - used for deploying code restart - used for restarting your application related services rollback - used for rolling back a release
A wide range of other tasks are available, and documented here:
http://capistranorb.com/documentation/getting-started/flow/
Custom tasks can be added, to extend the default deploy workflow. In this article, we will create two additional deployment tasks:
test - used for running tests npminstall - used for installing nodejs dependencies, via npm
A default Capistrano project consists of two deployment scenarios, one for a production server, and one for a staging server; with a common deployment script. These are stored in the following files:
config/deploy.rb - main deployment script config/staging.rb - staging deployment configuration config/production.rb - production deployment configuration
What are Capistrano roles?
Capistrano roles define the function of each server, within your cluster or cloud. Three major roles are defined by default:
app - application servers web - web servers db - database servers
This tutorial focuses on the app role; with instructions on how to configure provided further down the document.
How does a Capistrano deployment work?
Essentially, Capistrano executes a set of shell scripts on a given set of servers. This process starts by uploading a shell script for each task to a remote server, executing it and capturing it’s output. A failed command, results in a failed task and recipe. By default, the first executed script, clones a repository – configurable through the recipe file.
Below are configuration samples for your git repository, using HTTP authentication, stored in deploy.rb:
1. Defines the VCS:
set :scm, :git
2. Defines the application name:
set :application, ‘ApplicationName’
3. Defines the repository URL:
set :repo_url, 'http://hostname/repository.git'
4. Defined git repository authentication:
set :git_http_username, ‘GitUsername’ set :git_http_password, 'GitPassword'
5. Output formatting, and log level:
# Output format and log level: set :format, :pretty set :log_level, :info
Followed by directory structure settings:
set :deploy_to, '/path/to/application/directory/'
Directory structure notes:
Capistrano creates a couple of subdirectories, within the target directory, such as:
current - current release files, with an extra REVISION file holding the current revision number repo - git repository content releases - previous release directories, with subdirectories named after previous release year, month, day and time revisions.log - revision log shared - shared files *.tar.gz - compressed archives of each release
As such, your most recent application resides in current/. Should you decide to rollback a release, Capistrano would fall back to one of the previous releases, already found in this directory.
Once Capistrano is aware of where to fetch the from, and which directory to deploy to, it must be made aware of which servers to perform this tasks on:
Production server configuration (config/production.rb):
1. Define the app role, with a main build server:
role :app, %w{deployment@hostname.com}
2. Define servers for this role:
server 'hostname.com’, user: ‘deployment’, roles: %w{app}
Staging server configuration (config/staging.rb), is similar to a production configuration; but pointing to different servers:
role :app, %w{deployment@staging.hostname.com} server 'staging.hostname.com', user: 'deployment', roles: %w{app}
Having configured what and where to deploy, tasks can be created for each type of action to take.
1. Define the restart task, part of the deploy recipe (ruby namespace):
namespace :deploy do desc 'Restart application' task :restart do on roles(:app), in: :sequence, wait: 5 do within release_path do execute "npm", "stop", "; true" execute "npm", "start" end end end
2. Called after the publishing task:
after :publishing, :restart
3. Define an npminstall task, required for installing npm modules:
task :npminstall do on roles(:app) do within release_path do execute "npm", "install" end end end
4. Called before a restart task:
before :restart, :npminstall
5. Close namespace definition:
end
Tasks above ensure proper actions for a production server. On the staging server however, we want to run tests, prior to making a server restart:
1. Extend the deploy recipe defined above, and add the following:
namespace :deploy do desc 'Run tests, prior to an application restart.' task :test do on roles(:app), in: :sequence, wait: 5 do within release_path do execute "npm", "test" end end end after :npminstall, :test end
Calling it, after the npminstall task, and prior to the restart task.
How does Capistrano authenticate to remote servers?
Capistrano supports various SSH authentications models. However, to ensure that unwanted eyes do not view ssh passwords for live servers, capistrano shell users should have their public ssh keys added to remote servers.
Resulting code available here – with inline comments added:
1. config/staging.db
# Application role. role :app, %w{deployment@staging.hostname.com} # Target server(s). server 'staging.hostname.com', user: 'deployment', roles: %w{app} # Extend the deploy recipe. namespace :deploy do desc 'Run tests, prior to an application restart.' task :test do on roles(:app), in: :sequence, wait: 5 do within release_path do execute "npm", "test" end end end after :npminstall, :test end
2. config/production.rb
# Application role. role :app, %w{deployment@hostname.com} # Target server(s). server 'hostname.com', user: 'root', roles: %w{app}
3. deploy.rb
# config valid only for Capistrano 3.1 lock '3.2.1' # Application, and repository settings. set :application, ‘ApplicationName’ set :repo_url, 'http://hostname.com/repository.git' set :git_http_username, 'GitUsername' set :git_http_password, 'GitPassword' # Deploy path. set :deploy_to, '/path/to/application/directory/' # SCM settings. set :scm, :git # Output format and log level: set :format, :pretty set :log_level, :info # Common restart and npminstall tasks. namespace :deploy do desc 'Restart application' task :restart do on roles(:app), in: :sequence, wait: 5 do within release_path do execute "npm", "stop", "; true" execute "npm", "start" end end end after :publishing, :restart task :npminstall do on roles(:app) do within release_path do execute "npm", "install" end end end before :restart, :npminstall end
How to run these tasks, without Jenkins?
Issue the following commands:
1. Full production deployment:
cap production deploy
2. Production rollback:
cap production deploy:rollback
3. Restart your server(s):
cap production deploy:restart
Same tasks can be executed against the staging server, by replacing production with staging. Tests can be run individually using:
cap staging deploy:test
Results of tests can be viewed by changing the log level to debug.