prosseek
prosseek

Reputation: 190859

Making rbenv's ruby as system ruby (Using rbenv's ruby when start up) on Ubuntu

I'm trying to start the rails app when Ubuntu starts up.

For this, I added these lines in /etc/rc.local.

cd /home/ubuntu/webapp/rails/passenger-ruby-rails-demo
bundle exec passenger start --port 8000 --user ubuntu --daemonize

However, the rc.local exits with error

+ cd /home/ubuntu/webapp/rails/passenger-ruby-rails-demo
+ bundle exec passenger start --port 8000 --user ubuntu --daemonize
/usr/lib/ruby/vendor_ruby/bundler/spec_set.rb:92:in `block in materialize': Could not find rake-10.4.2 in any of the sources (Bundler::GemNotFound)
    from /usr/lib/ruby/vendor_ruby/bundler/spec_set.rb:85:in `map!'
    from /usr/lib/ruby/vendor_ruby/bundler/spec_set.rb:85:in `materialize'
    from /usr/lib/ruby/vendor_ruby/bundler/definition.rb:114:in `specs'
    from /usr/lib/ruby/vendor_ruby/bundler/definition.rb:159:in `specs_for'
    from /usr/lib/ruby/vendor_ruby/bundler/definition.rb:148:in `requested_specs'
    from /usr/lib/ruby/vendor_ruby/bundler/environment.rb:18:in `requested_specs'
    from /usr/lib/ruby/vendor_ruby/bundler/runtime.rb:13:in `setup'
    from /usr/lib/ruby/vendor_ruby/bundler.rb:120:in `setup'
    from /usr/lib/ruby/vendor_ruby/bundler/setup.rb:17:in `<top (required)>'
    from /usr/lib/ruby/1.9.1/rubygems/custom_require.rb:36:in `require'
    from /usr/lib/ruby/1.9.1/rubygems/custom_require.rb:36:in `require'

The error is caused from using the ruby installed from rbenv; the ruby is in /home/ubuntu/.rbenv/bin/ directory. I guess when ubuntu starts up, the system ruby is executed, but it does not know anything about installed packges with rbenv's ruby and gem.

How can I solve this issue? Is there any way to make the ruby from rbenv as system's ruby?

For getting the error, I used the hints from this post: Run script with rc.local: script works, but not at boot.

EDIT

mwp's answer works fine, but I think I'd better make things clearer.

development bundle

Run bundle --deployment --binstubs to create ./vendor and copy files in bundle directory.

The setup.sh

#!/bin/bash
export APP_ROOT="/home/ubuntu/webapp/rails/passenger-ruby-rails-demo"
export APP_USER="ubuntu"
export APP_PORT="8000"

export RBENV_ROOT="/home/ubuntu/.rbenv"

export PATH="$RBENV_ROOT/bin:$PATH"
eval "$(rbenv init -)"

# Assuming you installed bundle with --binstubs...
$APP_ROOT/bin/passenger start --port $APP_PORT --user $APP_USER --daemonize

The rc.local file

cd /home/ubuntu/webapp/rails/passenger-ruby-rails-demo
sh ./setup.sh

exit 0

Upvotes: 0

Views: 287

Answers (2)

prosseek
prosseek

Reputation: 190859

Upstart (http://upstart.ubuntu.com) can be a better way to replace rc.local.

# simple script
# http://uwsgi-docs.readthedocs.org/en/latest/Upstart.html

description "passenger "
start on runlevel [2345]
stop on runlevel [06]

respawn

# http://stackoverflow.com/questions/14823972/upstart-node-js-working-directory
script
    chdir /home/ubuntu/webapp/rails/passenger-ruby-rails-demo
    exec sh runme.sh
end script

Upvotes: 0

mwp
mwp

Reputation: 8467

Run these commands one time:

cd /home/ubuntu/webapp/rails/passenger-ruby-rails-demo
rbenv local <the version you want>

This will create a .ruby-version file in your application directory that tells rbenv which version to use.

I would also recommend that when you deploy the application to its "production" location, you install bundler with the --deployment --binstubs flags. This will install the Gems inside a vendor subdirectory (to insulate them from an errant Gem update) and create handy shortcuts inside a bin subdirectory to run e.g. passenger, rackup, etc. without needing to do bundle exec.

However, you have another problem, and that is that rbenv (the shell function) [probably] isn't available while rc.local is running. I would recommend creating a new shell script and stashing it somewhere, possibly within your application's directory structure, with (something like) the following contents:

#!/bin/bash
export APP_ROOT="/home/ubuntu/webapp/rails/passenger-ruby-rails-demo"
export APP_USER="ubuntu"
export APP_PORT="8000"

export RBENV_ROOT="/path/to/rbenv"

export PATH="$RBENV_ROOT/bin:$PATH"
eval "$(rbenv init -)"

# Assuming you installed bundle with --binstubs...
"$APP_ROOT"/bin/passenger start --port $APP_PORT --user $APP_USER --daemonize

Then mark this script executable and you can call it from rc.local to start the service. As far as what you set RBENV_ROOT to, you can either use an existing user's .rbenv directory (e.g. ~ubuntu/.rbenv, assuming you installed a copy there), or you can set up a system-wide rbenv at /opt/rbenv or elsewhere. There are some good notes here.

I can think of a million different ways to improve the above script, and indeed this is only one of a million different ways to tackle this problem. Starting and stopping services is quite a hot topic in the DevOps and SysAdmin communities right now. I've had great success running Ruby applications in production using rbenv and Bundler, and if you decide to go this route, I hope you will too!

Upvotes: 1

Related Questions