DEV Community

Slava Pocheptsov
Slava Pocheptsov

Posted on • Originally published at pocheptsov.com

Bootstrap Ruby project in Docker

In the Ruby community, we have a lot of tools to help us to create a new project. But, if you are a beginner, you can be lost in the middle of all these tools. This code is a simple way to start a new project in Ruby using Docker without Rails, dip or any other framework dependencies.
Great examples to start a new project in Ruby:

Development environment

Requirements

Installed Docker with BuildKit support and docker-compose are required:

Docker setup

This article will use Docker Compose to run the Ruby code. Docker Compose is a tool for defining and running multi-container Docker applications. With Compose, you use a YAML file to configure your application's services. Then, you create and start all the services from the configuration with a single command.

Let's build the image with the following docker/Dockerfile where we can pass the RUBY_VERSION, DEBIAN_CODENAME as build arguments. The UID and GID are the neat parameters to configure file permissions for container volume that will be set in docker/docker-compose. Another important thing is that we are using a non-root user (UID:GID -> app_user:app_group) to run the application.

ARG RUBY_VERSION=3.1.2
ARG DEBIAN_CODENAME=bullseye
FROM ruby:$RUBY_VERSION-$DEBIAN_CODENAME

ENV APP_DIR=/app
ARG UID=1000
ARG GID=1000

RUN groupadd --gid $GID app_group \
  && useradd --no-log-init --uid $UID --gid $GID app_user --create-home \
  \
  && mkdir -p $APP_DIR \
  && chown -R $UID:$GID $APP_DIR \
  \
  && gem update bundler \
  && chown -R $UID:$GID /usr/local/bundle \
  && bundler --version

# copy files required for `bundle install` step
COPY --chown=$UID:$GID Gemfile* $APP_DIR/

# entry point setup
COPY --chmod=755 docker/entrypoint.sh /usr/bin/

# switching to app user
USER $UID:$GID
WORKDIR $APP_DIR

RUN echo "!!!!! Install gems !!!!!" \
  && bundle install -j "$(($(nproc)+1))"

ENTRYPOINT ["entrypoint.sh"]

CMD /bin/bash
Enter fullscreen mode Exit fullscreen mode

Docker entrypoint script docker/entrypoint.sh can be used to run commands as a non-root user on container start:

#!/bin/bash -e

export PATH="$PATH:/app"

bundle check || bundle install -j "$(($(nproc) + 1))"

# Then exec the container's main process (what's set as CMD in the Dockerfile).
exec "$@"
Enter fullscreen mode Exit fullscreen mode

In this article, we have a simple Docker environment with Ruby-only app service. The docker-compose.yml file is responsible for creating the containers and the docker/Dockerfile is accountable for creating the image.

version: '3'
services:
  app:
    build:
      context: .
      dockerfile: docker/Dockerfile
      args:
        RUBY_VERSION: 3.1.2
        DEBIAN_CODENAME: bullseye
        UID: 1000
        GID: 1000
    environment:
      RAILS_ENV: development
    volumes:
      - .:/app:delegated
      - bundle:/usr/local/bundle
    stdin_open: true
    tty: true
volumes:
  bundle:
Enter fullscreen mode Exit fullscreen mode

Gemfile is copied to the container and installed gems. The bundle volume is used to cache the gems.

# frozen_string_literal: true

source "https://rubygems.org"

gem "byebug"
Enter fullscreen mode Exit fullscreen mode

We have a final file structure:

$ tree .
.
├── Gemfile
├── docker
│   ├── Dockerfile
│   └── entrypoint.sh
└── docker-compose.yml
Enter fullscreen mode Exit fullscreen mode

To run app container in other OS versions, different user/group ids, build composed containers with docker-compose build --build-arg RUBY_VERSION="3.0.4" --build-arg DEBIAN_CODENAME="buster" --build-arg UID="1001" --build-arg GID="1001", re-build it docker-compose build --no-cache. All the build arguments are optional.

The development environment can be started with

docker-compose run app
Enter fullscreen mode Exit fullscreen mode

and then run any ruby commands.

The complete repository source code is available on docker-rails-bootstrap. Feel free to use it as a template for your projects. If you have any questions, feel free to ask them in the comments or reach out to me at @pocheptsov.

Next steps

In the following article, we will add Rails app to the project and compare full-size solution with our skeleton bootstrap.

Top comments (1)

Collapse
 
giovapanasiti profile image
Giovanni Panasiti

Since I guess this one should be an article for beginners why don't you add the database service in docker compose and show them how to be completely independent from the host machine