One app, one user, one ruby
There are many ways to install and manage ruby installation in your
infrastructure. Some people like
rvm, others prefer
rbenv, some pack
their ruby installation into
deb packages. We like nothing.
You ain’t need it in production
Yes, you read it well. Using no tool is better than using some tool if we can simply avoid it. Let me state it clearly: RVM is a great tool for development environment however we do not see much use for it in production. Even in development some of us started to separate projects on higher level using Vagrant or LXC containers but that is another story.
A little background: Our customers usually host their applications using our infrastructure or their own. These solution are based on LXC, XEN, or KVM. Every project has its own container/VM .
Simplest thing that can possibly work
We do not have a globally installed ruby except for ruby coming from system package that is used mostly by littlechef to setup the virtual machine according to our conventions and application requirements. For every application that is a part of bigger project separate user is created and separate ruby is installed in its home directory. If we end up having five users using same ruby version but different ruby installation then fine. Storage is cheap. Easy upgrades are more important.
You might wonder how to execute your scripts and run applications with that ruby.
We just add the ruby bin path to user
.bashrc and voilà.
Whenever you run something inside bash it just works. And gem binaries are
installed into the same directory so they also work properly.
If your software is not directly executed inside bash you have two options:
- run it in bash anyway.
- just use the full path to your ruby.
Here is an example. Runit by default executes
supervised processes as
root. We use
su to switch to user with no
special abilities. The
-c switch allows you to execute a command that will
be invoked in a shell. You can use
-s, --shell SHELL specify which shell
is going to be used. Thanks to such behavior
.bashrc is used and
variable is set up properly.
Note: We use
exec twice here so that runit ends up monitoring our
application-name binary instead of monitoring
exec su - application-name -c "cd /var/lib/application-name/current/ \ && exec bundle exec ruby -Ilib ./bin/application-name"
And the second mentioned solution is to use full ruby binary (or gem) path in a script:
You can see our open-sourced cookbook for ruby installation on github arkency/ruby-build-cookbook. This is first thing that we open sourced as a company (we do have lot of open source experience as individuals) and we hope that in the future you can expect even more from us.
And if you are not that much into cooking (with chef) you can see for yourself how simple the whole ruby installation process just is.
- No need to use rvm wrappers in every possible place such as cron, capistrano recipes etc.
- No need to switch ruby versions because you just log in as proper user associated with the application and there is just the right ruby that you should be using with this app.
- Every application has its own user
- Every user has its own ruby