Dockerize a Rails App
Heard lots about Docker and you want to try it out? This tutorial will demonstrate one way to get a simple Rails app running in Docker.
You're going to need a linux environment to follow along. If you're using a Mac I recommend you just follow the directions I wrote about getting set up with Vagrant. That will cover installing Docker and Docker Compose. If you already have a linux environment, you can just install them as follows.
Installing Docker and Docker Compose
- Docker - There is pretty good documentation on the docker site. Here are the commands I used to install:
$ sudo apt-get update && apt-get install wget
$ wget -qO- https://get.docker.com/ | sh
$ sudo usermod -aG docker vagrant
$ sudo docker run hello-world
The last command should show you a bunch of things including: Hello from Docker.
- Docker Compose - This will help us manage multi-container apps. Installation docs are here or just copy and paste:
$ sudo -i
$ curl -L https://github.com/docker/compose/releases/download/1.3.3/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose
$ chmod +x /usr/local/bin/docker-compose
$ exit
Dockerizing your app
Clone your app down first. I'm using a demo rails app called storedom from the good people at Turing.
$ git clone git@github.com:turingschool-examples/storedom.git ~/src/storedom
The problem with that app is that it is using SQLite. We're going to use PostgreSQL so we can have two Docker containers running and talking to each other. To do that, we'll need to change a few files: database.yml
, and the Gemfile
#config/database.yml
development: &default
adapter: postgresql
encoding: unicode
database: storedom_dev
pool: 5
username: postgres
password:
host: postgres
test:
<<: *default
database: storedom_test
production:
<<: *default
database: storedom
#Gemfile
source 'https://rubygems.org'
gem 'rails', '4.1.4'
gem 'pg'
gem 'sass-rails', '~> 4.0.3'
gem 'uglifier', '>= 1.3.0'
gem 'coffee-rails', '~> 4.0.0'
gem 'jquery-rails'
gem 'turbolinks'
gem 'jbuilder', '~> 2.0'
gem 'faker'
gem 'haml-rails'
gem 'therubyracer'
gem 'less-rails-bootstrap'
group :development do
gem 'spring'
end
group :development, :test do
gem 'capybara'
gem 'pry', :require => 'pry'
end
Dockerfile
The Dockerfile
is a set of instructions Docker uses to build your container. You start with a base image and then layer on various commands that will install software, organize directories, etc. The commands are carried out in sequence.
Here is an example that will work for storedom:
#Dockerfile
FROM ruby:2.2.0
WORKDIR /usr/src/app/
RUN apt-get update -qq && apt-get install -y build-essential libpq-dev
RUN curl -o /usr/local/bin/gosu -SL "https://github.com/tianon/gosu/releases/download/1.2/gosu-$(dpkg --print-architecture)" && chmod +x /usr/local/bin/gosu
COPY Gemfile /usr/src/app/Gemfile
COPY Gemfile.lock /usr/src/app/Gemfile.lock
RUN bundle install
COPY . /usr/src/app
# copy our project into the WORKDIR
CMD ["rails", "s"]
# this is the default command we will run when starting the container*
Docker has good documentation on building a Dockerfile
, but you can see a quick explanation of the commands we are using below:
FROM
Our base image is ruby 2.2.0. This is a basic Docker image with Ruby 2.2.0 installed on top of Ubuntu. It is maintained by Docker. The rest of our commands will build off this starting point.
WORKDIR
The WORKDIR
is the working directory for all the other commands.
RUN
The first RUN
installs two libraries that we will need. The second installs gosu, a tool we use to avoid permissions hell.
COPY
COPY
copies files into the container. We are copying in the Gemfile
and Gemfile.lock
so that we can install our gems in the container. After they are copied into the container, we RUN
bundle install
to install all our gems. Then we copy our project into the container.
CMD
The default command for when the container is started. There are a few acceptable form for CMD
. This is the preferred form.
Docker Compose
Docker Compose, formerly called fig, is a tool that helps manage building, running, and linking Docker containers. It consists of a YAML file that sits in your project directory, called docker-compose.yml
, and a CLI.
Below is a docker-compose.yml
that we can use to get for this project.
#docker-compose.yml
rails:
build: .
command: bundle exec rails s -p 3000 -b '0.0.0.0'
volumes:
- .:/storedom
ports:
- "3000:3000"
links:
- postgres:postgres
postgres:
image: postgres
ports:
- "5432"
So what do those things mean? Luckily, the file is reasonably self-explanitory and well documented, but we can go into a little detail about what each key does.
Container Name
This sample app needs two containers running: rails
and postgres
. The first will run the rails app and the second will run the postgres database. They are defined at the top level of docker-compose.yml
, and we can use these friendly names to refer to the containers in the Docker Compose CLI.
build
build
maps to a path to a directory that contains a Dockerfile
. We have a Dockerfile
in the same directory as the docker-compose.yml
, and therefor just use.
.
command
command
overrides the default command as defined in the Dockerfile
[ ] check the actual command used in the Dockerfile. Do we even need to use command
?
volumes
volumes
mounts a path on the host to a path in the new container. Here, we are mapping the current directory to the /storedom
directory in the container.
ports
Similar to our Vagrant setup, ports
maps ports on the host to ports in the container. We're keeping everything on 3000 just to make it all easy. Using a string here isn't mandatory, but is idiomatic.
links
This is one of the really cool parts of Docker Compose. links
links containers together; in this case, we are giving our app container, rails
, access to our database container postgres
.
image
Every container in Docker Compose needs either build
or image
. image
will pull down the mapped image.
Tying it all together
Now, you should have everything you need to run your app in Docker containers. Run $ docker-compose up
and Docker Compose will build your containers and run them. Learn more about the Docker Compose CLI in the docs.
Go out and cargo-cult to your heart's content. Get it? Because Docker? And cargo!