Skip to content

Containerization and Deployment

Felix Lampe edited this page Jan 16, 2025 · 4 revisions
flowchart TB
    user-device([visitor's device])-- visit site -->reverse-proxy
    subgraph localzero-monitoring-vm
        subgraph testing
            nginx-testing-- forward -->djangoapp-testing
            nginx-testing-- forward -->dbeaver-testing
            dbeaver-testing
        end
        subgraph production
            nginx-production-- forward -->djangoapp-production
            nginx-production-- forward -->dbeaver-production
            dbeaver-production
        end
        subgraph exposed [exposed to web]
            reverse-proxy-- forward if HOST==monitoring-test.localzero.net -->nginx-testing
            reverse-proxy-- forward if HOST==monitoring.localzero.net -->nginx-production
            acme.sh-. configure updated certs .->reverse-proxy
        end
    end
Loading

The application is deployed to the server in the form of three Docker compositions:

  • reverse-proxy
  • testing environment
  • production environment

Each environment consists of:

  • the "djangoapp" container that run the gunicorn webserver to host the django app itself,
  • its own nginx (a proxy that hosts the static files while providing stability and security),
  • a server for the database web client (DBeaver),

Outside the environments and exposed to the web, there's a third "reverse-proxy" composition containing:

  • acme.sh, which handles SSL certificate renewal (see here),
  • the top-level reverse proxy nginx, which forwards requests to the environments based on the HOST header, or to acme.sh.

Building the Django app Docker image and running the container

The Dockerfile for the django app is based on the following resources:

It uses a multi-stage build to prevent shipping unnecessary files which would increase image size and attack surface.

To build the image, run the following command in the repository root directory:

docker compose build

Issues when building the Docker image on Apple CPU Macs (M1, M2)

You might run into errors building the Docker image on a Mac, getting messages like No working compiler found and Building wheel for cffi (setup.py): finished with status 'error'.

This is usually caused by certain Python packages not being available prebuilt for download for arm64-based macOS, because the macOS version gets encoded into package names on pypi. This leads to packages not being found after macOS updates until the package authors update their files.

A workaround is to add --platform linux/amd64 to the failing Docker command to simulate an amd64 architecture, so that generic linux packages are downloaded instead of the Apple CPU specific ones.

See also #45.

Deployment including nginx

To run both containers together, run the following command in the repository root directory (the app container will be built automatically if necessary):

docker compose up --detach

This will start both the Django app and the nginx containers in the background. The website can then be reached at https://localhost. You'll have to tell your browser to make an exception for the self-signed certificate we use when running locally, or import it into your browser.

To stop the containers from running in the background, run:

docker compose down --volumes

The --volumes flag is important to make sure that at the next start, the latest static resources from the app container are served instead of potentially outdated files from the previous run cached by Docker.