Production images in docker compose

So you want to create a Dockerfile that you can build and deploy to production and run as your development environment? You could build a bunch of layers, but that quickly turns into a mess requiring multiple build scripts. The easier option is to use the ARG directive in your Dockerfiles.

Here’s the skinny:

# Example Rails Dockerfile.
FROM ruby

# ARGS default to production settings. They are over-ridden
# by the compose file for development and CI environments.
ARG BUNDLE_WITHOUT="development:test"
ARG APT_DEV_PACKAGES=""

RUN apt-get -q update \
  && apt-get -q -y install \
    git \
    libxslt1-dev libxml2-dev \ # For nokogiri
    make \
    g++ \
    libmysqlclient-dev \ # For MySQL gem
    curl \
    ${APT_DEV_PACKAGES} \
  && apt-get -q -y clean \
  && rm -rf /var/lib/apt/lists

WORKDIR /app

COPY Gemfile* /app/

# Bundler ENV var http://bundler.io/man/bundle-config.1.html.
ENV BUNDLE_WITHOUT=${BUNDLE_WITHOUT}

RUN bundle install \
    --retry 3 \
    --jobs 4 \
    --binstubs \

CMD bundle exec rails server

If you build this image without any build-args, you’ll end up with a production-ready container.

The trick is how you set this up in your docker-compose.yml file:

version: '2'
services:
  rails:
    build:
      context: .
      args:
        BUNDLE_WITHOUT: ""
        APT_DEV_PACKAGES: "qt5-default libqt5webkit5-dev phantomjs xvfb nodejs redis-tools dbus mysql-client"

When you run docker-compose build you’ll end up with a development image with all the right gems and apt packages installed.

My oath: only run development environments in Docker containers

A year ago I decided that I’d only run development environments inside Docker containers so that I’d Learn The Hard Way™ all of the workflow pitfalls before rolling it out to the rest of the crew at Poll Everywhere. I’ve got a few more articles in the works that uncover more Docker development environment naunces that I’ll tweet from @bradgessler.

Bg