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.
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 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 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
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
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: 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
fig build test fig up test
This container will poll the file system for changes and run the appropriate spec for any modified code.
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>