-
-
Save natevick/96c22b18b6cb31fa458fafba32fa000f to your computer and use it in GitHub Desktop.
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 "$@" |
Hmm, I have not run into that issue. I’ll check it on a fresh rails project tomorrow.
Alright. Let me know, please.
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.
I use ruby 2.6.5. I'll try again using those files, following the article, and send you updates about it
@luchiago any luck? I have made a few more tweaks to the files over the last week.
@nvick I didn't try with the modifications yet, but I will. Could you explain the reason for this ENV PATH /gems/bin:$PATH
?
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
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
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.
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
Are the gems gonna be cached? Or every time I run docker-compose up
they will be installed?
They are cached in a docker volume.
The entrypoint does a check for Gemfile changes on every docker-compose up
, but if there are no changes it moves on.
Cool man. It works now. Thank you so much for your help and for these files
Glad it works and helps!
Great Gist, even two years on ;-) I also love the blog on hint.io. But allow me one question: In entrypoint.sh, you call unlock_setup
followed by while [ -f $APP_SETUP_LOCK ]; do wait_setup; done
-- but if I am not mistaken, the call to unlock_setup
will basically render the locking mechanism ineffective? It seems to me that this function call is erroneous, or am I missing something?
@bovender Thanks for the kind words! I have gone back and forth on that section of the entrypoint with my team over the years. I honestly believe we landed there because if a setup.lock file did not get cleaned up for some reason when the entrypoint was run again it would stall the starting of the app. Feel free to experiment with it to see what works best in your situation.
Thanks!
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 removeENV PATH /gems/bin:$PATH
. The same forchown
. I guess the problem is setting the variablePATH
withENV PATH /gems/bin:$PATH
. What are your thoughts?