During capistrano deployment of a Rails3 app, I want my server to install gems, using Gemfile.lock, every time I deploy. And since my server does not have rvm and all.. All gems should be installed as system gems.
To install system gems, we need to put sudo gem install anygem or for bunder, we need to give command sudo bundle install inside our current directory of capistrano deployment structure.
Everytime, I deploy, my deployment breaks at the gems installation process. I need sudo bundle install to run. For that, I need a deployment hook for capistrano. The prebuilt ones that are supplied by bundler gem itself is not working for me. My confusion boils down to these three questions.
When should I invoke the sudo bundle install command in the deployment process - i mean after which capistrano task ?
For running sudo commands using capistrano, what declarations I should specify in my cap file ? Note - i already have pushed my public key as authorized keys in my server.
How should the bundle install hook be written in the cap file ?
Please help.
Adding require "bundler/capistrano" to your deploy.rb should just work. It should declare a folder to install gems to that do not require sudo access, regardless of rvm.
Is that still failing for you?
If you run bundle install --deployment you shouldn't need sudo access as the gems should be installed to vendor/bundle in your app rather than to the system itself.
i use that in my deploy.rb:
require "bundler/capistrano"
... deploy recipe
namespace :bundle do
desc "Install bundles into application"
task :install, :roles => [:app] do
run "cd #{current_path} && LC_ALL='en_US.UTF-8' bundle install --deployment --without test"
end
end
Then after normal deploy i run "cap bundle:install"
note: Using UTF-8 to prevent ruby1.9 ASCII chars problems.
Related
I was heavily struggling with my Capistrano Setup, when my Hoster migrated the server:
Capistrano3 deploy fails after migrating the server
One thing I ran into that used to work just fine on the old machine and now seems to be a mess is bundler:
I could successfully run bundler through Capistrano:
cap staging bundler:install
This resulted in the following command on the server
/usr/bin/env bundle install --binstubs \
/var/www/mydomain.com/subdomains/dev/shared/bin \
--path /var/www/mydomain.com/subdomains/dev/shared/bundle \
--without development test \
--deployment
But now when I ran my server cap staging deploy:start_passenger which results in the following:
/usr/bin/env passenger start --socket tmp/passenger.socket -e staging -d
Then I got the error in my log file, that Rake was missing:
Could not find rake-10.2.2 in any of the sources (Bundler::GemNotFound)
<pre> /var/www/mydomain.com/.rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/bundler-1.7.3/lib/bundler/spec_set.rb:92:in `block in materialize'
What is very weird, is the fact that the ruby version 2.1.2(the one I really use) shows up with 2.1.0. I have no visible reference to2.1.0` in my project, and my Gemfile contains:
ruby '2.1.2'
Since RBENV is used on the server I can run rbenv versions which shows me:
system
* 2.1.2 (set by /var/www/mydomain.com/.rbenv/version)
So where does that weird 2.1.0 come from and how can I make sure that my server has all the dependencies it requires.
I finally managed to deploy my application on the new server.
These steps were required to do it. However since I fought with it for a few hours some of it might be redundant:
gem install bundler && rbenv rehash: This is required since bundler is one of the gems that I need outside of the Rails App context in terms of dependencies.
Another one is gem install passenger && rbenv rehash
I am now using https://github.com/capistrano/rbenv but for this I had to wipe RVM from my system, which was a step I wasn't too enthusiastic of doing.
I had to make sure the current symlink was created so I added this to the deploy.rb
after 'deploy:set_current_revision', 'deploy:symlink:release'
I had to delete some of the shared directories:
rm -fr bin
rm -fr shared/bundle/
rm -fr bundle
I use chef to run bundle.
bash "feedbin_bundle" do
cwd "/home/ubuntu/workspace/frontend"
user "root"
group "root"
code <<-EOH
bundle install
EOH
end
Now I want to run the below as ubuntu user:
ubuntu#ubuntu:~/workspace/frontend$ rake db:setup
'git://github.com/feedbin/activerecord-import.git (at b7851b1) is not checked out. Please run `bundle install`
If I run as root all is well. How to I avoid the above error and run rake db:setup?
The issue here is that your gems are installed for the user root, in the ~root/.gems directory. You don't want this. You have three possibilities:
Install gems system-wide, by tweaking the /etc/gemrc file
Install gems as the user who will run the application
The "clean" solution: install gems in a vendor subdirectory: bundle install --path=vendor/. This way, the gems are installed only for the project, and will not conflict with other projects.
You should run bundle install as ubuntu, the same user you want to use to run your program.
I have an interesting error when installing gems directly from github (:git => 'whatever').
Firstly, when I remove all gems and run bundle install command, I get the following:
Installing gem1
Installing gem2
Using gem3 (the one from github)
Then when I want to check what I've got I see the following by using gem list:
gem1 (x.x.x)
gem2 (y.y.y)
No gem3... now, looking closer to the file system, I see the following:
ls -l ~/.rvm/gems/ruby-1.9.3-p125/gems
gem1
gem2
So where is gem 3? Not where I'm expecting it to be:
ls -l ~/.rvm/gems/ruby-1.9.3-p125/bundler/gems
gem3-213213213
So it goes under bundler/gems and is not visible to gem list... and by Capistrano deploy, which gives me following:
git://github.com/author/gem3.git (at master) is not checked out. Please run `bundle install`
I'm more worried about Capistrano unable to deploy... Anyone has any clues?
Bundler gets its gems from various sources on your system. As long as they are the correct version, it will pull them in.
When deploying, it has more strict/conservative behavior.
From bundle help install, in the section about Deployment Mode, which is used when the --deployment flag is specified:
Gems are installed to vendor/bundle not your default system loca-
tion
In development, it's convenient to share the gems used in your
application with other applications and other scripts run on the
system.
In deployment, isolation is a more important default. In addition,
the user deploying the application may not have permission to
install gems to the system, or the web server may not have permis-
sion to read them.
As a result, bundle install --deployment installs gems to the ven-
dor/bundle directory in the application. This may be overridden
using the --path option.
I'm a new user to Capistrano and using it to deploy a rails 3.1 app. There seems to be an issue with gem installation on the remote server.
I have the following questions:
It looks like cap runs bundle install on the gemfile? Are there any dependencies for this to work successfully? I have rvm and bundler on my server. Does it need rails installed already?
I have manually set the bundle_cmd in my deploy.rb like this:
set :bundle_cmd, '/usr/local/rvm/gems/ruby-1.9.2-p290/bin/bundle'
Should this be correct?
Is there a way to have confirmation on a cap deploy that ALL the required gems are there? Or what is the best way to debug a failed bundle install on the remote server? Can you call something like cap gem-list; was hoping something like cap invoke=gem list would do it but doesn't look like it.
Edit #1
I'm getting the following error:
failed: "rvm_path=/usr/local/rvm /usr/local/rvm/bin/rvm-shell 'default' -c 'cd /data/sites/myserver/apps/myapp/releases/20111204181321 && bundle install --gemfile /data/sites/myserver/apps/myapp/releases/20111204181321/Gemfile --path /data/sites/myserver/apps/myapp/shared/bundle --deployment --quiet --without development test'" on 173.230.xxx.xxx
If I go into a previous release, and run bundle install, it says that everything installed correctly which it didn't.
It says:
Your bundle is complete! It was installed into /data/sites/myserver/apps/myapp/shared/bundle
but if I go in there, there is nothing other than the ruby 1.9.1 which to the best of my knowledge I didn't install (using ruby 1.9.2-p290)
Is there a way in capistrono to specify it not to delete the deployed release so that I can debug that explicitly? Shoud I need to hardcode the path to my bundler in my deploy.rb script?
thx again
EDIT 2
If I go into the current release at:
/data/sites/myserver/apps/myapp/current
and run:
$ which bundle
/usr/local/rvm/gems/ruby-1.9.2-p290/bin//bundle
I get:
$ bundle install
/usr/local/rvm/rubies/ruby-1.9.2-p290/lib/ruby/site_ruby/1.9.1/rubygems/dependency.rb:247:in `to_specs': Could not find bundler (>= 0) amongst [minitest-1.6.0,rake-0.8.7, rdoc-2.5.8] (Gem::LoadError)
from /usr/local/rvm/rubies/ruby-1.9.2-p290/lib/ruby/site_ruby/1.9.1/rubygems/dependency.rb:256:in `to_spec'
from /usr/local/rvm/rubies/ruby-1.9.2-p290/lib/ruby/site_ruby/1.9.1/rubygems.rb:1210:in `gem'
from /usr/local/rvm/gems/ruby-1.9.2-p290/bin/bundle:18:in `<main>'
You dont need to have rails installed already, but I do think that you need to have bundler installed. gem install bundler
You can use RVM and bundler integration from capistrano. In that case you dont have to set the path to bundler.
$:.unshift(File.expand_path('./lib', ENV['rvm_path']))
require "rvm/capistrano"
require "bundler/capistrano" # Load RVM's capistrano plugin.
set :rvm_type, :system
set :rvm_ruby_string, '1.9.2#gemset_name'
You can use 'cap shell' to run commands through Capistrano on the server. You could use this to check the installation of all your gems. Use cap -T to see all possibilities.
On a side note, do you really need rvm gemsets for your app? I use RVM to install and update my rubies on my production server, but I let Bundler handle the separation of my gems. Since the default bundler settings in production put all your gems in vendor/bundle, this already separates your gems from each other. This works great with Capistrano too.
See a similar question and answer here. Some more information a capistrano/bundler/rvm/passenger setup can be find in this tutorial.
When I run cap deploy:update I get the error below, indicating that bundle is not found. When I run echo $PATH from cap shell the /var/lib/gems/1.9.1/bin path which contains bundle is missing, however, this path is in both /etc/profile and ~/.bashrc. Anyone know how to solve this problem?
[192.168.10.100] executing command
*** [err :: 192.168.10.100] sh:
*** [err :: 192.168.10.100] bundle: not found
*** [err :: 192.168.10.100]
command finished in 25ms
failed: "sh -c 'bundle install --gemfile /data/www/apps/my_app/releases/201104
04163717/Gemfile --path /data/www/apps/my_apps/shared/bundle --deployment --qui
et --without development test'" on 192.168.10.100
To avoide such problem you should have most recent versions of RVM (currently it is 1.13.5) installed in both places: locally and on remote server.
Next, check if your deploy.rb has
require "rvm/capistrano"
require "bundler/capistrano"
This line is not needed anymore:
$:.unshift(File.expand_path('./lib', ENV['rvm_path']))
Hope this will help
Ok, I've recently had some experience with this. Looks like there are a couple of ways that this problem can be solved. First, you can determine if in fact the remote execution (via Capistrano) is what's messed up vs. the host itself. Looks like you've done this with the Capistrano remote shell:
$ cap shell
> echo $PATH
Good. I'll bet when you login to the machine and 'echo $PATH' there, the right stuff comes out... same here.
I've found two ways to fix this: One is to enable the environment execution in the remote host's ssh daemon. In theory this would work, but I didn't want to ask the sysadmin if it was ok to open this up. You basically edit the ssh configuration files to set the 'PermitUserEnvironment' to 'yes' and add the required environment settings to the deploy user's ~/.ssh/environment file -- your system-specific man pages are probably better than my trying to generalize.
I opted for what seems rather hackish, and has the drawback that it is global for all hosts you deploy the app to (so if your ruby / gems locations are different on different hosts, this won't work) -- but: I added the default_environment settings to the config/deploy.rb script:
set :default_environment, {
'PATH' => "/usr/local/bin:/bin:/usr/bin:/bin:/<ruby-dir>/bin",
'GEM_HOME' => '<ruby-dir>/lib/ruby/gems/1.8',
'GEM_PATH' => '<ruby-dir>lib/ruby/gems/1.8',
'BUNDLE_PATH' => '<ruby-dir>/lib/ruby/gems/1.8/gems'
}
AMMENDED: It isn't so 'hackish' if you consider the following:
- The environment-specific deploy scripts (deploy/foo.rb) can
override the default in deploy.rb
- PermitUserEnvironment hides the configuration deep in the
.ssh directory of the deploy user; :default_environment at
least exposes it in the checked-in sources.
This also solves the problem of not being able to do remote rake tasks, etc., via Capistrano. Be aware that the Capistrano gem, at least the version I have and with my deploy set up in the "standard" way, will install the gems into the /shared/bundle
directory, which gets picked up by the app. The method I described requires a minimal subset of gems in the system directories referenced by the default environment so that the remote Capistrano commands can execute bundle, rake, etc.
You didn't say if you were using RVM (my solution doesn't); however, this solution is very close to one of the recommended RVM solutions. Alternately, you could just use the 'rvm/capistrano' solution; look for RVM Capistrano integration on the RVM website for more details.
Have you manually installed the bundler gem on the remote box? You can't use the bundle command or install any bundles until you do.
Are you using RVM ?
DaneS some possible solutions:
place
require "bundler/capistrano"
in your script as bundler now has support for capistrano
https://github.com/carlhuda/bundler/blob/1-0-stable/lib/bundler/capistrano.rb
And maybe
before "deploy:cold",
"deploy:install_bundler"
task :install_bundler, :roles => :app do
run "type -P bundle &>/dev/null || { gem install bundler --no-rdoc --no-ri; }"
end
The install_bundler task will only be installed if not found.