crapapult

Crapapult is a thin wrapper around Capistrano for the sole purpose of deploying services at Yammer.

What the hell is going on here

At Yammer, we use Hudson/Jenkins to build all of our JVM-based services. Each time we commit to the various branches of a service, Hudson runs all the tests and (if they pass, naturally) builds a fat, deployable JAR containing all the various dependencies.

Crapapult allows us to deploy new versions of our services and synchronize those deploys with changes to application-specific configuration. (We use Puppet to provision and maintain machines with broad roles but use Crapapult to generate all the application-specific configuration.)

It does so by using Capistrano to SSH into each of the application servers and using curl to download the last successful build artifact from the specified Hudson job. This tends to be super-fast, especially if your CI box is located in the same data center as your app servers.

Once the artifact is staged (by default in /opt/APPNAME), it then uploads the specified set of asset files to each server. After that, it renders and uploads the specified set of template files to each server.

Then it restarts your service and gives you a high-five.

How to use this dang thing

Get yer install on:

gem install crapapult

Create yer dang deployer directory structure:

mkdir -p myapp-crapapult/{assets,templates}
cd myapp-crapapult

And start slingin' some crap in your Capfile:

require "crapapult"

# Give your application a name.
application "myapp" do
  # Upload the file in assets/myapp.jvm.conf to each host.
  asset "myapp.jvm.conf", "/etc/myapp.jvm.conf"

  # Render the ERB template in templates/myapp.conf.erb to each host.
  template "myapp.conf.erb", "/etc/myapp.conf", :mode => "0600"

  # Set up the file in assets/myapp.upstart as an Upstart config file and create
  # an /etc/init.d/myapp script.
  upstart "myapp.upstart"
end

# Specify where your Hudson/Jenkins server is.
hudson "http://build.example.com"

# Specify the various branches and their respective build jobs.
branch :master, "myapp-release"
branch :development, "myapp-development"

# Define environments with allowed branches.
environment :staging, [:master, :development] do
  # Set environment-specific data for your templates to work with.
  data :jdbc_url, "jdbc:postgresql://db.example.com/happy_fun_times"

  host "myapp-001.staging.example.com" do
    # Set host-specific data for your templates to work with.
    data :worker_id, "1"
  end
end

# This will disallow deploying the staging branch to production.
environment :production, [:master] do
  # Set environment-specific data for your templates to work with.
  data :jdbc_url, "jdbc:postgresql://db.example.com/happy_fun_times"

  host "myapp-001.example.com" do
    # Set host-specific data for your templates to work with.
    data :worker_id, "1"
  end

  host "myapp-002.example.com" do
    data :worker_id, "2"
  end
end

Deploying a thing

cap deploy           # Deploy the specified branch to the specified environment
cap from:development # Deploy the development branch
cap from:master      # Deploy the master branch
cap to:production    # Deploy to the production environment
cap to:staging       # Deploy to the staging environment

So to deploy your development branch to your staging environment, it's just a simple:

cap from:development to:staging deploy

And you're off to the races.


Copyright (c) 2011 Yammer, Inc. See LICENSE.txt for further details.