Docker support for production use

This commit adds a Docker infrastructure that is ready for production
use. It is meant to simplify the deployment of OSEM for everyone who
wants to host their own instances.

It includes many features like data persistence, automatic secret key
generation and persistence and automatic database initialization and
upgrading. This should make updating the Docker container as easy as
possible.
This commit is contained in:
TheAssassin 2017-03-25 22:51:21 +01:00 committed by Hernán Schmidt
parent b33e9ed28e
commit f15fe9ddb0
6 changed files with 167 additions and 0 deletions

2
.dockerignore Normal file
View file

@ -0,0 +1,2 @@
Dockerfile
docker-compose.*

46
Dockerfile Normal file
View file

@ -0,0 +1,46 @@
FROM ruby:2.3
MAINTAINER TheAssassin <theassassin@users.noreply.github.com>
# required for compiling assets
RUN apt-get update && \
apt-get install -y nodejs nodejs-legacy mariadb-client
# used to run the container without root permissions
RUN adduser --home /osem/ --system --group --disabled-login --disabled-password osem
# required to detect when the database is up and running in init.sh
RUN cd /usr/bin && \
wget https://github.com/jwilder/dockerize/releases/download/v0.3.0/dockerize-linux-amd64-v0.3.0.tar.gz -O dockerize.tar.gz && \
echo "36e8319cdf9d2b07340f456ec61cfa0f495ec6c130b02ad9c116fd55a5c43fa1 dockerize.tar.gz" | sha256sum -c && \
tar -xf dockerize.tar.gz && \
rm dockerize.tar.gz
# explicitly add Gemfile and install dependencies using bundler to make use of
# Docker's caching
WORKDIR /osem/
RUN gem install puma
COPY Gemfile /osem/
COPY Gemfile.lock /osem/
RUN bundle install --without test development
# add OSEM files and prepare them for use inside a Docker container
COPY . /osem/
RUN chown osem.osem /osem/ -R && \
mv /osem/config/database.yml.docker /osem/config/database.yml
# data directory is used to cache the secret key in a file
ENV DATA_DIR /data
RUN install -d -m 0700 -o osem $DATA_DIR
VOLUME ["$DATA_DIR"]
USER osem
EXPOSE 9292
COPY docker/init.sh /init.sh
# a user could override this if they wanted to serve the static files directly
# from a webserver
ENV RAILS_SERVE_STATIC_FILES 1
CMD ["bash", "/init.sh"]

View file

@ -0,0 +1,7 @@
production:
adapter: mysql2
host: <%= ENV['DATABASE_HOST'] %>
port: <%= ENV['DATABASE_PORT'] %>
username: <%= ENV['MYSQL_USER'] %>
password: <%= ENV['MYSQL_PASSWORD'] %>
database: <%= ENV['MYSQL_DATABASE'] %>

View file

@ -0,0 +1,38 @@
## database related variables ##
# variables prefixed with MYSQL_ are used by both database and web containers
# variables prefixed with DATABASE_ are used exlusively by the web container
MYSQL_DATABASE=osem
MYSQL_USER=osem
MYSQL_PASSWORD=changemeimmediately
MYSQL_ROOT_PASSWORD=changemeevenmoreimmediately
# the following settings should not be modified unless the database service
# is renamed in docker-compose.yml or you plan to use an external database
DATABASE_HOST=database
DATABASE_PORT=3306
## OSEM options ##
# you can configure any option described in this document here instead of
# having to create a .env file:
# https://github.com/openSUSE/osem/blob/master/dotenv.example
OSEM_NAME=Dockerized OSEM
OSEM_HOSTNAME=http://localhost:9292
OSEM_ERRBIT_HOST=localhost
SECRET_KEY_BASE=changemechangemechangeme
# these settings work for the MailHog server that is enabled by default in
# docker-compose.yml
# if you do not plan to use MailHog (you most likely don't want to), you need
# to change these settings to use an external working mailserver, otherwise
# your users are going to see the HTTP status 500 page
# you should comment out or remove the mailhog service from docker-compose.yml,
# too
OSEM_EMAIL_ADDRESS=osem@mailhog
OSEM_SMTP_ADDRESS=mailhog
OSEM_SMTP_PORT=1025
OSEM_SMTP_USERNAME=mailhog
OSEM_SMTP_PASSWORD=mailhog

View file

@ -0,0 +1,29 @@
version: "2"
services:
database:
image: mariadb:10.1
env_file: docker-compose.env
volumes:
- database:/var/lib/mysql
mailhog:
image: mailhog/mailhog:latest
ports:
- "127.0.0.1:8025:8025"
web:
build: .
env_file: docker-compose.env
depends_on:
- database
- mailhog
ports:
- "127.0.0.1:9292:9292"
volumes:
- "web:/data"
# these named volumes are used to persist data
volumes:
database:
web:

45
docker/init.sh Normal file
View file

@ -0,0 +1,45 @@
#! /bin/bash
set -e
# data directory is required for caching the secret key in a file
if [ "$DATA_DIR" == "" ]; then
echo -n "Error: DATA_DIR environment variable not set!"
echo "Are you sure you are running this script in a Docker container?"
exit 1
fi
SECRET_KEY_FILE="$DATA_DIR/secret_key"
if [ ! -f "$SECRET_KEY_FILE" ]; then
install -m 0600 /dev/null "$SECRET_KEY_FILE"
SECRET_KEY=$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 100 | head -n 1)
echo "$key" > "$SECRET_KEY_FILE"
chmod -w "$SECRET_KEY_FILE"
else
SECRET_KEY=$(cat "$SECRET_KEY_FILE")
fi
export SECRET_KEY
export RAILS_ENV=production
install -m 0600 /dev/null .my.cnf
cat > .my.cnf <<ABC
[client]
user=$MYSQL_USER
password=$MYSQL_PASSWORD
ABC
if [ $(echo "show tables;" | mysql --host $DATABASE_HOST --port $DATABASE_PORT $MYSQL_DATABASE | wc -l) -le 1 ]; then
echo ">>> Initializing database..."
dockerize -wait tcp://$DATABASE_HOST:$DATABASE_PORT -timeout 60s bundle exec rake db:schema:load
fi
echo ">>> Upgrading database..."
dockerize -wait tcp://$DATABASE_HOST:$DATABASE_PORT -timeout 60s bundle exec rake db:migrate
echo ">>> Precompiling assets..."
bundle exec rake assets:precompile
echo ">>> Starting application server..."
exec puma -e production