Simple Docker Setup for Ruby development
When forking a project, I like having a simple Docker setup to quickly start.
First, I create a docker
folder and I add the following files in it:
Then, I add a docker-compose.yml in the root folder of the project. Simply run:
docker compose run --rm cli <your_bundle_exec_command>
⚠️ The image will be built only at the first execution and subsequent calls won’t automatically rebuild the initial image.
If your making changes along the way you need to add the --build
option:
docker compose run --build --rm cli <your_bundle_exec_command>
Dockerfile
ARG RUBY_VERSION=3
FROM ruby:${RUBY_VERSION}-alpine
ENV BUNDLE_PATH /usr/local/bundle/gems
ENV LIB_PATH /var/gem
# --enable-frozen-string-literal maybe not be suitable for all projects
ENV RUBYOPT --enable-frozen-string-literal --yjit
# taken from dockerfile-rails https://github.com/fly-apps/dockerfile-rails/blob/f34fab26ae3b77a14c15b4bafb0fb91f911b8d8a/lib/generators/dockerfile_generator.rb#L981-L983
ENV LD_PRELOAD libjemalloc.so.2
ENV MALLOC_CONF dirty_decay_ms:1000,narenas:2,background_thread:true
# these packages should cover the basics but you might need more
RUN apk add --update --no-cache make g++ gcc git libc-dev gcompat jemalloc && \
gem update --system && gem install bundler
WORKDIR $LIB_PATH
COPY /docker/entrypoint.sh /usr/local/bin/docker-entrypoint.sh
RUN chmod +x /usr/local/bin/docker-entrypoint.sh
ENTRYPOINT ["docker-entrypoint.sh"]
entrypoint.sh
#!/bin/sh
set -e
# Useful information
echo -e "$(ruby --version)\nrubygems $(gem --version)\n$(bundle version)"
# Can run different gemfiles located in `gemfiles` folder
if [ -z "${GEMFILE}" ]
then
echo "Running default Gemfile"
else
export BUNDLE_GEMFILE="./gemfiles/${GEMFILE}.gemfile"
echo "Running gemfile: ${GEMFILE}"
fi
# Keep gems in the latest possible state
(bundle check || bundle install) && bundle update && exec bundle exec ${@}
docker-compose.yml
volumes:
gems:
x-base: &base
build:
context: .
dockerfile: docker/Dockerfile
args:
# you can set a specific version
- RUBY_VERSION=${RUBY_VERSION:-3}
stdin_open: true
tty: true
volumes:
- .:/var/gem
- gems:/usr/local/bundle
# if you have multiple gemfiles (see entrypoint.sh),
# simply uncomment the following lines and change <gemfile_name>
# environment:
# GEMFILE: <gemfile_name>
services:
cli:
<<: *base
If you need to run a server, you can add another service that will run a command and expose a port. Here’s a example to with jekyll
with live reload
server:
<<: *base
ports:
- 4000:4000
# need to change the host since we're running in Docker
command: [ 'jekyll', 'serve', '--host', '0.0.0.0', '-l' ]
To start the service: docker compose run --rm --service-ports server