How to create roles and run capistrano tasks for specific roles? - ruby-on-rails

Here is my production.rb in config/deploy
Instance Details
server '198.61.179.237', :web, :app, :db, primary: true
server '198.61.228.160', :file_server
# Rails Environment
set :rails_env, 'production'
And from deploy.rb
namespace :check do
task :function_1, :roles => :web do
puts 'function_1'
end
task :function_2, :roles => :file_server do
puts 'filesssss'
end
end
But when I try doing
cap HOSTS=198.61.228.160 production check:function_2
cap HOSTS=198.61.228.160 production check:function_1
cap HOSTS=198.61.179.237 production check:function_2
cap HOSTS=198.61.179.237 production check:function_1
Everyone of them gives respective output. But as per the declaration
function_1 should work only for :role => :web and similarly function_2 should work only for :role => :file_server.
Where I am going wrong ?
What is the correct way to approach ?

I believe what you want is cap HOSTFILTER=198.61.228.160 function_2 or cap HOSTFILTER=198.61.179.237 function_1
It's because the HOSTFILTER checks for the intersect of all the servers with the functions role and the server you're looking for. A great explanation can be found here by Pete Hodgson
Also we can see this because of the manual:
$ cap -H
HOSTS
Execute the tasks against this comma-separated list of hosts.
Effectively, this makes the host(s) part of every roles.
HOSTFILTER
Execute tasks against this comma-separated list of host,
but only if the host has the proper role for the task.
HOSTROLEFILTER
Execute tasks against the hosts in this comma-separated list of roles,
but only if the host has the proper role for the task.
ROLES
Execute tasks against this comma-separated list of roles. Hosts which
do not have the right roles will be skipped.

Related

How to use different user for a server in Capistrano?

I want to set the user for one of the roles to a different one in my Capistrano file. How do I do that? Right now the user is set to "sshadmin" for all the servers.
set :user, "sshadmin"
server "198.227.6.30", :app
server "192.9.1.17", :web
server "192.9.31.9", :db #I want this to use the user "sshadmin2"
In Capistrano v3 You can use this directive:
role :app, %w{sshadmin#198.227.6.30}
role :web, %w{sshadmin#192.9.1.17}
role :db, %w{sshadmin2#192.9.31.9}
From the Capistrano documentation
Servers can be defined in a bunch of ways, the following shows defining two servers, one where we set the username, and another where we set the port. These host strings are parsed and expanded out in to the equivalent of the server line after the comment:
role :web, %w{hello#world.com example.com:1234}
# ...is the same as doing...
server 'world.com' roles: [:web], user: 'hello'
server 'example.com', roles: [:web], port: 1234
Applied to your case
role :db, %w{sshadmin2#192.9.31.9}

deploy similar ruby on rails code to multiple server

I have a rails app looking good on my localhost. Now I want to deploy it to multiple server (one load balancer, and two application server to be exact, with possible increase in the future), and somehow I'm lost. This would be my first time deploying a web by myself, so I'm sorry for my lack of knowledge.
I want all application server to run exactly same code.
And when I create a new content, I want the new content to be stored on each server's database instance (MySQL). So when I took down one server for maintenance and updating, the rest of the server could serve users with exact same content. I've read that capistrano could help me with this, but somehow I managed to get lost in learning how to do this. So, how should I proceed from here? How should the capistrano recipe look like, and do I have to tweak database.yml in my rails also?
Thank you very much for help.
You can use roles to deploy the same application to multiple servers.
Assuming you're using the multistage extension, define the roles in production.rb:
server1 = 'appserver1.tld'
server2 = 'appserver2.tld'
server3 = 'webserver1.tld'
role :app, server1, server2
role :web, server3
The web server will run on servers specified by the :web role.
The app layer will run on servers specified by the :app role.
If you run migrations or other DB operations during deploy, you should also specify a server under the :db role. For example:
role :db, 'dbserver.tld', :primary => true
You may have multiple DB servers, but by specifying one as the primary server capistrano will only run DB operations on that server.
In your deploy.rb, you can also create tasks that run only for certain roles. For example:
task :restart, :roles => :app, :except => { :no_release => true } do
run "touch #{current_path}/tmp/restart.txt"
end
In the above example, :except => { :no_release => true } means that it will only run if at least one release exists on the server being deployed to.
This wiki article may be of further help to you.

capistrano, :db role, what's it for?

As far as I can tell, the capistrano :db role is used only to run migrations.
(Thus, in most cases it probably shouldn't actually be the server that runs your database. Why would you have a ruby/rails stack there (or allow ssh logins there)? it's just whatever server you want to actually execute the rails migrations).
And only the server identified as db role with :primary => true is used to run migrations.
So any other servers identified as 'db' role but without :primary => true... are used for nothing at all? So why does the default deploy.rb created by capify . encourage you to list them? What would you even list here?
Anything I'm missing?
Obviously, the name of role :db is misleading. As you pointed out, Capistrano defines it (with :primary => true) as a host that we execute rake db:migrate on, but database servers are not always running on such hosts. We can alter the schema of remote database server through a Rails app. The correct role name for this kind of host is not :db.
Inferring from the comments on lib/capistrano/configuration/roles.rb, the original meaning of the role :db is a host on which database servers are running. We are expected to login to the :db hosts and do some tasks.
The designers of Capistrano should have defined :migration role or something else for the deploy:migrate task. But the association between the :db role with this task was defined six years ago with 9a6d2fb and has not been changed since then.
Generally speaking, the users of Capistrano can define roles and associate them with tasks freely. The deploy:migrate task is provided just as a recipe for Rails developers. Unfortunately, this recipe includes a misconception about how we do the database migration and is used widely for a long time.
You may have a setup that includes a master database server and multiple slave servers. In some cases, you could have an capistrano task that needs to be run on all database servers. In others, you may want to run a task (for instance, a migration) only on the master server and allow the changes to propagate to the slave instances.

Rails3 ActiveRecord migrations on concurrent deploy

How do you ensure your migrations are run only once, when you deploy to multiple machines at the same time ?
What I have to do right now is select one machine to run the migrations when I do have a change of that sort. Ideally, deployment is brainless and the process would take care of that for me.
My idea currently is to have the migrator look for schemas to migrate and acquire a lock if it has something to do. If the lock is already acquired, it skips the migration alltogether. Reading the ActiveRecord code it doesn't seem to support such idea so it would need some patching.
What's your idea ?
Are you using Capistrano? You can specify a list of database servers and mark one as Primary. Migrations will only be run on that server:
role :app, 'example.com.com'
role :web, 'example.com'
role :db, 'db01.example.com', :primary => true
role :db, 'db02.example.com'
role :db, 'db03.example.com'
EDIT: the :db role is not intended to be used for a separate database server which is not running Rails application code. This probably isn't your setup.

Fastest way to deploy rails apps with Passenger

I am working on a Dreamhost server with Rails 2.3.5.
Every time I make changes to a site, I have to ssh into the site, remove all the files, upload a zip file containing all the new files for the site, unzip that file, migrate the database, and go.
Something tells me there's a faster way to deploy rails apps. I am using mac Time Machine to keep track of different versions of my applications. I know git tracks files, but I don't really know how to work with it to deploy my applications, since passenger takes care of all the magic for me.
What would be a faster way to deploy my applications (and avoid the downtime associated with my method when I delete all files on the server)?
Thanks!
Take a look at Capistrano.
And go get yourself Capistrano helpers: http://github.com/westarete/capistrano-helpers
Here's a simplified, annotated Deploy file for my own site.
require 'capistrano-helpers/branch' # prompts for branch
require 'capistrano-helpers/passenger' # Support for Apache passenger
require 'capistrano-helpers/version' # Record the version number after deploying
require 'capistrano-helpers/privates' # handle sensitive files
require 'capistrano-helpers/shared'
set :application, "site"
set :repository, "file://."
set :scm, "git"
set :branch, "rails3"
set :deploy_via, :copy
set :copy_exclude, [ ".git", "assets", "test", "Capfile", "vishvish.tmproj", "bin" ]
set :deploy_to, "/blah/blah.com/#{application}"
set :user, "blah"
set :domain, "blah.com"
#Things you want symlinked afterwards, not in version control.
set :privates, %w{
config/database.yml
}
#Things you want shared across deployments, not uploaded every time.
set :shared, %w{
uploads
}
role :app, domain
role :web, domain
role :db, domain, :primary => true
namespace :deploy do
desc "Restarting mod_rails with restart.txt"
task :restart, :roles => :app, :except => { :no_release => true } do
run "touch #{current_path}/tmp/restart.txt"
end
[:start, :stop].each do |t|
desc "#{t} task is a no-op with mod_rails"
task t, :roles => :app do ; end
end
end
You definitely need git and capistrano.
My deployment process:
git commit
git push
cap deploy
Git is pretty straight forward. There are a ton of resources and how-tos on github.com.
If you aren't using source control you absolutely MUST fix that ...

Resources