Deploying Rails With Docker and Jenkins

#docker #sysadmin #jenkins

Normally I would use Capistrano to deploy a rails application, but I’ve switched to Docker and Jenkins. This is how I setup the registry server and built the image so I could pull it with Docker Compose.

For this guide, I’ll be using registry v2 with TLS and http basic auth.

Let’s get our TLS setup first with the following command:

mkdir -p certs && \
    openssl req \ 
    -newkey rsa:4096 -nodes -sha256 -keyout certs/domain.key \ 
    -x509 -days 365 -out certs/domain.crt

This will take you through the process needed to create a self-signed certificate for your repository.

Next, we’ll setup the http auth.

$ mkdir auth && htpasswd -bn reguser regpassword > auth/htpasswd

Once you’ve done that, install Docker Compose and use the following docker-compose.yml file:

registry:
  environment:
    REGISTRY_HTTP_TLS_CERTIFICATE: '/home/YOUR-USER/certs/domain.crt'
    REGISTRY_HTTP_TLS_KEY: '/home/YOUR-USER/certs/domain.key'
    REGISTRY_AUTH: 'htpasswd'
    REGISTRY_AUTH_HTPASSWD_REALM: 'Registry Realm'
    REGISTRY_AUTH_HTPASSWD_PATH: '/auth/htpasswd'
  image: registry:2
  ports:
    - '5000:5000'
  restart: always
  volumes:
    - /home/YOUR-USER/certs:/certs:ro
    - /home/YOUR-USER/auth:/auth:ro
    - /home/YOUR-USER/data:/var/lib/registry:rw

Now run

$ docker-compose up -d

Use

$ docker login myregistrydomain:5000

to login to the registry server once it is running.

Now that we have a registry to push to, it’s time to setup our Rails project for docker.

Add the following Dockerfile to your Rails project’s root:

FROM ruby:2.3.1

ARG uid=1000
ARG gid=1000
ARG user=app
ARG group=app

RUN groupadd -g ${gid} ${group} && \
    useradd -u ${uid} -g ${gid} -m -s /bin/bash ${user} && \
    apt-get update -qq && \
    apt-get install -y build-essential \
      libpq-dev \
      nodejs && \
    mkdir -p /usr/local/app

WORKDIR /usr/local/app

ADD Gemfile /usr/local/app/Gemfile
ADD Gemfile.lock /usr/local/app/Gemfile.lock

RUN bundle install

ADD . /usr/local/app

USER ${user}

CMD ["bundle", "exec", "rails", "s", "-p", "3000", "-b", "0.0.0.0"]

and in a docker-compose.yml file add the following:

version: '2'
services:
  db:
    image: postgres
  app:
    build: .
    volumes:
      - .:/usr/local/app
    ports:
      - "3000:3000"
    depends_on:
      - db

The Dockerfile creates a user for your app to run, adds the directory for your project to run in and then runs it so that it listens on port 3000 on all addresses. The docker-compose.yml file specifies a database and app image to run.

Next, we’re going to setup Jenkins. This guide assumes you already have an instance available to you and that has the Git plugin installed.

We’re going to create a Freestyle project from the New Items menu. Add your git repository under SCM and build triggers. I’m just going to manually trigger the build from the home screen so I won’t go over how to setup any triggers. Add a build step that executes a command and enter the following into the textarea:

./build.sh

Add the following build.sh to your Rails project and commit:

#!/bin/bash

set -e

docker login YOUR-REGISTRY:5000 -u reguser -p regpassword
docker build -t YOUR-REGISTRY:5000/APP-NAME .
docker push YOUR-REGISTRY:5000/APP-NAME

This script builds an image from your project and then pushes it to your local registry. Now you can pull your image down using whichever management system you want.

[1] [2] [3]