Uncategorized

Localhost Railsless Capistrano Tutorial, including recipe creation

Unless you’re deploying on rails, to a remote server and doing exactly what’s assumed in Capistrano, the documentation is pretty unhelpful.

This tutorial will cover using Ubuntu, Git and going without Rails to deploy from another directory to another directory, all locally. You are not required to have ruby knowledge to understand this tutorial.

SSH and Git Install

If you have SSH client, server and Git, skip to Git Directory

sudo apt-get install openssh-client
sudo apt-get install openssh-server
sudo apt-get install git-core

Git Directory

Lets create a helloworld application

mkdir ~/helloworld
cd ~/helloworld

Create a brief text file for our repo to have.

echo "hello world" | sudo tee -a ~/helloworld/HelloWorld.txt
git init; git add .
git commit -a -m "This is our first commit"

Sweet, now lets quickly create our remoteworld directory. This will act as a remote server location.

cd ~
git clone ~/helloworld/.git ~/remoteworld/clone

You can view the clone example.

cd ~/remoteworld/clone

Capistrano Install

sudo apt-get install capistrano

Skip this command if you wish to use rails.

sudo gem install railsless-deploy --no-rdoc --no-ri

Capistrano Setup

Now set up a Capistrano directory, this will be in charge of deploying.

mkdir ~/capistrano
cd ~/capistrano
capify .

Create a recipes folder.

mkdir ~/capistrano/recipes

Skip this part if you wish to use rails.

rm -f Capfile
echo "require 'railsless-deploy'" | tee -a ~/capistrano/Capfile
echo "load 'config/deploy'" | tee -a ~/capistrano/Capfile

Now open the config/deploy.rb. I recommend making it look something like this.

# Ruby quote
## recipes ##
#require "recipes/nginx" # to only require a specific recipe
# grab all recipes in the folder
Dir[File.dirname(__FILE__) + '/../recipes/*.rb'].each {|file| require file }
## main config ##
set :application, "remoteworld"

## source control ##
set :repository, "~/helloworld/.git"
set :deploy_to, "~/remoteworld/"
set :scm, :git
# Or: 'accurev', 'bzr', 'cvs', 'darcs', 'git', 'mercurial', 'perforce', 'subversion' or 'none'

## misc ##
set :user, "andreas" # set this to whatever the remoteworld's user is
set :use_sudo, false # set use sudo to false for security reasons
default_run_options[:pty] = true # It solves 'pty ttl errors'. Not important.
set :deploy_via, :remote_cache # it compares deployed files with remote files to only implement changed files. Saves bandwidth.

## roles ##
#role :web, "your primary web-server here" #nginx, Apache, etc.
role :app, "localhost" # This may be the same as your web server.
#role :db, "your primary db-server here", :primary => true # This is where rails migrations will run
#role :db, "your slave db-server here"

Now run this command in the same directory of your Capfile. This prepares the location for future deployments (You’ll see later).

cd ~/capistrano
cap deploy:setup

Now it’s ready for deployment. Start deploying.

cap deploy

If you get a request for password, it’s the same as the user you specified in deploy.rb above.

This is what the process looked like to me.

	* executing `deploy'
	  * executing `deploy:update'
	 ** transaction: start
	  * executing `deploy:update_code'
	    updating the cached checkout on all servers
	    executing locally: "git ls-remote ~/helloworld/.git HEAD"
	  * executing "if [ -d ~/remoteworld/shared/cached-copy ]; then cd ~/remoteworld/shared/cached-copy && git fetch -q origin && git reset -q --hard 927b37dca3cdecb7fc2f35b08fa2a071446c9a75 && git clean -q -d -x -f; else git clone -q ~/helloworld/.git ~/remoteworld/shared/cached-copy && cd ~/remoteworld/shared/cached-copy && git checkout -q -b deploy 927b37dca3cdecb7fc2f35b08fa2a071446c9a75; fi"
	    servers: ["localhost"]
	Password: 
	    [localhost] executing command
	    command finished
	    copying the cached version to ~/remoteworld/releases/20120112221620
	  * executing "cp -RPp ~/remoteworld/shared/cached-copy ~/remoteworld/releases/20120112221620 && (echo 927b37dca3cdecb7fc2f35b08fa2a071446c9a75 > ~/remoteworld/releases/20120112221620/REVISION)"
	    servers: ["localhost"]
	    [localhost] executing command
	    command finished
	  * executing `deploy:finalize_update'
	  * executing "chmod -R g+w ~/remoteworld/releases/20120112221620"
	    servers: ["localhost"]
	    [localhost] executing command
	    command finished
	  * executing `deploy:symlink'
	  * executing "rm -f ~/remoteworld/current && ln -s ~/remoteworld/releases/20120112221620 ~/remoteworld/current"
	    servers: ["localhost"]
	    [localhost] executing command
	    command finished
	 ** transaction: commit

Have a look at remoteworld.

cd ~/remoteworld

There’s three folders; current and releases (and .git if showing hidden files). Open the current folder.

cd ~/remoteworld/current

Everything looks the same as helloworld? Yep. Now go to helloworld.

cd ~/helloworld

Lets create a new file called HelloWorld.txt in that directory. Add inside: hello crazy world.

echo "hello crazy world" | sudo tee -a ~/helloworld/HelloWorld.txt

Add new changes to the git repo

git add .
git commit -a -m "this is our second commit"

Now run this command in the same directory of your Capfile.

cd ~/capistrano
cap deploy

Lets look at remoteworld/current again.

cd ~/remoteworld/current

Now the file HelloWorld.txt says it’s a crazy world!

Lets roll it back. Go back to the directory with the Capfile.

cd ~/capistrano
cap deploy:rollback

Now back to remoteworld/current.

cd ~/remoteworld/current

The HelloWorld.txt got reverted!

What happened was that deploy:rollback sent a quick command remotely to use the previous release (hence the release folder full of releases!)

You should have now successfully installed capistrano and understand the basics.

Troubleshooting

Deploy for first time

	** [localhost :: out] fatal: could not create work tree dir '/home/andreas/remoteworld/shared/cached-copy'.: Permission denied

Most likely Capistrano attempted to use sudo by default which created the directories under root, not your user. Thus, when your user attempted to create the directory, it got denied.

If Capi fails and wants sudo (notable to clean up), disable use of sudo for Capistrano.

set :use_sudo, false

no tty present and no askpass program specified

Not sure how to explain it but setting this in deploy works

default_run_options[:pty] = true

Reference: the { buckblogs :here }: Capistrano 2.1

Your own recipe

Open a new file ~/capistrano/recipes/nginx.rb

A simple task to restart nginx on command.

unless Capistrano::Configuration.respond_to?(:instance)
  abort "This extension requires Capistrano 2"
end
  
Capistrano::Configuration.instance.load do
  namespace :nginx
    desc <<-DESC
	A general description blurb can go here. \
	
	Sends a command to target server to restart nginx.
	DESC
	task :restart, :roles => :web do
	  sudo "/etc/init.d/nginx restart"
	end		
  end # End namespace
end # End Capistrano instance

It will be included via deploy.rb or individually: require “recipes/nginx”

cd ~/capistrano
cap nginx:restart

More tasks (including Postgresql) at Doing Bad Things with Capistrano – Skills Matter [PDF]

My guidelines for automating repetitive commands

  • Document the process. Can it be automated?
  • Is a recipe already online? People usually share with Github too.
  • A recipe per program is usually sufficient.
  • For one command that does a lot of other commands, I usually put it in the custom recipe.

Notes

You don’t need to install RubyGems or Capistrano on the remote server, as you’ll usually be deploying from your local machine.

Available Tasks

Navigate to the directory where the config folder and Capfile is and run the following command to see a list of available tasks.

cap -T

There’s much more here: Basic guide of deploy options

Remote

There should be created directories:

  • ~/remoteworld/releases
  • ~/remoteworld/current (A symlink, not quite a folder)

It’s Capi’s way of allowing rollback with using a symlink and releases. Capi simply links the /release with /current. Which means if something crapped, rollback to a different /release folder.

Rollback

Local – Run this immediately

cap deploy:rollback

This is a very fast task which will simply make your current symlink point to the previous release.

To re-deploy again:

cap deploy

Cleanup manually

Capi will have the last 5 releases by default. Run to cleanup

cap deploy:cleanup

Addenum

Tutorial: Deploying WordPress with Capistrano – Theme.fm

Capistrano Handbook to lower barrier of entry to understanding Capistrano. Not railsless.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s