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:
>#!/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:
- up - runs all containers; builds containers if none are available
- rm - removes containers
- ps - inspects the state of all containers in your app and gives you easy access to logs from all your containers at once:
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.
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
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.