Deployment
Hier ein paar Tipps, wie ein Projekt heutzutage deployed wird. Django selbst bietet eine Checkliste, was alles gemacht werden muss, um sauber uns sicher zu Deployen
https://docs.djangoproject.com/en/stable/howto/deployment/checklist/
Git
Das Projekt sollte via git
versioniert und bei github
gehostet werden.
GitHooks
kein Code sollte ins share repository wie github
gehen, der schlecht
formatiert ist oder Test-Fehler enthält. Um diesem Problem entgegenzuwirken,
lassen sich sogenannte Hooks einrichten. Der Wichtigste Hook ist der
pre-commit-hook
, der VOR dem Commit den Code testet und dann erst den
Commit zulässt. Konfiguriert wird das ganze in einer
pre-commit-config.yaml
-Datei.
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v3.ref
hooks:
- id: check-docstring-first
- id: check-merge-conflict
- id: trailing-whitespace
- id: end-of-file-fixer
- id: check-yaml
- id: check-ast
- id: check-toml
- repo: https://gitlab.com/pycqa/flake8
rev: 3.9.2
hooks:
- id: flake8
args: ['--config=setup.cfg', '--ignore=Fstable,E501,F405,F403']
exclude: ^events/tests/
- repo: local
hooks:
- id: django-test
name: django-test
entry: python manage.py test
always_run: true
pass_filenames: false
language: system
- repo: https://github.com/pycqa/isort
rev: 5.9.3
hooks:
- id: isort
name: isort (python)
Dieser Pre-Commit-Hook zum Beisiel prüft den Code auf flake8-Verstöße, führt
mit manage.py test
die Tests durch, sortiert die Imports mit isort
und
prüft merge-Konflikte, Yaml und Toml - Dateien.
CI/CD - Pipeline
Heute kommt kein Projekt mehr ohne Continous Integration
bzw. Continous
Deployment
aus. Eine Einführung findet sich hier:
https://www.freecodecamp.org/news/how-to-setup-a-ci-cd-pipeline-with-github-actions-and-aws/
Docker
Wenn im Team gearbeitet wird, gibt es unweigerlich Unterschiede in der Konfiguration zwischen den lokalen Rechnern der einzelnen Entwickler. Ganz zu schweigen von dem Unterschied lokale Konfiguration mit der produktiven Konfiguration. Um diesem Problem entgegenzuwirken, wird heute fast ausschließlich mit Containern gearbeitet. So kann sichergestellt werden, dass jede lokale Instanz des Projekts inkl. der Peripherie wie Datenbank, Message-Broker, Celery etc, identisch mit der Produktiv-Instanz ist.
Eine kleine Einführung gibt es hier: https://docs.docker.com/samples/django/ Ansonsten finden sich unzählige Tutorials im Internet.
Docker Container sind einfach skalierbar und zum Beispiel mit Kubernetes
orchestrierbar.
eine einfache docker-compose - Datei für die lokale Entwicklungsumgebung könnte so aussehen:
version: '3.8'
services:
app:
build: ./app
command: >
sh -c "python manage.py runserver 0.0.0.0:8000"
volumes:
- ./app/:/usr/src/app/
ports:
- 8000:8000
env_file:
- ./.env
depends_on:
- db
- redis
db:
image: postgres:13.0-alpine
volumes:
- postgres_data:/var/lib/postgresql/data/
environment:
- POSTGRES_USER=basepro
- POSTGRES_PASSWORD=basepro
- POSTGRES_DB=basepro_dev
redis:
image: redis:alpine
volumes:
postgres_data:
driver: local
Auf Sicherheitslücken prüfen
Auf dem Livesystem sollte beim ersten Deploy festgestellt werden, ob es Sicherheitslücken gibt. Diese gleich fixen.
> python manage.py check --deploy
WARNINGS:
?: (security.W004) You have not set a value for the SECURE_HSTS_SECONDS setting.
If your entire site is served only over SSL, you may want to consider setting a
value and enabling HTTP Strict Transport Security. Be sure to read the
documentation first; enabling HSTS carelessly can cause serious, irreversible
problems.
Fehler still stellen
Manche Fehler werden an anderere Stelle besser behoben. Zum Beispiel werden die
HSTS-Header ( HTTP Strict-Transport-Security response header ) oft von NGINX
gesetzt. Dann kann man die Fehlermeldungen in den settings.py
auch muten:
SILENCED_SYSTEM_CHECKS = ["security.W004"]
Webserver
Bisher hatten wir zum Starten unserer Appliation den Runserver benutzt, den wir
mit python manage.py runserver
gestartet haben. Der Runserver ist für die
Entwicklungsphase auf dem lokalen Rechner gedacht, nicht aber für den
Produktivbetrieb. Die Gründe sind vielfältig: der Server ist nicht für hohen
Traffic ausgelegt und es besteht auch nicht die Möglicheit, den Server zu
tunen. Außerdem ist unsicher.
In einem Live-System betreiben wir nginx
als Proxyserver, der die Last
verteilt und den Input weiterroutet an den Webserver gunicorn
.
eigener Server
Das Endprodukt kann natürlich auf einem eigenen Server betrieben werden. Dazu
nötig ist ein Linux-Betriebsystem, Firewall, eine Datenbank und so weiter.
Idealerweise läuft auf diesem System Docker, dann lässt sich der
Docker-Container nutzen. Als Server dient nginx
, der bei mehreren
Docker-Containern auch gleich als Load-Balancer fungieren kann.
Allerdings ist das mit Aufwand verbunden.
Platform as a service
Einfacher geht’s mit Heroku
. Der hochspezialisierte
Platform-as-a-service-Dienst übernimmt die schwierigen Aufgaben, die
Infrastrutkur in Gang zu halten, während sich der Entwickler nur noch um die
Software kümmern muss.
Ein Tutorial dazu findet sich hier: https://realpython.com/django-hosting-on-heroku/
Fehler loggen mit Rollbar oder Sentry
Moderne Plattformen mit vielen Tausenden Usern produzieren Fehler. Um diese
Fehler komfortabel auszuwerten, nutzen wir kommerzielle Error-Tracking-Dienste,
die diese Aufgabe für uns übernehmen. Rollbar
zum Beispiel bietet
Gratis-Accounts für kleine websites an.
Projekt mit gunicorn starten
Um zu testen, ob das System soweit läuft, kann man es mit gunicorn starten.
gunicorn event_manager.wsgi