Skip to content
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

Build demo production settings #58

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 2 additions & 1 deletion .envs/.production/.postgres
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# PostgreSQL
# ------------------------------------------------------------------------------
POSTGRES_HOST=kc-med-oslerdb.kc.umkc.edu
POSTGRES_HOST=postgres
POSTGRES_PORT=5432
POSTGRES_DB=osler
POSTGRES_USER=django
# the following are missing: POSTGRES_PASSWORD
4 changes: 4 additions & 0 deletions .envs/.secrets/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Ignore everything in this directory
*
# Except this file
!.gitignore
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -278,4 +278,7 @@ osler/media/
!.envs/.local/
!.envs/.production/

# secrets has a .gitignore file that ignores everything inside it
!.envs/.secrets/

.vscode/*
4 changes: 4 additions & 0 deletions compose/production/nginx/certs/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Ignore everything in this directory
*
# Except this file
!.gitignore
2 changes: 1 addition & 1 deletion compose/production/postgres/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM postgres:11.3
FROM postgres:11.12

COPY ./compose/production/postgres/maintenance /usr/local/bin/maintenance
RUN chmod +x /usr/local/bin/maintenance/*
Expand Down
5 changes: 0 additions & 5 deletions compose/production/traefik/Dockerfile

This file was deleted.

69 changes: 0 additions & 69 deletions compose/production/traefik/traefik.yml

This file was deleted.

33 changes: 33 additions & 0 deletions config/settings/demo.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Custom settings for demo deployment
# -----------------------------------------------------------------------------
from .base import env

ALLOWED_HOSTS = ['demo.llemrconspiracy.org', '0.0.0.0']

TIME_ZONE = "America/Chicago"
LANGUAGE_CODE = "en-us"

OSLER_ROLE_DASHBOARDS = {
'Attending': 'dashboard-attending',
'Physician': 'dashboard-attending',
}

OSLER_DISPLAY_REFERRALS = False
OSLER_DISPLAY_APPOINTMENTS = False
OSLER_DISPLAY_CASE_MANAGERS = False
OSLER_DISPLAY_ATTESTABLE_BASIC_NOTE = False
OSLER_DISPLAY_DIAGNOSIS = False
OSLER_DISPLAY_VOUCHERS = False
OSLER_DISPLAY_WILL_RETURN = False
OSLER_DISPLAY_ATTENDANCE = True
OSLER_DISPLAY_FOLLOWUP = False
OSLER_DISPLAY_VACCINE = False

OSLER_DEFAULT_CITY = "Gotham"
OSLER_DEFAULT_STATE = "New Jersey"
OSLER_DEFAULT_ZIP_CODE = "00000"
OSLER_DEFAULT_COUNTRY = "USA"
OSLER_DEFAULT_ADDRESS = ""

OSLER_ABOUT_NAME = "About"
OSLER_ABOUT_URL = "https://llemrconspiracy.org"
2 changes: 2 additions & 0 deletions config/settings/production-demo.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
from .production import *
from .demo import *
159 changes: 159 additions & 0 deletions docs/running-in-production.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
Running in Production
====================================

Set up a docker compose file
----------------------------

The global configuration of your docker compose swarm is set up in `production.yml`.
We have a number of examples, including the demo (`production-demo.yml`). These set up
virtual machines for each of the elements of the web app.

The Database
------------

We use PostgresQL. The database container is named `postgres`. Here is an example of a configuration:

.. code-block:: yaml

postgres:
build:
context: .
dockerfile: ./compose/production/postgres/Dockerfile
image: llemr_production_postgres
container_name: postgres
volumes:
- production_postgres_data:/var/lib/postgresql/data
- production_postgres_data_backups:/backups
env_file:
- ./.envs/.production/.postgres
- ./.envs/.secrets/.postgres
networks:
- database_network

The key here is the `env_file` section, which sets some important environment variables:

.. code-block:: bash

POSTGRES_HOST=postgres
POSTGRES_PORT=5432
POSTGRES_DB=llemr
POSTGRES_USER=django

Furthermore, the file `./.envs/.secrets/.postgres` *does not exist*, and must be created. Create a file that looks something like:

.. code-block:: bash

POSTGRES_PASSWORD=FybL7H4ftzJPiEWQrWMDuogLUcLgv47iw78vUqHexPPnJGd9EJDPeDXH9RGdiTBC


.. warning::
POSTGRES_PASSWORD is **priviledged information** and should be kept secret. Do not check it in to your git repository. The string provided here is an example--do not use it yourself! Generate a long, random string yourself and use it instead.


The Web App
-----------

The web app is run with gunicorn in a custom Dockerfile. This guy accounts for by far the majority of the runtime of `docker-compose build`.

.. note::
We provide the postgres configuration environment files
(`.envs/.production/.postgres` and `./.envs/.secrets/.postgres`) to _both_
the django container and the postgres container. This is because the
django container needs to be able to connect and authenticate to the
postgres container!

.. code-block:: yaml

django:
build:
context: .
dockerfile: ./compose/production/django/Dockerfile
image: llemr_production_django
container_name: django
ports:
- 5000:5000
depends_on:
- postgres
- redis
environment:
- DJANGO_SETTINGS_MODULE=config.settings.production-demo
env_file:
- ./.envs/.production/.django
- ./.envs/.production/.postgres
- ./.envs/.secrets/.postgres
- ./.envs/.secrets/.django
command: /start
networks:
- nginx_network
- database_network

Notice that we use the `environment` section to provide `DJANGO_SETTINGS_MODULE`, which points to `config/settings/production-demo.py`. This file contains:

.. code-block:: python

from .production import *
from .demo import *

Thus, it combines the configurations listed in `config/settings/production.py` and `config/settings/demo.py`, with those in `demo.py` overriding anything in `production.py` (since `demo.py` comes second). Most of the settings in `production.py` are strong recommendations for production, whereas those in `demo.py` are likely to be configured by you.

.. code-block:: python
from .base import env

TIME_ZONE = "America/Chicago"
LANGUAGE_CODE = "en-us"

OSLER_ROLE_DASHBOARDS = {
'Attending': 'dashboard-attending',
'Physician': 'dashboard-attending',
}

OSLER_DISPLAY_REFERRALS = False
OSLER_DISPLAY_APPOINTMENTS = False
OSLER_DISPLAY_CASE_MANAGERS = False
OSLER_DISPLAY_ATTESTABLE_BASIC_NOTE = False
OSLER_DISPLAY_DIAGNOSIS = False
OSLER_DISPLAY_VOUCHERS = False
OSLER_DISPLAY_WILL_RETURN = False
OSLER_DISPLAY_ATTENDANCE = True
OSLER_DISPLAY_FOLLOWUP = False
OSLER_DISPLAY_VACCINE = False

OSLER_DEFAULT_CITY = "Gotham"
OSLER_DEFAULT_STATE = "New Jersey"
OSLER_DEFAULT_ZIP_CODE = "00000"
OSLER_DEFAULT_COUNTRY = "USA"
OSLER_DEFAULT_ADDRESS = ""

OSLER_ABOUT_NAME = "About"
OSLER_ABOUT_URL = "https://llemrconspiracy.org"


The Web Server
--------------

The web server we use is nginx. It's responsible for serving static files, terminating SSL, and passing data to gunicorn. The pertinent part of the docker compose file is here:

.. code-block:: yaml

nginx:
image: nginx:1.19
container_name: nginx
ports:
- 80:80
- 443:443
env_file:
- ./.envs/.production/.nginx
volumes:
- ./compose/production/nginx/templates:/etc/nginx/templates
- ./compose/production/nginx/certs:/etc/nginx/certs
depends_on:
- django
networks:
- nginx_network

To get this working, you need to put an SSL certificate named `cert.crt` in `compose/production/nginx/certs`. SSL certificates get kind of complicated, but you can usually get one from Let's Encrypt (https://letsencrypt.org/) or, if you're part of an organization with an IT department like a university, you can ask your friendly local IT professional. In a pinch, just to get things running, you can make a self-signed one like so:

.. code-block:: console

$ mkdir -p ./compose/production/nginx/certs
$ openssl req -x509 -sha256 -nodes -newkey rsa:2048 -days 365 -keyout ./compose/production/nginx/certs/cert.key -out ./compose/production/nginx/certs/cert.crt
69 changes: 69 additions & 0 deletions production-demo.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
version: "3"

volumes:
production_postgres_data: {}
production_postgres_data_backups: {}

services:
django:
build:
context: .
dockerfile: ./compose/production/django/Dockerfile
image: llemr_production_django
container_name: django
ports:
- 5000:5000
depends_on:
- postgres
- redis
environment:
- DJANGO_SETTINGS_MODULE=config.settings.production-demo
env_file:
- ./.envs/.production/.django
- ./.envs/.production/.postgres
- ./.envs/.secrets/.postgres
- ./.envs/.secrets/.django
command: /start
networks:
- nginx_network
- database_network

postgres:
build:
context: .
dockerfile: ./compose/production/postgres/Dockerfile
image: llemr_production_postgres
container_name: postgres
volumes:
- production_postgres_data:/var/lib/postgresql/data
- production_postgres_data_backups:/backups
env_file:
- ./.envs/.production/.postgres
- ./.envs/.secrets/.postgres
networks:
- database_network

nginx:
image: nginx:1.21
container_name: nginx
ports:
- 80:80
- 443:443
env_file:
- ./.envs/.production/.nginx
volumes:
- ./compose/production/nginx/templates:/etc/nginx/templates
- ./compose/production/nginx/certs:/etc/nginx/certs
depends_on:
- django
networks:
- nginx_network

redis:
image: redis:5.0

networks:
nginx_network:
driver: bridge
database_network:
driver: bridge
Loading