[001.1] Introduction to Docker

Learn how to Dockerize your first application

Subscribe now

Introduction to Docker [01.08.2018]

Today’s video is the first in a series about hosting a production app on AWS, with logging, monitoring, and CDN support. In today's video, we will be working through a few steps to get our app Dockerized and our image pushed to a hosted Docker registry.

Introduction to Docker

Docker is a tool that allows you to package your application code and any supporting libraries so you can ship and run that code anywhere. If you're familiar with virtual machines, it's similar, but avoids costly side effects, since it doesn’t need an entire operating system to run. A container runs on top of the hosts and will use the hosts’ kernels and allotted resources.

This makes Docker containers much smaller and easier to ship to colleagues, staging, and production. I'm sure you've heard or used the old adage It works on my box. Using Docker, you can be assured that your servers are running the exact same code that you were running locally, so you shouldn’t experience those problems.


Dockerizing our App

When Dockerizing an application, there are a few things that need to be done. First, you need to add a Dockerfile. This file is the most important and really, the only requirement. This file defines the Docker image and instructs Docker on how to build it. When you run docker build ., the Docker daemon is going to reference the Dockerfile to see exactly what should happen during the build process.

Next, there's a .dockerignore file that is used to specify certain files or folders that you don't want to include in the image being built. If you are familiar with Git you can think of this file as being equivalent to a .gitignore.

Last, we're adding a docker-compose.yml file that we will mainly be using to simplify local development. This can be configured for your dependencies such as redis, rabbitmq, postgres, mysql, along with many others. This will allow you to spin up containers for those dependencies, without the manual management that’s typically associated with installing those pieces of software. This comes in very handy if you have many services. Simply by typing docker-compose up a new employee can easily get started without having to know about all the supporting services and how to set them up.

Below is what we should have for our files.


# Base image
FROM ruby:2.4.2

# Setup environment variables that will be available to the instance
ENV APP_HOME /produciton

# Installation of dependencies
RUN apt-get update -qq \
  && apt-get install -y \
      # Needed for certain gems
    build-essential \
         # Needed for postgres gem
    libpq-dev \
         # Needed for asset compilation
    nodejs \
    # The following are used to trim down the size of the image by removing unneeded data
  && apt-get clean autoclean \
  && apt-get autoremove -y \
  && rm -rf \
    /var/lib/apt \
    /var/lib/dpkg \
    /var/lib/cache \

# Create a directory for our application
# and set it as the working directory

# Add our Gemfile
# and install gems

ADD Gemfile* $APP_HOME/
RUN bundle install

# Copy over our application code

# Run our app
CMD bundle exec rails s -p ${PORT} -b ''

For more information about the Dockerfile, you can reference https://docs.docker.com/engine/reference/builder/.




version: '3'
    image: postgres
    build: .
      - .:/produciton
      - "3000:3000"
      PORT: "3000"
      PGHOST: "db"
      PGUSER: "postgres"
      PGDBNAME: "produciton"
      - db

Running our app

Now, we should be able to spin up the dockerized app, with its dependencies.

First, we'll need to take care of setting up the database in the new container.

  • Create database: docker-compose run web rake db:create
  • Run migrations: docker-compose run web rake db:migrate
  • Run seeds: docker-compose run web rake db:seed

Now, we should be able to run our containers via: docker-compose up. You should see something like this:

➜  produciton.com git:(master) ✗ docker-compose up
Starting producitoncom_db_1 ...
Starting producitoncom_db_1 ... done
Starting producitoncom_web_1 ...
Starting producitoncom_web_1 ... done
Attaching to producitoncom_db_1, producitoncom_web_1
db_1   | 2017-12-16 04:28:51.561 UTC [1] LOG:  listening on IPv4 address "", port 5432
db_1   | 2017-12-16 04:28:51.561 UTC [1] LOG:  listening on IPv6 address "::", port 5432
db_1   | 2017-12-16 04:28:51.622 UTC [1] LOG:  listening on Unix socket "/var/run/postgresql/.s.PGSQL.5432"
db_1   | 2017-12-16 04:28:51.754 UTC [24] LOG:  database system was shut down at 2017-12-16 04:27:48 UTC
db_1   | 2017-12-16 04:28:51.806 UTC [1] LOG:  database system is ready to accept connections
web_1  | => Booting Puma
web_1  | => Rails 5.1.4 application starting in development
web_1  | => Run `rails server -h` for more startup options
web_1  | Puma starting in single mode...
web_1  | * Version 3.11.0 (ruby 2.4.2-p198), codename: Love Song
web_1  | * Min threads: 5, max threads: 5
web_1  | * Environment: development
web_1  | * Listening on tcp://
web_1  | Use Ctrl-C to stop

Now, if we switch over to our browser, we should be able to point to localhost:3000 and see our app running.


Lastly, if we switch back to our terminal, we should see that our logs are actually working correctly.



Using Docker and Docker-Compose, we Dockerized a Rails app and its dependencies to allow us to conveniently spin up a Rails app and allow others to pull down the service and run it, without having to know about all of its dependencies and have them pre-configured on their box.