Deployment
GitLab CI orchestriert das Ganze. Die Pipeline ist projekt-portabel
(parametrisiert über RUN_PROJECT_ID, WIF_SERVICE_ACCOUNT, AR_HOST),
sodass ein frisches GCP-Projekt durch erneutes Anwenden des
Terraform-Stacks plus Updates dieser Variablen aufgesetzt werden kann.
Stage-Diagramm
Promotion-Modell
| Service | Master-Push | Git Tag |
|---|---|---|
| nano-server (run) | Build + Deploy mit 0% Traffic | Latest auf 100% promoten |
| nano-mcp-server (run) | Build + Deploy mit 0% Traffic | Latest auf 100% promoten |
| Frontend (Hosting) | Preview Channel pro Branch | Live-Deploy |
| Docs (Hosting) | Preview Channel pro Branch | Live-Deploy |
Operators promoten eine Cloud-Run-Revision, indem sie einen Tag
(v3.x.y) pushen. Der RUN_update_traffic-Branch im CICD-Template
feuert nur, wenn $CI_COMMIT_TAG gesetzt ist.
Manuelles Promoten (falls nötig):
gcloud run services update-traffic nano-server --region=europe-west4 --project=cpl-gen-ai-marketing --to-latest
gcloud run services update-traffic nano-mcp-server --region=europe-west4 --project=cpl-gen-ai-marketing --to-latest
Firebase Hosting Multi-Site
Zwei Sites unter dem gleichen GCP-Projekt teilen sich Firestore, IAM und Billing:
| Target | Site-Name | URL (Firebase-Fallback) | Primäre Custom Domain |
|---|---|---|---|
app | cpl-gen-ai-marketing | https://cpl-gen-ai-marketing.web.app | https://nano.cpl.ai |
docs | cpl-gen-ai-marketing-docs | https://cpl-gen-ai-marketing-docs.web.app | https://docs.nano.cpl.ai |
Der MCP-Cloud-Run-Service hat eine eigene Custom-Domain-Mapping:
https://mcp.nano.cpl.ai → nano-mcp-server (Cloud Run, Region
europe-west1).
CI deployed jedes via firebase deploy --only hosting:<target>,
gesteuert über die GitLab-Variable FIREBASE_TOKEN (erzeugt mit
firebase login:ci, gespeichert als Masked + Protected).
One-Time-Setup für ein neues Projekt
-
GCP-Projekt anlegen; Cloud Run, Cloud Tasks, Firestore, Firebase, Secret Manager und IAM APIs aktivieren.
-
Den
gitlab-ci@<project>.iam.gserviceaccount.com-SA manuell anlegen (Terraform codifiziert ihn später alsdata-Block). -
terraform applyinterraform/bootstrap/laufen lassen, danachterraform/runtime/. -
Secret-Werte seeden:
gemini-api-key,mcp-private-key,mcp-google-oauth-client-id,mcp-google-oauth-client-secret. -
Die Firebase-Hosting-Sites anlegen:
firebase hosting:sites:create cpl-gen-ai-marketing --project cpl-gen-ai-marketingfirebase hosting:sites:create cpl-gen-ai-marketing-docs --project cpl-gen-ai-marketingfirebase target:apply hosting app cpl-gen-ai-marketing --project cpl-gen-ai-marketingfirebase target:apply hosting docs cpl-gen-ai-marketing-docs --project cpl-gen-ai-marketing -
Die GitLab-CI/CD-Variable
FIREBASE_TOKENseeden (firebase login:ci). -
Google-OAuth-Client (Web Type) konfigurieren, Redirect-URI
https://<mcp-url>/auth/google/callbackeintragen, Client-ID + Secret in den Secret Manager schreiben. -
Nach master pushen. Die erste Pipeline baut
ci-base, applied Terraform, baut + deployed die Cloud-Run-Services und einen Hosting-Preview-Channel pro Branch. -
Ein Release taggen (
vX.Y.Z), um Traffic zu promoten und Hosting live zu deployen.
DNS für Custom Domains
Live-Domains: nano.cpl.ai, docs.nano.cpl.ai, mcp.nano.cpl.ai.
DNS wird manuell in Cloud DNS gepflegt (noch nicht in Terraform).
Um eine neue Domain anzulegen oder eine umzubinden:
- Firebase-Hosting-Site (oder Cloud-Run-Service) → "Add custom domain".
- Verification-TXT-Record beim DNS-Provider eintragen.
- Auf Verification warten, dann die A- / CNAME-Records eintragen, die die Console ausspuckt. SSL-Provisioning läuft automatisch (managed Zertifikat).
- Damit Firebase Auth (Google Sign-In) auf der neuen Domain
funktioniert, die Domain in Firebase Console → Authentication →
Settings → Authorized domains hinzufügen. Sonst schlägt jeder
Sign-in mit
Firebase: Error (auth/unauthorized-domain)fehl. MCP_PUBLIC_URLaufnano-mcp-servermuss zur öffentlichen URL passen (https://mcp.nano.cpl.ai), sonst scheitert jede OAuth-iss/aud-Prüfung.CLOUD_RUN_URLzeigt weiterhin auf die interne Cloud-Run-Service-URL — siehe ADR-0003.- Die CORS-Allowlist in
packages/server/src/index.tsmuss das neue Frontend-Origin enthalten, sonst scheitern Browser-Fetches mit CORS-Fehlern.