At Bleacher Report, we’re beginning to use Docker in production for our new services. AWS Elastic Beanstalk support for Docker made deploying containers much easier.

However, I often experienced a few pain points when attempting to use Docker in development. I quickly compiled a long bash script of multiple docker run commands. It felt anything but efficient.

That’s where Fig comes in. Fig is a tool to easily build, configure and run Docker containers. To run services in isolation, all you need is fig.yml.

This tutorial will show you how to build a modern web stack using Docker and Fig. We’ll build a Rails 4 app using Postgres and Redis.

It’s worth noting that Docker Compose will replace Fig, however the same concepts apply.

Installation

To begin, you’ll need to install boot2docker and Fig. This tutorial uses boot2docker v1.3.2 and fig v1.0.1.

Setup

Next, you’ll need an app! You can clone my demo on GitHub, configure an existing project, or run rails new myapp --database=postgresql.

Dockerfile

For simplicity, we’ll use the official Rails image from Dockerhub as our Docker image. Add Dockerfile to your project directory:

FROM rails:onbuild
ADD . /app
WORKDIR /app
EXPOSE 3000

Fig

We’re going to define three services in our fig.yml. Each of these services will run as seperate containers:

  • web
  • db
  • redis

Add fig.yml to your project directory:

web:
  build: .
  command: bundle exec unicorn -p 3000 -c config/unicorn.rb
  volumes:
    - .:/app
  ports:
    - "3000:3000"
  links:
    - db
    - redis
  environment:
    - API_KEY=FOOBAR
db:
  image: postgres:9.3
  ports:
    - "5432"
redis:
  image: redis:2.8
  ports:
    - "6379"

build will use the current directory as the path and build our Dockerfile.

command overrides the default command. For this tutorial, we’re starting the Unicorn web server.

links will link to containers in another service. More specifically, we’ve linked db and redis to our web service.

environment will set environment variables for services.

In addition to those commands, we’ve also mapped the VM machine volume to our host machine and exposed ports for each service.

Fig supports more complex configurations as well. For more info, visit their documentation.

Configuration

For the services to work together, you’ll need to configure a few files in your project. Adding host: db and host: redis in *.yml links your web service to the Postgres and Redis services named db and redis, respectively.

config/database.yml:

default: &default
  adapter: postgresql
  encoding: unicode
  username: postgres
  password:
  pool: 5

development:
  <<: *default
  database: fig_demo_development
  host: db

test:
  <<: *default
  database: fig_demo_test
  host: db

production:
  <<: *default
  database: fig_demo_production
  username: fig_demo
  password: <%= ENV['FIG_DEMO_DATABASE_PASSWORD'] %>

config/redis.yml:

default: &default
  host: redis
  port: 6379

development:
  <<: *default

test:
  <<: *default

production:
  host: <%= ENV["FIG_DEMO_REDIS_HOST"] %>
  port: <%= ENV["FIG_DEMO_REDIS_PORT"] %>

config/initializers/redis.rb:

redis_host = YAML.load_file("#{Rails.root}/config/redis.yml")[Rails.env]["host"]
redis_port = YAML.load_file("#{Rails.root}/config/redis.yml")[Rails.env]["port"]
REDIS = Redis.new(host: redis_host, port: redis_port)

Building services

After configuration, run the following commands:

fig build
fig run web rake db:create db:migrate

fig build builds services specified in your fig.yml.

fig run allows you to run one-off commands on a service. For this tutorial, we’re creating the databases and running any migrations.

Running specs

It’s always good practice to write specs for your code. Since fig run supports one-off commands, it allows you to easily run specs. To ensure your environment is setup correctly, run the specs:

fig run web bundle exec rspec

Running services

After the tests pass, run the following command:

fig up

fig up builds, creates, starts and attaches to containers for a service. Linked services are also started. For this tutorial, web, db and redis services are now running as separate Docker containers.

The app should now be running on port 3000. To view your Docker daemon, run the following command:

boot2docker ip

After obtaining the IP address, visit XXX.XXX.XX.XXX:3000 in your browser.

That’s it. You’ve successfully built a modern web stack using Docker and Fig. Fig services are very customizable. Now you can create a worker service using Sidekiq, create test services in isolation, and much more.