deploy profiles

13 views
Skip to first unread message

Bryan Liles

unread,
Sep 19, 2006, 7:53:27 AM9/19/06
to capis...@googlegroups.com
I'm looking for tips on setting up capistrano to deploy to more than
one location. I want the following deploy profiles: "demo",
"staging", "production". Is this possible with capistrano?

Tom Ward

unread,
Sep 19, 2006, 7:58:19 AM9/19/06
to capis...@googlegroups.com

The way I've achieved this is to create a main deployment recipe, and
then individual recipes for each target. I can then deploy to the
desired platform with something like:

cap -f production.rb -f deploy.rb deploy

I'd be interested to hear if anyone has a better solution. I know
Bradley at rails machine has been working on something with yaml
files, but some of the differences in my environments can't be
encapsulated in just yaml.

Tom

Tron Jonathan

unread,
Sep 19, 2006, 9:07:20 AM9/19/06
to Capistrano

I used to rely on some ENV variables to set the differents part of my
recipe.

For exemple :

if ENV['DEPLOY_TYPE'] == 'production'
role :web, "web.prod_host.tld"
role :app, "app.prod_host.tld"
role :db, "db.prod_host.tld", :primary => true
set :deploy_to, "/var/www/myapp"
set :user, "myproduser"
else
role :web, "web.staging_host.tld"
role :app, "app.staging_host.tld"
role :db, "db.staging_host.tld", :primary => true
set :deploy_to, "/var/www/html/myapp"
set :user, "mystaginguser"
end

then
cap deploy : deploy my app on the staging machine
whereas
DEPLOY_TYPE=production : deploy my app on the production machine

Hope this can help.

Tron Jonathan
http://jonathan.tron.name

Tom Ward

unread,
Sep 19, 2006, 9:18:10 AM9/19/06
to capis...@googlegroups.com

Or even a combination of the two:

if ENV['DEPLOY_TYPE']
load "config/deployment/#{ENV['DEPLOY_TYPE']}.rb"
else
raise "DEPLOY_TYPE environment must be set"
end

Where config/deployment contains a number of small recipes
distinguishing deployment targets. It complains if no deploy type is
set but that could easily be changed.

The only thing I don't like about this is the use of environment
variables; they don't smell quite right though it's a common pattern
across rails and capistrano (rake migrate RAILS_ENV=development
VERSION=15, cap invoke COMMAND='rm -rf *').

Tom

Bryan Liles

unread,
Sep 19, 2006, 9:24:27 AM9/19/06
to capis...@googlegroups.com

On Sep 19, 2006, at 9:07 AM, Tron Jonathan wrote:

> I used to rely on some ENV variables to set the differents part of my
> recipe.
>
> For exemple :
>
> if ENV['DEPLOY_TYPE'] == 'production'
> role :web, "web.prod_host.tld"
> role :app, "app.prod_host.tld"
> role :db, "db.prod_host.tld", :primary => true
> set :deploy_to, "/var/www/myapp"
> set :user, "myproduser"
> else
> role :web, "web.staging_host.tld"
> role :app, "app.staging_host.tld"
> role :db, "db.staging_host.tld", :primary => true
> set :deploy_to, "/var/www/html/myapp"
> set :user, "mystaginguser"
> end
>
> then
> cap deploy : deploy my app on the staging machine
> whereas
> DEPLOY_TYPE=production : deploy my app on the production machine
>


I'm not the hugest fan of rails gratuitous use of environment
variables, but this seems like a good track to go done. It would be
nice if I could do a "cap -p production deploy" or a "cap -p staging
migrate" where -p would be the profile. Then in deploy.rb, we could
have something like this:

set :deploy_to, { :staging => "/var/www/html/myapp", :production => "/
var/www/myapp" }
set :default_profile, :staging
role :web, "web.prod_host.tld", :profile => :staging
role :web, "web.prod_host.tld", :profile => :production

Actually, I really like this idea. What does everyone else think?

Jamis Buck

unread,
Sep 19, 2006, 10:11:52 AM9/19/06
to capis...@googlegroups.com
On Sep 19, 2006, at 7:24 AM, Bryan Liles wrote:

> I'm not the hugest fan of rails gratuitous use of environment
> variables, but this seems like a good track to go done. It would be
> nice if I could do a "cap -p production deploy" or a "cap -p staging
> migrate" where -p would be the profile. Then in deploy.rb, we could
> have something like this:
>
> set :deploy_to, { :staging => "/var/www/html/myapp", :production => "/
> var/www/myapp" }
> set :default_profile, :staging
> role :web, "web.prod_host.tld", :profile => :staging
> role :web, "web.prod_host.tld", :profile => :production
>
> Actually, I really like this idea. What does everyone else think?
>

I'm still really pushing back against adding staging support into
Capistrano itself. You can accomplish what you want without using
environment environment variables by using cap's -S switch:

cap -S stage=production deploy

Then, your deploy.rb looks like:

# set the default, unless it was set on the CLI
set :stage, "development" unless variables[:stage]

# do the setup, based on the selected stage
case stage
when "production"
set :deploy_to, "..."
role :web, "..."
role :app, "..."
...
when "development"
...
when "demo"
...
else
raise "unsupported staging environment: #{stage}"
end

Now, if this pattern is used a lot, I'd encourage someone to put
together a Capistrano extension that makes it easier to do (though I
really don't think the above is "difficult" in any sense of the
word). It may be that Capistrano itself could be tweaked to make
setting this up easier--if that is the case, let me know and we can
try to make the road less bumpy, but I'm still opposed to Capistrano
itself knowing anything at all about the concept of "staging".

IIRC, a couple of people approached me at RailsConf at described some
novel approaches to this. If any of you are listening, please
consider writing up your approach and sharing.

- Jamis

Bryan Liles

unread,
Sep 19, 2006, 11:05:26 AM9/19/06
to capis...@googlegroups.com

I'm going to create an extension that does the following for my
environment. Thanks for your input.

Chris Wanstrath

unread,
Sep 19, 2006, 4:13:53 PM9/19/06
to capis...@googlegroups.com

What we do is 'chain' Capistrano commands to create this profile
concept.

desc "Set staging environment"
task : staging do
role :app, "app server"
role :web, "web server"
set :rails_env, :staging
set :deploy_to, "/opt/rails/#{application}/staging"
end
desc "Set production environment"
task :production do
role :app, "app1.whatever.com", "app1.whatever.com"
role :web, "web1.whatever.com", web2.whatever.com
set :rails_env, :production
set :deploy_to, "/opt/rails/#{application}/production"
end

Now:

$ cap production deploy
$ cap staging deploy

$ cap <production/staging> <any task>

Etc.

--
Chris Wanstrath
http://errtheblog.com

Lew Newby Jr

unread,
Sep 19, 2006, 4:28:45 PM9/19/06
to capis...@googlegroups.com
I use an environment variable to differentiate between staging and
production.

In my recipe I have the following:

Define production_host
Define staging_host

if ENV["STAGE"] == "production"
role :app, production_host
role :web, production_host
role :db, production_host, :primary=>true
set :rails_env, "production"
else
role :app, stage_host
role :web, stage_host
role :db, stage_host, :primary=>true
set :rails_env, "staging"
end

I would then be able to change individual host names by adding
different variables within the recipe.

Richard McMahon

unread,
Sep 19, 2006, 4:40:09 PM9/19/06
to capis...@googlegroups.com
Here's how I do it. Invocation is either:

rake RAILS_ENV=stage deploy

or

rake RAILS_ENV=production deploy

and deploy.rb follows this pattern:

if ENV["RAILS_ENV"] == "production"
  puts "********************************************************************************"
  puts "**                                                                            **"
  puts "**                     RUNNING IN PRODUCTION MODE                             **"
  puts "**                                                                            **"
  puts "********************************************************************************"
  set :rails_env, "production"
else
  set :rails_env, "stage"
end

# =============================================================================
# ROLES
# =============================================================================

if rails_env == "production"
  role :web, "xxx.xxx.sys"
  role :app, "xxx.xxx.sys"
  role :db,  "xxx.xxx.sys", :primary => true
else
  role :web, "stage.xxx.sys "
  role :app, "stage.xxx.sys"
  role :db,  "stage.xxx.sys", :primary => true
end

You get a nice warning banner before deploying live...
--Richie.

Lew Newby Jr

unread,
Sep 19, 2006, 5:04:45 PM9/19/06
to capis...@googlegroups.com
I like that addition. and using the RAILS_ENV is nice as well.

Richard McMahon

unread,
Sep 19, 2006, 5:14:43 PM9/19/06
to capis...@googlegroups.com
Glad you like it, keeps things consistent. You've probably got a stage environment in database.yml, etc that points at a different database server...
--
Richie
Reply all
Reply to author
Forward
0 new messages