Insights on Ruby, Git, jQuery, Cappuccino, WordPress, Debian and OS X. Please subscribe if you find something useful!

Dead Simple Rails Deployment

Posted: May 31st, 2009 | Author: Jerod | Filed under: Git | Tags: , , | View Comments

Deploying a Rails app used to suck. Reverse proxies, Mongrel clusters, Monit, etc. Capistrano helped out a lot (once you set it up the first time), but all in all the process was still pretty painful.

Thankfully, a couple of technologies have come along and made my deployment process a whole lot easier.

  1. Passenger
  2. This was the big one. The Phusion guys’ “Hello World” app (as they called it) has really had a positive impact on the Rails community, and me personally. Suddenly my Rails (and Rack) web apps are first class citizens to Apache (and Nginx), which means I can just point a virtual host at the public directory and go. I had almost forgotten how good it feels to just drop some files in a directory and have Apache serve them.

  3. Git
  4. Ok, so maybe Subversion allows a similar workflow, but for some reason Git is one of those tools that is so much fun to use that it makes me think of different ways I can use it.

My Flow

How I deploy these days (when I’m not deploying to Heroku) is dead simple. I host my private Git repos using Gitosis, but the same would work with GitHub or any Git server.

Initial Setup

  1. Clone the repository on production server.
  2. Create database.yml and any other production-specific configs
  3. Configure an Apache virtual host pointing to “public” folder of the repository

Deploys

  1. locally:
    git push origin master
  2. remotely:
    git pull origin master && touch tmp/restart.txt

I know what you’re thinking, “Wow, that is dead simple”. It’s even easier by using Capistrano to execute the remote commands. Here is an example Capistrano task from one of my Rails apps:

task :deploy, :roles  => :production do
  system "git push origin master"
  cmd = [ "cd #{root_dir}", "git pull", "touch tmp/restart.txt" ]
  run cmd.join(" && ")
end

This task can be extended to automatically install required gems, update Git submodules, migrate the database, and so on.

Other Benefits

Besides the simplicity and ease of deployment in this process, I have also enjoyed the ability to make edits in production and pull them back in to my development environment. And because my production environment has a complete history of code changes, it is trivial to revert commits that cause major problems.

This work flow is by no means a panacea. How do you handle deployment?


View Comments on “Dead Simple Rails Deployment”

  1. 1 vitaly said at 7:43 am on June 1st, 2009:

    you are missing out on a many 'features' of a traditional capistrano/vlad deployment setup.
    you can't easily revert to the previous version for example.
    Also your deployment is NOT atomic. A Rails requests coming during the deployment can fail etc.

  2. 2 Dead Simple Rails Deployment | blogt✪sk1 « Netcrema - creme de la social news via digg + delicious + stumpleupon + reddit said at 9:16 am on June 1st, 2009:

    [...] Dead Simple Rails Deployment | blogt✪sk1blog.jerodsanto.net [...]

  3. 3 Integrum said at 3:43 pm on June 1st, 2009:

    Rails deploy has come a long way from the pre 1.0 days.

  4. 4 Aron Pilhofer said at 6:13 am on June 2nd, 2009:

    Wow. I couldn’t agree with Vitaly more… Can you explain why you would want to do this over, say, a traditional Capistrano deploy? Sorry to sounds like a debbie downer here, but I can’t think of a single upside to this strategy (and I can see plenty of downsides).

  5. 5 sant0sk1 said at 6:08 pm on June 2nd, 2009:

    Hi Vitaly-

    Wondering if you could explain the “not atomic” piece and tell me how a traditional cap deploy solves this.

  6. 6 Nils said at 12:50 am on June 3rd, 2009:

    With basic capistrano you would have a folder “releases” and a link “current” that links to the active realease within the release folder. So each time you deploy, a new release is created.

    So it first pulls the release from the repo and when this is done, it refreshes the link to the new release. In that way you can easily switch between releases in a blink of an eye. Whereas this one would possibly create errors during the “pull”.

  7. 7 sant0sk1 said at 5:44 am on June 3rd, 2009:

    Correct me if I'm wrong, but won't Passenger continue to serve the “old” data (in production mode) until it is restarted? I have never received Rails errors during a pull, but the apps I'm deploying aren't sustaining constant requests either.

  8. 8 vitaly said at 2:38 pm on June 3rd, 2009:

    The production environment only caches code that is loaded.
    So if you go to a controller that was not yet visited since the last restart *during* another”pull in progress” you can get an error.

    Also consider static files. when you 'git pull' they do not change all at once, so you can have new html pointing to new images that are not yet there. etc.

    in short: its not atomic :)

    changing a symlink is.

    well, almost ..:) you can still serve some old html and once the request comes for the accompanying images or css files they can already be served from the new release. but thats another story…

  9. 9 vitaly said at 9:38 pm on June 3rd, 2009:

    The production environment only caches code that is loaded.
    So if you go to a controller that was not yet visited since the last restart *during* another”pull in progress” you can get an error.

    Also consider static files. when you 'git pull' they do not change all at once, so you can have new html pointing to new images that are not yet there. etc.

    in short: its not atomic :)

    changing a symlink is.

    well, almost ..:) you can still serve some old html and once the request comes for the accompanying images or css files they can already be served from the new release. but thats another story…

  10. 10 git monthly links: 2009-06 « git blog said at 9:16 am on June 7th, 2009:

    [...] Dead Simple Rails Deployment: Simple instructions to integrate git into Rails deployment scripts [...]

  11. 11 itarmareare said at 9:19 pm on August 28th, 2010:

    need to check

blog comments powered by Disqus