Skip to content

Instantly share code, notes, and snippets.

@microstudi
Last active October 5, 2023 11:13
Show Gist options
  • Save microstudi/615d82a3a4552b30ad58476e959ce379 to your computer and use it in GitHub Desktop.
Save microstudi/615d82a3a4552b30ad58476e959ce379 to your computer and use it in GitHub Desktop.
Decidim 0.28 Optimized Dockerfile (for an app)

Optimized Dockerfile for Decidim

This Dockerfile can be used for using Decidim through docker in production. It optimises the image (comparing from the official one, you downsize the image from about 2G to about 600Mb).

Has an integrated HEALTHCHECK to ensure no downtime on upgrades when used in a docker swarm for instance.

Note that requires some env variables to work

  1. Copy the files in the root directory of your Decidim application (version 0.26)
  2. Build the docker image, deploy!
version: '3'
services:
app:
build: .
volumes:
- ./tmp/pids:/app/tmp/pids
# - ./entrypoint.sh:/app/entrypoint.sh
# - ./db/seeds.rb:/app/db/seeds.rb
# - .:/app
# - bundle:/usr/local/bundle
# - node_modules:/app/node_modules
environment:
- DATABASE_URL=postgres://postgres:decidim@db/decidim
- SECRET_KEY_BASE=my-key-secret
- DECIDIM_FORCE_SSL=false
- QUEUE_ADAPTER=sidekiq
- REDIS_URL=redis://redis:6379/1
ports:
- 3000:3000
depends_on:
- db
- redis
sidekiq:
build: .
volumes:
# - ./entrypoint.sh:/app/entrypoint.sh
# - .:/app
# - bundle:/usr/local/bundle
# - node_modules:/app/node_modules
environment:
- DATABASE_URL=postgres://postgres:decidim@db/decidim
- SECRET_KEY_BASE=my-key-secret
- DECIDIM_FORCE_SSL=false
- QUEUE_ADAPTER=sidekiq
- REDIS_URL=redis://redis:6379/1
- RUN_SIDEKIQ=true
depends_on:
- redis
db:
image: postgres:13
ports:
- "54321:5432"
environment:
- POSTGRES_PASSWORD=decidim
volumes:
- pg_data:/var/lib/postgresql/data
redis:
image: redis
volumes:
- redis_data:/data
volumes:
pg_data:
redis_data:
# bundle:
# node_modules:
FROM ruby:3.1 AS builder
RUN NODE_MAJOR=20 && \
apt-get update && apt-get upgrade -y && apt-get install -y ca-certificates curl gnupg && \
mkdir -p /etc/apt/keyrings && \
curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg && \
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 && \
curl -sL 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 && \
apt-get update && apt-get install -y nodejs yarn \
build-essential \
postgresql-client \
libpq-dev && \
apt-get clean
# throw errors if Gemfile has been modified since Gemfile.lock
RUN bundle config --global frozen 1
WORKDIR /app
# Copy package dependencies files only to ensure maximum cache hit
COPY ./package-lock.json /app/package-lock.json
COPY ./package.json /app/package.json
COPY ./Gemfile /app/Gemfile
COPY ./Gemfile.lock /app/Gemfile.lock
RUN gem install bundler:$(grep -A 1 'BUNDLED WITH' Gemfile.lock | tail -n 1 | xargs) && \
bundle config --local without 'development test' && \
bundle install -j4 --retry 3 && \
# Remove unneeded gems
bundle clean --force && \
# Remove unneeded files from installed gems (cache, *.o, *.c)
rm -rf /usr/local/bundle/cache && \
find /usr/local/bundle/ -name "*.c" -delete && \
find /usr/local/bundle/ -name "*.o" -delete && \
find /usr/local/bundle/ -name ".git" -exec rm -rf {} + && \
find /usr/local/bundle/ -name ".github" -exec rm -rf {} + && \
# whkhtmltopdf has binaries for all platforms, we don't need them once uncompressed
rm -rf /usr/local/bundle/gems/wkhtmltopdf-binary-*/bin/*.gz && \
# Remove additional unneded decidim files
find /usr/local/bundle/ -name "decidim_app-design" -exec rm -rf {} + && \
find /usr/local/bundle/ -name "spec" -exec rm -rf {} +
RUN npm ci
# copy the rest of files
COPY ./app /app/app
COPY ./bin /app/bin
COPY ./config /app/config
COPY ./db /app/db
COPY ./lib /app/lib
COPY ./packages /app/packages
COPY ./public/*.* /app/public/
COPY ./config.ru /app/config.ru
COPY ./Rakefile /app/Rakefile
COPY ./babel.config.json /app/babel.config.json
COPY ./postcss.config.js /app/postcss.config.js
# Compile assets with Webpacker or Sprockets
#
# Notes:
# 1. Executing "assets:precompile" runs "webpacker:compile", too
# 2. For an app using encrypted credentials, Rails raises a `MissingKeyError`
# if the master key is missing. Because on CI there is no master key,
# we hide the credentials while compiling assets (by renaming them before and after)
#
RUN mv config/credentials.yml.enc config/credentials.yml.enc.bak 2>/dev/null || true
RUN mv config/credentials config/credentials.bak 2>/dev/null || true
RUN RAILS_ENV=production \
SECRET_KEY_BASE=dummy \
RAILS_MASTER_KEY=dummy \
DB_ADAPTER=nulldb \
bundle exec rails assets:precompile
RUN mv config/credentials.yml.enc.bak config/credentials.yml.enc 2>/dev/null || true
RUN mv config/credentials.bak config/credentials 2>/dev/null || true
RUN rm -rf node_modules tmp/cache vendor/bundle test spec app/packs .git
# This image is for production env only
FROM ruby:3.1-slim AS final
RUN apt-get update && \
apt-get install -y postgresql-client \
imagemagick \
curl \
supervisor && \
apt-get clean
EXPOSE 3000
ENV RAILS_LOG_TO_STDOUT true
ENV RAILS_SERVE_STATIC_FILES true
ENV RAILS_ENV production
ARG RUN_RAILS
ARG RUN_SIDEKIQ
ARG COMMIT_SHA
ARG COMMIT_TIME
ARG COMMIT_VERSION
ENV COMMIT_SHA ${COMMIT_SHA}
ENV COMMIT_TIME ${COMMIT_TIME}
ENV COMMIT_VERSION ${COMMIT_VERSION}
# Add user
RUN addgroup --system --gid 1000 app && \
adduser --system --uid 1000 --home /app --group app
WORKDIR /app
COPY ./entrypoint.sh /app/entrypoint.sh
COPY ./supervisord.conf /etc/supervisord.conf
COPY --from=builder --chown=app:app /usr/local/bundle/ /usr/local/bundle/
COPY --from=builder --chown=app:app /app /app
USER app
HEALTHCHECK --interval=1m --timeout=5s --start-period=30s \
CMD (curl -sSH "Content-Type: application/json" -d '{"query": "{ decidim { version } }"}' http://localhost:3000/api) || exit 1
ENTRYPOINT ["/app/entrypoint.sh"]
CMD ["/usr/bin/supervisord"]
#!/bin/bash
# Run rails by default if sidekiq is specified
if [ -z "$RUN_RAILS" ] && [ -z "$RUN_SIDEKIQ" ]; then
RUN_RAILS=true
echo "⚠️ RUN_RAILS and RUN_SIDEKIQ are not set, defaulting to RUN_RAILS=true"
fi
if [ "$QUEUE_ADAPTER" != "sidekiq" ]; then
RUN_SIDEKIQ=false
echo "⚠️ Sidekiq is disabled because QUEUE_ADAPTER is not set to sidekiq"
fi
# ensure booleans
if [ "$RUN_RAILS" == "true" ] || [ "$RUN_RAILS" == "1" ]; then
RUN_RAILS=true
else
RUN_RAILS=false
fi
if [ "$RUN_SIDEKIQ" == "true" ] || [ "$RUN_SIDEKIQ" == "1" ]; then
RUN_SIDEKIQ=true
else
RUN_SIDEKIQ=false
fi
if [ "$RUN_RAILS" == "true" ]; then
echo "✅ Running Rails"
fi
if [ "$RUN_SIDEKIQ" == "true" ]; then
echo "✅ Running Sidekiq"
fi
export RUN_RAILS
export RUN_SIDEKIQ
# Check all the gems are installed or fails.
bundle check
if [ $? -ne 0 ]; then
echo "❌ Gems in Gemfile are not installed, aborting..."
exit 1
else
echo "✅ Gems in Gemfile are installed"
fi
# Check no migrations are pending migrations
if [ -z "$SKIP_MIGRATIONS" ]; then
bundle exec rails db:migrate
else
echo "⚠️ Skipping migrations"
fi
echo "✅ Migrations are all up"
echo "🚀 $@"
exec "$@"
[supervisord]
nodaemon=true
logfile=/tmp/supervisord.log
pidfile=/tmp/supervisord.pid
[program:puma]
command=bin/rails server -b 0.0.0.0
directory=/app
# If RUN_RAILS is not set, defaults to RUN_SIDEKIQ not being defined
autostart=%(ENV_RUN_RAILS)s
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
[program:sidekiq]
command=bundle exec sidekiq -C config/sidekiq.yml
directory=/app
autostart=%(ENV_RUN_SIDEKIQ)s
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
[supervisorctl]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment