Zum Inhalt springen

How to: Weldall auf Google Cloud bereitstellen

Weldall und den Discovery-Proxy als Cloud-Run-Dienste mit Cloud SQL for PostgreSQL und Secret Manager betreiben.

Diese Anleitung stellt Weldall als Cloud-Run-Dienst mit einer Instanz bereit, speichert die Daten in Cloud SQL for PostgreSQL und die Secrets im Secret Manager und stellt den Discovery-Proxy als zweiten, unabhängigen Cloud-Run-Dienst bereit. Sie endet mit einem Backup, einem Upgrade und einem Rollback, damit du den Ablauf kennst, bevor du ihn brauchst.

Docker-Images erklärt die Images, Tags und das Startverhalten, auf denen diese Anleitung aufbaut.

  • Ein Google-Cloud-Projekt mit aktiver Abrechnung und die Owner-Rolle darin.
  • Die Cloud Shell. Dort sind gcloud, node und jq vorinstalliert; alle Befehle unten laufen dort.
  • Die Versionen der beiden Images, die du betreiben willst, zum Beispiel 0.5.1 für Weldall und 0.1.1 für den Discovery-Proxy. Die verfügbaren Versionen sind die Tags auf Docker Hub: seibertgroup/weldall und seibertgroup/weldall-discovery-proxy. Verwende ein vollständiges X.Y.Z-Tag, siehe Docker-Images.
  • Zugriff auf deinen Identity Provider, um einen OIDC-Client anzulegen, siehe How to: Installer ausführen.

Setze diese Variablen einmal pro Cloud-Shell-Sitzung:

Terminal-Fenster
PROJECT=your-project-id
PROJECT_NUMBER=$(gcloud projects describe "$PROJECT" --format="value(projectNumber)")
REGION=europe-west3
WELDALL_VERSION=0.5.1
PROXY_VERSION=0.1.1
DB_TIER=db-f1-micro # database machine type for a test; for production e.g. db-custom-1-3840
gcloud config set project "$PROJECT"
Terminal-Fenster
gcloud services enable run.googleapis.com sqladmin.googleapis.com \
secretmanager.googleapis.com iam.googleapis.com
Terminal-Fenster
gcloud sql instances create weldall-db \
--region "$REGION" \
--database-version POSTGRES_16 \
--edition ENTERPRISE \
--tier "$DB_TIER"
gcloud sql databases create weldall --instance weldall-db
  • Das Anlegen der Instanz dauert etwa 15 Minuten.
  • Der Befehl legt nur fest, was Weldall braucht: die Region des Cloud-Run-Dienstes, PostgreSQL 16 und eine Maschinengröße. Für Speicher, Verfügbarkeit und automatische Backups gelten die Standardwerte von Cloud SQL; prüfe sie in den Instanzeinstellungen gegen deine Anforderungen.
  • db-f1-micro ist eine Shared-Core-Maschinengröße für Tests und nicht vom Cloud-SQL-SLA abgedeckt. Für Produktion setzt du DB_TIER auf eine Größe mit dediziertem Kern, zum Beispiel db-custom-1-3840.
  • --edition ENTERPRISE ist für diese Maschinengrößen nötig; PostgreSQL 16 verwendet sonst Enterprise Plus.

Weldall wendet bei jedem Start seine Migrationen an, deshalb muss sein Datenbanknutzer das Schema ändern dürfen. Ein mit gcloud sql users create angelegter Nutzer gehört zu cloudsqlsuperuser und darf im Schema public von weldall Tabellen anlegen und ändern.

Das Passwort landet direkt in der Verbindungs-URL im Secret Manager und wird nirgends sonst gespeichert:

Terminal-Fenster
CONN="${PROJECT}:${REGION}:weldall-db"
pw=$(node -e 'process.stdout.write(require("node:crypto").randomBytes(24).toString("base64url"))')
gcloud sql users create weldall --instance weldall-db --password "$pw"
printf 'postgresql://weldall:%s@localhost/weldall?host=/cloudsql/%s' "$pw" "$CONN" \
| gcloud secrets create weldall-postgres-url \
--replication-policy user-managed --locations "$REGION" --data-file=-
unset pw

Cloud Run verbindet sich über einen Unix-Socket unter /cloudsql/ mit Cloud SQL. Der Host in der URL bleibt localhost; der Socket-Pfad steht im Parameter host. Die Instanz braucht keine freigegebenen Netzwerke.

Jeder Dienst läuft unter einem eigenen Konto mit genau den Rechten, die er braucht. Der Proxy braucht keine.

Terminal-Fenster
gcloud iam service-accounts create weldall-run --display-name "Weldall on Cloud Run"
gcloud iam service-accounts create weldall-proxy-run --display-name "Weldall discovery proxy on Cloud Run"
gcloud projects add-iam-policy-binding "$PROJECT" \
--member "serviceAccount:weldall-run@${PROJECT}.iam.gserviceaccount.com" \
--role roles/cloudsql.client --condition=None

Der Befehl erzeugt die Secrets, schreibt jedes direkt in den Secret Manager, ohne es auszugeben, und erlaubt nur weldall-run das Lesen:

Terminal-Fenster
tmp=$(mktemp); chmod 600 "$tmp"
node -e '
const { generateKeyPairSync, randomBytes, randomUUID } = require("node:crypto");
const { privateKey, publicKey } = generateKeyPairSync("ec", { namedCurve: "P-256" });
process.stdout.write(JSON.stringify({
"weldall-better-auth-secret": randomBytes(32).toString("base64url"),
"weldall-setup-token": randomBytes(32).toString("base64url"),
"weldall-credential-encryption-key": randomBytes(32).toString("base64"),
"weldall-connector-kek": randomBytes(32).toString("base64"),
"weldall-signing-private-jwk": JSON.stringify(privateKey.export({ format: "jwk" })),
"weldall-signing-public-jwk": JSON.stringify(publicKey.export({ format: "jwk" })),
"weldall-signing-kid": randomUUID(),
}));' > "$tmp"
for name in weldall-better-auth-secret weldall-setup-token weldall-credential-encryption-key \
weldall-connector-kek weldall-signing-private-jwk weldall-signing-public-jwk \
weldall-signing-kid; do
jq -j --arg k "$name" '.[$k]' "$tmp" | gcloud secrets create "$name" \
--replication-policy user-managed --locations "$REGION" --data-file=-
done
rm -f "$tmp"
for name in weldall-postgres-url weldall-better-auth-secret weldall-setup-token \
weldall-credential-encryption-key weldall-connector-kek \
weldall-signing-private-jwk weldall-signing-public-jwk weldall-signing-kid; do
gcloud secrets add-iam-policy-binding "$name" \
--member "serviceAccount:weldall-run@${PROJECT}.iam.gserviceaccount.com" \
--role roles/secretmanager.secretAccessor
done

Erzeuge diese Secrets einmal und ersetze sie nicht, solange diese Installation besteht. Docker-Images erklärt, warum.

Die URL eines Cloud-Run-Dienstes steht schon vor der ersten Bereitstellung fest: https://SERVICE-PROJECT_NUMBER.REGION.run.app. Weldall braucht sie ab dem ersten Start als WELDALL_ISSUER, weil die Callback-URL, die du bei deinem Identity Provider einträgst, daraus gebildet wird.

Terminal-Fenster
WELDALL_URL="https://weldall-${PROJECT_NUMBER}.${REGION}.run.app"
gcloud run deploy weldall --region "$REGION" \
--image "docker.io/seibertgroup/weldall:${WELDALL_VERSION}" \
--service-account "weldall-run@${PROJECT}.iam.gserviceaccount.com" \
--port 3000 \
--max-instances 1 \
--add-cloudsql-instances "$CONN" \
--set-env-vars "WELDALL_ISSUER=${WELDALL_URL}" \
--set-secrets "POSTGRES_URL=weldall-postgres-url:latest,BETTER_AUTH_SECRET=weldall-better-auth-secret:latest,WELDALL_SETUP_TOKEN=weldall-setup-token:latest,WELDALL_CREDENTIAL_ENCRYPTION_KEY=weldall-credential-encryption-key:latest,WELDALL_CONNECTOR_KEK=weldall-connector-kek:latest,WELDALL_SIGNING_PRIVATE_JWK=weldall-signing-private-jwk:latest,WELDALL_SIGNING_PUBLIC_JWK=weldall-signing-public-jwk:latest,WELDALL_SIGNING_KID=weldall-signing-kid:latest" \
--liveness-probe "httpGet.path=/.well-known/openid-configuration,httpGet.port=3000,periodSeconds=30,timeoutSeconds=5,failureThreshold=3" \
--allow-unauthenticated
  • Der Befehl legt nur fest, was Weldall braucht. Für CPU, Speicher und Mindestinstanzen gelten die Standardwerte von Cloud Run; passe sie an deine Anforderungen an, siehe die Referenz zu gcloud run deploy.
  • --port 3000 ist der Port, auf dem das Weldall-Image lauscht.
  • --max-instances 1 begrenzt Weldall auf eine Instanz; Docker-Images erklärt, warum. Die Grenze gilt pro Revision: Während eines Deploys laufen die alte und die neue Revision kurz nebeneinander.
  • --liveness-probe lässt Cloud Run eine hängende Instanz neu starten. Ohne sie bemerkt Cloud Run nur einen Prozess, der sich beendet.
  • --allow-unauthenticated macht Weldall für Browser, CLI und Resource-Server erreichbar. Cloud Run stellt das HTTPS-Zertifikat für die run.app-URL bereit. Ohne Setup-Token bleibt der Installer geschlossen.
  • Cloud Run zieht öffentliche Docker-Hub-Images ohne Zugangsdaten und legt pro Revision den genauen Image-Digest fest. Ein wandernder Tag wie 0.5 oder latest ändert einen laufenden Dienst deshalb nicht; erst das nächste gcloud run deploy löst ihn neu auf.
  • Standardmäßig stoppt Cloud Run die Instanz im Leerlauf. Die erste Anfrage danach wartet einige Sekunden auf einen Kaltstart. --min-instances 1 vermeidet das und wird dauerhaft abgerechnet.
Terminal-Fenster
curl -s "$WELDALL_URL/.well-known/openid-configuration" | jq -r .issuer # prints $WELDALL_URL
curl -s "$WELDALL_URL/api/me/skills"; echo # invalid_token
gcloud logging read \
'resource.type="cloud_run_revision" AND resource.labels.service_name="weldall"' \
--order=asc --limit 200 --format="value(textPayload,jsonPayload.message)" \
| grep -E "migrations found|Applying migration|successfully applied|No pending|Deployment initialization|server initialized"

Der zweite Aufruf antwortet mit invalid_token. Das ist das erwartete Ergebnis: Die API verlangt eine Anmeldung.

Beim ersten Start zeigt das Log, wie jede Migration angewendet wird, dann All migrations have been successfully applied., dann Deployment initialization completed, dann Weldall server initialized.

Öffne $WELDALL_URL und folge How to: Installer ausführen. Kopiere den Setup-Token in die Zwischenablage, ohne ihn anzuzeigen, zum Beispiel in einem lokalen Terminal unter macOS:

Terminal-Fenster
gcloud secrets versions access latest --secret weldall-setup-token --project "$PROJECT" | pbcopy

Überspringe diesen Schritt, wenn alle deine Resource-Server $WELDALL_URL direkt erreichen.

Terminal-Fenster
gcloud run deploy weldall-discovery-proxy --region "$REGION" \
--image "docker.io/seibertgroup/weldall-discovery-proxy:${PROXY_VERSION}" \
--service-account "weldall-proxy-run@${PROJECT}.iam.gserviceaccount.com" \
--set-env-vars "WELDALL_UPSTREAM=${WELDALL_URL}" \
--allow-unauthenticated

Für alles andere gelten die Standardwerte von Cloud Run, auch für Port 8080, auf dem der Proxy lauscht.

Prüfe, dass der Proxy beide Dokumente unverändert weiterreicht und alles andere blockiert:

Terminal-Fenster
PROXY_URL="https://weldall-discovery-proxy-${PROJECT_NUMBER}.${REGION}.run.app"
cmp <(curl -s "$WELDALL_URL/.well-known/oauth-authorization-server") \
<(curl -s "$PROXY_URL/.well-known/oauth-authorization-server") && echo identical
cmp <(curl -s "$WELDALL_URL/api/oauth/jwks") <(curl -s "$PROXY_URL/api/oauth/jwks") && echo identical
curl -s -o /dev/null -w "%{http_code}\n" "$PROXY_URL/.well-known/openid-configuration" # 404
curl -s -o /dev/null -w "%{http_code}\n" -X POST "$PROXY_URL/api/oauth/jwks" # 405

Resource-Server verwenden $PROXY_URL als discoveryProxyOrigin und behalten $WELDALL_URL als Issuer, siehe Discovery-Proxy.

Erstelle direkt vor dem Upgrade ein Backup und notiere seine ID:

Terminal-Fenster
NEW_VERSION=0.5.2 # the version you upgrade to
gcloud sql backups create --instance weldall-db --description "before Weldall ${NEW_VERSION}"
gcloud sql backups list --instance weldall-db --limit 3

Stelle die neue Version bereit. Nur das Image ändert sich; alle anderen Einstellungen übernimmt Cloud Run aus der vorigen Revision:

Terminal-Fenster
gcloud run deploy weldall --region "$REGION" \
--image "docker.io/seibertgroup/weldall:${NEW_VERSION}"

Das Log der neuen Revision zeigt nur die neuen Migrationen, dann die Initialisierung und den Serverstart. Führe die Prüfungen aus Schritt 7 erneut aus.

Das vorige Image allein zu starten, genügt nicht. Die ältere Version startet ohne Warnung und meldet No pending migrations to apply., während die Datenbank das Schema der neueren Version behält. Die Folgen erklärt Docker-Images.

Stelle das Backup aus Schritt 9 wieder her und starte dann das vorige Image:

Terminal-Fenster
gcloud sql backups restore BACKUP_ID --restore-instance weldall-db --backup-instance weldall-db
gcloud run deploy weldall --region "$REGION" \
--image "docker.io/seibertgroup/weldall:${WELDALL_VERSION}"
  • Die Wiederherstellung ersetzt die gesamte Instanz durch den Stand des Backups. Anmeldungen, Änderungen in der Administration und Audit-Einträge nach dem Backup gehen verloren.
  • Während der Wiederherstellung ist die Datenbank nicht erreichbar; sie dauert einige Minuten. Plane ein Wartungsfenster ein.

Der Proxy speichert nichts und ist unabhängig von Weldall. Du aktualisierst ihn mit einem neuen Image und rollst ihn zurück, indem du den Traffic auf die vorige Revision lenkst:

Terminal-Fenster
NEW_PROXY_VERSION=0.1.2 # the version you upgrade to
gcloud run deploy weldall-discovery-proxy --region "$REGION" \
--image "docker.io/seibertgroup/weldall-discovery-proxy:${NEW_PROXY_VERSION}"
gcloud run revisions list --service weldall-discovery-proxy --region "$REGION"
gcloud run services update-traffic weldall-discovery-proxy --region "$REGION" \
--to-revisions PREVIOUS_REVISION=100

Nach --to-revisions bleibt der Traffic an diese Revision gebunden, und spätere Bereitstellungen erhalten keinen. Hebe die Bindung vor dem nächsten Upgrade auf:

Terminal-Fenster
gcloud run services update-traffic weldall-discovery-proxy --region "$REGION" --to-latest

Rolle Weldall nicht auf diese Weise zurück: Damit würde eine alte Revision aktiv, ohne dass die Datenbank wiederhergestellt ist.