Bundle optimization for ruby on Docker - ruby-on-rails

I'm new to docker and was wondering how does ruby bundler behave when re-building docker images? The first time I build an image it takes forever to bundle install. What will happen when I add another gem into the Gemfile? Is there a way to ensure previous gems are cached somehow in the image and used for this new bundling?
Dockerfile:
FROM rails:onbuild
RUN apt-get install -y imagemagick

It depends on how you ADD your Gemfile.
ADD Gemfile /var/www/yourapp/
ADD Gemfile.lock /var/www/yourapp/
RUN bundle install
In this case bundle install would only run if either the Gemfile or the Gemfile.lock changed. Note that the placement of this instruction in your Dockerfile matters. As soon as a previous build-steps cache is invalidated all subsequent instructions are no longer cached. (e.g. you ADD a config file before the Gemfile, and that changed -> bundle install will run).
What will happen when I add another gem into the Gemfile?
If you just want to add a couple of gems without bundling everything you could also do something like:
ADD Gemfile /var/www/yourapp/
ADD Gemfile.lock /var/www/yourapp/
RUN bundle install
...
ADD Gemfile.tip /var/www/yourapp/
RUN bundle install
Here is a rails example project you can check out (well documented).

Related

Ruby Workflow - Bundle Install

Where does bundle install fit into the add-commit-push workflow? In other words, when is it necessary.
You will need to launch bundle install every time that you update your Gemfile.
Before you run it, make sure you have bundler gem installed:
$ gem install bundler
You can integrate this command and several others adding some git hooks. For example, I use overcommit gem to make sure that some actions are performed before commit, merge and push.
You would want to ensure that you have run bundle install before adding files to a git commit.
You should be in the habit of running bundle install every time your Gemfile is changed.
Please note: Git and Bundler are independent. The only reason you want to have run bundle install before adding to git is to ensure that your Gemfile.lock is updated to contain the latest information.

Globally available Gemfile

I have numerous gems that I use across all Rails projects, but that aren't part of the projects' Gems, for example powder for managing POW.
It would make sense to me to manage these with a global Gemfile, but I can't see any examples of this.
How should I manage global Gems that I don't want in my project gemfiles? It would be good to have a single point of install for when I set up a new machine etc.
I'm using chruby alongside ruby-install to manage my Ruby versions.
Make a Gemfile as usual, and place it in any folder. It does not need to be a project folder. Then you can just do:
bundle install --system
This will install the gems in the Gemfile system-wide, and will ask for the root password if you do not have access to the system folder.
--system:
Installs the gems in the bundle to the system location. This overrides any previous remembered use of --path.
You can also name your Gemfile(s), if you want to organize them in some way:
bundle install --system --gemfile=/path/to/my_special_gemfile
As an addition to #Casper's answer:
I created a directory for my system Gem files.
I then added a dir for each version of ruby I wanted to install system gems for. I added a Gemfile to each dir and a .ruby-version file with the correct version. I can now install system gems for a ruby version using:
$ cd path/to/system_gems_dir/1.9.3-p484
$ bundle install --system
or
$ cd cd path/to/system_gems_dir/2.0.0-p353
$ bundle install --system
You can create GlobalGemfile file (or whatever you name it) and than you can do.
bundle install --gemfile GlobalGemfile
Cool isn't it :)

Why is "install" run twice?

I'm going through Micharl Hartl's well known Rails tutorial, and this piece is confusing me. Every time a new app is set up, these commands are run:
$ bundle install --without production
$ bundle update
$ bundle install
I don't really get why install is being run twice. What is the effect of these three commands run in this sequence?
You should not have to run bundle install twice as bundle update will also install all of your gems (as well as updating them to their most current version). I have not read the tutorial you mentioned but perhaps the purpose of the second install is to install all of the gems, including those reserved for production.
Your second question, what is the effect of these three commands:
bundle install --without production
Inspect the gemfile, ignoring gems that are reserved for production
Resolve all dependencies
Install all gems and dependent gems
Save the exact version of each gem to Gemfile.lock
bundle update
Inspect the gemfile
Resolve all dependencies from scratch using the newest version of each gem and completely ignoring Gemfile.lock
Install all gems and dependent gems
Save the exact version of each gem to Gemfile.lock
bundle install
Because this is the first run of the production gems, inspect the gemfile and resolve dependencies of the production gems
Use Gemfile.lock for exact versions of all other gems to be installed
Install all gems and dependent gems
Save the exact version of each gem to Gemfile.lock
Hoped this helped, for more detailed info about the two commands check out this and this.
$ bundle install --without production prevents bundler from installing any of the production gems. It also gets saved in your local repository and you don't have to run it more than once. Any subsequent run of bundle install will include --without production.
bundle install installs only the missing gems from your Gemfile, while bundle update updates/installs every single gem to the latest version as specified in the GemFile..

Is it possible to use Rails 3 without bundler?

We are deploying our apps as RPM linux packages (with all the dependencies also packaged in RPMs). It turns out that bundler is problematic in this situation and it only complicates our build process - we would like to get rid of it.
Is it possible to run Rails 3 app without it forcing Ruby to use system rubygems? How?
In the book Rails 3 Way there is a statement describing that the easiest way to remove Bundler is to delete Gemfile* files. That's it. It just works.
You could install all gems manually using gem install gemname. In your situation or if you do not have sudo rights it is perhaps recommendable to install the gem files locally in your user directory using
gem install --user-install gemname
You can also install your gems locally with bundler:
bundle install --path ~/.gem

How do I use bundler to get a gem from a git repository?

Authlogic has a couple unfortunate deprecation warnings that are fixed in a fork.
How do I use this forked version? I tried adding the following to my Gemfile:
gem 'authlogic', :git => 'git://github.com/railsware/authlogic.git'
And it didn't work quite that well. I started getting:
git://github.com/railsware/authlogic.git (at master) is not checked out. Please run bundle install
And
The git source git://github.com/railsware/authlogic.git is not yet checked out. Please run bundle install before trying to start your application
Assistance will be rewarded with virtual cookies.
Have you tried running bundle install after removing Gemfile.lock?
rm Gemfile.lock
bundle install
Your Gemfile configuration should work, I was able to use the same for and my bundle install command executes as does my bundle list command.
My other suggestion would be removing you ~/.bundler and .bundle directories and checking that you have properly configured git.
You need to run bundle install from the terminal after updating your Gemfile.

Resources