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
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
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
> 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?
> 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
I'm going to create an extension that does the following for my
environment. Thanks for your input.
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
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.