Hello Rok: Part 1, Rails on Docker

This is a very simple Hello World guide for getting your Rails application running on Kubernetes.

In Part 1 we are going to cover how to get Rails running on Docker. In Part 2, we are going to learn how to run Rails on K8s in our local machine. In Part 3, we are going to deploy our Kubernetes setup to the cloud.

Every step consists of a title, an explanation (in italic) and links for instructions. If you want the quickest setup possible, skip the explanations for now.

Code

If you want to skip this guide feel free to navigate through the code here. All running steps are pushed to Github. For Part 1, take a look at branch part_1.


1- Install Docker

The first step is to install the Docker platform on your local machine. I’m running docker over OSX. So be aware that maybe there are some steps that may not be the same for other operating systems.

For a complete installation guide, see here.

2- Identify Components

The idea here is to run different components in different containers, so we can easily scale only the piece that needs to scale.

You can divide your application into as many components as you like. One basic rule to easily determine your components is to identify all the different services that you are running in order to have your whole application running. In our basic Hello-Rok App, we have only 2 components: web application and database. Other typical Rails components are Redis, Sidekiq, Postgres, etc.

Every component should run its own image. In Docker, an image is defined in a Dockerfile. For more information about Dockerfiles, see Docker user guide and Dockerfile reference. You can define a Dockerfile for your own image or you can use a public image.

For our basic example, we are going to use the official Postgres image for our db service and the following Dockerfile for defining our web app image:

FROM ruby:2.3.3
RUN apt-get update -qq && apt-get install -y build-essential libpq-dev nodejs
RUN mkdir /hello-rok
WORKDIR /hello-rok
COPY Gemfile /hello-rok/Gemfile
COPY Gemfile.lock /hello-rok/Gemfile.lock
RUN bundle install
ADD . /hello-rok
COPY docker-entrypoint.sh /usr/local/bin
ENTRYPOINT ["docker-entrypoint.sh"]

Save the above code in the root directory under the name “Dockerfile”. And create a docker-entrypoint.sh file also at the root, with the following content:

#!/bin/sh
set -e
if [ -f tmp/pids/server.pid ]; then
rm tmp/pids/server.pid
fi
exec bundle exec "$@"

3- Define components as services

As we saw in the previous step, we are using one image/container for each service/component. In a multi-container app, there are numerous ways to orchestrate this architecture.

First, we are going to explore one of the most used tools (before K8s) for running these services: Docker Swarm, the proposed solution from Docker Enterprise. We are going to discuss it briefly, keeping in mind that the goal of this guide is to run Rails on Kubernetes. Docker CE proposes a docker-compose.yml file where you can define some characteristics of how to build and run our services. It’s important to note that you can run this file either:

a) using Docker Swarm (out of the scope of this guide) or,

b) using the Docker Compose tool, where you can run docker-compose commands to build and run services as you would using the docker command.

We define our services in a docker-compose.yml file in the root of our project:

version: '3.2'
services:
db:
image: postgres
volumes:
- ./tmp/db:/var/lib/postgresql/data
app:
build: .
image: iufuenza/hello-rok:v1
command: "bin/bundle exec rails s -p 3000 -b 0.0.0.0"
depends_on:
- db
volumes:
- .:/hello-rok
ports:
- "3000:3000"

4- Build

As noted, we have 2 services defined. The db is using the Postgres official image, that means that we don’t have to bother building it, we only have to run it. For building our web app service we can either user docker commands (if you are running on OSX, the tool comes by default when installing Docker), or docker commands.

Build app with docker compose cli:

docker-compose build app

In order to build the app using docker cli, we will need to specify the same parameters used in the docker-compose.yml, such as ports, volumes, commands, and others. Or we can add them to the Dockerfile (see here), and then build and tag (-t) our image with the following command (mind the trailing dot):

docker build -t iufuenza/hello-rok:v1 .

5- Run

Again, we can either use docker compose commands, or use docker commands.

If we want to build and run everything at once, we run:

docker-compose up --build

To run our web app using docker-compose cli:

docker-compose up app

To run our web app using docker cli:

docker run iufuenza/hello-rok:v1

At this point, you should have your application up and running. Now we need to create the initialize the database inside the web app container:

docker-compose run app rails db:create

Now you can go to http://localhost:3000 in your browser and see the application running.