CODEX
Dockerize your Ruby on Rails App
What and Why Docker is Useful?
Docker allows you to package up an application or service with all of its dependencies into a standardized unit. This unit is typically labeled as a Docker image.
In essence, Docker allows you to containers on top of a Host OS (Ubuntu, Mac, Windows) without having difficult configuration.
Installing Docker
Download and Install Docker from https://www.docker.com/
Creating Rails App
rails new rails_docker -d postgresql
cd rails_docker
bundle install
rails server
Currently when we visit localhost:3000, it’s running from our local machine not yet from the docker image.
Setup Docker for Rails
Create a Dockerfile on the root directory of your project and add the following content.
Note: I’m currently using Rails 6.0.2.2 and Ruby 2.6.0.
FROM ruby:2.6.0-slimRUN apt-get update -qq \
&& apt-get install -y \
# Needed for certain gems
build-essential \
# Needed for postgres gem
libpq-dev \
# Others
nodejs \
vim-tiny \
# 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 \
/var/lib/log# Changes localtime to Singapore
RUN cp /usr/share/zoneinfo/Asia/Singapore /etc/localtimeRUN mkdir /rails_dockerWORKDIR /rails_dockerCOPY Gemfile /rails_docker/GemfileCOPY Gemfile.lock /rails_docker/Gemfile.lockRUN bundle installADD . /rails_dockerCMD bash -c "rm -f tmp/pids/server.pid && rails s -p 3000 -b '0.0.0.0'"
Dockerfile is a human readable shell script and this does the following:
- Fetches ruby 2.6.0-slim from DockerHub, this is the base image and it has a lightweight operating system called slim with ruby 2.6.0
- Running the dependencies
- Changing the image timezone to Singapore (or change it depending on the timezone you want)
- Creating a rails_docker directory inside the image and setting this up as a work directory
- Copying the Gemfile and Gemfile.lock from the project to the rails_docker directory image
- Running bundle install in the image
- Running rails app using shell command in localhost:3000
In order to run these commands, run this using
docker build .
Once the building process is finished, run `docker images` to see the list of docker images you just built.
To run the Rails app. Tag the built docker image and Run it in localhost:3000
docker tag <image-id> rails_docker:v1.0.0docker run -it -p 3000:3000 rails_docker:v1.0.0 bundle exec rails server -b 0.0.0.0 -p 3000
Run the Rails app using docker-compose
We now have a working Ruby on Rails app on top of Docker.
We may also want to use other services like Postgres, Redis, Sidekiq. To achieve this we can use docker-compose
Create a docker-compose.yml in the root directory of our project.
version: '3'
services:
db:
image: postgres:alpine
restart: always
volumes:
- ./tmp/db:/var/lib/postgresql/data
ports:
- "5432:5432" app:
build: .
restart: always
command: bash -c "rm -f tmp/pids/server.pid && rails s -p 3000 -b '0.0.0.0'"
volumes:
- .:/rails_docker
- bundle_path:/bundle
ports:
- "3000:3000"
depends_on:
- dbvolumes:
bundle_path:
In this configuration file. We define 2 services:
- Postgres as our DB. It’s currently using an image came from DockerHub. It’s currently running on port 5432 of host OS
- Rails App which depends on db and running on port 3000
We also added the restart flag to always so that even we restart the host OS, the docker image will still run.
List all the running docker images using docker ps
after running docker-compose up
We also need to change our database.yml
to connect to our postgres image.
default: &default
adapter: postgresql
encoding: unicode
pool: <%= ENV.fetch("RAILS_MAX_THREADS") %>development:
<<: *default
database: rails_docker_development
host: db
username: postgres
port: 5432
The host is now pointing to db
because our postgres is running in db service
We also need to run the rake db:create db:migrate
manually using
docker-compose run app rake db:create
You can also bundle install using this command by just changing the last part.
Run the application using docker-compose up
Now, you should be able to see the rails app in localhost:3000
Running Rails Console
As part of our development, it’s also important to access our database through rails console
To do this run docker ps
and access the app image using docker exec -it <container_id> sh
This will access the working directory. You can also list all the folders using ls.
Access Rails console now inside the image using rails console
Distributing Image to DockerHub
To distribute the image in DockerHub. Run the following commands
- Create account in Dockerhub
- Create Respository
- On the local machine run
docker build -t <username>/<container_image> .
- Push it to Dockerhub Repo using
docker push <username>/<container_name>
- To pull this image run `docker pull <username>/<container_name>