I've previously posted a short guide on creating a Docker container to run a Rails application. This covered the basics of creating a Dockerfile and starting a container but to use Docker as part of your development environment you need to do a little more work.
Most Rails applications will want at the very least a database to connect to and often a cache store or worker queue. To simplify running all these services in our development environment we can start a container for each service, however managing all these containers by hand and linking them together can quickly become a tedious task, thankfully there are utilities to simplify this task.
Fig is a project from Docker that allows you to define the services required by your application in a YAML file and then manage the entire stack with a few simple commands.
Prerequisites
To follow along with this example you'll need to have Docker installed. If your using OS X or Windows you'll need to install Boot2Docker.
When you have docker/boot2docker install clone the example rails project from Github - https://github.com/invisiblelines/docker-fig-rails-example.git
The repo contains a sample Rails application with Dockerfile. In your terminal change into the example project directory and follow along from there.
Installing Fig
Installing Fig is a single shell command to pull the latest release from Github.
curl -L https://github.com/docker/fig/releases/download/1.0.1/fig-`uname -s`-`uname -m` > /usr/local/bin/fig; chmod +x /usr/local/bin/fig
Alternatively you can install Fig using Pip
sudo pip install -U fig
Defining our Services
To make use of fig we need to create a fig.yml in the root of our application. We'll start small by just adding our application container and a PostgreSQL database.
db:
image: postgres:9.4
environment:
POSTGRES_USER: 'docker'
POSTGRES_PASSWORD: 'mysupersecretpassword'
app:
build: .
volumes:
- .:/var/www
ports:
- "5000:5000"
links:
- db
environment:
RACK_ENV: development
In the example above we define two services, db
and app
.
db
uses prebuilt postgres image from dockerhub. I've specified the exact tag to use rather than just using the latest tag. I've then specified environment variables for the user to be created.
app
uses the Dockerfile in the application root rather than a prebuilt image. It specifies volumes and ports to be mapped, and adds a link to the db
container.
Before running the application we need to build the Docker image for our application, this can be done directly with Fig:
fig build app
This step should only need to be repeated if the Dockerfile or Gemfile is changed.
We can now start our development stack with one command:
fig up app
You should now see output in your terminal showing the startup of the postgres server and the application server. Fig will start any services linked to the contaier you launch automatically.
Before going any further we need to create a database for this application. We can do this by running a one off command with Fig in another terminal tab:
fig run app bundle exec rake db:create
If you now visit localhost (or your boot2docker ip) port 5000 in your browser you will see a familar greeting.
Adding Further Services
Now we have our application up and running lets add a Redis container. To do this we just need to edit the fig.yml
and add a new service definition:
db:
image: postgres:9.4.0
environment:
POSTGRES_USER: 'docker'
POSTGRES_PASSWORD: 'mysupersecretpassword'
redis:
image: redis:2.8.19
app:
build: .
volumes:
- .:/var/www
ports:
- "5000:5000"
links:
- db
- redis
environment:
RACK_ENV: development
Running Specs/Tests
Now we have the development environment setup its time to start running our tests using the same containers. I like to have Guard watching my code and run specs automatically during development. For this we need another container setup for the test environment. In fig.yml
add a service for test
test:
build: .
volumes:
- .:/var/www
links:
- db
environment:
RACK_ENV: test
command: bundle exec guard -i -p -l 1
This is almost identical to the app definition however the RACK_ENV
has been changed to "test" and the default command has been changed to start Guard.
In another terminal tab build then start the test
container
fig build test
fig up test
This container will poll the file system for changes and run the appropriate spec for any modified code.
Cleaning Up
When you swap between projects you'll want to stop the current set of containers from running. You can stop any services start by Fig that are running in the foreground with Ctrl-C. For any other service run fig stop <service name>
To remove any containers any you no longer require run fig rm <service name>