Skip to content

Dockerfile setup improvements #732

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 43 commits into from
Jun 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
3a80017
WIP
JulianPasquale Dec 1, 2023
cd8b02a
WIP: Improve dockerfile, add version for node, yarn
PerezIgnacio Dec 13, 2023
a458d08
bundler changes
smerlo Dec 27, 2023
10789f7
Add ENTRYPOINT to dockerfile
guillermoap Jan 3, 2024
fa1c8d2
Fix tests with docker
PerezIgnacio Jan 10, 2024
e51fee7
Update docker-compose. Do we need to precomiple assets to access the …
JulianPasquale Jan 17, 2024
2169cd7
Merge branch 'main' into improve-dev-docker
PerezIgnacio Jan 18, 2024
271ca0f
Revert "Upgrade to Ruby 3.3 (#571)"
PerezIgnacio Jan 18, 2024
8f5518f
Add support for capybara tests with docker
PerezIgnacio Jan 23, 2024
de3c6d7
Change depends_on to web service in compose
PerezIgnacio Jan 24, 2024
9e1f93c
docker compose capybara config
smerlo Jan 24, 2024
775c5ed
Config in spec_helper
PerezIgnacio Jan 31, 2024
73ae605
Merge branch 'main' into improve-dev-docker
JulianPasquale Feb 7, 2024
917d96d
Start with prod Dockerfile
JulianPasquale Feb 7, 2024
b999a3f
Improve prod docker file
PerezIgnacio Feb 14, 2024
9f455e3
Progress reducing final image size
JulianPasquale Feb 21, 2024
41cbedd
Use slim image, remove spring, fixes in dockerfile
PerezIgnacio Feb 28, 2024
f7d7861
Remove bloated floders from docker build
guillermoap Mar 6, 2024
8103466
add jemalloc to dockerfile.prod
smerlo Mar 25, 2024
618164a
change docker compose
smerlo Mar 25, 2024
458f168
Add back ruby 3.3.0
PerezIgnacio Apr 8, 2024
4f7dc3b
Fix dev dockerfile
PerezIgnacio Apr 8, 2024
10463ec
Merge branch 'main' into improve-dev-docker
PerezIgnacio Apr 8, 2024
825967c
Use bin/dev in docker-compose
PerezIgnacio Apr 9, 2024
aec76c5
Fixes
PerezIgnacio Apr 10, 2024
d0a1713
Add docs
PerezIgnacio Apr 11, 2024
1c2f6c0
Use watch in docker-compose
JulianPasquale Apr 23, 2024
0c4e291
Separate chrome server to different dockercompose
PerezIgnacio Apr 29, 2024
7903097
Update bin files to execute tests without running the server
axelpontetto May 7, 2024
ad9db6b
Remove compose dependency + add -rm option to rspec command
JulianPasquale May 9, 2024
7c8616f
Fix rspec bin command
JulianPasquale May 13, 2024
c77ba8f
Merge branch 'main' into improve-dev-docker
JulianPasquale May 13, 2024
83b22a4
Docs WIP
JulianPasquale May 13, 2024
54f20ff
Update docker.md
smerlo May 20, 2024
1457396
Update docker.md
PerezIgnacio May 27, 2024
ba928cc
Update docker.md
JulianPasquale May 27, 2024
badeec9
Update command for dev Dockerfile and compose
JulianPasquale May 27, 2024
96d4ebd
Merge branch 'main' into improve-dev-docker
PerezIgnacio May 27, 2024
a21a89b
Fix linters
PerezIgnacio May 28, 2024
e1ed754
Setup node on GHA
JulianPasquale May 28, 2024
1fedd3f
Update yarn version to not include patch number
JulianPasquale May 28, 2024
9d6f2cb
Add yarn version && remove compose version
axelpontetto Jun 10, 2024
0797cbd
Fix pr comments
smerlo Jun 10, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 27 additions & 16 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -1,35 +1,46 @@
# See https://docs.docker.com/engine/reference/builder/#dockerignore-file for more about ignoring files.

.git
.gitignore
.github

# Ignore bundler config.
/.bundle
.bundle

# Ignore all default key files
config/master.key
config/credentials/*.key

# Ignore all logfiles and tempfiles.
/log/*
/tmp/*
!/log/.keep
!/tmp/.keep
log/*
tmp/*
!log/.keep
!tmp/.keep

# Ignore pidfiles, but keep the directory.
/tmp/pids/*
!/tmp/pids/
!/tmp/pids/.keep
tmp/pids/*
!tmp/pids/
!tmp/pids/.keep

# Ignore storage (uploaded files in development and any SQLite databases).
/storage/*
!/storage/.keep
/tmp/storage/*
!/tmp/storage/
!/tmp/storage/.keep
storage/*
!storage/.keep
tmp/storage/*
!tmp/storage/
!tmp/storage/.keep

public/assets

/public/assets
coverage

# Ignore node_modules
/node_modules
node_modules

# Ignore .env files
!.env.test
.env*
!.env.test

.DS_Store
.byebug_history

vendor/bundle
15 changes: 15 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@ jobs:
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version-file: '.nvmrc'
cache: 'yarn'
- name: Setup Ruby
uses: ruby/setup-ruby@v1
with:
Expand Down Expand Up @@ -85,6 +90,11 @@ jobs:
if [ $(git diff ${{ github.event.before }} ${{ github.event.after }} --name-only | grep 'spec/requests/api' | wc -l) -gt 0 ]; then
echo "OPENAPI=true" >> $GITHUB_ENV
fi
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version-file: '.nvmrc'
cache: 'yarn'
- name: Setup Ruby
uses: ruby/setup-ruby@v1
with:
Expand Down Expand Up @@ -173,6 +183,11 @@ jobs:
run: |
./cc-test-reporter sum-coverage coverage/**/*.json
./cc-test-reporter upload-coverage
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version-file: '.nvmrc'
cache: 'yarn'
- name: Setup Ruby
if: ${{ env.OPENAPI }}
uses: ruby/setup-ruby@v1
Expand Down
1 change: 1 addition & 0 deletions .nvmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
20.10.0
99 changes: 71 additions & 28 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,45 +1,88 @@
FROM ruby:3.3.1
ARG RUBY_VERSION=3.3.1
ARG NODE_VERSION=20.10.0
ARG YARN_VERSION=1.22.19

RUN apt-get update -qq && \
apt-get install -y build-essential libssl-dev libpq-dev less vim nano libsasl2-dev
RUN curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add -
RUN echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list

RUN mkdir -p /etc/apt/keyrings
RUN curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg

ENV NODE_MAJOR=18
RUN echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_$NODE_MAJOR.x nodistro main" | tee /etc/apt/sources.list.d/nodesource.list
# Use Node image so we can pull the binaries from here.
FROM node:$NODE_VERSION as node

RUN apt update && apt install -y yarn nodejs
# Ruby build image.
FROM ruby:${RUBY_VERSION}-slim as base

# Setup environment variables.
ENV WORK_ROOT /src
ENV APP_HOME $WORK_ROOT/myapp/
ENV APP_HOME $WORK_ROOT/app
ENV LANG C.UTF-8
ENV GEM_HOME $WORK_ROOT/bundle
ENV BUNDLE_BIN $GEM_HOME/gems/bin
ENV PATH $GEM_HOME/bin:$BUNDLE_BIN:$PATH
ENV BUNDLE_PATH $APP_HOME/vendor/bundle

# Set prod environment to avoid installing dev dependencies
ENV BUNDLE_WITHOUT development:test
ENV BUNDLE_DEPLOYMENT 1
ENV RAILS_ENV production
ENV NODE_ENV production

# Throw-away build stage to reduce size of final image
FROM base as builder

RUN gem install bundler
RUN apt-get update -qq && \
apt-get install -y build-essential libssl-dev libpq-dev git libsasl2-dev && \
rm -rf /var/lib/apt/lists/*

# Copy node binaries from node image.
COPY --from=node /usr/local /usr/local
COPY --from=node /opt /opt

# Create app directory.
RUN mkdir -p $APP_HOME

RUN bundle config --path=$GEM_HOME
# Setup work directory.
WORKDIR $APP_HOME

# Copy dependencies files and install libraries.
COPY --link Gemfile Gemfile.lock package.json yarn.lock ./

RUN gem install bundler && bundle install -j 4 && yarn install --frozen-lockfile && \
bundle exec bootsnap precompile --gemfile && \
rm -rf ~/.bundle/ $BUNDLE_PATH/ruby/*/cache $BUNDLE_PATH/ruby/*/bundler/gems/*/.git

# Copy application code
COPY --link . .

# Precompile bootsnap code for faster boot times
RUN bundle exec bootsnap precompile app/ lib/

# Precompiling assets for production without requiring secret RAILS_MASTER_KEY
RUN SECRET_KEY_BASE=DUMMY ./bin/rails assets:precompile

# Build runtime image.
FROM base

# Install packages needed for deployment
RUN apt-get update -qq && \
apt-get install --no-install-recommends -y curl libpq-dev libvips libjemalloc2 && \
apt-get clean

# Create app directory.
RUN mkdir -p $APP_HOME

# Setup work directory.
WORKDIR $APP_HOME

ADD Gemfile ./
ADD Gemfile.lock ./
RUN bundle update --bundler
RUN bundle install
# Copy everything from the builder image
COPY --link . .
COPY --from=builder $APP_HOME/public/ $APP_HOME/public/
COPY --from=builder $APP_HOME/tmp/ $APP_HOME/tmp/
COPY --from=builder $APP_HOME/vendor/ $APP_HOME/vendor/

ADD package.json ./
ADD yarn.lock ./
RUN ln -s /usr/lib/*-linux-gnu/libjemalloc.so.2 /usr/lib/libjemalloc.so.2

RUN yarn install
# Deployment options
ENV RAILS_LOG_TO_STDOUT true
ENV RAILS_SERVE_STATIC_FILES true
ENV LD_PRELOAD=/usr/lib/libjemalloc.so.2

ADD . $APP_HOME
# Entrypoint prepares the database.
ENTRYPOINT ["./bin/docker-entrypoint"]

# Start the server by default, this can be overwritten at runtime
EXPOSE 3000

ENTRYPOINT bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -b 0.0.0.0 -p 3000"
CMD ["./bin/rails", "server"]
47 changes: 47 additions & 0 deletions Dockerfile.dev
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
ARG RUBY_VERSION=3.3.1
ARG NODE_VERSION=20.10.0
ARG YARN_VERSION=1.22.19

# Use Node image so we can pull the binaries from here.
FROM node:$NODE_VERSION as node

# Ruby build image.
FROM ruby:${RUBY_VERSION}-slim

RUN apt-get update -qq && \
apt-get install -y build-essential libssl-dev libpq-dev vim git libsasl2-dev && \
rm -rf /var/lib/apt/lists/*

# Copy node binaries from node image.
COPY --from=node /usr/local /usr/local
COPY --from=node /opt /opt

# Setup environment variables.
ENV WORK_ROOT /src
ENV APP_HOME $WORK_ROOT/app/
ENV LANG C.UTF-8
ENV BUNDLE_PATH $WORK_ROOT/bundle

# Create app directory.
RUN mkdir -p $APP_HOME

# Setup work directory.
WORKDIR $APP_HOME

RUN gem install foreman bundler

# Copy dependencies files and install libraries.
COPY --link package.json yarn.lock ./
RUN yarn install --frozen-lockfile

COPY --link Gemfile Gemfile.lock ./
RUN bundle install -j 4

COPY --link . .

# Entrypoint prepares the database.
ENTRYPOINT ["./bin/docker-entrypoint"]

# Start the server by default, this can be overwritten at runtime
EXPOSE 3000
CMD ["./bin/dev"]
4 changes: 2 additions & 2 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -669,7 +669,7 @@ DEPENDENCIES
yaaf (~> 2.2)

RUBY VERSION
ruby 3.3.1p55
ruby 3.3.1p55

BUNDLED WITH
2.5.10
2.5.10
2 changes: 1 addition & 1 deletion Procfile.dev
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
web: bin/rails server -p3000
web: ./bin/rails server -p 3000 -b 0.0.0.0
js: yarn build --watch
12 changes: 12 additions & 0 deletions bin/docker-entrypoint
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#!/bin/bash -e

# If running the rails server then create or migrate existing database
if ([ "${1}" == "./bin/rails" ] && [ "${2}" == "server" ]) || [ "${1}" == "./bin/dev" ]; then
./bin/rails db:prepare
fi

if [ "${1}" == "./bin/rspec" ]; then
./bin/rails db:test:prepare
fi

exec "${@}"
12 changes: 1 addition & 11 deletions bin/helpers.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,9 @@
end

def running_with_docker?
ENV['DOCKER_ENABLED'] == 'true' && docker_compose_installed? && web_service_running?
ENV['DOCKER_ENABLED'] == 'true' && docker_compose_installed?
end

def docker_compose_installed?
system('which docker-compose > /dev/null 2>&1')
end

def web_service_running?
docker_compose_installed? && !web_service.empty?
end

def web_service
abort("\n** ABORTED: docker-compose not installed **") unless docker_compose_installed?
out, = Open3.capture2("docker-compose ps --services --filter 'status=running' | grep web")
out.strip
end
2 changes: 1 addition & 1 deletion bin/rails
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ require 'shellwords'
require_relative 'helpers'

if running_with_docker?
exec "bin/web 'bin/rails #{Shellwords.join(ARGV)}'"
exec "bin/web './bin/rails #{Shellwords.join(ARGV)}'"
else
APP_PATH = File.expand_path('../config/application', __dir__)
require_relative '../config/boot'
Expand Down
20 changes: 18 additions & 2 deletions bin/rspec
Original file line number Diff line number Diff line change
@@ -1,10 +1,26 @@
#!/usr/bin/env ruby
require 'shellwords'
require_relative 'helpers'
require 'optparse'

options = {}
OptionParser.new do |opts|
opts.banner = "Usage: ./bin/rspec [options]"

opts.on("-rm", "--remove-containers", "If provided, all services will be stopped after the test is completed.") do
options[:remove_containers] = true
end
end.parse!

if running_with_docker?
exec "bin/web 'ITERATIONS=#{ENV['ITERATIONS']} bin/rspec #{Shellwords.join(ARGV)}'"
compose_command = "docker compose -f docker-compose.test.yml run --build web ./bin/rspec #{Shellwords.join(ARGV)}"

if options[:remove_containers]
compose_command += '&& docker compose -f docker-compose.test.yml down'
end

exec "ITERATIONS=#{ENV['ITERATIONS']} #{compose_command}"
else
require 'bundler/setup'
load Gem.bin_path('rspec-core', 'rspec')
load(Gem.bin_path('rspec-core', 'rspec'))
end
4 changes: 2 additions & 2 deletions bin/web
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ require 'shellwords'
require_relative 'helpers'

command = if running_with_docker?
puts "Running in service #{web_service}...\n"
puts "Running in service web...\n"

"docker-compose exec #{web_service} sh -c #{Shellwords.join(ARGV)}"
"docker compose run --service-ports web sh -c #{Shellwords.join(ARGV)}"
else
args = ARGV.length > 1 ? Shellwords.join(ARGV) : ARGV.first
# we remove '' if the command has it
Expand Down
32 changes: 32 additions & 0 deletions docker-compose.test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
name: 'tests'

services:
chrome-server:
image: seleniarm/standalone-chromium
ports:
- 4444:4444
- 7900:7900
- 5900:5900
web:
build:
context: .
dockerfile: Dockerfile.dev
environment:
POSTGRES_USER: postgres
POSTGRES_HOST: db
SELENIUM_BROWSER: remote
SELENIUM_BROWSER_HOST: http://chrome-server:4444
HEADLESS: true
tty: true
stdin_open: true
depends_on:
- db
- chrome-server
links:
- db:db
- chrome-server:chrome-server
db:
image: postgres:15
environment:
POSTGRES_USER: postgres
POSTGRES_HOST_AUTH_METHOD: trust
Loading