diff --git a/Changelog.md b/Changelog.md index f099f2b..63d1722 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,5 +1,46 @@ # CHANGELOG.md +## 2.0 (2022-09-19) Dockerify https://redmine.ungleich.ch/issues/10884 + +Steps: + - Create .env.prod and .env.prod.db files + +#### .env.prod +``` +DEBUG=0 +SECRET_KEY=secret_key_here +DJANGO_ALLOWED_HOSTS=localhost 127.0.0.1 [::1] +DJANGO_SETTINGS_MODULE=gmba_django.settings.production +ALLOWED_HOSTS=localhost,127.0.0.1,[::1] +SQL_ENGINE=django.db.backends.postgresql +SQL_DATABASE=psql_db_name +SQL_USER=psql_username_name +SQL_PASSWORD=psql_passwordd +SQL_HOST=db +SQL_PORT=5432 +``` + +#### .env.prod.db +``` +POSTGRES_USER=psql_username_name +POSTGRES_PASSWORD=psql_passwordd +POSTGRES_DB=psql_db_name +``` + +Building containers + - docker-compose -f docker-compose.prod.yml down -v --remove-orphans + - docker-compose -f docker-compose.prod.yml up -d --build + +Copy db and adust + - docker cp gd.sql gmba_django_db_1:/gd.sql + - docker-compose exec db psql --username=psql_username_name --dbname=psql_db_name < /gd.sql + +Migrate / check + - docker-compose exec web python manage.py migrate --noinput + +Static resources + - docker-compose -f docker-compose.prod.yml exec web python manage.py collectstatic --no-input --clear + ## 1.12 (2022-01-19) Bugfixes: diff --git a/Dockerfile.prod b/Dockerfile.prod new file mode 100644 index 0000000..408c26a --- /dev/null +++ b/Dockerfile.prod @@ -0,0 +1,73 @@ +########### +# BUILDER # +########### + +# pull official base image +FROM python:3.9.6-alpine as builder + +# set work directory +WORKDIR /usr/src/gmba_django + +# set environment variables +ENV PYTHONDONTWRITEBYTECODE 1 +ENV PYTHONUNBUFFERED 1 + +# install psycopg2 dependencies +RUN apk update \ + && apk add postgresql-dev gcc python3-dev musl-dev + +# lint +RUN pip install --upgrade pip +RUN pip install flake8==3.9.2 +COPY . . +#RUN flake8 --ignore=E501,F401 . + +# install dependencies +COPY ./requirements.txt . +RUN pip wheel --no-cache-dir --no-deps --wheel-dir /usr/src/gmba_django/wheels -r requirements.txt + + +######### +# FINAL # +######### + +# pull official base image +FROM python:3.9.6-alpine + +# create directory for the app user +RUN mkdir -p /home/app + +# create the app user +RUN addgroup -S app && adduser -S app -G app + +# create the appropriate directories +ENV HOME=/home/app +ENV APP_HOME=/home/app/app +RUN mkdir $APP_HOME +RUN mkdir $APP_HOME/static +RUN mkdir $APP_HOME/media +WORKDIR $APP_HOME + +# install dependencies +RUN apk update && apk add libpq +COPY --from=builder /usr/src/gmba_django/wheels /wheels +COPY --from=builder /usr/src/gmba_django/requirements.txt . +RUN pip install --no-cache /wheels/* + +# copy entrypoint.prod.sh +COPY ./entrypoint.prod.sh . +RUN sed -i 's/\r$//g' $APP_HOME/entrypoint.prod.sh +RUN chmod +x $APP_HOME/entrypoint.prod.sh + +# copy project +COPY . $APP_HOME + +# chown all the files to the app user +RUN chown -R app:app $APP_HOME + +# change to the app user +USER app + +# run entrypoint.prod.sh +ENTRYPOINT ["/home/app/app/entrypoint.prod.sh"] + diff --git a/docker-compose.prod.yml b/docker-compose.prod.yml new file mode 100644 index 0000000..575027d --- /dev/null +++ b/docker-compose.prod.yml @@ -0,0 +1,37 @@ +version: '3.8' + +services: + web: + build: + context: ./ + dockerfile: Dockerfile.prod + command: gunicorn gmba_django.wsgi:application --bind 0.0.0.0:8000 + volumes: + - static_volume:/home/app/app/static + - media_volume:/home/app/app/media + expose: + - 8000 + env_file: + - ./.env.prod + depends_on: + - db + db: + image: postgres:13.0-alpine + volumes: + - postgres_data:/var/lib/postgresql/data/ + env_file: + - ./.env.prod.db + nginx: + build: ./nginx + volumes: + - static_volume:/home/app/app/static + - media_volume:/home/app/app/media + ports: + - 1337:80 + depends_on: + - web + +volumes: + postgres_data: + static_volume: + media_volume: diff --git a/entrypoint.prod.sh b/entrypoint.prod.sh new file mode 100755 index 0000000..2cc61cd --- /dev/null +++ b/entrypoint.prod.sh @@ -0,0 +1,15 @@ +#!/bin/sh + +if [ "$DATABASE" = "postgres" ] +then + echo "Waiting for postgres..." + + while ! nc -z $SQL_HOST $SQL_PORT; do + sleep 0.1 + done + + echo "PostgreSQL started" +fi + +exec "$@" + diff --git a/gmba_django/settings/production.py b/gmba_django/settings/production.py index 45a8caf..bcb825e 100644 --- a/gmba_django/settings/production.py +++ b/gmba_django/settings/production.py @@ -8,10 +8,10 @@ DATABASES = { 'default': { 'ENGINE': os.environ.get('SQL_ENGINE', 'django.db.backends.sqlite3'), 'NAME': os.environ.get('SQL_DATABASE', os.path.join(BASE_DIR, 'db.sqlite3')), - # 'USER': os.environ.get('SQL_USER', 'user'), - # 'PASSWORD': os.environ.get('SQL_PASSWORD', 'password'), - # 'HOST': os.environ.get('SQL_HOST', 'localhost'), - # 'PORT': os.environ.get('SQL_PORT', ''), + 'USER': os.environ.get('SQL_USER', 'app'), + 'PASSWORD': os.environ.get('SQL_PASSWORD', ''), + 'HOST': os.environ.get('SQL_HOST', 'localhost'), + 'PORT': os.environ.get('SQL_PORT', ''), } } diff --git a/nginx/Dockerfile b/nginx/Dockerfile new file mode 100644 index 0000000..4580e8d --- /dev/null +++ b/nginx/Dockerfile @@ -0,0 +1,4 @@ +FROM nginx:1.21-alpine + +RUN rm /etc/nginx/conf.d/default.conf +COPY nginx.conf /etc/nginx/conf.d diff --git a/nginx/nginx.conf b/nginx/nginx.conf new file mode 100644 index 0000000..ceab716 --- /dev/null +++ b/nginx/nginx.conf @@ -0,0 +1,28 @@ +upstream gmba_django { + server web:8000; +} + +server { + listen 80; + + client_max_body_size 256m; + + location / { + proxy_pass http://gmba_django; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header Host $host; + proxy_redirect off; + } + + location /static/ { + alias /home/app/app/static/; + expires max; + } + + location /media/ { + alias /home/app/app/media/; + expires max; + } + + add_header Content-Security-Policy "frame-ancestors https://www.gmba.unibe.ch" +} diff --git a/requirements.txt b/requirements.txt index ad8eda7..ce977aa 100644 --- a/requirements.txt +++ b/requirements.txt @@ -6,3 +6,4 @@ sqlparse==0.4.1 typing-extensions==3.10.0.0 psycopg2==2.9.1 Werkzeug==2.0.2 +gunicorn==20.1.0