How to use Docker and gemstash to not download Gems over and over again
Using Docker for Rails development is an obvious fit now. But it doesn’t come with only advantages. One of the most valid counter argument is the fact that you’ll download gems over and over again from Internet.
Even if your Dockerfile is written with these Best Practices in mind, you end up downloading every gem each time one is added to the Gemfile
.
This post explains how to use gemstash running in a sidecar container to ease that pain.
Run gemstash in a container
Gemstash helps you run a cache or private gem server. We are going to use it as a proxy to rubygems.org
.
Here’s the two commands you’ll need to run gemstash in a container:
cat <<EOF | docker build -t gemstash -
FROM ruby:2.4.1
RUN gem install --no-ri --no-rdoc gemstash
EXPOSE 9292
VOLUME /root/.gemstash
ENTRYPOINT ["gemstash"]
CMD ["start", "--no-daemonize"]
EOF
docker run -d --name gemstash -v $(PWD)/gemstash:/root/.gemstash -p 9292:9292 gemstash
Change your app’s Dockerfile to use gemstash
Here’s the line that you should add to your existing Dockerfile to use gemstash as a proxy to rubygems.org
:
FROM ...
RUN bundle config mirror.https://rubygems.org http://docker.for.mac.localhost:9292
...
RUN bundle install
We tell bundle
to connect to docker.for.mac.localhost
for it now runs a rubygems proxy. Now, docker build
will point at gemstash and all subsequent builds will be much faster.
FYI docker.for.mac.localhost
is the magic hostname that makes your containers connect to your Mac. On Windows, replace docker.for.mac.localhost
with docker.for.windows.localhost
.
Or use docker build –network
Another (maybe cleaner) way of achieving the same goal without using docker.for.mac.localhost
special hostname is to run the gemstash
container on a specific docker network and run docker build
with a --network
flag:
docker network create rails
docker run -d --name gemstash -v $(PWD)/gemstash:/root/.gemstash --network rails gemstash
The modification to your Dockerfile will then be:
RUN bundle config mirror.https://rubygems.org http://gemstash:9292
This solution is more portable that using docker.for.mac.localhost
special hostname. Also, it makes the gemstash container and the build container communicate directly without going through Docker for Mac’s vpnkit-based proxy.