DevOps: Docker: Build locally

New to a team? New to a project? No need to spend all day or days fetching dependencies to make sure you have the configuration just right so the target application will run on your local computer. Docker and Docker Compose to the rescue. Docker provides the mechanism to have a build script for the target application. Docker Compose provides a higher level build to take care of standard infrastructure dependencies such as postgresql and redis. Performing the build using Docker and Docker Compose always for quick deployment of the application locally. Of course there is a necessary step of applying an application database snapshot to your local instance of Postgresql.

The Dockerfile:


FROM ruby:2.1.9-slim

ENV DEBIAN_FRONTEND noniteractive
COPY ./script/nodejs_setup_6.x.sh /tmp/nodejs_setup_6.x.sh
RUN chmod +x /tmp/nodejs_setup_6.x.sh && /tmp/nodejs_setup_6.x.sh

# nodejs automatically runs `apt-get update` so there's no need to run it again here
RUN apt-get install -y \
      apt-transport-https \
      build-essential \
      emacs24-nox \
      emacs-goodies-el \
      git-core \
      imagemagick \
      libbz2-dev \
      libcurl4-openssl-dev \
      libncurses-dev \
      libexpat-dev \
      libffi-dev \
      libpq-dev \
      libreadline-dev \
      libsqlite3-dev \
      libssl-dev \
      libxml2-dev \
      libxslt1-dev \
      libyaml-dev \
      logrotate \
      nodejs \
      openjdk-7-jre-headless \
      python-software-properties \
      sqlite3 \
      ssh \
      supervisor \
      texinfo \
      vim \
      zlib1g-dev \
      --fix-missing --no-install-recommends \
    && apt-get clean \
    && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*

RUN mkdir -p /hammerhead
WORKDIR /hammerhead

# add options to gemrc
RUN echo "gem: --no-document --no-ri --no-rdoc" > ~/.gemrc

COPY Gemfile Gemfile.lock /hammerhead/
COPY engines/ /hammerhead/engines/

RUN gem install bundler --no-ri --no-rdoc && bundle install --jobs 5 --retry 3

ENV SECRET_KEY_BASE $(openssl rand -base64 32)

RUN \
  mkdir -p log && \
  mkdir -p tmp/cache && \
  mkdir -p tmp/pids && \
  mkdir -p tmp/sockets && \
  mkdir -p public && \
  chmod -R a+rw log tmp public

# run puma
CMD bundle exec puma -C config/puma.rb

 

The Docker Compose configuration:


version: '2'
services:
  web:
    build:
      context: .
      dockerfile: Dockerfile
    env_file:
      - config/application.yml
    command: bundle exec puma -C config/puma.rb
    working_dir: /hammerhead
    environment:
      PORT: 3000
      DATABASE_URL: 'postgres://postgres:@postgres:5432/hammerhead_local'
      RAILS_ENV: 'local'
      REDIS_URL: 'redis://redis:6379'
    ports:
      - '3000:3000'
    links:
      - postgres
      - redis
    volumes_from:
      - postgres
  redis:
    image: redis:3.2-alpine
    ports:
      - '6379:6379'
  postgres:
    image: postgres:9.6
    volumes:
      - '.:/hammerhead'
 

Finally the exerpt from the application README file for putting it all together locally:

#### Grab files from AWS S3

You will need access to AWS S3. From there navigate to the hammerhead_local bucket. And copy these guys:

 2017-04-20.dump                     copy to:            /. (project root)
 application.yml                     copy to:            /config/

## Docker and Docker Compose Installation

### Clear unwanted containers Only needed on repeat attempts.

 $ docker rm $(docker ps -a -q) 

### Clear dangling images Only needed on repeat attempts.

 $ docker rmi $(docker images -q -f dangling=true) 

### Now the good stuff Create.

 $ docker-compose create

Build.

 $ docker-compose build

Start.

 $ docker-compose start

If you get some sort of network error (but only if you get an error) with start try the up command..

 $ docker-compose up

This will fire a non-daemon process that we do not want, but will probably solve the network issue. After it does its thing and the terminal is staring at you, kill the proces by Ctrl-C.

Now try the Start. Again.

 $ docker-compose start

Check for your container processes.

 $ docker ps 
 CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                    NAMES
 f40e4ad0ce01        hammerhead_web      "bundle exec puma ..."   About an hour ago   Up About an hour    0.0.0.0:3000->3000/tcp   hammerhead_web_1
 19761c628c84        postgres:9.6        "docker-entrypoint..."   About an hour ago   Up About an hour    5432/tcp                 hammerhead_postgres_1
 fd7d3e7b44bd        redis:3.2-alpine    "docker-entrypoint..."   About an hour ago   Up About an hour    0.0.0.0:6379->6379/tcp   hammerhead_redis_1

Now lets address the db. First create it.

 $ docker-compose exec web bundle exec rake db:create

Remember that file you copied to the project root a few steps back? Time to use it to load the database.

 $ docker-compose exec postgres pg_restore  -v -O -c -d 'postgres://postgres@postgres:5432/hammerhead_local' /hammerhead/2017-04-20.dump

When this completes, you can now hit the url for your local on port 3000 served by Puma

Now lets do a little bit of cleanup, we no longer need the snapshot so be gone with it!

 $ rm 2017-04-20.dump

Your are done. Can you say favorite beverage time?