Skip to content

Instantly share code, notes, and snippets.

@nvick nvick/Dockerfile

Last active Jul 25, 2020
Embed
What would you like to do?
Base Rails Docker Development Environment
default: &default
adapter: postgresql
encoding: unicode
pool: <%= ENV.fetch("RAILS_MAX_THREADS", 5) %>
username: <%= ENV.fetch("DATABASE_USER", 'postgres') %>
host: <%= ENV.fetch("DATABASE_HOST", 'localhost') %>
port: 5432
development:
<<: *default
database: docker_development
test:
<<: *default
database: docker_test
production:
<<: *default
database: docker_production
username: docker
password: <%= ENV['DOCKER_DATABASE_PASSWORD'] %>
version: '3.7'
services:
rails:
build:
context: ./docker/ruby
args:
- RUBY_VERSION=2.6.5
- BUNDLE_JOBS=15
- BUNDLE_RETRY=2
- NODE_VERSION=12
- INSTALL_PG_CLIENT=true
- UID=500
- GID=500
environment:
- DATABASE_USER=postgres
- DATABASE_HOST=postgres
command: bundle exec rails server -p 3000 -b '0.0.0.0'
entrypoint: docker/ruby/entrypoint.sh
volumes:
- .:/app:cached
- gems:/gems
- node_modules:/app/node_modules
- packs:/app/public/packs
- rails_cache:/app/tmp/cache
ports:
- "3000:3000"
user: ruby
tty: true
stdin_open: true
depends_on:
- postgres
postgres:
image: postgres:11
environment:
- POSTGRES_HOST_AUTH_METHOD=trust
volumes:
- postgres:/var/lib/postgresql/data
volumes:
gems:
postgres:
node_modules:
packs:
rails_cache:
ARG RUBY_VERSION=2.6
FROM ruby:$RUBY_VERSION
ARG DEBIAN_FRONTEND=noninteractive
ARG NODE_VERSION=11
RUN curl -sL https://deb.nodesource.com/setup_$NODE_VERSION.x | bash -
RUN curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - && \
echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list
RUN apt-get update && apt-get install -y \
build-essential \
nodejs \
yarn \
locales \
git \
netcat \
vim \
sudo
ARG UID
ENV UID $UID
ARG GID
ENV GID $GID
ARG USER=ruby
ENV USER $USER
RUN groupadd -g $GID $USER && \
useradd -u $UID -g $USER -m $USER && \
usermod -p "*" $USER && \
usermod -aG sudo $USER && \
echo "$USER ALL=NOPASSWD: ALL" >> /etc/sudoers.d/50-$USER
ENV LANG C.UTF-8
ENV BUNDLE_PATH /gems
ENV BUNDLE_HOME /gems
ARG BUNDLE_JOBS=20
ENV BUNDLE_JOBS $BUNDLE_JOBS
ARG BUNDLE_RETRY=5
ENV BUNDLE_RETRY $BUNDLE_RETRY
ENV GEM_HOME /gems
ENV GEM_PATH /gems
ENV PATH /gems/bin:$PATH
ARG INSTALL_PG_CLIENT=false
RUN if [ "$INSTALL_PG_CLIENT" = true ]; then \
apt-get install -y postgresql-client \
;fi
RUN mkdir -p "$GEM_HOME" && chown $USER:$USER "$GEM_HOME"
RUN mkdir -p /app && chown $USER:$USER /app
WORKDIR /app
RUN mkdir -p node_modules && chown $USER:$USER node_modules
RUN mkdir -p public/packs && chown $USER:$USER public/packs
RUN mkdir -p tmp/cache && chown $USER:$USER tmp/cache
USER $USER
RUN gem install bundler
#! /bin/bash
set -e
: ${APP_PATH:="/app"}
: ${APP_TEMP_PATH:="$APP_PATH/tmp"}
: ${APP_SETUP_LOCK:="$APP_TEMP_PATH/setup.lock"}
: ${APP_SETUP_WAIT:="5"}
# 1: Define the functions to lock and unlock our app container's setup
# processes:
function lock_setup { mkdir -p $APP_TEMP_PATH && touch $APP_SETUP_LOCK; }
function unlock_setup { rm -rf $APP_SETUP_LOCK; }
function wait_setup { echo "Waiting for app setup to finish..."; sleep $APP_SETUP_WAIT; }
# 2: 'Unlock' the setup process if the script exits prematurely:
trap unlock_setup HUP INT QUIT KILL TERM EXIT
# 3: Wait for postgres to come up
echo "DB is not ready, sleeping..."
until nc -vz postgres 5432 &>/dev/null; do
sleep 1
done
echo "DB is ready, starting Rails."
# 4: Specify a default command, in case it wasn't issued:
if [ -z "$1" ]; then set -- bundle exec rails server -p 3000 -b 0.0.0.0 "$@"; fi
# 5: Run the checks only if the app code is executed:
if [[ "$3" = "rails" ]]
then
# Clean up any orphaned lock file
unlock_setup
# 6: Wait until the setup 'lock' file no longer exists:
while [ -f $APP_SETUP_LOCK ]; do wait_setup; done
# 7: 'Lock' the setup process, to prevent a race condition when the
# project's app containers will try to install gems and set up the
# database concurrently:
lock_setup
# 8: Check if dependencies need to be installed and install them
bundle install
yarn install
# 9: Run migrations or set up the database if it doesn't exist
# Rails >= 6
bundle exec rails db:prepare
# Rails < 6
# bundle exec rake db:migrate 2>/dev/null || bundle exec rake db:setup
# 10: 'Unlock' the setup process:
unlock_setup
# 11: If the command to execute is 'rails server', then we must remove any
# pid file present. Suddenly killing and removing app containers might leave
# this file, and prevent rails from starting-up if present:
if [[ "$4" = "s" || "$4" = "server" ]]; then rm -rf /app/tmp/pids/server.pid; fi
fi
# 12: Replace the shell with the given command:
exec "$@"
@luchiago

This comment has been minimized.

Copy link

luchiago commented May 1, 2020

Hi. I was reading your article, btw it's a good tutorial, about dockerizing a rails app and I tried to implement it on my app. I was having trouble with RUN mkdir -p commands in dockerfile bc it wasn't finding the command mkdir, so I had to remove ENV PATH /gems/bin:$PATH. The same for chown. I guess the problem is setting the variable PATH with ENV PATH /gems/bin:$PATH. What are your thoughts?

@nvick

This comment has been minimized.

Copy link
Owner Author

nvick commented May 1, 2020

Hmm, I have not run into that issue. I’ll check it on a fresh rails project tomorrow.

@luchiago

This comment has been minimized.

Copy link

luchiago commented May 1, 2020

Alright. Let me know, please.

@nvick

This comment has been minimized.

Copy link
Owner Author

nvick commented May 1, 2020

I did find a couple of typos in docker-compose file that I fixed, but other than that it built the container as expected with no changes to the Dockerfile. What version of Ruby are you using for your app? I've used this config with Ruby 2.2-2.7 without much tweaking, but older versions run on an unsupported version of Debian.

@luchiago

This comment has been minimized.

Copy link

luchiago commented May 2, 2020

I use ruby 2.6.5. I'll try again using those files, following the article, and send you updates about it

@nvick

This comment has been minimized.

Copy link
Owner Author

nvick commented May 11, 2020

@luchiago any luck? I have made a few more tweaks to the files over the last week.

@luchiago

This comment has been minimized.

Copy link

luchiago commented May 11, 2020

@nvick I didn't try with the modifications yet, but I will. Could you explain the reason for this ENV PATH /gems/bin:$PATH?

@nvick

This comment has been minimized.

Copy link
Owner Author

nvick commented May 11, 2020

Yes, we need to prepend the path with where the gem executables are. The prepend is required to override the prepend that is done by the official Ruby Docker container for the gem executable location. https://github.com/docker-library/ruby/blob/a6b23d587aa4ce804f69b40d3fb48bc27c4a39db/2.6/buster/Dockerfile#L83

@luchiago

This comment has been minimized.

Copy link

luchiago commented May 11, 2020

There's a problem with permissions ERROR: Cannot start service rails: OCI runtime create failed: container_linux.go:349: starting container process caused "exec: \"docker/ruby/entrypoint.sh\": permission denied": unknown

I tried to solve with chown +x file

@luchiago

This comment has been minimized.

Copy link

luchiago commented May 11, 2020

Yes, we need to prepend the path with where the gem executables are. The prepend is required to override the prepend that is done by the official Ruby Docker container for the gem executable location. https://github.com/docker-library/ruby/blob/a6b23d587aa4ce804f69b40d3fb48bc27c4a39db/2.6/buster/Dockerfile#L83

Now I get it, thanks.

@nvick

This comment has been minimized.

Copy link
Owner Author

nvick commented May 11, 2020

There's a problem with permissions ERROR: Cannot start service rails: OCI runtime create failed: container_linux.go:349: starting container process caused "exec: \"docker/ruby/entrypoint.sh\": permission denied": unknown

Make sure the entrypoint is executable: chmod +x docker/ruby/entrypoint.sh

@luchiago

This comment has been minimized.

Copy link

luchiago commented May 11, 2020

Are the gems gonna be cached? Or every time I run docker-compose up they will be installed?

@nvick

This comment has been minimized.

Copy link
Owner Author

nvick commented May 11, 2020

They are cached in a docker volume.

@nvick

This comment has been minimized.

Copy link
Owner Author

nvick commented May 11, 2020

The entrypoint does a check for Gemfile changes on every docker-compose up, but if there are no changes it moves on.

@luchiago

This comment has been minimized.

Copy link

luchiago commented May 11, 2020

Cool man. It works now. Thank you so much for your help and for these files

@nvick

This comment has been minimized.

Copy link
Owner Author

nvick commented May 11, 2020

Glad it works and helps!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.