compose/README.md

7.2 KiB

Fig

Punctual, lightweight development environments using Docker.

Fig is a tool for defining and running isolated application environments. You define the services which comprise your app in a simple, version-controllable YAML configuration file that looks like this:

web:
  build: .
  links:
   - db
  ports:
   - 8000:8000
db:
  image: orchardup/postgresql

Then type fig up, and Fig will start and run your entire app:

$ fig up
Pulling image orchardup/postgresql...
Building web...
Starting example_db_1...
Starting example_web_1...
example_db_1 | 2014-01-02 14:47:18 UTC LOG:  database system is ready to accept connections
example_web_1 |  * Running on http://0.0.0.0:5000/

There are commands to:

  • start, stop and rebuild services
  • view the status of running services
  • tail running services' log output
  • run a one-off command on a service

Fig is a project from Orchard, a Docker hosting service. Follow us on Twitter to keep up to date with Fig and other Docker news.

Getting started

Let's get a basic Python web app running on Fig. It assumes a little knowledge of Python, but the concepts should be clear if you're not familiar with it.

First, install Docker. If you're on OS X, you can use docker-osx:

$ curl https://raw.github.com/noplay/docker-osx/master/docker > /usr/local/bin/docker
$ chmod +x /usr/local/bin/docker
$ docker version

Docker has guides for Ubuntu and other platforms in their documentation.

Next, install Fig:

$ sudo pip install fig

You'll want to make a directory for the project:

$ mkdir figtest
$ cd figtest

Inside this directory, create app.py, a simple web app that uses the Flask framework and increments a value in Redis:

from flask import Flask
from redis import Redis
import os
app = Flask(__name__)
redis = Redis(
    host=os.environ.get('FIGTEST_REDIS_1_PORT_6379_TCP_ADDR'),
    port=int(os.environ.get('FIGTEST_REDIS_1_PORT_6379_TCP_PORT'))
)

@app.route('/')
def hello():
    redis.incr('hits')
    return 'Hello World! I have been seen %s times.' % redis.get('hits')

if __name__ == "__main__":
    app.run(host="0.0.0.0", debug=True)```

We define our Python dependencies in a file called `requirements.txt`:

    flask
    redis

And we define how to build this into a Docker image using a file called `Dockerfile`:

    FROM stackbrew/ubuntu:13.10
    RUN apt-get -qq update
    RUN apt-get install -y python python-pip
    ADD . /code
    WORKDIR /code
    RUN pip install -r requirements.txt
    EXPOSE 5000
    CMD python app.py

That tells Docker to create an image with Python and Flask installed on it, run the command `python app.py`, and open port 5000 (the port that Flask listens on).

We then define a set of services using `fig.yml`:

    web:
      build: .
      ports:
       - 5000:5000
      volumes:
       - .:/code
      links:
       - redis
    redis:
      image: orchardup/redis

This defines two services:

 - `web`, which is built from `Dockerfile` in the current directory. It also says to forward the exposed port 5000 on the container to port 5000 on the host machine, connect up the `redis` service, and mount the current directory inside the container so we can work on code without having to rebuild the image.
 - `redis`, which uses the public image [orchardup/redis](https://index.docker.io/u/orchardup/redis/). 

Now if we run `fig up`, it'll pull a Redis image, build an image for our own app, and start everything up:

    $ fig up
    Pulling image orchardup/redis...
    Building web...
    Starting figtest_redis_1...
    Starting figtest_web_1...
    figtest_redis_1 | [8] 02 Jan 18:43:35.576 # Server started, Redis version 2.8.3
    figtest_web_1 |  * Running on http://0.0.0.0:5000/

Open up [http://localhost:5000](http://localhost:5000) in your browser (or [http://localdocker:5000](http://localdocker:5000) if you're using [docker-osx](https://github.com/noplay/docker-osx)). That's it!

You can also pass the `-d` flag to `fig up` to run your services in the background, and use `fig ps` to see what is currently running:

    $ fig up -d
    Starting figtest_redis_1...
    Starting figtest_web_1...
    $ fig ps
            Name                 Command            State       Ports
    -------------------------------------------------------------------
    figtest_redis_1   /usr/local/bin/run         Up
    figtest_web_1     /bin/sh -c python app.py   Up      5000->5000/tcp

`fig run` allows you to run one-off commands for your services. For example, to see what environment variables are available to the `web` service:

    $ fig run web env


Run `fig --help` to see what other commands are available. You'll probably want to stop them when you've finished:

    $ fig stop

That's more-or-less how Fig works. See the reference section below for full details on the commands, configuration file and environment variables.


Reference
---------

### fig.yml

Each service defined in `fig.yml` must specify exactly one of `image` or `build`. Other keys are optional, and are analogous to their `docker run` command-line counterparts.

As with `docker run`, options specified in the Dockerfile (e.g. `CMD`, `EXPOSE`, `VOLUME`, `ENV`) are respected by default - you don't need to specify them again in `fig.yml`.

```yaml
-- Tag or partial image ID. Can be local or remote - Fig will attempt to pull if it doesn't exist locally.
image: ubuntu
image: orchardup/postgresql
image: a4bc65fd

-- Path to a directory containing a Dockerfile. Fig will build and tag it with a generated name, and use that image thereafter.
build: /path/to/build/dir

-- Override the default command.
command: bundle exec thin -p 3000

-- Link to containers in another service (see "Communicating between containers").
links:
 - db
 - redis

-- Expose ports. Either specify both ports (HOST:CONTAINER), or just the container port (a random host port will be chosen).
ports:
 - 3000
 - 8000:8000

-- Map volumes from the host machine (HOST:CONTAINER).
volumes:
 - cache/:/tmp/cache

-- Add environment variables.
environment:
  RACK_ENV: development

Environment variables

Fig uses Docker links to expose services' containers to one another. Each linked container injects a set of environment variables, each of which begins with the uppercase name of the container.

name_PORT
Full URL, e.g. MYAPP_DB_1_PORT=tcp://172.17.0.5:5432

name_PORT_num_protocol
Full URL, e.g. MYAPP_DB_1_PORT_5432_TCP=tcp://172.17.0.5:5432

name_PORT_num_protocol_ADDR
Container's IP address, e.g. MYAPP_DB_1_PORT_5432_TCP_ADDR=172.17.0.5

name_PORT_num_protocol_PORT
Exposed port number, e.g. MYAPP_DB_1_PORT_5432_TCP_PORT=5432

name_PORT_num_protocol_PROTO
Protocol (tcp or udp), e.g. MYAPP_DB_1_PORT_5432_TCP_PROTO=tcp

name_NAME
Fully qualified container name, e.g. MYAPP_DB_1_NAME=/myapp_web_1/myapp_db_1