Deploying to Staging and Production Environments via Capistrano
by David Orkin on Oct.26, 2009,under Ubuntu, Capistrano, Ruby
Ok, so I admit it. Im late to the game as far as using capistrano for deployment of my rails applications.
But I figured, today is a nice rainy day and a great opportunity to give this a shot. Below is the play by play for getting capistrano set up to work.
Im going to make some initial assumptions. First, you are using subversion.
Second, you want to be able to deploy to different environments, (in my case Staging and Production).
Third, you are using a shared hosting environment, using Phusion Passenger
Fourth, you are running your deployment for a linux machine. What follows below assumes Ubuntu in particular.
Fifth, and finally, you like reading verbose posts about technology on random blogs that you come across 'dem internet tubes.
So follow me inside, for more on deploying your ruby on rails application with Capistrano
Follow up:
Using Capistrano to Deploy to Staging and Production Environments
1.sudo gem install capistrano-ext
This Gem extends Capistrano to deploy to Staging and Production Environments. (Or any other environments that you may need to define). You can read more about this on Jamis Buck's blog or you can check it out the capistrano-ext repository on GitHub.
Below is the output you see from running the gem install command.
Successfully installed capistrano-ext-1.2.1
1 gem installed
Installing ri documentation for capistrano-ext-1.2.1...
Installing RDoc documentation for capistrano-ext-1.2.1...
2. Run "capify ." in the root directory for your application
This command will create the basic files needed for deployment. Namely the ./config/deploy.rb and ./Capfile files. The cap command will look for a capfile.
This Capfile in turn loads the ./config/deploy.rb file and the default tasks that we will be using for deployment. Below is the output you will likely see
david@david-eee-pc-box:~/Programming/ProjectLocker/MiniMaid$ capify .
[add] writing './Capfile'
[add] writing './config/deploy.rb'
[done] capified!
3. Run "mkdir ./config/deploy/"
Since we will the multistage recipe for Capistrano we need to go ahead and make the ./config/deploy/ directory which will hold whatever code is specific
to our particular environments.
4. Create the ./config/deploy/staging.rb and ./config/deploy/production.rb files
These files hold any code or variables that are unique to your environments. For my simple case the files have one line a piece which is the
"set :deploy_to, 'your-deployment-path'" line
5. Modify config/deploy.rb
We need to add a require line to get the multistage environment set up. To do that we add the require line listed below
require 'capistrano/ext/multistage'
Add svn username, password (optional)
Depending on how your specific environment is set up, you may need to add your username and password for accessing the svn repository. Add these lines to the ./config/deploy.rb file
set :svn_username, 'your-svn-username'
set :svn_password, 'your-svn-password'
6. Set your username (optional)
If the username on the box you are deploying to is different than the username on the box you are deploying from you can set it by adding the following line to your config/deploy.rb file.
set :user, 'yourusername'
7. Uncomment Out the namespace block if your using Phusion Passenger
If your using using Phusion Passenger with your rails application you will need to uncomment the block of code at the bottom of the config/deploy.rb file to
have capistrano successfully restart your application. I got syntax errors for the stop and start lines so I commented them out. Also as I am running this in a
shared hosting environment I needed to turn off sudo which I did with line "set :sudo,false". Now with the block code below added to config/deploy.rb I was ready
to deploy to my Staging Environment.
set :sudo, false
namespace :deploy do
#task :start {}
#task :stop {}
task :restart, :roles => :app, :except => { :no_release => true } do
run "#{try_sudo} touch #{File.join(current_path,'tmp','restart.txt')}"
end
end
8. Run 'cap staging deploy'
And thats all there is to it... At this point you should have deployed your code. If all works you should see some output like whats below.
david@david-eee-pc-box:~/Programming/ProjectLocker/MiniMaid$ cap staging deploy
* executing `staging'
triggering start callbacks for `deploy'
* executing `multistage:ensure'
* executing `deploy'
* executing `deploy:update'
** transaction: start
* executing `deploy:update_code'
executing locally: "svn info https://free2.projectlocker.com/138LLC/MiniMaid/svn -rHEAD" /usr/bin/svn
* executing "svn checkout -q -r236 https://free2.projectlocker.com/138LLC/MiniMaid/svn /home/randombu/apps/Staging/MiniMaid/releases/20091026102640 && (echo 236 > /home/randombu/apps/Staging/MiniMaid/releases/20091026102640/REVISION)"
servers: ["gaea.site5.com"]
[gaea.site5.com] executing command
command finished
* executing `deploy:finalize_update'
* executing "chmod -R g+w /home/randombu/apps/Staging/MiniMaid/releases/20091026102640"
servers: ["gaea.site5.com"]
[gaea.site5.com] executing command
command finished
* executing "rm -rf /home/randombu/apps/Staging/MiniMaid/releases/20091026102640/log /home/randombu/apps/Staging/MiniMaid/releases/20091026102640/public/system /home/randombu/apps/Staging/MiniMaid/releases/20091026102640/tmp/pids &&\\\n mkdir -p /home/randombu/apps/Staging/MiniMaid/releases/20091026102640/public &&\\\n mkdir -p /home/randombu/apps/Staging/MiniMaid/releases/20091026102640/tmp &&\\\n ln -s /home/randombu/apps/Staging/MiniMaid/shared/log /home/randombu/apps/Staging/MiniMaid/releases/20091026102640/log &&\\\n ln -s /home/randombu/apps/Staging/MiniMaid/shared/system /home/randombu/apps/Staging/MiniMaid/releases/20091026102640/public/system &&\\\n ln -s /home/randombu/apps/Staging/MiniMaid/shared/pids /home/randombu/apps/Staging/MiniMaid/releases/20091026102640/tmp/pids"
servers: ["gaea.site5.com"]
[gaea.site5.com] executing command
command finished
* executing "find /home/randombu/apps/Staging/MiniMaid/releases/20091026102640/public/images /home/randombu/apps/Staging/MiniMaid/releases/20091026102640/public/stylesheets /home/randombu/apps/Staging/MiniMaid/releases/20091026102640/public/javascripts -exec touch -t 200910261027.24 {} ';'; true"
servers: ["gaea.site5.com"]
[gaea.site5.com] executing command
command finished
* executing `deploy:symlink'
* executing "rm -f /home/randombu/apps/Staging/MiniMaid/current && ln -s /home/randombu/apps/Staging/MiniMaid/releases/20091026102640 /home/randombu/apps/Staging/MiniMaid/current"
servers: ["gaea.site5.com"]
[gaea.site5.com] executing command
command finished
** transaction: commit
* executing `deploy:restart'
* executing "touch /home/randombu/apps/Staging/MiniMaid/current/tmp/restart.txt"
servers: ["gaea.site5.com"]
[gaea.site5.com] executing command
command finished
Afterthoughts
Overall the process is pretty straight forward and a good way to deploy those rails applications that you are cooking up. As with alot of rails stuff there isn't necessarily a ton of great documentation out there, but there is enough to get you going and some google searches should help with the rest.
Also where I think, Capistrano is fairly robust at this point I am not sure if it's still actively being maintained (I think it is but don't quote me on it).
Also this project has been forked a bunch of times over at github but I really haven't done any research at all on any of the forks.
My biggest gripe was with capify. I really would have liked to see capify ask me some questions and then generate a more intelligent and functional Capfile.
Depending on my time that is one area that I would potentially like to improve myself. There is really no reason that it can't walk you through the initial setup
and get you going in a better way.
Errors that I ran into along the Way
Overall the process was pretty smooth, but I did run into a few issues while doing setting up the deployment. Ill list the issues I had and what I did to fix
them below.
svn: Can't convert string from 'UTF-8' to native encoding:
One error that I ran into while doing this was the dreaded "Can't convert string from 'UTF-8' to native encoding" and this one confused me at first as the command in
question would run fine if I was on the server. The application I am working on is in japanese and uses utf8 so because some of the file names have japanese
characters, I get this error. To fix the problem I added the line below to my config/deploy.rb file. Here is a discussion about the issue from Google groups
default_environment["LC_CTYPE"] = "en_US.UTF-8"
usr/lib/ruby/gems/1.8/gems/capistrano-2.5.9/lib/capistrano/recipes/deploy.rb:54:in `join': can't convert nil into String (TypeError)
Another Error that I encountered was related to not having the deploy_to variable set and the release_path variable set which caused Capistrano to try to find
/u/apps/YOUR-APPLICATION-NAME which didn't exist. If you have neither release_path or deploy_to set you likely get the can't convert nil to String error.
This was a total rookie error on, removed release_path correctly set the deploy_to variable and poof the magic error was gone
Missing Symbolic Link for the log directory.
Looking through the deployed code, It seems that there was a symbolic link for a shared log directory that was never created. As such the logging wasn't working correctly.
This was easily fixed by going in the directory that I set my deploy_to variable to and creating shared/log directory. But in reality this was another rookie error as I should have run "cap staging deploy:setup" before running the "cap staging deploy" command. Its the deploy:setup task that does the creation of those directories. Live and learn.
capify: command not found
Where I didn't run into this one. It does seem to catch beginners on Ubuntu. Basically if you ran the gem installs and you are getting this. There is a
really good chance that you need to update your PATH environment variable. In my case, I have the following in my $HOME/.bashrc file. Anyways, I hope this helps you
on your way to being a cap jedi master or a sith something. Anyways, I really havent liked a Star Wars movie since Return of the Jedi so Im going to just stop this really bad analogy here.
export PATH=$PATH:/var/lib/gems/1.8/bin
One last thing to look out for potentially is that if you are using phusion passenger you will most likely need to adjust your .htaccess file so and correct your PassengerAppRoot variable.