Deployment is a hard problem. A working environment might rely on a bunch of configuration to be in sync across init scripts, conf files, install paths, environment variables, all in different types of codebases involving ruby, C, java and all with their own breed of dependency management. Imagine getting your database yaml in sync with your sphinx.conf and your nginx virtual host configuration pointing to your ports set up in mongrel or thin, and everything should be under something like monit which is checking ports and pid files in case something blows chunks along the way, and not to mention making sure all your logs go somewhere sane and configured to use syslog or logrotate. And trying to remember common setup tasks for the system itself, like setting up the database, setting grants, adding user(s), even building and installing packages from scratch. My brain can’t handle all that.
So I setup a project, called capitate which provides 3 things (and you can take or leave any of them at will): Plugins, Recipes and Templates.
Plugins
Capistrano has a plugin architecture. For example, the capitate prompt plugin gives you a beefier password prompt:
This will prompt for a password, ask you to re-type to verify, up to 3 times and will not be lazy initialized.
set :db_pass, prompt.password("DB password: ", :verify => true,
:max_attempts => 3, :lazy => false)
This one prompts for a password and verifies it against an md5 hash and prompt happens when variable is first accessed.
set :db_pass, prompt.password("DB password: ", :verify => false,
:check_hash => "3e5e1c82fbed35282cf53608b80503a7")
More plugins are at: lib/capitate/plugins
Adding plugins into capistrano is done by Capistrano.plugin [namespace] [module]. For example,
module Capitate::Plugins::Prompt
def password(label, options = {})
...
end
end
Capistrano.plugin :prompt, Capitate::Plugins::Prompt
Templates
Most of the configuration files in capitate are erb templates, which allows you to dry up and share your configuration across templates. Here are some examples of templates we use:
- Nginx vhost config
- Merb init script
- An example sphinx config with main/delta indexing
- Mysql cnf for dedicated machine (1024 mb)
Your templates maybe vary, but you get the idea.
Recipes
Recipes combine your templates, configuration and plugins into something more useful.
set :application, "capitate"
# Merb config
set :merb_nodes, 5
set :merb_port, 9000
set :merb_pid_dir, "#{shared_path}/pids"
set :merb_pid_path, "#{fetch(:merb_pid_dir)}/merb.pid"
# Nginx config
set :nginx_upstream_size, fetch(:merb_nodes)
set :nginx_upstream_port, fetch(:merb_port)
set :nginx_pid_path, "/var/run/nginx.pid"
task :setup do
merb.centos.setup
merb.monit.setup
nginx.host.setup
end
The setup task would generate /etc/init.d/merb_capitate init script, /etc/monit/merb_capitate.monitrc, and /etc/nginx/vhosts/capitate.conf files all with matching ports and pid files.
To use it
Throw this in your Capfile
require 'capitate' require 'capitate/recipes' set :project_root, File.dirname(__FILE__)
Documenting recipes
Part of creating recipes is documenting them, you can view capitate’s recipe documentation at:
http://capitate.rubyforge.org/recipes/index.html
Contribute
Capitate is located at github.
Deployment and configuration varies a lot, so your mileage will vary, but capitate can be a resource for storing all different types of recipes and templates, so feel free to fork and pull request. Forking is the new friending.


