| As someone who deploys Ruby software to our servers, I've come up with a formula that's served us well. We take all gems associated with the app (like a Rails app, but we do it with others), and stuff them along with the code into a package created by fpm. In other words, the packages are completely self-contained; no gems are used from the environment. The key to this is the --path option to bundle install, i.e.: bundle install --path vendor/bundle This command makes sure all my gems are in a sub directory of my project called vendor/bundle. When creating the debian package using fpm which includes all the source code, vendor/bundle also comes along with the package. After installing the app on our Linux servers, 'bundle exec rails server' uses the gems from vendor/bundle. This approach does require that I create the debian package on a machine that closely mirrors the deployed servers, so that compiled gems make any sense. Most all the issues described in the article have not been problems because of this approach. I used to use rvm as part of my build process; it was very brittle. I'm completely happy now; just wanted to share in case that helps someone else. |
That is exactly what I've started doing at work, actually. It's a short-term win and rather simple, but it's a pretty big hack. Package bundling is quite poor form as it leads to file system duplication and for each duplication you have an additional location to patch when a security vulnerability is inevitably discovered. Ideally each Ruby gem would be its own package. I'm also concerned with reproducibility, so I build packages in as isolated of an environment as possible where I run 'bundle install' with a fresh vendor/bundle directory. Builds take longer than they should because of all the re-downloading. Using Guix, where I can easily represent each Ruby component in a package object, I can take advantage of its content-addressable storage to save time on repeated builds by using the cached gem builds from previous times.