Communitygithub.com

Bohdan-Meshcheriakov/deploy-data-clerk

Bereitstellung, Konfiguration und Betrieb einer App auf dem Data-Clerk-Kubernetes-Cluster (data-clerk.com). Verwende dies, wenn der Benutzer die App bereitstellen, veröffentlichen oder live schalten möchte, Umgebungsvariablen, API-Schlüssel oder Secrets ändern, secrets.env bearbeiten oder sops verwenden, Tools dafür installieren, eine Datenbanktabelle oder Migration hinzufügen, Fragen zur Datenbank, Backups oder Datenwiederherstellung hat, eine Domain oder HTTPS konfigurieren möchte oder wissen will, warum die Seite ausgefallen ist oder sich nach einem Push nicht aktualisiert hat.

Was ist deploy-data-clerk?

Diese Fähigkeit beschreibt den vollständigen Bereitstellungs- und Betriebsworkflow für eine Anwendung, die auf Data Clerk gehostet wird – einem kleinen, von einem menschlichen Operator verwalteten Kubernetes-Cluster. Sie ist als zentrale Anleitung für Entwickler gedacht, die keine Infrastruktur-Experten sind: Sie pushen Code in den `main`-Branch, und der Cluster kümmert sich um den Rest. Die Fähigkeit definiert einen klaren Vertrag, der sicherstellt, dass Bereitstellungen zuverlässig sind: Die App muss auf `$PORT` lauschen, das Docker-Image muss für `linux/amd64` als Nicht-Root-Benutzer erstellt werden, und Datenbankmigrationen müssen sicher für die alte Version sein (zuerst hinzufügen, später umbenennen/löschen). Die Fähigkeit behandelt auch die Verwaltung von Umgebungsvariablen und Secrets mittels sops (verschlüsselt in `secrets.env`), die Datenbank (Postgres 18, automatische Backups), Netzwerkdetails (Cloudflare, Traefik, Proxy-Header, Outbound-Verbindungen) und die Zusammenarbeit mit dem Operator für Aufgaben, die Clusterzugriff erfordern (neue Domains, mehr Ressourcen, Datenbank-Wiederherstellungen). Die Fähigkeit unterstützt jede Sprache oder jedes Framework, solange die Regeln eingehalten werden, und enthält Verweise auf detaillierte Referenzdokumente für Stacks, neue Projekte, Secrets, Datenbanken, Tools und Fehlerbehebung.

Funktioniert mit~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/Bohdan-Meshcheriakov/data-clerk-skills/tree/HEAD/skills/deploy-data-clerk

In Ihrer bevorzugten KI fragen

Öffnet einen neuen Chat, in dem dieser Agent-Skill bereits geladen ist.

Dokumentation

Bereitstellung auf Data Clerk

Diese App läuft auf Data Clerk, einem kleinen, von einem Betreiber (einer Person, Kontakt in PROJECT.md) verwalteten Kubernetes-Cluster. Der Besitzer dieses Repos ist normalerweise keine Infrastruktur-Person. Er sollte niemals Server, Kubernetes oder eine Cloud-Konsole berühren müssen: Er pusht in main, und der Cluster erledigt den Rest. Deine Aufgabe ist es, das so zu halten: Arbeite innerhalb des Repos, befolge den untenstehenden Vertrag und schreibe dem Betreiber eine klare Anfrage, wenn etwas wirklich auf der Clusterseite erledigt werden muss, anstatt zu improvisieren.

Erkläre dem Benutzer Dinge in einfachen Worten ("Deine Seite wird in etwa fünf Minuten aktualisiert"), nicht in Kubernetes-Begriffen.

Starte hier

  1. Lies deploy-data-clerk/PROJECT.md. Es enthält die Werte dieses Projekts: öffentliche URL, das Bereitstellungsverzeichnis, den Image-Namen, den Port, den Migrationsbefehl, Limits und wer der Betreiber ist. Alles, was unten "aus PROJECT.md" sagt, bezieht sich auf diese Datei. Wenn der Ordnername in PROJECT.md von deploy-data-clerk/ abweicht (ältere Projekte verwenden deploy/), verwende das, was PROJECT.md sagt.
  2. Keine PROJECT.md oder sie enthält noch __PLACEHOLDER__-Werte? Das Projekt ist noch nicht onboarded: Folge references/new-project.md.
  3. Du schreibst oder änderst ein Dockerfile, entscheidest, wie du die App strukturierst, oder der Stack ist nicht Node? Lies references/stacks.md (jede Sprache, Full-Stack vs. getrenntes Frontend + API, FastAPI, Go).
  4. Bevor du die erste Secrets-Aufgabe auf einem Rechner ausführst, stelle sicher, dass die Tools funktionieren: sops --version und eine Test-Entschlüsselung (sops decrypt <deploy folder>/secrets.env > /dev/null). Wenn etwas fehlschlägt, folge references/setup-tools.md.

Wie eine Änderung die Live-Seite erreicht

Was sich geändert hatWas passiertLive nach
Code (Push in main)GitHub Actions erstellt ein Docker-Image und pusht es; der Cluster bemerkt den neuen Image-Tag und rollt es aus~3–7 Min (Build-Zeit + ~1 Min)
secrets.env (Push in main)Der Cluster liest alle 5 Minuten das Bereitstellungsverzeichnis neu, entschlüsselt es, aktualisiert die Umgebung der App und startet die App neu~5 Min
Eine neue Datei in migrations/Wird automatisch ausgeführt, bevor die neue Version startetmit dem Code-Deploy
Alles außerhalb von mainNichts. Branches und PRs werden nicht deployed—

Die Ausrollung erfolgt vorsichtig: Die neue Version startet neben der alten, Migrationen werden zuerst ausgeführt, und der Datenverkehr wechselt erst, wenn die neue Version ihren Healthcheck besteht. Wenn der Build, eine Migration oder der Healthcheck fehlschlägt, bedient die alte Version weiter und die Seite bleibt online. Ein fehlgeschlagener Deploy bedeutet "die Änderung ist nicht live", nicht "die Seite ist down".

Um einen Deploy zu überprüfen: gh run list --workflow "Deploy to cluster" --limit 3 (oder den Reiter "Actions" auf GitHub), dann öffne die öffentliche URL. Um ohne Codeänderung neu zu deployen: gh workflow run "Deploy to cluster", das einen neuen Tag erstellt, sodass die App mit einer frischen Umgebung neu startet.

Der Vertrag (was Deploys funktionieren lässt)

Jede Regel existiert, weil ein Verstoß sie stillschweigend fehlschlagen lässt oder Daten verloren gehen. Halte dich daran und sage dem Benutzer, wenn eine Anfrage eine Regel verletzen würde.

  • Höre auf $PORT (der Port in PROJECT.md, vom Cluster gesetzt), auf 0.0.0.0, nicht localhost.
  • Das Image wird aus <deploy folder>/Dockerfile für linux/amd64 erstellt und läuft als Nicht-Root-Benutzer. Kein Root, keine Ports unter 1024, keine zusätzlichen Linux-Fähigkeiten.
  • Image-Tags sind YYYYMMDDHHMMSS-<shortsha>. Der Cluster deployt die höchste Zahl und ignoriert stillschweigend jeden Tag, der nicht in diesem Format ist. Ändere niemals den Tag-Schritt in .github/workflows/deploy-cluster.yml.
  • Die Festplatte des Containers wird bei jedem Deploy und Neustart gelöscht. Behalte niemals Benutzer-Uploads, SQLite-Dateien oder etwas Wertvolles auf der lokalen Festplatte. Lege Daten in der Datenbank ab; für Dateien (Fotos, Videos) frage den Betreiber nach Objektspeicher.
  • Healthcheck: Der Cluster prüft den Health-Pfad in PROJECT.md (/healthz empfohlen). Lass ihn schnell 200 zurückgeben, ohne Datenbankaufruf oder Seitenrendering, da eine langsame Datenbank den Cluster glauben lässt, die App sei tot.
  • DATABASE_URL kommt vom Cluster. Setze sie niemals in secrets.env (das würde die echte überschreiben) und setze sie niemals zur Image-Build-Zeit.
  • Laufzeit vs. Build-Zeit. secrets.env erreicht die App nur zur Laufzeit. Das Image wird in GitHub Actions ohne sie erstellt. Alles, was zur Build-Zeit in das Frontend eingebunden wird (VITE_*, NEXT_PUBLIC_*, REACT_APP_*), kann nicht aus secrets.env kommen: Lies solche Werte zur Laufzeit auf dem Server und gib sie an die Seite weiter, oder (falls nicht geheim) committe sie im Code.
  • Secrets, die die App für sich selbst generiert, wenn sie fehlen (Auth/Session-Secret, Verschlüsselungs-Salze, Push-Schlüssel): Setze sie in secrets.env. Andernfalls erstellt jeder Neustart neue, Benutzer werden ausgeloggt, Push-Abonnements brechen und so weiter.
  • Migrationen müssen für die alte Version sicher sein. Für etwa eine Minute laufen beide Versionen gegen das neue Schema. Füge Spalten und Tabellen frei hinzu. Benenne um oder lösche in zwei Deploys: Verwende es zuerst nicht mehr, dann entferne es. Details in references/database.md.

Umgebungsvariablen und Secrets

Die gesamte Laufzeitkonfiguration lebt in <deploy folder>/secrets.env, verschlüsselt mit sops committet. Nur Werte sind verschlüsselt; Schlüsselnamen bleiben lesbar. Ändere sie mit sops selbst. Entschlüssele sie niemals in eine Datei, die du committen könntest, und gib niemals Secret-Werte in den Chat oder in Logs aus.

sops set deploy-data-clerk/secrets.env '["STRIPE_SECRET_KEY"]' '"sk_live_..."'
sops unset deploy-data-clerk/secrets.env '["OLD_KEY"]'
sops decrypt deploy-data-clerk/secrets.env | cut -d= -f1

Dann committe und pushe in main; es ist in ~5 Min live. Wenn der Benutzer den Wert bereitstellen muss (einen API-Schlüssel von einem Dashboard), lass ihn die sops set-Zeile selbst ausführen oder füge den Wert nur in sein eigenes Terminal ein. Die vollständige Anleitung (Schlüssel, wo sie leben, Rotieren, Fallstricke) befindet sich in references/secrets.md.

Datenbank

Postgres 18, verwaltet vom Betreiber. Die App bekommt ihre eigene Datenbank und ihren eigenen Benutzer über DATABASE_URL. Schemaänderungen sind Migrationsdateien, die sich beim Deploy selbst anwenden (references/database.md).

Backups: Ein vollständiges Backup jede Nacht um 03:00 UTC plus ein kontinuierliches Log jeder Änderung, das außerhalb des Servers in Google Cloud Storage gespeichert wird. Der Betreiber kann die Datenbank zu jedem Zeitpunkt innerhalb der letzten 7 Tage wiederherstellen. Wenn also Daten gelöscht werden oder eine Migration schiefgeht, keine Panik und versuche nicht, es von Hand zu beheben: Notiere den Zeitpunkt und bitte den Betreiber um eine Wiederherstellung (Vorlage in references/troubleshooting.md). Eine Wiederherstellung dreht die gesamte Datenbank zurück, sodass Änderungen, die nach diesem Zeitpunkt vorgenommen wurden, verloren gehen.

Netzwerk-Fakten, die dein Code kennen könnte

  • Verkehrsweg: Besucher → Cloudflare → Traefik (Cluster-Ingress) → App. HTTPS-Zertifikate sind automatisch. Die App selbst spricht einfaches HTTP auf $PORT; X-Forwarded-Proto: https sagt, dass das Original HTTPS war. Vertraue den Proxy-Headern und leite in der App nicht auf HTTPS um (das würde eine Schleife erzeugen).
  • Echte Besucher-IP: Lies den CF-Connecting-IP-Header. X-Forwarded-For enthält eine Cloudflare-Adresse, daher würde eine Ratenbegrenzung darauf alle Besucher in einen Topf werfen.
  • Traefik fügt diese Header hinzu: HSTS (2 Jahre, Preload), X-Content-Type-Options: nosniff, X-Frame-Options: SAMEORIGIN (die Seite kann nicht in einem Iframe auf anderen Domains eingebettet werden). Zusätzliche Header (CSP, COOP/COEP für SharedArrayBuffer, Erlauben von Iframes) werden vom Betreiber auf Anfrage gesetzt.
  • Der Ingress komprimiert Antworten nicht. Cloudflare komprimiert gängige Texttypen; für die volle Kontrolle komprimiere in der App oder liefere vor-komprimierte Assets aus.
  • Lange Verbindungen (SSE, Websockets) sind in Ordnung, aber Cloudflare beendet eine Verbindung, die ~100 s idle ist. Sende alle ~30 s einen Heartbeat und stelle die Verbindung auf Client-Seite wieder her.
  • Ausgehend: Die App kann jeden öffentlichen Internet-Endpunkt auf jedem Port aufrufen. Das umfasst LLM-APIs, Stripe, E-Mail, S3 und verwaltete Datenbanken oder Redis (Neon, Supabase, Atlas, Upstash) auf ihren öffentlichen Endpunkten. Sie kann keine privaten Netzwerke (VPC-Peering, PrivateLink, private IPs) oder andere Projekte auf dem Cluster erreichen. Eingehender Datenverkehr kommt nur über die öffentliche URL.
  • Drittanbieter-Dienste: Lege ihre Schlüssel und URLs in secrets.env. Wenn ein Dienst eine IP-Allowlist benötigt, hat der Cluster eine statische ausgehende IP: Frage den Betreiber danach (sie ist nicht veröffentlicht) und sage dem Benutzer, dass sie mit anderen Projekten auf dem Cluster geteilt wird. Der Server befindet sich in US-central, daher bevorzuge US-central/us-east-Regionen für externe Datenbanken (eine EU-Datenbank fügt ~100 ms pro Abfrage hinzu). Eine externe Datenbank gehört dem Benutzer selbst: Data Clerks Backups decken sie nicht ab. Für langsame LLM-Aufrufe streamst du die Antwort oder führst sie als Hintergrundjobs aus; eine Browseranfrage, die über ~100 s wartet, wird abgeschnitten.
  • Ressourcen sind begrenzt (Speicher/CPU in PROJECT.md). Das Überschreiten des Speicherlimits tötet und startet die App neu. Wenn das passiert, frage den Betreiber nach mehr Spielraum, anstatt es im Code zu bekämpfen.
  • Eine Kopie der App läuft (ein Replica). Verlasse dich nicht auf den In-Memory-Zustand, der einen Deploy überlebt, und behalte Sitzungen in der DB oder in signierten Cookies.

Was nur der Betreiber tun kann

Der Benutzer hat keinen Cluster-Zugriff, und das ist beabsichtigt. Schreibe dem Betreiber eine kurze Anfrage (siehe references/troubleshooting.md für die Vorlage) für:

neue Domain oder Subdomain · mehr Speicher/CPU · Datei-/Objektspeicher · eine Datenbankwiederherstellung · App-Logs oder Absturzursachen · geänderte Sicherheitsheader · Ändern des Migrations- oder Startbefehls, Ports oder Health-Pfads · geplante Jobs (Cron) · zusätzliche Dienste (Redis, Warteschlangen) · eine zweite App im selben Projekt · Onboarding eines neuen Repos.

Mehr Details

  • references/stacks.md: Der universelle Vertrag für jede Sprache; Full-Stack vs. SPA + API vs. statisch; Node, Python FastAPI, Go und andere Stacks.
  • references/new-project.md: Onboarding eines Repos (hinzuzufügende Dateien, was den Betreiber zu fragen, Dockerfile pro Stack).
  • references/secrets.md: sops im Detail, die Schlüsseldatei, Rotieren, Build-Zeit-Variablen.
  • references/database.md: Migrationen, Verbindungszeichenfolge, Backups, Datenkorrekturen.
  • references/setup-tools.md: Sicheres Installieren von sops/git/gh auf macOS, Linux und Windows. Führe scripts/install-tools.sh oder scripts/install-tools.ps1 aus.
  • references/troubleshooting.md: "Meine Änderung ist nicht live", "Seite ist down", häufige Fehler, die Vorlage für Betreiberanfragen.
  • assets/: Dockerfile-Vorlagen (Node, Python, Go) und Vorlagen für den Deploy-Workflow, kustomization.yaml, .sops.yaml, .gitattributes und PROJECT.md.

Verwandte Skills