From e47ccaeb2622c62d811a36757e9a22da03e033ad Mon Sep 17 00:00:00 2001 From: Tim Neumann <neumantm@fius.informatik.uni-stuttgart.de> Date: Wed, 10 Mar 2021 14:30:22 +0100 Subject: [PATCH] Add Dockerfile and dependencies Also add some documentation on deploying with docker --- .docker/entrypoint.sh | 37 ++++++++++ .docker/extra_requirements.txt | 1 + .docker/uwsgi.ini | 6 ++ .dockerignore | 11 +++ Dockerfile | 13 ++++ INSTALL.md | 130 +++++++++++++++++++++++++++++++++ 6 files changed, 198 insertions(+) create mode 100644 .docker/entrypoint.sh create mode 100644 .docker/extra_requirements.txt create mode 100644 .docker/uwsgi.ini create mode 100644 .dockerignore create mode 100644 Dockerfile diff --git a/.docker/entrypoint.sh b/.docker/entrypoint.sh new file mode 100644 index 00000000..ecd068c6 --- /dev/null +++ b/.docker/entrypoint.sh @@ -0,0 +1,37 @@ +#!/bin/sh + +function wait_for_db() +{ + while ! ./manage.py sqlflush > /dev/null 2>&1 ;do + echo "Waiting for the db to be ready." + sleep 1 + done +} + +if [ "$SECRET_KEY" == "" ] ;then + echo "Need the environment variable SECRET_KEY." + exit 1 +fi + +echo "SECRET_KEY = '$SECRET_KEY'" >> ./AKPlanning/settings_secrets.py +echo "HOSTS = $HOSTS" >> ./AKPlanning/settings_secrets.py +echo "DB_NAME = '$DB_NAME'" >> ./AKPlanning/settings_secrets.py +echo "DB_USER = '$DB_USER'" >> ./AKPlanning/settings_secrets.py +echo "DB_PASSWORD = '$DB_PASSWORD'" >> ./AKPlanning/settings_secrets.py +echo "DB_HOST = '$DB_HOST'" >> ./AKPlanning/settings_secrets.py + +if [ "$AUTO_MIGRATE_DB" == "true" ] ;then + wait_for_db + echo "Applying DB migrations" + ./manage.py migrate +fi + +if [ "$DJANGO_SUPERUSER_PASSWORD" != "" ] ;then + wait_for_db + echo "Trying to create superuser." + ./manage.py createsuperuser --noinput +fi + +./manage.py collectstatic --noinput +./manage.py compilemessages -l de_DE +uwsgi --ini .docker/uwsgi.ini diff --git a/.docker/extra_requirements.txt b/.docker/extra_requirements.txt new file mode 100644 index 00000000..b64ab47d --- /dev/null +++ b/.docker/extra_requirements.txt @@ -0,0 +1 @@ +uwsgi==2.0.19.1 diff --git a/.docker/uwsgi.ini b/.docker/uwsgi.ini new file mode 100644 index 00000000..7115f719 --- /dev/null +++ b/.docker/uwsgi.ini @@ -0,0 +1,6 @@ +[uwsgi] +socket = 0.0.0.0:3035 +wsgi-file = AKPlanning/wsgi.py +env = DJANGO_SETTINGS_MODULE=AKPlanning.settings_production +processes = 4 +threads = 2 diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 00000000..ba3357ef --- /dev/null +++ b/.dockerignore @@ -0,0 +1,11 @@ +apache-akplanning.conf +CODE_OF_CONDUCT.md +CONTRIBUTING.md +CONTRIBUTORS.md +.git +.gitignore +.gitlab-ci.yml +INSTALL.md +LICENSE.md +README.md +uwsgi-akplanning.ini diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 00000000..8743d273 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,13 @@ +FROM python:3-alpine + +RUN apk add --no-cache gcc python3-dev musl-dev libffi-dev mariadb-connector-c-dev gettext + +ADD . /app +WORKDIR /app + +RUN pip install -r requirements.txt -r .docker/extra_requirements.txt + +ENV DJANGO_SETTINGS_MODULE=AKPlanning.settings_production + +EXPOSE 3035 +CMD ["sh", "/app/.docker/entrypoint.sh"] diff --git a/INSTALL.md b/INSTALL.md index 040a5aa8..c351d075 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -100,9 +100,139 @@ start uwsgi using the configuration file ``uwsgi --ini uwsgi-akplanning.ini`` 1. execute the update script ``./Utils/update.sh --prod`` +## Deployment Setup using Docker +This project also provides a docker file for easy deployment. + +The container described by the docker file only contains the project itself. +Additional containers for the database and webserver are needed to use it. + +The following [docker-compose](https://docs.docker.com/compose/) file shows a typical usage: +``` +version: "3" + +networks: + akplanning: + external: false + +volumes: + static-files: + +services: + mariadb: + image: mariadb:10 + restart: always + environment: + MYSQL_ROOT_PASSWORD: supermegasecrey + MYSQL_DATABASE: akplanning + MYSQL_USER: akplanning + MYSQL_PASSWORD: secret + TZ: Europe/Berlin + networks: + - akplanning + + akplanning-server: + image: neumantm/akplanning:2021-03-10 + restart: always + environment: + SECRET_KEY: superlongandsupersecret + DB_HOST: mariadb + DB_USER: akplanning + DB_NAME: akplanning + DB_PASSWORD: secret + HOSTS: "['akplanning.example.net', 'akplanning.example.de']" + TZ: Europe/Berlin + AUTO_MIGRATE_DB: 'true' + DJANGO_SUPERUSER_USERNAME: admin + DJANGO_SUPERUSER_EMAIL: admin@example.com + DJANGO_SUPERUSER_PASSWORD: supersecret + depends_on: + - mariadb + networks: + - akplanning + volumes: + - static-files:/app/static + + web-server: + image: nginx + restart: always + volumes: + - /path/to/nginx.conf:/etc/nginx/nginx.conf:ro + - static-files:/var/www/ak-static + ports: + - "8080:80" + depends_on: + - ak-server + networks: + - akplanning +``` + +The `nginx.conf` would look like this: + +``` +user nginx; +worker_processes 1; +error_log /var/log/nginx/error.log warn; +pid /var/run/nginx.pid; + +events { + worker_connections 1024; +} + +http { + include /etc/nginx/mime.types; + default_type application/octet-stream; + log_format main '$remote_addr - $remote_user [$time_local] "$request" ' + '$status $body_bytes_sent "$http_referer" ' + '"$http_user_agent" "$http_x_forwarded_for"'; + access_log /var/log/nginx/access.log main; + sendfile on; + keepalive_timeout 65; + server { + listen 80; + server_name localhost:8080; + + location /static/ { + alias /var/www/ak-static/; + } + + location / { + include /etc/nginx/uwsgi_params; + uwsgi_pass uwsgi://ak-server:3035; + } + } +} +``` +### Initializing and migrating database +On the first start, the database must be initialized (the Tables created and so on). +When updating the project the database must be migrated. +Both are done using the `migrate` command. + +This can be done manually by runningthe following command after the container has started: +`docker-compose exec -it akplanning-server ./manage.py migrate` + +It can also be done automatically on each container start by setting `AUTO_MIGRATE_DB` to the string `true` +(as shown in the docker-compose file above). + +Database migration may lead to the corruption or loss of data in some cases. +Make sure you have a backup before running the command and be very careful with enabling auto migration. + +### Creating initial superuser +There are two ways to create the initial superuser when using the docker container. +For both the database must have been intialized before. + +The first way is already shown in the docker-compose file above: +Using the environment variables `DJANGO_SUPERUSER_{USERNAME,EMAIL,PASSWORD}`. + +The second way is to run the following command after the container has started: +`docker-compose exec -it akplanning-server ./manage.py createsuperuser` + ## Updates To update the setup to the current version on the main branch of the repository use the update script ``Utils/update.sh`` or ``Utils/update.sh --prod`` in production. Afterwards, you may check your setup by executing ``Utils/check.sh`` or ``Utils/check.sh --prod`` in production. +### Updating when using docker + +To update when using docker, just switch the tag of the image for `akplanning-server`. +Then (if `AUTO_MIGRATE_DB` is not enabled), do a database migration as described in [Initializing and migrating database](#initializing-and-migrating-database) -- GitLab