Eine Django-SaaS deployen
Hello-World-Deployments lassen alles weg, was Produktion schwierig macht. Dieser Guide deployt UpCheck, eine echte, quelloffene Django-SaaS (ein Uptime-Monitor mit Registrierung, Hintergrund-Checks und öffentlichen Statusseiten), von Anfang bis Ende: Datenbank, Hintergrund-Worker, geplante Tasks, Migrationen, HTTPS. Das Setup lässt sich auf fast jede Django-, Rails- oder Laravel-Anwendung übertragen.
Das ist der Weg von Hand, mit kubectl und helm. Auf einem PaaSbox-Cluster mit dem Add-on
PaaSbox Platform (im Labor gebaut, noch nicht veröffentlicht) ersetzt ihn eine einzige SaaSApplication: Sie betreibt die vier
Rollen, legt Postgres und einen Redis-kompatiblen Cache (Valkey) an, führt vor jedem Release die
Migrationen aus und fordert das Zertifikat an. Schritt 2 des Lernpfads,
Deine erste App deployen, deployt UpCheck auf diese Weise.
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-Objekte |
|---|---|---|
| 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 Kubernetes-Cluster; ein einzelner
cpx32-Node reicht für UpCheck. Dazukubectl,helmund eine Domain, die dir gehört. - Das Repo:
git clone https://github.com/mitja/upcheck && cd upcheck
Auf einem PaaSbox-Cluster
Abschnitt betitelt „Auf einem PaaSbox-Cluster“Ohne das Plattform-Add-on folgst du den Schritten unten mit vier Änderungen. Das Overlay
deploy/overlays/paasbox/ des Repos wurde für einen Cluster mit ingress-nginx und Hetzner-Volumes
geschrieben:
- Schritt 1: Installiere nur den Operator CloudNativePG. Lass ingress-nginx weg: Traefik bedient
schon die Ports 80 und 443 des Servers, und der Cluster legt keinen Hetzner Load Balancer an. Lass
die Helm-Installation von cert-manager und
deploy/cluster-issuer.yamlweg: Schalte stattdessen das cert-manager-Add-on an, wie in Eine App mit Ingress und TLS veröffentlichen. - Schritt 2: Richte den A-Eintrag auf die öffentliche IPv4-Adresse des Servers, die Adresse, auf die der API-Name des Clusters auflöst.
ingress.yamlim Overlay: SetzingressClassName: traefikund die Annotationcert-manager.io/cluster-issuer: letsencrypt-production.kustomization.yamlim Overlay: Zwei Patches verlangen die Storage-Classhcloud-volumes, einer für Postgres, einer für Redis. Schalte das Add-on Hetzner volumes an (hcloud-csi), oder ändere beide auflocal-lvm-thin, die eigene Platte des Servers.
1. Cluster-Add-ons installieren (einmalig)
Abschnitt betitelt „1. Cluster-Add-ons installieren (einmalig)“Drei Add-ons, die ohnehin jeder Produktions-Cluster braucht. 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 alle Konten im Free-Plan, was für einen Walkthrough 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 als eigenen Schritt ausführen
Abschnitt betitelt „4. Deployen, und Migrationen als eigenen Schritt 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 „alles anwenden“ kann sie also nicht erneut ausführen. Löschen-dann-anwenden pro Release ist
das zuverlässige Muster. Der Job führt manage.py migrate aus und registriert den Beat-Schedule,
und die Deployments für web/worker/beat starten, 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. Das ist das komplette SaaS: 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 Aus GitHub Actions deployen: dieselben Befehle mit einer kurzlebigen kubeconfig.
Auf deine eigene App übertragen
Abschnitt betitelt „Auf deine eigene App übertragen“Die UpCheck-Manifeste sind eine Vorlage, die du kopieren kannst: 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 Fußnoten: Setze Resource-Requests auf jeder Rolle (die Manifeste im Repo tun das; nur so kann der Scheduler mehr Workloads auf einem kleinen Cluster unterbringen), und wenn du mit dem Walkthrough fertig bist, räum auf (unten) oder lösche den Cluster, statt seine Server 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 balancerAuf einem PaaSbox-Cluster reicht die erste Zeile. Schalte das cert-manager-Add-on auf dem Reiter Add-ons des Clusters aus, wenn nichts anderes es nutzt.