Make Your Docker Workflow Awesome With Fig.sh

Justyna IlczukJustyna Ilczuk

Fig simplified our complicated docker setup and life is awesome again.

Update: Fig has been replaced by Docker Compose, and is now deprecated. Docker Compose should serve as a drop-in replacement for fig.sh used in this article.

What is fig?

Fig is a python application that helps you run groups of docker containers. The docker command line interface is awesome, but if you start working with many containers at once and link them in the development environment, typing the commands into the command line gets burdensome.

The most pragmatic approach to this problem is creating a bash script:

run_docker_containers.sh  
>#!/bin/bash
# Usage:
# `./run_docker_containers.sh`
# or
# `./run_docker_containers.sh python manage.py test`
  
# Postgres container
docker run -d -v /var/docker/postgresql:/data --name=postgres -e USER='root' \  
    -e PASS='amazing_pass' -e DB='my_db' paintedfox/postgresql
 
# Redis container
docker run -d -v /var/docker/redis:/data -p 0.0.0.0:6379:6379 \  
    --name=redis dockerfile/redis
  
# Rabbit container
docker run -d -v /var/docker/rabbit:/data -p 0.0.0.0:15672:15672 \  
    -p 0.0.0.0:5672:5672 -e RABBITMQ_PASS="amazing_pass" \
    --name=rabbitmq tutum/rabbitmq
  
# Worker container
docker run -i -t -e INSTANCE_TYPE="worker" --name='my-worker' \  
    -v /home/syncano/app:/home/syncano/app \
    --link=postgres:postgres --link=redis:redis --link=rabbitmq:rabbit my_docker_image &
  
# Web server container
docker run -i -t -e INSTANCE_TYPE="web-server" --name='my-web' -p 0.0.0.0:8000:8000 \  
    -v /home/my/app:/home/my/app
    --link=postgres:postgres --link=redis:redis --link=rabbitmq:rabbit my_docker_image "$@"

Woah, it's super complicated and ugly – and that's only for running containers. What about inspecting containers, stopping them, or rebuilding them? You need more scripts for that. Managing docker this way can easily become a nightmare. Luckily, you can use fig.sh instead.

Fig lets you configure the setup of your docker containers with a simple yaml file and provides you with commands such as:

Fig logs

How do you get started with fig?

Step 1 - Install it.

Fig is available in pip, so all you have to do is type this into your command line:

$ sudo pip install fig

You can more information about installing fig.sh on the official website.

Step 2 - Create a fig config.

Fig config is written in yaml and is called fig.yml - you should place it in the directory in which you want to call fig commands.

Fig helps you manage docker containers, so its options are similar to those of the docker run command. In fig.yml, you'll start by entering the name of the container. Then, choose build or image to either run docker build or start a container based on the image you specified, respectively. You can specify many containers this way. Here's a simple example:

my_app:  
  build: . # will run docker build in local directory
redis:  
  image: redis

Of course you can do more things, like forwarding ports by choosing the ports field , mounting directories using the volumes field, and linking containers with links. It's really intuitive! You can read more about configuration options in the fig.yml reference.

Now for a less-simple example. Here's how you can migrate your first nightmarish bash script to fig.yml.

postgres:  
    image: paintedfox/postgresql
    environment:
        - USER=root
        - PASS=awesome_pass
        - DB=my_db
    ports:
        - "5432"
    volumes:
        - /var/docker/postgresql:data
redis:  
    image: dockerfile/redis
    volumes:
        - /var/docker/redis:data
    ports:
        - "6379"
rabbit:  
    image: tutum/rabbitmq
    volumes:
        - /var/docker/rabbit:data
    environment:
        - RABBITMQ_PASS=awesome_pass
    ports:
        - "5672"
        - "15672"
web:  
    build: .
    ports:
        - "8000:8000"
    links:
        - postgres:postgres
        - redis:redis
        - rabbit:rabbit
    volumes:
        - .:/home/my/app
    environment:
        - INSTANCE_TYPE=web-server
worker:  
    build: .
    links:
        - postgres:postgres
        - redis:redis
        - rabbit:rabbit
    volumes:
        - .:/home/my/app
    environment:
        - INSTANCE_TYPE=worker

To run containers, now use:

$ fig up

In another terminal window, you can inspect all of your containers with:

$ fig ps
  
Name                         Command               State                 Ports  
-------------------------------------------------------------------------------------------------------
app_redis_1      redis-server /etc/redis/re ...   Up      49417->6379/tcp  
app_postgres_1   /sbin/my_init                    Up      49418->5432/tcp  
app_rabbit_1     /run.sh                          Up      49419->15672/tcp, 49420->5672/tcp  
app_worker_1     /sbin/my_init                    Up      8000/tcp, 2023->22/tcp  
app_web_1        /sbin/my_init                    Up      8000->8000/tcp, 2022->22/tcp  

That's it! Pretty easy, right?

Issues with fig (troubleshooting)

Unexpected quotes in environment variables

I'm used to wrapping string environment variables in double quotes " ". I did the same in my fig.yml config and to my surprise app wasn't working.

This is how I configured my INSTANCETYPE_ variable:

environment:  
    - INSTANCE_TYPE="web-server"

During debugging I noticed that fig leaves double quotes in actual variable value:

$ fig run web printenv
  
...
POSTGRES_1_ENV_USER=root  
POSTGRES_1_ENV_PASS=amazing_pass  
INSTANCE_TYPE="web-server"  
HOME=/root  
...

So, my advice is to strip quotes in environment specification.

Rebuilding images

I also noticed fig occasionally doesn't notice when a Dockerfile changes and its image needs to be rebuilt. When that happens, you'll just need to enter this into the command line:

$ fig rm  # removes containers
$ fig build  # rebuild images
$ fig up  # run whole setup again

Summary

Fig simplified our complicated docker setup.
If you're looking for improving your docker workflow even more, check out nsenter - a tool for entering docker containers - and serf - a decentralized solution for cluster membership, failure detection, and orchestration.

Build powerful apps in half the time

Use our serverless platform to set up your backend in minutes.

Learn more