Skip to content

GreenRefuge/quango-smoothie

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

12 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

🍹 Quango Smoothie

Quasar in the front, Django in the back.

Blended to perfection and served up in your containers.

🧘‍♂️ Treat Yourself

  • Fast Development ⚡ Live Reloading environment with a single docker-compose up
  • Easy Deployment 📦 Package your project for Production into a single .tar.gz

🌅 Setup

Download Project

git clone https://github.com/GreenRefuge/quango-smoothie.git
cd quango-smoothie

Container images will be built on-demand (depending on the commands run below)

💻 Developing

Running Development Containers

docker-compose -f dev.yml up

The application can be accessed at https://127.0.0.1

  • Django Dev Environment
    • DEBUG=True is enabled in settings.py
    • collectstatic command is run before server start
  • Live/Hot Reloading
    • the Quasar server will watch for file changes under ./mount/quasar_app/quango_frontend
    • the Django server will watch for file changes under ./mount/django_app/quango_backend
    • ℹ️ changes to settings-related things (e.g. quasar.conf.js or settings.py) will possibly require a restart of the container
    • ℹ️ changes to package-related things (e.g. package.json or requirements.txt) will likely require a rebuild of the container image
    • ℹ️ changes to Django static files will requre a re-run of collectstatic command

🚀 Deploying

0. Collect Django static files

ℹ️ This step is only necessary if you have never run the Development containers, or static files changed since the last run

docker-compose -f dev.yml run --rm django_app /bin/bash -c ". ~/venv_django/bin/activate && cd /home/user/app_src/quango_backend && python manage.py collectstatic --noinput"
  • The static files will now be located in the django_staticfiles Docker named volume

1. Build Quasar app

docker-compose -f dev.yml run --rm quasar_app /bin/bash -c "cd app_src/quango_frontend && npx quasar build"
  • The build artifacts will now be located in the quasar_dist Docker named volume

1.5 (optional) Test Production build in-place

docker-compose -f prod.yml up
  • This will start the Production containers in your local environment
  • The application can be accessed at https://127.0.0.1
  • ℹ️ make sure to provide your own config/secrets in ./config/prod
    • you can just copy all the files under ./config/dev if you want to mirror the Development config/secrets
    • these will not be included by "pack" script (see Step 3) and are ignored by .gitignore
  • ⚠️ avoid doing this while Development containers are running! (volumes/ports are shared across environments)

2. Run "pack" script

This will create a minimal archive for easy deployment:

  • Production-related files are isolated, static files are extracted, and final config tweaks are applied
  • (this default project compresses down to 1.2 MB 💾)
docker-compose -f deploy.yml run --rm deploy_app
  • The generated prod_[TIMESTAMP].tar.gz file will now be located in ./mount/deploy_app

3. 🎉 Move, Build, Up

  • Move and extract prod_[TIMESTAMP].tar.gz to somewhere on your Production server
    • 🔑 IMPORTANT you must provide your own config/secrets
      • these will be .txt files under ./config/prod
      • use ./config/dev as a reference (just copy each file, replacing the contents with your own config)
  • docker-compose build
  • docker-compose up

📖 Notes

Repo Directory

  • things under the ./build directory are used during container image build(s) only
  • things under the ./mount directory are mounted within the container(s) during runtime
  • things under the ./config directory are Docker Secrets, distinguished by dev and prod subdirectories
  • on first run, Django creates a file db.sqlite3 in the (host-mounted) ./mount/databases directory
  • on each (Development) run, a symbolic link node_modules is created in the (host-mounted) ./mount/quasar_app/quango_frontend directory
  • on running "pack" script, the Production archive is created in the (host-mounted) ./mount/deploy_app directory

Pre-generated Apps

  • ./mount/django_app/quango_backend is:
    • a minimal Django app created with the django-admin startproject command (uses the default SQLite for storage)
  • ./mount/quasar_app/quango_frontend is:
    • a minimal Quasar app created with the quasar create command (base installation)

Interaction between Django and Quasar

  • Both apps operate independently
  • The files generated by quasar build are served at the site root (i.e. /)
  • All other routes are covered by Django (i.e. Django's static files, the /admin routes, and routes from urls.py)

NGINX

NGINX is used as a reverse proxy in both Development and Production environments in order to:

  • provide central point for SSL termination (HTTPS)
  • serve static files (Django static files and Quasar build artifacts)
  • facilitate environment-dependent routing

URL Routing

NGINX matches URLs according to the following rules:

  • anything under /static/ will be served from Django static files directory
    • errors for missing static files/routes are handled by NGINX directly (Django server is bypassed)
    • ⚠️ as you extend your Quasar project make sure it does not emit a directory /static, or else path conflict here
  • all other routes are handled as follows:
    • the Quasar dist directory is searched, file is returned if a match
      • when in Development mode, this request is passed to the Quasar dev server
    • if no match, the route is finally passed to the @fallback location (i.e. Django server)

SSL Support

Self-Signed Certificates

  • when the NGINX image is built, a self-signed certificate is generated in order to facilitate HTTPS handling
    • in Production, you will probably want to use a "real" certificate (e.g. via Caddy and/or Let's Encrypt)

HTTPS Redirection

  • by default, nothing is done to redirect clients from HTTP to HTTPS (both protocols are served)
    • ⚠️ if a client switches between protocols, may cause unexpected issues in browser (e.g. with protocol-dependent Cookies or Local Storage or remote resources)
  • Django has a setting SECURE_SSL_REDIRECT to address this (see commented-out line in settings.py)
    • (however, probably should handle redirect at NGINX layer only for better predictability)
  • NGINX could be configured to handle the redirection (as described here)
    • this would ensure all static assets are properly redirected in addition to Django routes

Django Server

  • Uvicorn is used to serve the Django project within its container
    • the server is bound to a Unix domain socket, which is exposed to the NGINX container via shared volume
    • in Production mode, Gunicorn is used to "drive" Uvicorn (as is recommended by the docs)