I've been using Capistrano to deploy several rails apps to a single EC2 instance. The apps are all served with Apache + Passenger. The deployment phases form most of them is as follows:
-- fetch code, stage in a "releases/[timestamp]" subdirectory of the main app directory.
-- run bundler for staged release
-- run migrations for staged release
-- run asset compilation ("assets:precompile") rake task for staged release
-- restart the delayed_job task queue processing daemon and any other background processes
-- symlink the staged release to "current" (the passenger web root)
-- restart passenger (by touching "tmp/restart" in app directory)
This is a very standard Rails deployment procedure. I've noticed that a huge bottleneck in it is loading of the rails environment for each task that requires it. For one of my larger apps, environment loading takes ~40 seconds or more and that's repeated n times for the n tasks that require the rails environment (running bundler, migrations, asset compilation, delayed_job daemon). Forgive if this is a naive question, but I was wondering if there is an easy way to load the environment only once for all of these tasks (preferably easier than consolidating the implementations of all of these tasks/jobs into a single rake task that loads the environment).
I suggest looking into vagrant for this. It's a quick and easy way to deploy. It utilizes chef for customizing the vagrant box. I think you'll want to create your own recipies (a chef thing..) to hit most of the items you've listed. Once that's done ur good to go.
Update: I ultimately concocted my own solution for this which works fine. Instead of running each of the commands that depend on the rails environment individually from the shell (using the Capistrano "run" method), I've bundled them together into a single rake task that depends on the rails environment. Where I previously ran "rake db:migrate", then "rake assets:precompile", etc., I now run a single rake task whose body includes "Rake::Task['db:migrate'].invoke" and "Rake::Task['assets:precompile'].invoke". The environment now only gets loaded once.
Related
Capistrano v2 had two helpful tasks: cap deploy:update_code would do a full deployment to a new releases/ directory, but not change the current symlink or start/restart the server (so the server keeps running the current version without interruption). And cap deploy:update did the same thing plus changing the current symlink, but didn't start/restart the server. These were useful to shake out issues e.g. with asset compilation, before doing a real deploy.
Those two "update" tasks are gone in Capistrano v3. Is there an equivalent way to do a full deploy without changing the current symlink or restarting the server?
A custom task list this should do it:
task :deploy_without_symlink do
set(:deploying, true)
%w{ starting started
updating updated }.each do |task|
invoke "deploy:#{task}"
end
end
You can look at the code here: https://github.com/capistrano/capistrano/blob/master/lib/capistrano/tasks/framework.rake#L58 to see what deploy triggers. And the Publishing task per https://github.com/capistrano/capistrano/blob/master/lib/capistrano/tasks/deploy.rake#L38 is what changes the symlinks. So by omitting everything afterwards, you get what you are looking for.
I've never worked with Capistrano before and currently I am fighting the urge to just scrap it and go back to my old manual ways.
As I understand, Capistrano V3 does not create the initial database because they feel it is the duty of the DB administrator.
So I must be missing something but I have followed their instructions but the initial cap staging deploy fails when it gets to the rake db:migrate step because the database does not exist.
Because of the failure, the symlink for current -> releases never gets created.
Is it just accepted general practice that we SSH into our boxes and cd into the first folder under releases and manually run rake db:create...?
And then from there, am I supposed to just run cap staging deploy again so that it finishes creating the symlinks?
Seems hacky for something that is supposed to make things easier and I am not sure if I am understanding this correctly or not.
Thanks.
It does make sense to leave certain things out of a deployment. As the initial set up and the routine deployments are very separate functions and require different specialties, or in large deployments even different skillsets. That said.. I'm totally with you - on the first deploy having to manually set up the database and certain files (specifically linked files like secrets.yml) is a step that just wastes my time.
I use this plugin:
https://github.com/capistrano-plugins/capistrano-postgresql
just add the require capistrano/postgresql to your capfile as you would any plugin
then run cap staging setup before the first time you run cap staging deploy
Capistrano on the whole is a very useful tool, but the definitions are so modular and distributed it can be difficult (or near impossible) to find the definition of a task when needed, or easily piece together the order of events.
I had only vaguely worked with Capistrano before v3, and I recall there being a "cold deploy" task.
However, I can't seem to find it anywhere within the capistrano repository, nor within any of the plugins (capistrano/rvm, capistrano/bundler, capistrano/rails, etc...). A simple repository search for the term 'cold' yields nothing
Where is this task defined? Does it exist in Capistrano v3? And is there an easy way to visualize all the tasks, in order, that run when I execute a certain command (e.g. bundle exec cap production deploy would list all 10,000+ deploy tasks)
Thanks!
actually there's no such task in capistrano 3.
You can see all task with command:
cap -T
for deploying i usually start with
cap production setup # Server setup tasks
cap production deploy:check # Check required files and directories exist
There is no such task like deploy:cold in capistrano 3 rather you can use the following command for the same thing
bundle exec cap production deploy setup
You can read the task definition in the lib files located in
lib/capistrano/tasks/deploy.rake
I would like my development environment for Rails to automatically start redis and resque (and potentially in other projects, mongod, mysql-server etc.) for me, in the following cases:
When starting up the development server rails server.
Additionally, it would be nice if the following cases detect already running services, and, if not running start them up too:
Rake rspec, rspec /spec, when running tests.
When starting up a rails console.
When shutting down the rails server, the started child-services should be shut down too.
What is the correct place for such additional startup scripts?
And how to avoid them being started in production too (where I run everything trough /etc/init.d services)?
A lot of these built-in tasks are available as rake tasks already.
You can create a master rake task that does it all.
For example, with resque, you get "rake resque:start" "rake resque:scheduler:start", etc.
You can create a generic "start" task that depends on the rest. Similarly, a "stop" task would shut everything down.
So you would do:
rake start # starts all associated processes
rake stop # stops them all
This is also very use to use from Capistrano, when you end up deploying your code somewhere else. Rake tasks are very easy to call from Capistrano.
I think it's really better to do that in some external script. Do it in your rails server command can be really annoying to anyone to try your code.
By example, in one year, a nez developper come to your project. He can be desoriented if your rails server commande launch a such of other application in background.
In same idea, if you do that you need maintain your code in your rails env. Can be a little tricky. Maintain an independant script can be more usefull.
You can add your script in script directory. That be a good pratice. But not when you launch a command with a manual who do not that.
I'm looking at ways to deploy a Ruby on Rails app (running on JRuby) to a Tomcat instance for testing.
The tomcat instance is running on a Solaris server that I can SSH to. I've looked at using Capistrano, but there doesn't seem to be a lot out there about using it to deploy to Tomcat, or even about running it under JRuby, and I keep hitting bugs in Capistrano due to the Windows/JRuby environment my PC is running (yeah, it's corporate - not my choice, but I've got to live with it).
I'm using warble to build the .war file, and the app deploys and runs fine once I manually copy it up and deploy it. I'm wanting something easier and more automated to actually get it there.
Anyone done this before? Documentation on the web seems pretty thin.
I am running a Rails project using JRuby and deploying to a Tomcat server. I have chosen to deploy with Capistrano because it automates just about everything. I had to make a few minor modifications to Capistrano's deployment lifecycle in order to get it to run on Tomcat:
Step 1: I created a warble task to be run on the server after Capistrano updates the code:
desc "Run the warble command to deploy the site"
namespace(:deploy) do
task :warble do
run ". ~/.profile;cd #{release_path};warble"
end
end
And hooked it into Capistrano lifecycle using:
after 'deploy:update_code', 'deploy:warble'
My Tomcat server has a symlink pointing to the #{release_path}/tmp/war directory created by warble. If you don't like this, you can easily modify the warble task to move the war file into the Tomcat directory instead.
Step 2: I overrode the deploy:start and deploy:stop tasks so that they kick off the Tomcat server instead of a Mongrel server:
desc "Starts the Tomcat Server"
namespace(:deploy) do
task :start do
sudo "#{tomcat_home}/bin/startup.sh"
end
end
desc "Shutdown the Tomcat Server"
namespace(:deploy) do
task :stop do
sudo "#{tomcat_home}/bin/shutdown.sh"
end
end
I run Capistrano tasks using MRI rather than the JRuby interpreter.
I don't have much experience on this, so I don't know if I can give you the BEST way, but if Capistrano doesn't work, and you can't have a separate MRI install just to run it, you have just a few alternatives left:
Try running plain Rake and write your own deployment target:
http://www.gra2.com/article.php/deploy-ruby-on-rails-applications-rake
Or use Ant or Maven.
Or if it just ONE server you have to deploy to, you could just hack together two Ruby scripts - one that listens on the server for shutdown/startup requests, and one local that you run to: Send shutdown, scp over the file, send startup.
By the way, have you submitted any integration bugs you find with Capistrano to the JRuby team? I'm sure they'd be happy to have any contribution.
:)
Might be worth looking at 'Vlad the deployer' it adds remote_task to Rake allowing you to run tasks on a remote server. Personally however I prefer to have a standard Rake task on the server, ssh in and run that task - which would then do an svn checkout, make the WAR file, whatever...
I would probably use Ant for this. After all, it's just another WAR file, right? I don't know which version of Tomcat you're using but version 4.1x comes with an Ant task for deploying to Tomcat.
There's a few Capistrano recipes for deploying to Tomcat -- I built one into a gem called capistrano-tomcat. It takes a WAR you've built (probably with Warbler) and deploys and starts a Tomcat instance on a remote server.
The source is up on Github: http://github.com/rhunter/capistrano-tomcat