Ein Django-SaaS deployen
Hello-World-Deployments verstecken alles, was Produktion interessant macht. Dieser Guide deployt UpCheck – ein echtes, quelloffenes Django-SaaS (ein Uptime-Monitor mit Registrierung, Hintergrund-Checks und öffentlichen Statusseiten) – von Anfang bis Ende: Datenbank, Hintergrund-Worker, geplante Tasks, Migrationen, HTTPS. Es ist dasselbe Setup, mit dem die Live-Instanz auf upcheck.paasbox.com läuft, und die Form lässt sich auf fast jede Django- (oder Rails- oder Laravel-)Anwendung übertragen.
Die Form einer echten App
Abschnitt betitelt „Die Form einer echten App“Ein Container-Image (ghcr.io/mitja/upcheck) übernimmt per Command-Override vier Rollen:
| Rolle | Was sie ausführt | Kubernetes-Form |
|---|---|---|
| web | gunicorn + WhiteNoise | Deployment + Service |
| worker | Celery-Worker (die eigentlichen Uptime-Checks) | Deployment |
| beat | Celery Beat (plant die Checks) | Deployment, eine Replica |
| migrate | manage.py migrate + Task-Bootstrap | einmaliger Job, pro Release |
Dazu PostgreSQL über den CloudNativePG-Operator
und ein Redis mit einer Instanz als Celery-Broker. Die Manifeste liegen im Repo unter
deploy/ als kustomize-Base mit Overlays (kind für lokal, paasbox für Produktion).
Was du brauchst
Abschnitt betitelt „Was du brauchst“- Einen Cluster (Quickstart – ein
cpx32-Worker reicht für UpCheck locker),kubectl,helmund eine Domain, die dir gehört. - Das Repo:
git clone https://github.com/mitja/upcheck && cd upcheck
1. Cluster-Add-ons installieren (einmalig)
Abschnitt betitelt „1. Cluster-Add-ons installieren (einmalig)“Drei Add-ons, die ohnehin jeder Produktions-Cluster haben will – der Ingress-und-TLS-Guide erklärt jedes im Detail:
# CloudNativePG operatorkubectl apply --server-side -f \ https://raw.githubusercontent.com/cloudnative-pg/cloudnative-pg/release-1.30/releases/cnpg-1.30.0.yaml
# ingress-nginx — provisions a Hetzner load balancer (on your Hetzner bill)helm upgrade --install ingress-nginx ingress-nginx \ --repo https://kubernetes.github.io/ingress-nginx \ --namespace ingress-nginx --create-namespace \ --set controller.service.annotations."load-balancer\.hetzner\.cloud/location"=nbg1
# cert-manager + a Let's Encrypt issuer (edit the email in the file first)helm upgrade --install cert-manager cert-manager \ --repo https://charts.jetstack.io \ --namespace cert-manager --create-namespace \ --set crds.enabled=truekubectl apply -f deploy/cluster-issuer.yaml2. DNS auf den Load Balancer zeigen lassen
Abschnitt betitelt „2. DNS auf den Load Balancer zeigen lassen“kubectl -n ingress-nginx get svc ingress-nginx-controller \ -o jsonpath='{.status.loadBalancer.ingress[0].ip}'Lege einen A-Eintrag für deinen Host an, der auf diese IP zeigt, und ändere den Hostnamen in
deploy/overlays/paasbox/ von upcheck.paasbox.com auf deine eigene Domain.
3. Secrets anlegen (außerhalb des Repos, nie committet)
Abschnitt betitelt „3. Secrets anlegen (außerhalb des Repos, nie committet)“kubectl create namespace upcheckkubectl -n upcheck create secret generic upcheck-secrets \ --from-literal=SECRET_KEY="$(python3 -c 'import secrets; print(secrets.token_urlsafe(50))')"Das ist das Minimum – UpCheck wickelt seine Abrechnung über Polar ab, und ohne die optionalen
POLAR_*-Keys laufen einfach alle Konten im Free-Plan, was für einen Walkthrough genau richtig
ist. Beachte, was hier nicht steht: kein Datenbank-Passwort. CNPG erzeugt das Secret pg-app
selbst, und die App verwendet dessen uri-Key als DATABASE_URL.
4. Deployen – und Migrationen ehrlich ausführen
Abschnitt betitelt „4. Deployen – und Migrationen ehrlich ausführen“kubectl apply -k deploy/overlays/paasbox
# wait for Postgres, then migratekubectl -n upcheck wait --for=condition=Ready cluster/pg --timeout=420skubectl -n upcheck delete job upcheck-migrate --ignore-not-foundkubectl apply -f deploy/overlays/paasbox/migrate-job.yamlkubectl -n upcheck wait --for=condition=complete job/upcheck-migrate --timeout=300sDer Migrate-Job ist bewusst nicht Teil der Kustomization: Kubernetes-Jobs sind unveränderlich,
ein „einfach alles anwenden“ kann sie also nicht erneut ausführen. Löschen-dann-anwenden pro
Release ist das langweilige, zuverlässige Muster – der Job führt manage.py migrate aus und
registriert den Beat-Schedule, und die Deployments für web/worker/beat legen los, sobald das
Schema existiert.
5. Prüfen
Abschnitt betitelt „5. Prüfen“kubectl -n upcheck get podscurl -I https://upcheck.example.com # your domain: valid Let's Encrypt cert + 200Öffne die Seite, registriere dich, lege einen Monitor für example.com an und sieh zu, wie der
Worker ihn nach Zeitplan prüft – ein kompletter SaaS-Kreislauf: Web-Schicht, asynchrone Worker,
Scheduler, Datenbank, TLS.
6. Updates ausrollen
Abschnitt betitelt „6. Updates ausrollen“Die CI veröffentlicht bei jedem Commit ghcr.io/mitja/upcheck:latest und :sha-<commit>. Für
reproduzierbare Deploys pinnst du newTag in overlays/paasbox/kustomization.yaml (und das Image
in dessen migrate-job.yaml) auf einen sha-Tag, dann:
kubectl apply -k deploy/overlays/paasboxkubectl -n upcheck delete job upcheck-migrate --ignore-not-foundkubectl apply -f deploy/overlays/paasbox/migrate-job.yamlkubectl -n upcheck rollout restart deploy/web deploy/worker deploy/beatWie du das aus der CI statt vom Laptop ausführst, zeigt der Guide CI/CD mit GitHub Actions – dieselben Befehle, angetrieben von einer kurzlebigen kubeconfig.
Auf deine eigene App übertragen
Abschnitt betitelt „Auf deine eigene App übertragen“Die UpCheck-Manifeste sind eine Vorlage, die man guten Gewissens klauen darf: ein Image mit
Command-Overrides pro Rolle, ein CNPG-Cluster mit dem generierten Secret pg-app, Secrets
außerhalb des Repos angelegt, ein Migrationsschritt als unveränderlicher Job und ein Ingress mit
der Annotation cert-manager.io/cluster-issuer. Tausche Image, Hostname und Umgebungsvariablen
aus, und derselbe deploy/-Baum betreibt die meisten Web-Anwendungen.
Zwei ehrliche Fußnoten: Setze Resource-Requests auf jeder Rolle (die Manifeste im Repo tun das – nur so kann der Scheduler einen kleinen Cluster effizient packen), und wenn dein Walkthrough-Cluster nichts zu tun hat, versetze ihn in den Ruhezustand, statt ihn weiter abrechnen zu lassen.
Aufräumen
Abschnitt betitelt „Aufräumen“kubectl delete namespace upcheckhelm -n cert-manager uninstall cert-managerhelm -n ingress-nginx uninstall ingress-nginx # deletes the Hetzner load balancer