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
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 "$@"
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:
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"
We have a final file structure:
$ tree . . ├── Gemfile ├── docker │ ├── Dockerfile │ └── entrypoint.sh └── docker-compose.yml
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
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)
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