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
$ git clone firstname.lastname@example.org: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
#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 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:
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 is the working directory for all the other commands.
RUN installs two libraries that we will need. The second installs gosu, a tool we use to avoid permissions hell.
COPY copies files into the container. We are copying in the
Gemfile.lock so that we can install our gems in the container. After they are copied into the container, we
bundle install to install all our gems. Then we copy our project into the container.
The default command for when the container is started. There are a few acceptable form for
CMD. This is the preferred form.
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.
This sample app needs two containers running:
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 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 overrides the default command as defined in the
[ ] check the actual command used in the Dockerfile. Do we even need to use
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.
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.
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
Every container in Docker Compose needs either
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!