Red Green Repeat Adventures of a Spec Driven Junkie

Dockerizing git Version in a Rails App

Ruby on Rails Icon

git logo

Docker Icon

Intro

From my article on tracking a Ruby on Rails server version with git, this provided an easy way to track the version the server is running from going to a specific endpoint and you can track the server version all the way down to the commit it is running through the git branch name and SHA.

I will show how to construct a Dockerfile that includes the .git directory so the version information is in the container.

Requirements

For the rest of the article, I will be working from the directory of the cloned repository.

Create Docker Image

I have the following contents in my Dockerfile that describes specific steps to build the Docker image:

FROM ruby:2.5.0-slim

RUN apt-get update && apt-get install -qq -y --no-install-recommends \
    build-essential \
    libsqlite3-dev \
    nodejs \
    sqlite3 \
 && rm -rf /var/lib/apt/lists/*

RUN mkdir /app
WORKDIR /app

COPY Gemfile Gemfile.lock ./
RUN bundle install

COPY . .

CMD ["bundle", "exec", "rails", "s", "-p", "3000", "-b", "0.0.0.0"]

Dockerfile Highlights

A quick high level overview of each section:

FROM ruby:2.5.0-slim use the ruby 2.5.0 docker image as a base
RUN apt-get install operating dependencies
RUN mkdir & WORKDIR make and set the working directory
COPY Gemfile & RUN bundle Copy the Gemfiles and bundle install items
COPY . . Copy the application to the WORKDIR
CMD The default command to run for the container, in this case, start the server

To build the container, with an image tag: rails_git_version run the following command:

$ docker build . -t rails_git_version
... # lots of Docker build output

Let’s check to make sure the build succeeded:

$ docker images
REPOSITORY                  TAG    IMAGE ID            CREATED             SIZE
rails_git_version           latest fa57fe007740        4 minutes ago       525MB

Now we are ready to test things out by running the container and verifying endpoints.

Run Container

Start the container from the just created Docker image rails_git_version:

$ docker run -p 3100:3000 rails_git_version

Let’s do a quick check to see if it’s really running by loading the default Rails endpoint using the curl command:

$ curl localhost:3100
... # lots of output

      <p class="version">
        <strong>Rails version:</strong> 5.1.6<br />
        <strong>Ruby version:</strong> 2.5.1 (x86_64-darwin16)
      </p>
    </section>
  </div>
</body>
</html>

Cool, the main homepage is working, let’s check for the server version by using the curl command on the /version endpoint:

$ curl localhost:3100/version
{ "branch": "master", "sha": "66650149ce6a972a6d7a54e240206505f004adb5" }

Great - just what we expected. It’s the same result as the local server, which we can also quickly test, by starting up the server using command:

$ rails s

In another terminal, run the same curl command, but on a different port (3000 vs. 3100):

$ curl localhost:3000/version
{ "branch": "master", "sha": "66650149ce6a972a6d7a54e240206505f004adb5" }

If these don’t match, make sure the git branch is same as the container’s build (or rebuild the container.)

Make Container from Different Branch

Now, let’s create a new docker image from a different branch and run that.

First, let’s switch to another branch with git checkout and build the Docker image with docker build, this time tagging the image as: rails_git_version_feature.

$ git checkout feature/new_version
$ docker build . -t rails_git_version_feature
... # docker build output

With a different tag, now we can have both the master branch container and the feature/new_version container at the same time.

Run docker images to Make sure we have the new Docker image

$ docker images
REPOSITORY                  TAG    IMAGE ID            CREATED             SIZE
rails_git_version_feature   latest 152e4fa647b1        53 seconds ago      525MB
rails_git_version           latest fa57fe007740        6 minutes ago       525MB

Verify New Container Version

Just like before, we run the container with docker run, but this time, specify rails_git_version_feature and a different port (3200) instead:

$ docker run -p 3200:3000 rails_git_version_feature

And just like before, use curl command to do a quick test for the version, on port 3200:

$ curl localhost:3200/version
{ "branch": "feature/new_version", "sha": "9fd5074bab721b5757305e2944e352434290e96c" }

We can also test the local version to see:

$ rails s

in another terminal:

$ curl localhost:3000/version
{ "branch": "feature/new_version", "sha": "9fd5074bab721b5757305e2944e352434290e96c" }

Tags

I used Docker tags when building the image so there can be multiple Docker images at the same time.

Why not use this for the version?

One definitely can, and should!

I would recommend using Docker image tags as a way to manage the version behind the scenes from the deployment control center. The tag is never seen by the user from the other side of the server.

Having another way to validate the version helps when there’s a server issue.

Conclusion

We just covered building a Docker image for a Ruby on Rails app that incorporates the git version.

By having the git version within the Docker container, one can know exactly what version of the server is the container is running without digging into container.

This also multiple containers to have different versions by using tags, but also absolute verification of the server.