1. Einführung
Willkommen beim Workshop Rails 8 in Google Cloud! In diesem praktischen Codelab migrieren Sie eine moderne Rails 8-Anwendung von einer einfachen lokalen SQLite-Baseline zu einer produktionsreifen, unternehmenstauglichen Referenzarchitektur in Google Cloud.
In diesem Workshop stellen wir nicht nur eine App bereit, sondern führen eine meinungsstarke Cloud-Modernisierung auf Produktionsniveau durch (Lift-and-Shift richtig gemacht!).
Sie beginnen mit der typischen lokalen Einrichtung „funktioniert auf meinem Computer“ (flüchtiges Laufwerk, eingebettetes SQLite, In-Process-Jobs) und entwickeln sie schrittweise zu einer robusten Cloud-Architektur für Unternehmen in Google Cloud weiter:
- 🐘 Von lokaler SQLite-Datenbank → Cloud SQL (PostgreSQL): Die Datenbank wird bei Neustarts nicht mehr gelöscht. Wir migrieren zu verwaltetem PostgreSQL, das sicher über den Cloud SQL Auth-Proxy (mTLS, keine öffentlichen IP-Adressen) verbunden ist.
- 🪣 Vom sitzungsspezifischen lokalen Speicher → privater GCS:Die serverlose Festplatte ist temporär. Wir verbinden ActiveStorage mit privatem Google Cloud Storage über IAM signierte URLs (
iam: true) – keine öffentlichen Buckets, keine weitergegebenen Schlüssel. - 🚀 Von In-Process-Jobs → Multi-Container Cloud Run:Wir verbinden den Rails-Monolithen mit der serverlosen Cloud. Mit Docker Compose führen wir Solid Queue als dedizierten Worker-Container neben Puma in einem Cloud Run-Pod mit mehreren Containern aus – ohne Mikrodienst-Wildwuchs, ohne Thread-Starvation. DHH wäre stolz!
🍌 Und weil wir im Jahr 2026 leben, haben wir den gesamten Stack mit Google Antigravity ausgestattet. Das ist kein nachträglicher Gedanke. Wir haben Prompts und Skills, die Ihnen helfen, diesen Workshop besser durchzuführen und zu genießen.
🏛️ Ziel-Referenzarchitektur (Variante 1: Clean Flat Vector Enterprise)
Hier sehen Sie die kanonische Google Cloud-Referenzarchitektur, die Sie erstellen und bereitstellen werden (Variante 1: Clean Flat Vector Enterprise). Sie zeigt unseren Produktions-Cloud Run-Dienst mit mehreren Containern, der mit allen verwalteten Google Cloud-Persistenz- und KI-Diensten verbunden ist:

🎞️ Die architektonische Entwicklung: Von Null zu cloudnativ
Sehen Sie sich an, wie unser Stack in jedem Workshop-Meilenstein schrittweise modernisiert wird – von einer kurzlebigen Einzelmaschinen-Baseline zu einem vollständig verwalteten Google Cloud-Blueprint:

Lerninhalte
- So können Sie mit Google Antigravity Pair-Programming durchführen, um Rails 8 und Google Cloud zu entmystifizieren.
- So führen Sie die automatische Pre-Flight-Diagnose aus (
just workshop-test). - Google Cloud-Infrastruktur asynchron mit Terraform bereitstellen und gleichzeitig die lokale Entwicklung ohne Blockierung mit dem
google-Provider fortsetzen. - Sicherheits-Antipatterns vermeiden: private GCS-Buckets (
iam: true) und Cloud SQL Auth-Proxy-mTLS-Tunnel anstelle von0.0.0.0/0öffnen. - Secrets direkt aus Google Cloud Secret Manager einfügen.
- So orchestrieren Sie asynchrone Hintergrundjobs für generative KI (NanoBanana-Covergenerator, zweisprachige Podcastsynthese) über Solid Queue.
Los geht's!
2. Schritt 0: Voraussetzungen, Antigravity-Einrichtung und Abrechnungsbestätigung
💡 Szenario:Sie und Ihr Team entwickeln eine geschäftskritische Rails 8-Anwendung. Bevor wir Code bearbeiten oder Cloud-Ressourcen starten, müssen wir unsere Toolchain einrichten, Google Antigravity verbinden und unsere Google Cloud-Anmeldedaten und Abrechnungsgrundlagen überprüfen.
1. Checkliste für Voraussetzungen
Bevor wir beginnen, müssen die folgenden Tools in Ihrer Umgebung verfügbar sein:
just(1.21+): (just --version) Der Task-Runner – jeder Befehl in diesem Workshop ist einjustRezept. Bitten Sie Ihre KI-Harness, es zu installieren, oder sehen Sie sichskills/rails8app-workshopan.- Git (2.30+): (
git --version) für die Versionsverwaltung, das Erstellen von Branches und das Klonen des Repositorys. - Google Cloud SDK (
gcloud-CLI): Installiert und auf dem neuesten Stand. - Terraform-Befehlszeile (Version 1.5 oder höher): für die deklarative Infrastrukturbereitstellung.
docker&docker-compose: Die App ist installiert und wird lokal ausgeführt.- Ruby
3.4.5: (ruby -v– angepinnt vonblog/.ruby-version; bitten Sie Ihre KI-Harness,3.4.5zu installieren, falls es fehlt). Rails 8 wird in derGemfiledeklariert und vonbundle installautomatisch installiert. - Google Antigravity 2.0:Ihr autonomer KI-Assistent für das Pair Programming (Google Antigravity 2.0 herunterladen). Sie melden sich mit Ihrem privaten Gmail-Konto an. Ein API-Token ist nicht erforderlich.
2. Google Cloud-Authentifizierung, Dedicated-Konfiguration und ADC
Um Konflikte mit vorhandenen geschäftlichen, privaten oder Multi-Account-gcloud-Einrichtungen zu vermeiden, empfehlen wir dringend, für diesen Workshop eine dedizierte benannte Konfiguration zu erstellen:
# 1. Create and activate dedicated workshop configuration (Fixes Issue #38)
gcloud config configurations create rails8-on-gcp-workshop --activate 2>/dev/null || \
gcloud config configurations activate rails8-on-gcp-workshop
# 2. Authenticate your account and Application Default Credentials (ADC)
gcloud auth login $GOOGLE_CLOUD_ACCOUNT
gcloud auth application-default login
# 3. Configure active project and region
gcloud config set project $GOOGLE_CLOUD_PROJECT
gcloud config set compute/region europe-west1
💡 Warum eine dedizierte Konfiguration? Durch die Verwendung von gcloud config configurations create rails8-on-gcp-workshop werden alle CLI-Einstellungen (Konto, Kontingentprojekt, Standardregion) speziell für diesen Workshop isoliert. Wenn Sie fertig sind, können Sie mit gcloud config configurations activate default jederzeit wieder zu Ihrer normalen Einrichtung zurückkehren.

3. 🚨 GCP-Abrechnungsüberprüfung
⚠️ Hinweis: Für Google Cloud SQL- und Cloud Run-Bereitstellungen ist ein aktives verknüpftes Abrechnungskonto oder gültige Workshop-Guthaben erforderlich. Wir prüfen jetzt, ob deine Einrichtung korrekt ist. Führen Sie dazu die Abrechnungsüberprüfung aus:
gcloud beta billing projects describe $GOOGLE_CLOUD_PROJECT
Prüfen Sie, ob billingEnabled: true zurückgegeben wird. Sie können auch alle Ihre Rechnungskonten auflisten:
gcloud billing accounts list
Achten Sie darauf, dass mindestens eines davon OPEN: True zeigt. Wenn keines aktiv ist, verknüpfen Sie ein Rechnungskonto oder lösen Sie Ihren Gutschein für Workshop-Guthaben auf der Abrechnungsseite der Google Cloud Console ein.

4. Repository klonen und mit Antigravity koppeln
Klonen Sie das Repository und wechseln Sie in das Verzeichnis. Wir bleiben vollständig auf main:
git clone https://github.com/palladius/rails8-app-on-gcp.git
cd rails8-app-on-gcp
Öffnen Sie dieses Verzeichnis in Google Antigravity. Antigravity untersucht das Repository automatisch, liest AGENTS.md und steht Ihnen als Co-Programmierer zur Seite.
5. 🪫 Wenn Antigravity das kostenlose Guthaben aufgebraucht hat
⚠️ Das gerade eingelöste Cloud-Guthaben wird NICHT für Antigravity verwendet. Es handelt sich um zwei separate Abrechnungsoberflächen: Das Kontingent von Antigravity befindet sich in Google AI-Plänen (Google One), während Gutscheine und Cloud-Guthaben in einem Cloud-Rechnungskonto landen. Wenn Sie ein Rechnungskonto mit Ihrem GCP-Projekt verknüpfen, erhalten Sie nicht einen zusätzlichen Antigravity-Prompt.
Wenn der Agent mit einer Kontingentmeldung beendet wird, gehen Sie diese Liste durch. Die ersten beiden Optionen sind kostenlos und sofort verfügbar:
- Modellpool wechseln: Das Kontingent wird pro Modellfamilie erfasst und Antigravity zeigt zwei unabhängige Pools (Gemini-Modelle im Vergleich zu Claude-/GPT-Modellen). Claude- und GPT-OSS-Modelle sind in der kostenlosen Stufe verfügbar. Wenn also ein Gemini-Pool aufgebraucht ist, bleibt der andere oft unberührt. Verwenden Sie die Modellauswahl unter dem Prompt-Feld.

- Wählen Sie ein Flash-Modell anstelle von Pro aus. Ratenbegrenzungen hängen damit zusammen, wie viel Arbeit der Agent pro Anfrage leistet. Ein leichteres Modell kann also mehr leisten.
- Verwenden Sie die Antigravity CLI mit Ihrem eigenen Gemini API-Schlüssel. BYOK wird in der Antigravity IDE nicht unterstützt. Die CLI ist die dokumentierte Alternative. Erstellen Sie einen kostenlosen Schlüssel in Google AI Studio (dazu ist ein Projekt, aber kein Rechnungskonto erforderlich). Laden Sie dann die Antigravity CLI herunter und konfigurieren Sie sie.
- Warten oder ein Upgrade durchführen. Das Kontingent für das kostenlose Kontingent wird wöchentlich aktualisiert. Das Datum, an dem das Kontingent zurückgesetzt wird, ist in der Fehlermeldung angegeben. Google AI Pro/Ultra ist die einzige dokumentierte Möglichkeit, die Baseline in der Desktop-App zu erhöhen. Diese Abos werden alle fünf Stunden aktualisiert und das gekaufte KI‑Guthaben kann für Überschreitungen verwendet werden.
- Dies ist zwar ein Antigravity-Workshop, aber die meisten KI-Codierungs-Tools sollten auch funktionieren. Verweisen Sie Ihr Tool einfach auf das Verzeichnis
AGENTS.mdundskills/im Repository.
6. Automatisierte Validierung in Schritt 0
Prüfen Sie, ob Ihre Umgebung in Schritt 0 zu 100% mit der Evaluierungssuite kompatibel ist:
just workshop-eval 0
✨ Der Wow-Moment:Antigravity und die Workshop-Bewertungs-Engine überprüfen Ihre Befehlszeilenversionen, die Ruby-Umgebung und die Standardanmeldedaten für Anwendungen-Authentifizierung in weniger als 2 Sekunden.
3. Schritt 1: Terraform-Infrastruktur – Einführung und Pre-Flight-Diagnose
💡 Strategie:Die Bereitstellung verwalteter Datenbanken wie Google Cloud SQL PostgreSQL dauert etwa 10–12 Minuten. Anstatt später untätig zu warten, starten wir die unveränderliche Infrastruktur über Terraform jetzt im Hintergrund, während wir lokal entwickeln.
1. Automatisierte Preflight-Diagnosesuite ausführen
Führen Sie vor der Einführung der Cloud-Infrastruktur die umfassende Preflight-Testsuite aus:
just workshop-test
Dieses Script (bin/workshop_diagnostics.rb):
- Überprüft die Konfiguration der
GOOGLE_CLOUD_ACCOUNT-Identität. - Prüft, ob die Abrechnung aktiv ist und das Projekt verknüpft ist.
- Überprüft die Standardanmeldedaten für Anwendungen (Application Default Credentials, ADC) für Vertex AI.
- Bestätigt das Canary-Seed-Image für Active Storage (
blog/app/assets/images/gcs_dev_image.jpg).

Wenn .env fehlt, kopieren Sie es aus der dokumentierten Vorlage:
cp .env.dist .env
# Edit .env and configure GOOGLE_CLOUD_ACCOUNT with your Google/Gmail account
💡 Tipp:Wenn just workshop-test meldet, dass die Billing API in Ihrem Projekt deaktiviert ist, können Sie sie schnell über die folgenden Schritte aktivieren:
gcloud services enable cloudbilling.googleapis.com
2. ⏱️ Terraform-Infrastruktur asynchron starten
Führen Sie das einstufige Terraform-Rezept aus, um den Remote-Backend-Zustands-Bucket zu erstellen und die Bereitstellung der Infrastruktur auszulösen:
just terraform-apply

Manuelle Alternative (oder `iac/bin/terraform-apply.sh` direkt ausführen)
# Fall back to active gcloud config if environment variables are unset
GOOGLE_CLOUD_PROJECT="${GOOGLE_CLOUD_PROJECT:-$(gcloud config get-value project)}"
GOOGLE_CLOUD_REGION="${GOOGLE_CLOUD_REGION:-europe-west1}"
# Create remote state bucket idempotently
gcloud storage buckets create "gs://${GOOGLE_CLOUD_PROJECT}-tfstate" --location="$GOOGLE_CLOUD_REGION" 2>/dev/null || \
gcloud storage buckets describe "gs://${GOOGLE_CLOUD_PROJECT}-tfstate" >/dev/null
cd iac
terraform init -backend-config="bucket=${GOOGLE_CLOUD_PROJECT}-tfstate"
terraform apply -auto-approve -var="project_id=${GOOGLE_CLOUD_PROJECT}" -var="region=${GOOGLE_CLOUD_REGION}"
cd ..
Was Terraform bereitstellt:
- Google Cloud Storage-Bucket:Erstellt mit privatem Zugriff und IAM-Anmeldedaten-Signierung (
iam: true). - Canary-Testbild:Lädt
gcs_dev_image.jpgin den Bucket hoch, um die End-to-End-Blob-Bestätigung zu ermöglichen. - Google Cloud SQL PostgreSQL-Instanz:Startet die Hintergrundbereitstellung (ca. 10–12 Minuten).

💡 Hinweis:Sie können die Warnung zu fehlenden automatischen Sicherungen ignorieren. Wir benötigen sie für diese Workshop-Datenbank nicht. Automatische tägliche Sicherungen sind jedoch eine wichtige Best Practice für jede echte Produktionsdatenbank.

📝 Cloud Run-URL notieren:Der Terraform-Befehl „apply“ sollte erfolgreich ausgeführt werden und die Ausgaben Ihrer Infrastruktur ausgeben. Notieren Sie sich Ihre cloud_run_url oder kopieren Sie sie in die Zwischenablage. Sie benötigen sie in späteren Schritten, um Ihren Live-Dienst zu bestätigen.
3. Automatisierte Validierung von Schritt 1 (optional)
Prüfen Sie, ob die Voraussetzungen und Konfigurationen für Schritt 1 erfüllt sind:
just workshop-eval 1
⏱️ Hinweis:Bei dieser Bewertung werden aktive Cloud-Ressourcen geprüft. Es kann einige Minuten dauern, bis sie abgeschlossen ist. Dieser Schritt ist optional. Während er in Ihrem Terminal ausgeführt wird, können Sie sofort mit dem nächsten Schritt fortfahren.
4. Schritt 2: Lokale Baseline, Mailpit und Admin-Onboarding
Wir beginnen mit einer sauberen, modernen Rails 8-Bloganwendung, die auf localhost mit SQLite, Mailpit-E-Mail-Abfang und ActiveStorage auf Festplatte ausgeführt wird.
1. App lokal starten
📁 Achten Sie auf das Verzeichnis. Dieses Repository enthält die Rails-App in blog/ und die Terraform-Konfiguration in iac/. Nach Schritt 1 befinden Sie sich im Stammverzeichnis des Repositorys. Jeder Befehl in Schritt 2 wird also von
blog/: Gemfile, bin/rails und compose.yaml sind alle dort zu finden. Wenn Sie sie über das Stammverzeichnis ausführen, schlagen sie mit no configuration file provided: not found oder einem fehlenden Gemfile fehl.
Wechseln Sie zur Rails-App, prüfen Sie, ob Sie die angepinnte Ruby-Version verwenden, installieren Sie die Gems und richten Sie die Datenbank ein:
cd blog
ruby -v # must print 3.4.5 — see Step 0 if it does not
bundle install
bin/rails db:setup
🧯 Berechtigungsfehler beim Schreiben in
/var/lib/gems/
oder
ruby -v
wird die System-Ruby-Version (z.B. 3.3.x) angezeigt? Bei einem Vanilla-Linux-System ignoriert Ruby .ruby-version-Dateien vollständig und versucht, Gems systemweit zu installieren. Prüfen Sie, ob rbenv in Ihrer aktiven Terminal-Shell geladen ist:
eval "$(rbenv init - bash)" # or: eval "$(rbenv init - zsh)"
ruby -v # confirm it now outputs 3.4.5!
Hinweis:Wenn Sie die Installation von Version 3.4.5 in Schritt 0 übersprungen haben, führen Sie rbenv install 3.4.5 aus. Oder verwenden Sie einfach Modus A (Docker Compose) unten (just compose-up). Damit wird der angepinnte Ruby-Stack vollständig in Containern ausgeführt, ohne dass Host-Gems verwendet werden.
💡 Möchten Sie sich lieber nicht damit beschäftigen? just install und just compose-up aus dem Stammverzeichnis des Repositorys erledigen das cd blog für Sie.
2. 🌱 Automatische Erkennung von Smart Seeds und Admin-Bootstrap (Problem 21 und 25)
Der Datenbank-Seed (db/seeds.rb) bietet die automatische Erkennung von Smart Home-Umgebungen:
- Es wird Ihr aktiver Datenbankadapter (SQLite oder Postgres) und Ihre Speicherkonfiguration geprüft.
- Es wird Phase 0 (Localhost) erkannt und der erste Administratornutzer wird automatisch erstellt und der pädagogische Beitrag wird eingefügt:
[LOCAL BASELINE] Welcome to Rails 8 on Localhost!- Standardmäßig wird ein lokales SSD-Image (
local_sad_image.png) mit einem Wasserzeichen angehängt, das darauf hinweist, dass der lokale Festplattenspeicher sitzungsspezifisch ist.
- Dadurch wird automatisch eine E‑Mail zum Zurücksetzen des Passworts über ActionMailer ausgelöst.
Bestätigen oder wiederholen Sie den Seed (dabei wird automatisch Ihr GOOGLE_CLOUD_ACCOUNT aus .env verwendet):
bin/rails db:seed # or from repo root: just seed
Starten Sie den lokalen Entwicklungs-Stack über Docker Compose:
docker compose up -d # from blog/ — or `just compose-up` from the repo root

Die Anwendung, der lokale Mailpit-SMTP-Server und der Adminer-Datenbank-Viewer werden jetzt zusammen in isolierten Containern ausgeführt:
- Rails-App: http://localhost:3000
- Mailpit-Web-UI: http://localhost:8025
- Adminer-DB-Benutzeroberfläche: http://localhost:8081
🧯 Konflikt mit Port 3000 oder
server.pid
-Fehler? Wenn Sie zuvor einen nativen Entwicklungsserver (bin/dev) gestartet haben, beenden Sie ihn mit Ctrl+C. Wenn Docker meldet, dass Port 3000 bereits zugewiesen ist, oder ein übrig gebliebenes server.pid findet, können Sie es mit folgendem Befehl entfernen:
just compose-down
rm -f blog/tmp/pids/server.pid
just compose-up
3. Mailpit-Benutzeroberfläche und Administratoranmeldung
- Ausgehende E‑Mails mit Mailpit abfangen: Öffnen Sie
http://localhost:8025in Ihrem Browser. Sehen Sie in Ihrem lokalen Posteingang nach. Währenddb:seedhat ActionMailer eine E-Mail zur Administratorregistrierung gesendet, die von Mailpit lokal erfasst wurde, ohne dass externe E-Mail-Server oder Anmeldedaten verwendet wurden:
2. Im Blog anmelden: Öffnen Sie http://localhost:3000 in Ihrem Browser.
- Sie können direkt in der Mailpit-E-Mail auf den Link zum Zurücksetzen des Passworts klicken, um Ihr Passwort festzulegen.
- Alternativ können Sie sich mit der E-Mail-Adresse Ihres Google Cloud-Kontos (aus
.env) und dem standardmäßigen StartpasswortCh4ng3m3!!1anmelden.
- Visuelle Telemetrie-Badges ansehen
- :
- Achten Sie auf das gelbe Umgebungsbanner und die Badges in der Benutzeroberfläche:
Notice: Ephemeral Database Active (POSTGRESQL)und[EPHEMERAL DB / STORAGE] 💾 Local. - Achten Sie auf das Wasserzeichen des Beitrags: Das 🏠-Symbol (
nanobanana_stamp_local.png) befindet sich rechts unten auf dem Titelbild. So können Sie sofort visuell bestätigen, dass Ihre Assets und Ihre Datenbank derzeit an den temporären lokalen Speicher gebunden sind.
- Achten Sie auf das gelbe Umgebungsbanner und die Badges in der Benutzeroberfläche:

💡 Optionaler Profi-Tipp: Rails-Konsolenübung Möchten Sie wissen, wie Rails über die CLI mit Ihren Seed-Daten interagiert? Wechseln Sie zur interaktiven Konsole:
bin/rails console
Sehen Sie sich den initialisierten Administratornutzer dynamisch mit Ihrer Umgebungsvariable an:
user = User.find_by(email_address: ENV.fetch("GOOGLE_CLOUD_ACCOUNT"))
# Or simply grab the first user:
user = User.first
puts "Admin email: #{user.email_address} (created via: #{user.created_via})"
exit
4. Automatisierte Validierung in Schritt 2
Lokale Kostenbasislinie und Administratoreinrichtung überprüfen:
just workshop-eval 2

5. Der Haken: Zustandslose Container
Cloud Run-Container sind zustandslos und kurzlebig. Wenn wir unsere SQLite-Datenbank und das lokale storage/-Verzeichnis direkt in Cloud Run bereitstellen, werden alle Beiträge und hochgeladenen Bilder dauerhaft gelöscht, wenn ein Container auf null skaliert oder neu gestartet wird.
Im nächsten Schritt stellen wir diese kurzlebige Konfiguration absichtlich in Cloud Run bereit, um den Stateless Shock aus erster Hand zu erleben.
5. Schritt 3: Bereitstellung 1 – Der zustandslose Schock (früher WOW-Effekt in 3 Minuten!)
Anstatt 15 bis 20 Minuten auf Cloud-Datenbanken zu warten, bevor etwas im Web angezeigt wird, beginnt die moderne serverlose Entwicklung mit einem schnellen Erfolg: Die Bereitstellung unserer Rails-Anwendung mit einem einzigen Container direkt in Google Cloud Run dauert weniger als 3 Minuten.
1. Dein Rückblick auf die Zeitmaschine
Um sicherzustellen, dass unsere Startkonfiguration zu 100% sitzungsspezifisch ist (lokale SQLite-Datenbank und lokaler Festplattenspeicher), verwenden Sie die Zero-Branch Time-Machine-Engine:
just workshop-rewind 1
💡 Was ist gerade passiert?workshop-rewind 1 hat das Konfigurations-Overlay stage-1-stateless auf blog/config/ angewendet, ohne den Branch main zu verlassen. Ihre App ist mit SQLite auf der Container-Festplatte und ActiveStorage im lokalen Dateisystem konfiguriert.
2. Puma-Einzelcontainer in Cloud Run bereitstellen
Direkt aus Quellcode in Cloud Run bereitstellen Modern Rails 8 generiert automatisch eine offizielle, produktionsbereite Dockerfile (mit mehrstufigen Builds, jemalloc und Non-Root-Sicherheit). Wenn Sie die Bereitstellung über den Ordner blog/ vornehmen, erkennt Google Cloud Build diese native Dockerfile direkt und stellt einen verwalteten serverlosen Dienst bereit:
# Ensure you are inside the Rails application directory
cd blog
# Ensure default region is set
export GOOGLE_CLOUD_REGION="europe-west1"
# Deploy single-container service from source (with dummy key fallback if starting without credentials)
gcloud run deploy blog \
--source . \
--region $GOOGLE_CLOUD_REGION \
--allow-unauthenticated \
--set-env-vars GOOGLE_CLOUD_ACCOUNT=$GOOGLE_CLOUD_ACCOUNT,SECRET_KEY_BASE_DUMMY=1
Die Fortschrittsausgabe sollte in etwa so aussehen:

⏳ Das sollte einige Minuten dauern, während Cloud Build Ihren Container verpackt und die Cloud Run-Revision bereitstellt.
🧯 Fehlerbehebung und häufige Einschränkungen
PERMISSION_DENIED: Build failed because the default service account is missing required IAM permissions
? Für zwei verschiedene Ursachen wird derselbe Fehler angezeigt:
- gcloud hat gerade eine API für Sie aktiviert. Wenn beim Bereitstellen
The following APIs are not enabled ... cloudbuild.googleapis.comausgegeben wurde und Sie mitYgeantwortet haben, wurde der Build möglicherweise gestartet, bevor die neuen Berechtigungen vollständig übernommen wurden. In der Aufforderung von gcloud wird gewarnt, dass dies einige Minuten dauern kann. Warten Sie eine Minute und führen Sie genau denselben Befehl noch einmal aus. In der Regel funktioniert es dann. Im Normalfall wird diese API in Schritt 1terraform applyfür Sie aktiviert. Sie sollten den Prompt also gar nicht sehen. - Dem Standard-Compute-Dienstkonto fehlen tatsächlich Rollen. In modernen GCP-Projekten wird das Prinzip der geringsten Berechtigung erzwungen, was zu Problemen bei der Bereitstellung von Quellen führt. So beheben Sie das Problem:
just project-status # grants storage.admin, logging.logWriter, artifactregistry.writer, cloudbuild.builds.builderjust workshop-testmeldet dies jetzt auch. Es lohnt sich also, den Vorgang noch einmal auszuführen, wenn die Bereitstellung immer wieder fehlschlägt.
Während der Bereitstellung:
- Cloud Run erstellt Ihr Rails-Container-Image.
- Es wird eine öffentliche, sichere TLS-Domain zugewiesen:
https://blog-[hash]-[region].a.run.app. - Der Traffic wird an Puma auf Port 8080 weitergeleitet.
3. ✨ Der frühe WOW-Moment
Öffnen Sie die generierte Cloud Run-URL in Ihrem Browser.
- Ihre moderne Rails 8-Anwendung ist jetzt in Google Cloud verfügbar.
- Melden Sie sich mit Ihren Administratoranmeldedaten (
GOOGLE_CLOUD_ACCOUNTundAPP_ADMIN_PASSWORD) an. Wenn Sie keinen Anmeldebutton finden, klicken Sie auf Neuer Beitrag. Sie werden dann aufgefordert, zuerst Nutzername und Passwort einzugeben:
- Klicken Sie auf Neuer Beitrag, schreiben Sie einen Artikel mit dem Titel Mein erster Cloud Run-Beitrag, hängen Sie ein Bild an und klicken Sie auf Beitrag erstellen.
- Ihr Beitrag wird mit der vollständigen Formatierung veröffentlicht und Ihr Bild wird gerendert.
- Beachten Sie die visuellen Telemetriedaten:
- Header-Badge:
[EPHEMERAL DB / STORAGE] 💾 Local - Bild-Wasserzeichen: Der 🏠-Stempel (
127.0.0.1-Badge für flüchtiges Laufwerk unten rechts).
- Header-Badge:
🐝 Am Live-Workshop-Hive-Leaderboard teilnehmen Wenn Sie online sind und Ihr Prüfer die Bestenliste anzeigt und Sie daran teilnehmen möchten, fügen Sie hier Ihre Cloud Run-URL hinzu: 👉 Cloud Run in der Bestenliste registrieren

4. 💥 Der Haken: Der schockierende Fall von Stateless und die „Puma-Workaround“-Falle
Cloud Run ist eine zustandslose, serverlose Plattform. Wenn der Web-Traffic auf null sinkt, skaliert Cloud Run auf null Containerinstanzen herunter, um Kosten zu sparen. Wenn eine neue HTTP-Anfrage eingeht oder eine neue Containerversion bereitgestellt wird, startet Cloud Run ein brandneues, sauberes Container-Image.
Banner für festhängende Jobs
Wenn Sie einen Beitrag erstellen oder ein Bild in einer Einzelcontainerbereitstellung anhängen, stellt Rails ActiveJob-Aufgaben (z. B. die Analyse von Bilddimensionen oder die Indexierung von Metadaten) in die Warteschlange. Da aber niemand einen Hintergrund-Worker ausführt, wird das Warnbanner angezeigt:

Die verlockende Lösung: Solid Queue in Puma ausführen
Ein cleverer Entwickler könnte sagen: „Moment mal! Mit Rails 8 können wir Solid Queue direkt im Puma-Webserverprozess ausführen, indem wir die
SOLID_QUEUE_IN_PUMA=true
Umgebungsvariable
Testen wir diesen Workaround in Cloud Run:
# Force a revision update to enable Solid Queue inside Puma
gcloud run services update blog \
--region $GOOGLE_CLOUD_REGION \
--update-env-vars SOLID_QUEUE_IN_PUMA=true
Kehren Sie nun zu Ihrem Browser zurück und aktualisieren Sie die Seite:
💥 Der schockierende Zustand:
- Die gute Nachricht:Der Solid Queue-Worker ist jetzt in Puma aktiv. Alle neuen Jobs werden sofort ausgeführt.
- Die kalte Dusche (Der Catch!)
- :
- Da in Cloud Run eine neue Überarbeitung bereitgestellt wurde, wurde die vorherige Containerinstanz ersetzt.
- Der Artikel, den Sie geschrieben haben, und die SQLite-Datenbankdatei auf der Festplatte wurden vollständig gelöscht.
- Die architektonische Lektion:Das Ausführen von Hintergrund-Workern in Puma verbraucht wertvolle CPU/RAM-Ressourcen für Web-Threads und löst das Problem der Persistenz immer noch nicht.
5. Automatisierte Validierung in Schritt 3
Cloud Run-Bereitstellung und Benachrichtigungsbearbeitung prüfen:
just workshop-eval 3
✨ Die Lektion:Workarounds mit einem einzelnen Container wie SOLID_QUEUE_IN_PUMA sind für die lokale Entwicklung praktisch, aber in modernen Cloud-Architekturen gilt Folgendes:
- Für Mediendateien ist Google Cloud Storage (GCS) erforderlich (Schritt 4).
- Für relationale Daten und Jobwarteschlangen ist verwaltetes Google Cloud SQL erforderlich (Schritt 5).
- Aufwendige Hintergrund-Worker gehören in einen dedizierten Sidecar-Container (Schritt 6).
6. Schritt 4: Bereitstellung 3 – GCS Persistent Storage und POLA-Warnung
In diesem Schritt entkoppeln wir den Medien- und Dateispeicher vom Containerlaufwerk, indem wir ActiveStorage auf Google Cloud Storage (GCS) umstellen und kurzlebige signierte URLs über die IAM Credentials API (iam: true) verwenden.
Bevor Sie eine Konfiguration ändern, sollten Sie sich mit den drei Dingen vertraut machen, die Rails für die Kommunikation mit GCS benötigt:
① Projekt-ID + Bucket-Name: Rails muss wissen, wo Blobs gespeichert werden sollen. Die App liest GOOGLE_CLOUD_PROJECT aus der Umgebung und leitet den Bucket-Namen als ${GOOGLE_CLOUD_PROJECT}-activestorage-prod ab. Dieser Bucket wurde bereits durch Ihr Terraform aus Schritt 1 erstellt. Sie müssen nichts weiter tun.
② Ein Dienstkonto mit den richtigen Berechtigungen: Cloud Run wird als Compute Engine-Standarddienstkonto (PROJECT_NUMBER-compute@developer.gserviceaccount.com) ausgeführt. Für dieses Dienstkonto sind zwei IAM-Rollen für den Bucket erforderlich:
roles/storage.objectAdmin– zum Hochladen und Bereitstellen von Blobsroles/iam.serviceAccountTokenCreatorauf sich selbst – zum Aufrufen der IAM CredentialssignBlobAPI und zum Generieren kurzlebiger signierter URLs
⚠️ Die verlockende Abkürzung –
public: true Am schnellsten können Sie GCS verwenden, wenn Sie public: true in storage.yml festlegen und allUsers:objectViewer für den Bucket gewähren. Bilder werden sofort geladen, ohne dass eine Anmeldung erforderlich ist. Das sollten Sie nicht tun. Bei einem öffentlichen Bucket werden alle hochgeladenen Nutzermedien für immer im öffentlichen Internet veröffentlicht. In unserem Blueprint wird iam: true verwendet, um den Bucket zu 100% privat zu halten. Jede Bild-URL ist ein signiertes, ablaufendes Token, das von der IAM Credentials API dynamisch generiert wird.
③
ACTIVE_STORAGE_SERVICE=google: Die einzelne Umgebungsvariable, mit der Rails zur Laufzeit von der lokalen Festplatte zu GCS wechselt. Es sind keine Codeänderungen und keine erneute Bereitstellung der Anwendungslogik erforderlich – es muss nur eine Umgebungsvariable umgeschaltet werden.
1. Dein Rückblick auf die Zeitmaschine
Stelle die Zeitmaschine auf Phase 2 ein:
just workshop-rewind 2
Sehen Sie sich blog/config/storage.yml an. Sie werden feststellen, dass die App drei benannte GCS-Umgebungen (dev / test / prod) definiert, die alle dasselbe sichere Muster verwenden:
<% gcp_project = ENV.fetch("GOOGLE_CLOUD_PROJECT") { Rails.application.credentials.dig(:gcs, :project) } %>
<% gcs_signer_sa = ENV.fetch("GCS_SIGNER_SA_EMAIL") { "rails-cloudrun-sa@#{gcp_project}.iam.gserviceaccount.com" } %>
google_prod: &google_prod
service: GCS
project: <%= gcp_project %>
bucket: <%= gcp_project %>-activestorage-prod # ← derived from project ID, no extra env var!
iam: true # Sign URLs via IAM Credentials signBlob API (no private key JSON required!)
gsa_email: <%= gcs_signer_sa %>
# Convenience alias — ACTIVE_STORAGE_SERVICE=google points here
google:
<<: *google_prod

2. IAM-Berechtigungen für Speicher und Signierung erteilen
Prüfen Sie, ob Ihr Cloud Run-Laufzeitdienstkonto die Berechtigungen zum Signieren von URLs und Hochladen von Objekten hat:
export PROJECT_NUMBER=$(gcloud projects describe $GOOGLE_CLOUD_PROJECT --format="value(projectNumber)")
export RUN_SA="${PROJECT_NUMBER}-compute@developer.gserviceaccount.com"
export GCS_BUCKET="${GOOGLE_CLOUD_PROJECT}-activestorage-prod"
# Grant Storage Object Admin
gcloud storage buckets add-iam-policy-binding gs://$GCS_BUCKET \
--member="serviceAccount:$RUN_SA" \
--role="roles/storage.objectAdmin"
# Grant Service Account Token Creator (required for IAM signed URLs)
gcloud iam service-accounts add-iam-policy-binding $RUN_SA \
--member="serviceAccount:$RUN_SA" \
--role="roles/iam.serviceAccountTokenCreator"
3. Drittens: In Cloud Run mit angehängtem GCS bereitstellen
Stellen Sie die Anwendung mit aktiviertem GCS noch einmal bereit. Achten Sie darauf, dass Sie sich im Ordner blog/ befinden. Andernfalls versucht Cloud Run, mit Buildpacks anstelle von Rails 8 Dockerfile zu erstellen, was zu Build-Fehlern führt.
Verwenden Sie --update-env-vars (nicht --set-env-vars), um vorhandene Umgebungsvariablen (Hauptschlüssel, IAP-Konfiguration usw.) beizubehalten:
cd blog
gcloud run deploy blog \
--source . \
--region $GOOGLE_CLOUD_REGION \
--update-env-vars ACTIVE_STORAGE_SERVICE=google
💡 Tipp:Wenn die Bereitstellung fehlschlägt, klicken Sie auf den Link zu den Cloud Build-Logs, der in Ihrer Terminalausgabe angegeben ist (siehe Abbildung unten). Sie können Antigravity auch um Hilfe beim Entschlüsseln und Beheben des Fehlers bitten.

4. ✨ Das überlebende Bild und der Cloud-Stempel
- Aktualisieren Sie die Blog-URL.
- Erstelle einen neuen Blogbeitrag mit dem Titel „Surviving the Cloud“ und lade ein Foto hoch.
- Sehen Sie sich die untere rechte Ecke des Bildes an:
- Der 🏠-Stempel ist weg!
- Es wird durch den farbigen Cloud GCS-Stempel (
nanobanana_stamp_cloud.png) ersetzt.
- Erzwingen Sie einen weiteren Container-Neustart (der eine vierte Überarbeitung auslösen sollte):
gcloud run services update blog --region $GOOGLE_CLOUD_REGION --update-env-vars RESTART_TRIGGER=$(date +%s) - Aktualisieren Sie die Seite: Während die SQLite-Datenbank zurückgesetzt wird, bleibt das Bild-Binärfile in Google Cloud Storage erhalten. Über die Befehlszeile überprüfen:
gcloud storage ls -l -r gs://$GCS_BUCKET/
Hier ist eine Liste der hochgeladenen Blobs und Media-Objekte, die Sie möglicherweise in der Google Cloud Storage Browser Console in Ihrem Produktions-Bucket (gs://$GCS_BUCKET) sehen:

5. ⚠️ Der Haken: Warnbanner für festhängende Jobs
Als Sie das Bild hochgeladen haben, hat ActiveStorage einen Analysejob (ActiveStorage::AnalyzeJob) in die Warteschlange gestellt, um Abmessungen und Metadaten zu extrahieren.
In Cloud Run wird derzeit jedoch nur ein einzelner Webcontainer (puma) ausgeführt. In Rails 8 werden Hintergrundjobs mit Solid Queue in der Datenbank gespeichert, aber niemand führt bundle exec rails solid_queue:start aus.
Oben auf der Blogseite sehen Sie ein helles Warnbanner, das von blog/app/views/layouts/_check_stuck_jobs.html.erb gerendert wird.
Wir werden dieses Problem in Schritt 6 richtig lösen, wenn wir zu einer produktionsreifen Sidecar-Architektur mit mehreren Containern wechseln, in der ein dedizierter worker-Container Solid Queue unabhängig vom Web-Traffic ausführt.
6. Automatisierte Validierung in Schritt 4
GCS-Konfiguration und Telemetrie für Jobs, die nicht abgeschlossen werden können, prüfen:
just workshop-eval 4
7. Schritt 5: Pre-Flight-Checkliste: Cloud SQL, Secrets und Datenbankverbindung
Während Sie in den Schritten 3 und 4 zustandslose Container und Google Cloud Storage kennengelernt haben, hat Terraform im Hintergrund Ihr Produktions-Backend fertiggestellt.
Bevor Sie unsere vollständige Sidecar-Architektur mit drei Containern für die Produktion bereitstellen (Schritt 6: „4 bereitstellen“), dient dieser Schritt als schnelle Vorflugkontrolle, um den Datenbankstatus, die Konnektivität und den Zugriff auf Secrets zu prüfen.
0. Bootstrap-Umgebungsvariablen
Exportieren Sie alle erforderlichen Shell-Variablen direkt aus Ihren Terraform-Ausgaben:
# Core project variables (should already be set from Step 0)
export GOOGLE_CLOUD_REGION="${GOOGLE_CLOUD_REGION:-europe-west1}"
# Compute runtime service account
export PROJECT_NUMBER=$(gcloud projects describe $GOOGLE_CLOUD_PROJECT --format="value(projectNumber)")
export RUN_SA="${PROJECT_NUMBER}-compute@developer.gserviceaccount.com"
# Cloud SQL instance name (from Terraform output, NOT hardcoded)
export SQL_INSTANCE_NAME=$(cd iac && terraform output -raw sql_instance_name 2>/dev/null || gcloud sql instances list --format='value(name)' --limit=1)
# Database password (from Terraform output)
export DB_PASSWORD=$(cd iac && terraform output -raw db_password 2>/dev/null || echo "CHANGE_ME")
# GCS bucket names
export GCS_BUCKET="${GOOGLE_CLOUD_PROJECT}-activestorage-prod"
echo "✅ Pre-flight environment variables ready:"
echo " RUN_SA=$RUN_SA"
echo " SQL_INSTANCE_NAME=$SQL_INSTANCE_NAME"
echo " GCS_BUCKET=$GCS_BUCKET"
1. Cloud SQL-Integritätsprüfung
Prüfen Sie, ob die Erstbereitstellung Ihrer verwalteten PostgreSQL-Instanz abgeschlossen ist und sie fehlerfrei ist:
echo "Checking instance: $SQL_INSTANCE_NAME"
gcloud sql instances describe $SQL_INSTANCE_NAME --format="value(state)"
Die Ausgabe muss RUNNABLE sein.
2. (Optional) Datenbankverbindung von Ihrem Laptop aus testen
In der Produktion stellen Cloud Run-Container über einen verschlüsselten Sidecar-Proxy (127.0.0.1:5432) eine sichere Verbindung zu Cloud SQL her, ohne die Datenbank dem öffentlichen Internet (0.0.0.0/0) auszusetzen.
ℹ️ Hinweis:Dieser Schritt ist optional. In Cloud Run wird die mTLS-Verbindung automatisch vom offiziellen Cloud SQL Auth-Proxy-Sidecar-Container verarbeitet. Sie müssen nichts lokal installieren, um den Workshop durchzuführen.
Wenn Sie cloud-sql-proxy und psql auf Ihrem Computer installiert haben und die direkte Verbindung von Ihrem Laptop aus überprüfen möchten, gehen Sie so vor:
# Optional: test connectivity via Google-managed mTLS proxy
gcloud sql connect $SQL_INSTANCE_NAME --user=rails_user --database=rails_production
Wenn Sie zur Eingabe eines Passworts aufgefordert werden, geben Sie
$DB_PASSWORD
Andernfalls können Sie direkt mit Schritt 3 unten fortfahren.
3. Mit Terraform bereitgestellte Secrets prüfen
Speichern Sie niemals Datenbankpasswörter, API-Schlüssel oder Rails-Hauptschlüssel im Nur-Text-Format in Git oder in Umgebungsvariablen von Containern. In modernen Cloud-Architekturen verwenden wir Google Cloud Secret Manager für die Zero-Trust-Laufzeiteinfügung.
ℹ️ Terraform hat das für Sie in Schritt 1 erledigt:
rails-master-key– zum Entschlüsseln von Rails-Anmeldedaten zur Laufzeit.rails-db-password: Ein kryptografisch sicheres zufälliges Passwort, das dem Cloud SQL-Nutzer entspricht.rails-admin-password– ein sicheres Passwort für Ihren ersten Administratornutzer.
Prüfen Sie, ob Ihre Secrets in Secret Manager vorhanden und aktiv sind:
gcloud secrets list --filter="name:rails-"

🔑 master.key mit Ihrem Laptop synchronisieren (lokale Synchronisierung)
Da blog/config/master.key aus Sicherheitsgründen ignoriert wird, ist es möglicherweise noch nicht in Ihrem lokalen Klon vorhanden. Führen Sie diesen benutzerfreundlichen Snippet zur Selbstheilung aus, um ihn aus Secret Manager abzurufen, damit Ihre lokalen Rails-Tools Anmeldedaten entschlüsseln können:
if [ ! -f blog/config/master.key ]; then
echo "📥 Pulling rails-master-key from Secret Manager to local blog/config/master.key..."
gcloud secrets versions access latest --secret=rails-master-key > blog/config/master.key
echo "🔑 Created local blog/config/master.key! 🎉"
else
echo "✅ Local blog/config/master.key already exists! 🚀"
fi
🧪 Playground: Möchten Sie ein benutzerdefiniertes Secret erstellen, um zu sehen, wie einfach das ist? Secret Manager ist nicht nur für Rails geeignet. Sie können jedes Secret mit einem einfachen CLI-Befehl erstellen:
echo -n "MySuperSecretValue123!" | gcloud secrets create workshop-fun-secret --data-file=-
echo "✨ Created workshop-fun-secret in Secret Manager! 🪄"
4. Berechtigungen für Secret-Zugriffspersonen prüfen
Damit Cloud Run-Container diese Secrets beim Start als Umgebungsvariablen oder Volume-Bereitstellungen einbinden können, benötigt das Laufzeit-Dienstkonto ($RUN_SA) die Rolle roles/secretmanager.secretAccessor für jedes Secret.
Terraform hat diese Berechtigung bereits in Schritt 1 erteilt. IAM-Richtlinienbindung für rails-master-key prüfen:
# Verify that Cloud Run runtime SA has Secret Accessor role
gcloud secrets get-iam-policy rails-master-key \
--flatten="bindings[].members" \
--format="table(bindings.role,bindings.members)" \
--filter="bindings.members:$RUN_SA"
Hier sollten Sie dies sehen:
ROLE MEMBERS
roles/secretmanager.secretAccessor serviceAccount:PROJECT_NUMBER-compute@developer.gserviceaccount.com

5. Automatisierte Preflight-Validierung
Führen Sie die automatisierte Testsuite für Schritt 5 aus, um zu bestätigen, dass Ihre Datenbank ausgeführt werden kann, die Secrets nicht leer sind und die IAM-Berechtigungen grün sind:
just workshop-eval 5
8. Schritt 6: Bereitstellung 4 – Enterprise-Multi-Container-Sidecars (Goldstandard)
Nun stellen wir die ultimative Referenzarchitektur zusammen: Cloud Run mit mehreren Containern.
1. Goldstandard wiederherstellen
Stellen Sie die Repository-Konfiguration auf den kanonischen main-Zustand zurück:
just workshop-restore-gold
2. 3‑Container-Produktionskonzept prüfen
Öffnen Sie blog/compose.prod.yaml und prüfen Sie die Architektur:

graph LR
Client[Internet / HTTPS Client] -->|Port 8080| Web[Web Container: Puma]
Web -->|Localhost:5432| Proxy[Sidecar: Cloud SQL Auth Proxy]
Worker[Worker Container: Solid Queue] -->|Localhost:5432| Proxy
Proxy -->|IAM mTLS Tunnel| CloudSQL[(Google Cloud SQL PostgreSQL)]
Bei der Produktionsbereitstellung werden drei koordinierte Container ausgeführt, die sich dasselbe lokale Netzwerk teilen:
web: HTTP-Traffic wird über Puma auf Port 8080 bereitgestellt.worker: Dedizierter Container für die Hintergrundverarbeitung, in dembundle exec rails solid_queue:startausgeführt wird.cloudsql-proxy: Offizieller Google Cloud SQL Auth-Proxy-Sidecar (gcr.io/cloud-sql-connectors/cloud-sql-proxy:2), der an127.0.0.1:5432gebunden ist.
3. Datenbankmigrationen über Cloud Run-Jobs ausführen
Bevor wir Web-Traffic an unsere neue Bereitstellung weiterleiten, müssen wir Datenbankmigrationen und das erste Seeding für Cloud SQL ausführen.
⚖️ Migrationen in Containern ausführen: Zwei Strategien
In containerisierten Cloud-Umgebungen gibt es zwei gängige Ansätze für die Ausführung von Datenbankmigrationen:
- Option A: Automatisch im Docker-Einstiegspunkt (
entrypoint.shführtdb:migratebeim Start des Containers aus)- Vorteile:Vollständig automatisiert; Entwickler müssen nicht daran denken, einen Befehl auszuführen.
- Nachteile:Gefährlich beim serverlosen Autoscaling. Wenn Cloud Run bei hohem Traffic gleichzeitig auf 10 Instanzen skaliert wird, versuchen 10 Container, Migrationen gleichzeitig auszuführen. Dies kann zu Datenbanksperrungen, Race Conditions im Schema oder Boot-Timeouts führen.
- Option B: Explizit über Cloud Run-Job (unsere Architektur)
- Vorteile:Vollständige Kontrolle, Transaktionssicherheit und keine Race Conditions. Wird als dedizierte Einmal-Containeraufgabe ausgeführt, die vollständig vom Bereitstellen von Web-Traffic getrennt ist. Wenn eine Migration fehlschlägt, ist die Webbereitstellung davon nicht betroffen.
- Nachteile:Vor der Bereitstellung muss ein CLI-Job oder ein CI/CD-Schritt ausgelöst werden.
Wir wählen Option B, um die Produktionszuverlässigkeit zu maximieren.
⚠️ Kritisch: DATABASE_URL-Format und Ruby 3.4.5 RFC 3986-Strenge
Cloud Run-Jobs stellen über den nativen Unix-Socket-Proxy (/cloudsql/PROJECT:REGION:INSTANCE) eine Verbindung zu Cloud SQL her. Für DATABASE_URL muss das Format mit drei Schrägstrichen verwendet werden:
postgresql:///rails_production?user=rails_user&password=PASS&host=/cloudsql/PROJECT:REGION:INSTANCE
# Core environment variables for database migration & initial admin seed
export GOOGLE_CLOUD_ACCOUNT="${GOOGLE_CLOUD_ACCOUNT:-$(gcloud config get-value account)}"
echo "Admin user will be seeded for: $GOOGLE_CLOUD_ACCOUNT"
# Get the latest blog image from Cloud Run (jobs don't support --source)
export BLOG_IMAGE=$(gcloud run services describe blog --region=$GOOGLE_CLOUD_REGION --format='value(spec.template.spec.containers[0].image)')
# Build the DATABASE_URL in triple-slash format (required for Unix socket proxy)
export DB_PASSWORD=$(gcloud secrets versions access latest --secret=rails-db-password)
export CLOUDSQL_CONNECTION="${GOOGLE_CLOUD_PROJECT}:${GOOGLE_CLOUD_REGION}:${SQL_INSTANCE_NAME}"
export DB_URL="postgresql:///rails_production?user=rails_user&password=${DB_PASSWORD}&host=/cloudsql/${CLOUDSQL_CONNECTION}"
# Create migration job — note ALL 4 database URL env vars and GOOGLE_CLOUD_ACCOUNT for seed user creation
gcloud run jobs create rails-migrate \
--image=$BLOG_IMAGE \
--command "bin/rails" \
--args "db:prepare" \
--set-env-vars="DATABASE_URL=${DB_URL},DATABASE_QUEUE_URL=${DB_URL},DATABASE_CACHE_URL=${DB_URL},DATABASE_CABLE_URL=${DB_URL},GOOGLE_CLOUD_PROJECT=${GOOGLE_CLOUD_PROJECT},GOOGLE_CLOUD_ACCOUNT=${GOOGLE_CLOUD_ACCOUNT}" \
--set-secrets="RAILS_MASTER_KEY=rails-master-key:latest" \
--set-cloudsql-instances="${CLOUDSQL_CONNECTION}" \
--service-account=$RUN_SA \
--region $GOOGLE_CLOUD_REGION 2>/dev/null || true
# Execute migration job
gcloud run jobs execute rails-migrate --region $GOOGLE_CLOUD_REGION --wait
💡 Rails 8 – Multi-Database:Die App verwendet vier Datenbanken (primär, Warteschlange, Cache, Kabel) pro database.yml. Alle vier DATABASE_*_URL-Umgebungsvariablen müssen auf dieselbe Cloud SQL-Instanz verweisen. Andernfalls werden die Tabellen für Solid Queue, Cache und Cable nicht erstellt.
Laden Sie nach db:prepare die Schemas für Solid Queue, Cache und Kabel:
# Schema load for queue, cache, and cable databases (creates solid_queue_jobs, etc.)
gcloud run jobs update rails-migrate \
--command "bash" \
--args "-c,DISABLE_DATABASE_ENVIRONMENT_CHECK=1 bin/rails db:schema:load:queue db:schema:load:cache db:schema:load:cable" \
--region $GOOGLE_CLOUD_REGION
gcloud run jobs execute rails-migrate --region $GOOGLE_CLOUD_REGION --wait
Die Abbildung oben zeigt eine mögliche Ausgabe von
gcloud run jobs executions describe $JOBNAME
Google Cloud Run Jobs Console mit
rails-migrate
Ausführung erfolgreich
4. Vierte Bereitstellung: Cloud Run-Multicontainer über Docker Compose bereitstellen
Stellen Sie nun den echten Produktions-Stack mit drei Containern (web, worker, cloudsql-proxy) direkt über compose.prod.yaml bereit:
# 1. Self-healing environment exports (guarantees no missing master key or DB password)
export RAILS_MASTER_KEY="${RAILS_MASTER_KEY:-$(cat config/master.key 2>/dev/null || gcloud secrets versions access latest --secret=rails-master-key)}"
export DB_PASSWORD=$(gcloud secrets versions access latest --secret=rails-db-password)
export CLOUDSQL_INSTANCE_CONNECTION_NAME="${GOOGLE_CLOUD_PROJECT}:${GOOGLE_CLOUD_REGION}:${SQL_INSTANCE_NAME}"
# 2. Database credentials & GCS attachments
export DB_USER="rails_user"
export DB_NAME="rails_production"
export GCS_BUCKET="${GCS_BUCKET}"
export ACTIVE_STORAGE_SERVICE="google"
export GOOGLE_CLOUD_ACCOUNT="${GOOGLE_CLOUD_ACCOUNT:-$(gcloud config get-value account)}"
export GEMINI_API_KEY="${GEMINI_API_KEY:-dummy-key}"
# 3. Deploy the full multi-container sidecar architecture to Cloud Run
gcloud run compose up compose.prod.yaml \
--region=$GOOGLE_CLOUD_REGION \
--allow-unauthenticated
Google Cloud Run Console: Tab „Container“ mit allen drei Sidecar-Containern (
cloudsql-proxy
,
web
,
worker
)
💡 UI-Fehler / Konsolenfehler:Im Drop-down-Menü der Konsole wird der oberste Eintrag in Cloud Run möglicherweise als Ingress container: cloudsql-proxy bezeichnet. Keine Sorge! Dies ist lediglich ein visueller UI-Fehler in der Google Cloud Console (#149), der durch die Reihenfolge der Containerabhängigkeiten verursacht wird. In Wirklichkeit ist web der einzige Container, der den HTTP-Port 8080 überwacht und 100% des Ingress-Web-Traffics verarbeitet, während cloudsql-proxy ausschließlich privaten PostgreSQL-Traffic auf Port 5432 bereitstellt.
5. ✨ Der Wow-Moment: Keine Warnungen und vollständige Cloud-Persistenz!
Atmen Sie tief durch und sehen Sie sich Ihren Bildschirm an: Alle Warnbanner sind verschwunden. 🪄
The production Rails 8 blog: pristine UI, zero warning banners, and persistent Cloud SQL state!
Die Anwendung ist jetzt offiziell produktionsreif und cloudnativ:
- Unterstützt durch verwaltetes Google Cloud SQL (PostgreSQL) über sicheres mTLS-Tunneling.
- Medien werden sicher in privatem Google Cloud Storage mit IAM-Blob-Signierung gespeichert.
- Keine Warnungen zu flüchtigem Speicher und keine Benachrichtigungen zu Jobs, die nicht abgeschlossen werden können.
Öffnen Sie die Cloud Run-URL:
- Sehen Sie sich die Telemetrie-Badges an:
[CLOUD PERSISTENT 🐘 ☁️]ist in Ihrem Datenbank-Seed überprüft.- Sowohl das Google Cloud Run- als auch das GCS-Logo in der Fußzeile sind grün.
- Das Warnbanner für hängende Jobs ist nicht mehr vorhanden.
- Blogposts und Kommentare erstellen
- Sie können die Instanz beliebig oft neu starten oder neu bereitstellen. Ihre Daten, Beiträge, Kommentare und Assets bleiben in Cloud SQL und GCS erhalten.
6. Automatisierte Validierung in Schritt 6
Multi-Container-Konfiguration prüfen:
just workshop-eval 6
9. Schritt 7: Generative KI-Pipelines, Podcastifier und die GCS-Schatzsuche 🏴☠️
Wenn Solid Queue in einem dedizierten Container ausgeführt wird und Google Cloud Storage aktiv ist, können wir asynchrone generative KI nutzen.
1. Der NanoBanana Vintage Cover Generator (einsatzbereite GenAI-Pipeline)

Gute Neuigkeiten: Diese Funktion ist bereits vollständig im Code implementiert. Sie müssen keinen Code schreiben. Ihre Aufgabe besteht darin, eine asynchrone Cloud GenAI-Pipeline auszulösen und zu beobachten.
🧠 So funktioniert es im Hintergrund
- Authentifizierung:Es sind keine API-Schlüssel erforderlich. Es verwendet automatisch Standardanmeldedaten für Anwendungen (
roles/aiplatform.userauf Vertex AI) über das Cloud Run-Laufzeitdienstkonto. Alternativ wird die Gemini API direkt aufgerufen, wennGEMINI_API_KEYangegeben ist. - Die Pipeline:Wenn ein Artikel ohne Titelbild erstellt wird, wird durch einen
after_commit-CallbackGenerateCoverImageJobin die Solid Queue eingereiht. - Modell:Das multimodale Modell von Google (Gemini 2.5 Flash Image / Imagen in Vertex AI) wird aufgefordert, ein authentisches italienisches Filmplakat aus den 1960er-Jahren („Locandina di un film 1960“) zu generieren, komplett mit einer Banane und einer glänzenden rubinroten „8“.
- Dynamisches Herkunfts-Wasserzeichen:Hier wird
libvipsverwendet, um dynamisch ein visuelles Logo in der Ecke einzufügen (farbiges Cloud-Logo in GCS). - Turbo Stream Hot-Swap:Wenn das Bild angehängt ist, aktualisiert
Turbo::StreamsChannel.broadcast_refresh_to(post)den Browser des Lesers live, ohne dass die Seite manuell neu geladen werden muss.

📐 Mermaid-Sequenzdiagrammquelle ansehen
sequenceDiagram
autonumber
actor User as 👤 Reader / Author
participant Web as 🌐 Web (Puma)
participant DB as 🐘 Cloud SQL (Solid Queue)
participant Worker as ⚙️ Worker (Solid Queue)
participant Vertex as 🧠 Vertex AI (Gemini Flash / Imagen)
participant GCS as ☁️ Google Cloud Storage
User->>Web: POST /posts (Title & Body, No Cover)
Web->>DB: 1. Save Post & Enqueue GenerateCoverImageJob
Web-->>User: Redirect to Post (turbo_stream subscribed)
Worker->>DB: 2. Dequeue GenerateCoverImageJob
Worker->>Vertex: 3. Prompt for 1960s Italian Poster (ADC auth)
Vertex-->>Worker: 4. Raw Image Buffer
Worker->>Worker: 5. Stamp Provenance Watermark (libvips)
Worker->>GCS: 6. Attach Blob via ActiveStorage (IAM signBlob)
Worker->>Web: 7. Turbo::StreamsChannel.broadcast_refresh_to(post)
Web-->>User: ⚡ Live UI Hot-Swap: Poster magically appears!
🧪 Live ausprobieren
Sie können sie auf zwei Arten auslösen:
- Option A (Web-UI): Klicken Sie auf Neuer Beitrag, geben Sie einen Titel wie „Serverlose Architektur mit Ruby on Rails 8“ ein, schreiben Sie etwas Inhalt und lassen Sie die Dateieingabe für das Titelbild leer. Klicke auf Beitrag erstellen.
- Option B (CLI Runner): Führen Sie den folgenden Befehl in Ihrem Terminal aus:
bin/rails runner 'Post.create!(title: "Serverless Architecture with Ruby on Rails 8", body: "Exploring asynchronous AI pipelines with Solid Queue and NanoBanana!")'
Warten Sie etwa 15 bis 30 Sekunden und sehen Sie sich die Solid Queue-Worker-Logs in Cloud Run an. Das Vintage-Poster wird direkt in Ihrem Beitrag angezeigt.
📸 TODO(riccardo): add screenshot of a blog post with an AI-generated vintage 1960s Italian movie poster featuring a cameo banana and ruby 8
2. Die zweisprachige Podcastifier-Quest (praktische Antigravity-Programmierübung)
⚠️ Wichtiger Hinweis:Im Gegensatz zum Cover-Generator oben ist diese Funktion noch nicht implementiert.
Wenn Sie blog/app/jobs/podcastifier_job.rb öffnen, sehen Sie einen leeren Gerüst-Stub:
class PodcastifierJob < ApplicationJob
queue_as :default
def perform(post_id)
# TODO(student): COMPLETE_ME — Pair program with Google Antigravity to implement
# Italian TTS podcast generation using voice 'it-IT-Wavenet-A' via Cloud TTS / ADC!
end
end
Ihre Aufgabe in dieser praktischen Übung ist es, gemeinsam mit Google Antigravity zu programmieren, um diese Funktion zu implementieren:
- Prompt für Antigravity:„Hilf mir, PodcastifierJob in
app/jobs/podcastifier_job.rbzu implementieren. Es soll den Beitrag abrufen, eine italienische Audioübersicht mit Google Cloud Text-to-Speech (Stimme „it-IT-Wavenet-A“ mit Sprachcode „it-IT“ über Standardanmeldedaten für Anwendungen) übersetzen oder synthetisieren und die Audiodatei mit ActiveStorage anpost.podcast_audio_itanhängen.“ - Player zur Ansicht hinzufügen:Fügen Sie in
app/views/posts/show.html.erbeinen HTML5--Player hinzu, wenn@post.podcast_audio_it.attached?. - Synthese auslösen:Wenn Sie die Solid Queue speichern, wird der Text-to-Speech-Job asynchron im Hintergrund ausgeführt.

🎧 Beispielausgaben von Podcastifier:
💡 Benötigen Sie Hilfe oder kommen Sie nicht weiter? Eine vollständige, praxiserprobte Referenzlösung ist im Branch solutions/podcastifier verfügbar. Sie können es jederzeit mit git diff solutions/podcastifier überprüfen.
3. [OPTIONAL] 🏴☠️ Die GCS-Schatzsuche (Console Blob Recovery)
ℹ️ Voraussetzungsprüfung: Lokal
cloud-sql-proxy
CLI erforderlich – In dieser optionalen Übung wird Ihr lokaler Laptop über einen verschlüsselten mTLS-Tunnel direkt mit Google Cloud SQL verbunden. Prüfen Sie, ob der CLI-Proxy installiert ist:
which cloud-sql-proxy
- Wenn installiert:Fahren Sie unten fort.
- Wenn die Erweiterung NICHT installiert ist und Sie diese Quest absolvieren möchten, installieren Sie sie mit:
# Linux (x86_64) curl -o /tmp/cloud-sql-proxy https://storage.googleapis.com/cloud-sql-connectors/cloud-sql-proxy/v2.14.0/cloud-sql-proxy.linux.amd64 chmod +x /tmp/cloud-sql-proxy && sudo mv /tmp/cloud-sql-proxy /usr/local/bin/cloud-sql-proxy # macOS (Homebrew) brew install cloud-sql-proxy - Andernfalls:Fahren Sie mit der automatischen Validierung in Schritt 7 fort.
Erinnern Sie sich an das Foto, das Sie in Schritt 4 hochgeladen haben, bevor die temporäre SQLite-Datenbank durch den Neustart des Containers gelöscht wurde? Diese Bilddatei befindet sich weiterhin sicher in Ihrem privaten GCS-Bucket als „verwaister Blob“.
Wir verwenden die Rails-Konsole, um das Bild zu retten und an einen Cloud SQL-Beitrag anzuhängen:
# Connect to your production database via Rails console and Cloud SQL Proxy
cloud-sql-proxy --port 5432 ${GOOGLE_CLOUD_PROJECT}:${GOOGLE_CLOUD_REGION}:${SQL_INSTANCE_NAME} &
DATABASE_URL=postgresql://rails_user:${DB_PASSWORD}@127.0.0.1:5432/rails_production bin/rails c
In der Rails-Konsole:
# 1. Search for orphaned GCS blobs in ActiveStorage
orphan_blobs = ActiveStorage::Blob.where.missing(:attachments)
puts "🏴☠️ Found #{orphan_blobs.count} orphaned GCS blobs!"
# 2. Attach the surviving blob to your latest post
if orphan_blobs.any?
post = Post.last
post.cover_image.attach(orphan_blobs.first)
post.save!
puts "🎉 Rescued blob #{orphan_blobs.first.filename} attached to '#{post.title}'!"
end
exit
📸 TODO(riccardo): add screenshot of the interactive Rails console executing the GCS Treasure Hunt snippet and rescuing orphaned ActiveStorage blobs
Aktualisieren Sie Ihren Blog: Das in Schritt 4 hochgeladene Foto wird wiederhergestellt und dauerhaft an Ihren Cloud SQL-Beitrag angehängt.
4. Automatisierte Validierung in Schritt 7
GenAI-Jobs und ‑Assets prüfen:
just workshop-eval 7
10. Schritt 8: „Choose Your Own Adventure“ / Erweiterte Quests 🏆
Nachdem Sie die kanonische Referenzarchitektur gemeistert haben, können Sie Ihre Abschluss-Quest auswählen.
🛡️ Quest 1: Zero-Trust Google IAP (Identity-Aware Proxy)
- Schwierigkeitsgrad:Mittel (Enterprise Security)
- Ziel:Ihre Cloud Run-Anwendung so schützen, dass nur Ihre bestätigten Google- oder Gmail-Konten darauf zugreifen können. Die Anmeldung mit einem Passwort wird dadurch vollständig überflüssig.
- Funktionsweise
- Ein externer HTTPS Application Load Balancer beendet Google OAuth und überprüft die Identität, bevor Traffic Cloud Run erreicht.
- Google leitet Header mit bestätigter Identität (
X-Goog-Authenticated-User-Email) weiter. - Rails meldet die bestätigte Google-Identität automatisch über
blog/app/controllers/concerns/iap_authenticatable.rban:module IapAuthenticatable extend ActiveSupport::Concern included { before_action :authenticate_via_iap } private def authenticate_via_iap return unless (raw = request.headers["X-Goog-Authenticated-User-Email"]).present? email = raw.sub(/^accounts\.google\.com:/, "") user = User.find_or_create_by!(email_address: email) { |u| u.password = SecureRandom.hex(16) } start_new_session_for(user) unless authenticated? end end - Aktivieren Sie das Terraform-Modul in
iac/iap.tfmitenable_iap = trueund geben Sie Ihre zulässigen Google-Konten an:iap_allowed_users = [var.google_cloud_account]

📊 Aufgabenreihe 2: Telemetrie und Cloud Logging für Production SRE
- Schwierigkeitsgrad:Mittel (Beobachtbarkeit)
- Ziel:Strukturierte JSON-Anwendungsprotokolle mit Trace-Korrelations-IDs direkt an Google Cloud Logging streamen und Produktionsausnahmen in Echtzeit mit Cloud Error Reporting abfangen.
- Funktionsweise
- Konfigurieren Sie
blog/config/environments/production.rbso, dass strukturierte JSON-Logs mit GCP-Trace-Labels ausgegeben werden. - Lösen Sie eine absichtliche Testausnahme aus und sehen Sie zu, wie Google Cloud Error Reporting sie sofort gruppiert und Sie benachrichtigt.
- Konfigurieren Sie
📸 TODO(riccardo): add screenshot of Google Cloud Error Reporting showing grouped production exceptions and Cloud Logging structured JSON payload with trace labels
🧠 Aufgabenreihe 3: pgvector Semantische Suche und Gemini RAG
- Schwierigkeitsgrad:Schwer (GenAI-Abschlussprojekt)
- Ziel:Artikel konzeptionell mithilfe von Vektoreinbettungen durchsuchen, die in PostgreSQL in Cloud SQL gespeichert sind.
- Funktionsweise
- Aktivieren Sie die Erweiterung
vectorin Ihrer Cloud SQL PostgreSQL-Instanz:CREATE EXTENSION IF NOT EXISTS vector; - Fügen Sie das
neighbor-Gem zublog/Gemfilehinzu und generieren Sie mit Gemini (text-embedding-004) aufPost#after_saveTexteinbettungen. - Führen Sie Kosinus-Distanz-Abfragen (
<=>) aus, um eine semantische Suchleiste mit Turbo Streams zu erstellen.
- Aktivieren Sie die Erweiterung
📸 TODO(riccardo): Screenshot der semantischen Suchleiste des Liveblogs hinzufügen, in der konzeptionelle Übereinstimmungen mit Cosinus-Ähnlichkeitswerten zurückgegeben werden
⚡ Aufgabenreihe 4: SEO & Performance Audit Assistant
- Schwierigkeit:Einfach / Unterhaltsam (Entwicklung)
- Ziel:Core Web Vitals, Largest Contentful Paint (LCP) und die Lesbarkeitsindizes von Flesch-Kincaid und Fog mit den Tools Antigravity und Speedgrapher prüfen.
📸 TODO(riccardo): add screenshot of Speedgrapher / Lighthouse SEO and Core Web Vitals audit summary
🤔 Curiosity Box: Getting a Live Rails Console on Cloud Run
💡 Die Frage:Bei herkömmlichen VMs oder PaaS-Plattformen im Heroku-Stil stellen Entwickler häufig eine SSH-Verbindung zu einer laufenden Instanz her oder verwenden heroku run rails console, um Produktionsdaten live zu prüfen oder zu korrigieren. Was ist das Cloud Run-native Äquivalent und wie härten Sie es?
Warum?
gcloud run exec
ist für Cloud Run-Dienste nicht vorhanden
Cloud Run ist eine serverlose Plattform: Ihr Container kann als null, eine oder Hunderte identischer Instanzen ausgeführt werden, ohne stabile Identität oder adressierbare Shell. Das unterscheidet sich grundlegend von Kubernetes (kubectl exec), wo ein bestimmter Pod einen benannten Socket hat, an den Sie sich anhängen können.
# ❌ This does NOT exist for Cloud Run Services:
gcloud run services exec blog --region europe-west1 -- rails console
# ✅ This exists for Cloud Run JOBS (non-interactive, one-shot tasks):
gcloud run jobs execute my-job --region europe-west1 --wait
Die vier GCP-nativen Muster
Muster | Befehl | Interaktiv? | Sicherheit |
1. Lokaler Proxy + Remote-Datenbank |
| ✅ Vollständig | 🔒 Cloud SQL Auth-Proxy – gegenseitige TLS-Authentifizierung |
2. Cloud Run-Job (einmalig) |
| ❌ Nur Script | 🔒 IAM-Rolle erforderlich |
3. Webkonsole + IAP | Browser → | ✅ Vollständig | 🛡️ IAP Zero-Trust |
4. Cloud Shell + Proxy | Cloud Shell → | ✅ Vollständig | 🔒 Google-Identität |
Muster 1 (empfohlen für die Datenprüfung): Führen Sie eine lokale Rails-Konsole aus, die über den Cloud SQL Auth-Proxy direkt mit Ihrer Cloud SQL PostgreSQL-Instanz kommuniziert:
# In one terminal: start the auth proxy
cloud-sql-proxy rails8-fl-20260907b-xm8ko4:europe-west1:your-instance
# In another terminal: open a read-write or sandbox console
DATABASE_URL=postgresql://rails_user:${DB_PASSWORD}@127.0.0.1:5432/rails_production \
bin/rails console --sandbox
Sie erhalten die volle IRB-Interaktivität ohne Netzwerkexposition, da der Cloud SQL-Proxy mTLS über einen Unix-Domain-Socket oder Loopback verwendet.
Muster 3 (Webkonsole + IAP Zero-Trust, der gehärtete Browserpfad):
Das web-console-Gem bietet eine browserbasierte IRB-Sitzung. Ohne Schutz ist es eine kritische Sicherheitslücke. Geben Sie es niemals öffentlich preis. In Kombination mit Google IAP (Quest 1) wird die Angriffsfläche jedoch reduziert: Nur bestätigte Google-Identitäten auf Ihrer Zulassungsliste können den /rails/console-Endpunkt erreichen.
# Gemfile — only load in development/staging, never production without IAP!
gem "web-console", group: :development
# config/environments/production.rb — if IAP is enabled:
config.web_console.allowed_ips = ["0.0.0.0/0"] # IAP terminates auth before us
⚠️ Für Muster 3 muss zuerst Quest 1 (IAP) aktiviert werden. Ohne sie ist /rails/console für eine öffentliche URL so, als würden Sie Ihren Serverraum unverschlossen lassen. Mit IAP wird es zu einem leistungsstarken Betreibertool, das durch Zero-Trust-Sicherheit auf Google-Niveau geschützt ist.
Antigravity fragen : „Zeige mir, wie ich
rails console --sandbox
against my Cloud SQL production database safely using the Cloud SQL Auth Proxy."
🏆 Abschluss im Hive: Von Prüfern bestätigter Proof-of-Work
Wenn Sie die ausgewählte Quest abgeschlossen haben, können Sie auf der The Hive-Bestenliste die Abschluss-Trophäe für Schritt 8 🏆 einfordern:
- Quest auf GitHub einreichen:
- Erstellen Sie ein neues Issue im offiziellen Repository: github.com/palladius/rails8-app-on-gcp/issues/new.
- Titelformat:
🎓 [Step 8 Completed]: - Fügen Sie in den Text eine kurze Beschreibung Ihrer Leistung und einen Link zu Ihrer aktiven Cloud Run-Bereitstellung ein.
- Cloud Run-App mit Ihrem Problem verknüpfen:
- Notieren Sie sich die Problem-ID (z.B.
88) oder die vollständige URL (https://github.com/palladius/rails8-app-on-gcp/issues/88). - Fügen Sie die Umgebungsvariable
STEP_8_GHIin Ihren Cloud Run-Dienst ein:gcloud run services update blog \ --region europe-west1 \ --update-env-vars STEP_8_GHI=<YOUR_ISSUE_NUMBER> - Prüfen Sie, ob Ihr
/status.json-Endpunkt jetzt Ihre Quest meldet: Sie sollten Folgendes sehen:curl -s https://<YOUR_APP>.run.app/status.json | jq .quest{ "step_8_completed": true, "ghi_issue": 88, "ghi_url": "https://github.com/palladius/rails8-app-on-gcp/issues/88" }
- Notieren Sie sich die Problem-ID (z.B.
- Prüferüberprüfung erhalten und goldene Trophäe freischalten
- :
- Sehen Sie sich die Hive-Rangliste an. In Ihrer Zeile wird jetzt ein bernsteinfarbenes Logo angezeigt:
⏳ GHI #XX review pending. - Bitten Sie die Workshop-Leiter (@palladius, @emilianodellacasa oder @ricc), Ihre Bereitstellung zu prüfen.
- Sobald ein Prüfer
LGTMzu deinem Problem kommentiert, wird dein Fortschritt in The Hive automatisch auf 8/8 🏆 aktualisiert. Du erhältst ein goldenes/violettes, leuchtendes Badge und eine permanente Trophäe, die direkt zu deinem Capstone-Problem verlinkt ist.
- Sehen Sie sich die Hive-Rangliste an. In Ihrer Zeile wird jetzt ein bernsteinfarbenes Logo angezeigt:
11. Zusammenfassung und Bereinigung 🎓
Glückwunsch! 🎉
Sie haben eine produktionsreife, unternehmensfähige Rails 8-Anwendung in der Google Cloud Platform erstellt und bereitgestellt:
- Zero-Branch Progression:Moderne Workflows mit Time-Machine-Overlays auf
maingemeistert. - Cloud Storage:Skalierbarer, privater Objektspeicher mit IAM-Blob-Signierung (
iam: true). - Cloud SQL:Verwaltete PostgreSQL-Instanzen, die mit Cloud SQL Auth-Proxy-mTLS-Tunneln gesichert sind.
- Secret Manager:Keine Klartextanmeldedaten oder
.env-Dateilecks. - Cloud Run-Multi-Container:Isolierte Puma-Web-, Solid Queue-Worker- und Proxy-Sidecars.
- Generative KI:Asynchrone Generierung von Vintage-Postern und TTS-Podcasts mit Vertex AI.
- Quests:Zero-Trust-IAP, SRE-Observability und pgvector-Einbettungen
🧹 Ressourcen bereinigen
Damit nach Abschluss des Workshops keine laufenden Kosten anfallen, müssen Sie Ihre Google Cloud-Ressourcen bereinigen. Wählen Sie den Ansatz aus, der am besten zu Ihrer Umgebung passt:
Option 1: Terraform-Abbau (empfohlen / Standard 🟢)
Verwenden Sie diese Option, wenn Sie ein vorhandenes oder freigegebenes Google Cloud-Projekt verwenden, in dem sich andere Ressourcen oder Daten befinden. Es werden nur die Ressourcen gelöscht, die während dieses Workshops bereitgestellt wurden (Cloud Run, Cloud SQL, Secret Manager, GCS-Buckets). Der Rest Ihres Projekts bleibt unverändert.
cd iac
terraform destroy -auto-approve
Option 2: Gesamtes Projekt löschen (keine Spuren hinterlassen 🌪️)
Verwenden Sie diese Option, wenn Sie ein spezielles Workshop-Projekt erstellt haben (z.B. mit Workshop-Guthaben oder einer Sandbox) und sicherstellen möchten, dass keine Spuren zurückbleiben, einschließlich Logs, Metadaten, Dienstkonten und Abrechnungslinks.
gcloud projects delete $GOOGLE_CLOUD_PROJECT --quiet