1. Wprowadzenie
Witamy na warsztatach Rails 8 w Google Cloud. W tym praktycznym ćwiczeniu przekształcisz nowoczesną aplikację Rails 8 z prostej lokalnej wersji podstawowej SQLite w gotową do wdrożenia w środowisku produkcyjnym architekturę referencyjną klasy korporacyjnej w Google Cloud.
Podczas tych warsztatów nie tylko wdrożymy aplikację, ale też przeprowadzimy opartą na naszych doświadczeniach modernizację chmury na potrzeby produkcji (metoda lift-and-shift w odpowiedni sposób).
Zaczynasz od typowej konfiguracji lokalnej „działa na moim komputerze” (dysk tymczasowy, wbudowana baza danych SQLite, zadania w procesie) i stopniowo przekształcasz ją w architekturę chmurową klasy korporacyjnej, odporną na awarie w Google Cloud:
- 🐘 Z lokalnej bazy danych SQLite → Cloud SQL (PostgreSQL): koniec z czyszczeniem bazy danych po ponownym uruchomieniu. Przenosimy się do zarządzanej bazy danych PostgreSQL, która jest bezpiecznie połączona za pomocą serwera proxy uwierzytelniania Cloud SQL (mTLS, bez publicznych adresów IP).
- 🪣 Z efemerycznej pamięci lokalnej → prywatny GCS: bezserwerowy dysk jest tymczasowy. Łączymy ActiveStorage z prywatnym Google Cloud Storage za pomocą podpisanych adresów URL IAM (
iam: true) – bez publicznych zasobników i wycieków kluczy. - 🚀 Od zadań w procesie do Cloud Run z wieloma kontenerami: łączymy monolityczną aplikację Rails z bezserwerową chmurą. Za pomocą standardowego narzędzia Docker Compose uruchamiamy Solid Queue jako dedykowany kontener roboczy obok Pumy w podzie Cloud Run z wieloma kontenerami – bez rozrastania się mikrousług i bez głodzenia wątków. DHH byłby dumny!
🍌 A ponieważ żyjemy w 2026 roku, wzbogacamy cały pakiet o Google Antigravity. To nie jest coś, o czym pomyśleliśmy na końcu. Mamy wskazówki i umiejętności, które pomogą Ci lepiej wykorzystać (i czerpać przyjemność z) tych warsztatów.
🏛️ Docelowa architektura referencyjna (wariant 1: czysta, płaska grafika wektorowa dla przedsiębiorstw)
Oto kanoniczna architektura referencyjna Google Cloud, którą utworzysz i wdrożysz (wariant 1: czysta, płaska, wektorowa architektura klasy enterprise). Pokazuje ona naszą produkcyjną usługę Cloud Run z wieloma kontenerami połączoną ze wszystkimi zarządzanymi usługami Google Cloud do przechowywania danych i usługami AI:

🎞️ Ewolucja architektury: od zera do architektury chmurowej
Obserwuj, jak nasz stos jest stopniowo modernizowany od efemerycznej konfiguracji na jednym urządzeniu do w pełni zarządzanego projektu Google Cloud na każdym etapie warsztatów:

Czego się nauczysz
- Jak programować w parach z Google Antigravity, aby wyjaśnić działanie Rails 8 i Google Cloud.
- Jak uruchomić automatyczną diagnostykę przed lotem (
just workshop-test) - Jak asynchronicznie udostępniać infrastrukturę w chmurze Google za pomocą Terraform, kontynuując lokalne programowanie bez blokowania za pomocą aprowizatora
google. - Jak wyeliminować antypatenty związane z bezpieczeństwem: prywatne zasobniki GCS (
iam: true) i tunele mTLS serwera proxy uwierzytelniania Cloud SQL zamiast otwierania0.0.0.0/0. - Jak wstrzykiwać obiekty tajne bezpośrednio z Google Cloud Secret Managera.
- Jak koordynować asynchroniczne zadania w tle generatywnej AI (generator okładek NanoBanana, synteza dwujęzycznego podcastu) za pomocą Solid Queue.
Zaczynajmy!
2. Krok 0. Wymagania wstępne, konfiguracja Antigravity i weryfikacja płatności
💡 Scenariusz: Ty i Twój zespół tworzycie aplikację Rails 8 o znaczeniu krytycznym. Zanim zaczniemy pisać kod lub uruchamiać zasoby w chmurze, musimy skonfigurować łańcuch narzędzi, połączyć się z Google Antigravity oraz zweryfikować dane logowania do Google Cloud i podstawy rozliczeń.
1. Lista kontrolna wymagań wstępnych
Zanim zaczniemy, upewnij się, że masz w swoim środowisku te narzędzia:
just(1.21+): (just --version) narzędzie do wykonywania zadań – każde polecenie w tych warsztatach tojustprzepis (poproś AI Harness o jego zainstalowanie lub zobaczskills/rails8app-workshop).- Git (2.30 lub nowszy): (
git --version) do kontroli wersji, rozgałęziania i klonowania repozytorium. - Pakiet SDK Google Cloud (
gcloudCLI): zainstalowany i aktualny. - Interfejs wiersza poleceń Terraform (wersja 1.5 lub nowsza): do deklaratywnego udostępniania infrastruktury.
dockeridocker-compose: zainstalowane i działające lokalnie.- Ruby
3.4.5: (ruby -v– przypięte przezblog/.ruby-version; poproś AI Harness o zainstalowanie3.4.5, jeśli go brakuje). Rails 8 jest zadeklarowany wGemfilei automatycznie instalowany przezbundle install. - Google Antigravity 2.0: autonomiczny asystent AI do programowania w parach (pobierz Google Antigravity 2.0). Zalogujesz się za pomocą osobistego konta Gmail – nie potrzebujesz tokena API.
2. Uwierzytelnianie Google Cloud, konfiguracja dedykowana i ADC
Aby uniknąć kolizji z istniejącymi konfiguracjami gcloud na kontach firmowych, osobistych lub wielu kontach, zdecydowanie zalecamy utworzenie dedykowanej konfiguracji nazwanej na potrzeby tych warsztatów:
# 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
💡 Dlaczego warto używać konfiguracji dedykowanej? Użycie gcloud config configurations create rails8-on-gcp-workshop izoluje wszystkie ustawienia interfejsu CLI (konto, projekt limitu, region domyślny) specjalnie na potrzeby tych warsztatów. Gdy skończysz, możesz w każdej chwili wrócić do normalnej konfiguracji, klikając gcloud config configurations activate default.

3. 🚨 Weryfikacja rozliczeń GCP
⚠️ Uwaga: wdrożenia Google Cloud SQL i Cloud Run wymagają aktywnego połączonego konta rozliczeniowego lub ważnych środków edukacyjnych na warsztaty. Sprawdźmy teraz, czy konfiguracja jest prawidłowa. Aby to zrobić, uruchom weryfikację płatności:
gcloud beta billing projects describe $GOOGLE_CLOUD_PROJECT
Upewnij się, że urządzenie billingEnabled: true zostało zwrócone. Możesz też wyświetlić listę wszystkich kont rozliczeniowych:
gcloud billing accounts list
Upewnij się, że co najmniej jeden z nich zawiera symbol OPEN: True. Jeśli żadne z nich nie są aktywne, połącz konto rozliczeniowe lub wykorzystaj kupon na środki na szkolenie na stronie Płatności w konsoli Google Cloud.

4. Sklonuj repozytorium i sparuj je z Antigravity
Sklonuj repozytorium i otwórz katalog. Zwróć uwagę, że pozostajemy w całości w przestrzeni main:
git clone https://github.com/palladius/rails8-app-on-gcp.git
cd rails8-app-on-gcp
Otwórz ten katalog w Google Antigravity. Antigravity automatycznie sprawdzi repozytorium, odczyta AGENTS.md i będzie czekać na Twoje polecenia jako programista pracujący w parze.
5. 🪫 Jeśli Antigravity wyczerpie bezpłatne środki
⚠️ Środki w chmurze, które właśnie zostały wykorzystane, NIE uzupełniają Antigravity. Są to 2 osobne platformy rozliczeniowe: limit Antigravity jest powiązany z abonamentami Google AI (Google One), a vouchery i środki w Google Cloud są powiązane z kontem rozliczeniowym Cloud. Połączenie konta rozliczeniowego z projektem GCP nie spowoduje dodania ani jednego dodatkowego promptu Antigravity.
Jeśli agent zatrzyma się z komunikatem o wyczerpaniu limitu, wykonaj te czynności – pierwsze 2 są bezpłatne i natychmiastowe:
- Przełącz pulę modeli Limit jest śledzony w przypadku każdej rodziny modeli, a Antigravity wyświetla 2 niezależne pule (modele Gemini i modele Claude/GPT). Modele Claude i GPT-OSS są dostępne na poziomie bezpłatnym, więc wyczerpanie puli Gemini często nie wpływa na drugą pulę. Użyj selektora modelu pod polem promptu.

- Wybierz model Flash zamiast Pro. Limity częstotliwości są powiązane z ilością pracy, jaką agent wykonuje w ramach każdego żądania, więc lżejszy model pozwala na większą liczbę żądań.
- Używaj Antigravity CLI z własnym kluczem Gemini API. Funkcja Bring-your-own-key nie jest obsługiwana w IDE Antigravity – udokumentowaną alternatywą jest interfejs CLI. Utwórz bezpłatny klucz w Google AI Studio (wymaga projektu, ale nie wymaga konta rozliczeniowego), a następnie pobierz i skonfiguruj Antigravity CLI.
- Poczekaj lub przejdź na wyższą wersję. Limit poziomu bezpłatnego jest odświeżany co tydzień (data resetu jest podana w komunikacie o błędzie). Google AI Pro/Ultra to jedyny udokumentowany sposób na zwiększenie limitu podstawowego w aplikacji na komputery. Te pakiety są odświeżane co 5 godzin i można w nich wykorzystywać kupione środki na AI na przekroczenie limitu.
- Chociaż są to warsztaty Antigravity, większość uprzęży do kodowania AI powinna również działać – wystarczy skierować je na katalogi
AGENTS.mdiskills/w repozytorium.
6. Automatyczna weryfikacja na etapie 0
Sprawdź, czy środowisko na etapie 0 jest w 100% zgodne z pakietem oceniającym:
just workshop-eval 0
✨ Wow Moment: Antigravity i silnik oceny warsztatów weryfikują wersje interfejsu CLI, środowisko Ruby i uwierzytelnianie ADC w mniej niż 2 sekundy.
3. Krok 1. Rozpoczęcie pracy z infrastrukturą Terraform i diagnostyka przed lotem
💡 Strategia: aprowizacja zarządzanych baz danych, takich jak Google Cloud SQL PostgreSQL, trwa około 10–12 minut. Zamiast czekać bezczynnie, uruchamiamy niezmienną infrastrukturę za pomocą Terraform w tle, podczas gdy pracujemy lokalnie.
1. Uruchom automatyczny pakiet diagnostyczny przed lotem
Przed uruchomieniem infrastruktury w chmurze przeprowadź kompleksowy zestaw testów przed lotem:
just workshop-test
Ten skrypt (bin/workshop_diagnostics.rb):
- Weryfikuje konfigurację tożsamości
GOOGLE_CLOUD_ACCOUNT. - Sprawdza aktywne płatności i powiązanie projektu.
- Weryfikuje domyślne uwierzytelnianie aplikacji (ADC) w Vertex AI.
- Potwierdza obraz testowy ActiveStorage (
blog/app/assets/images/gcs_dev_image.jpg).

Jeśli brakuje znaku .env, skopiuj go z udokumentowanego szablonu:
cp .env.dist .env
# Edit .env and configure GOOGLE_CLOUD_ACCOUNT with your Google/Gmail account
💡 Wskazówka: jeśli just workshop-test zgłosi, że interfejs Billing API jest wyłączony w Twoim projekcie, możesz go szybko włączyć w ten sposób:
gcloud services enable cloudbilling.googleapis.com
2. ⏱️ Uruchamianie infrastruktury Terraform asynchronicznie
Uruchom jednoetapowy przepis Terraform, który utworzy zdalny zasobnik stanu backendu i uruchomi wdrażanie infrastruktury:
just terraform-apply

Alternatywna metoda ręczna (lub bezpośrednie uruchomienie skryptu `iac/bin/terraform-apply.sh`)
# 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 ..
Co zapewnia Terraform:
- Zasobnik Google Cloud Storage: utworzony z dostępem prywatnym i podpisywaniem certyfikatów IAM (
iam: true). - Obraz testowy Canary: przesyła
gcs_dev_image.jpgdo zasobnika, aby włączyć pełną weryfikację obiektu blob. - Instancja Google Cloud SQL PostgreSQL: inicjuje udostępnianie w tle (ok. 10–12 minut).

💡 Uwaga: możesz bezpiecznie zignorować ostrzeżenie o braku automatycznych kopii zapasowych – nie będą one potrzebne w przypadku tej bazy danych warsztatowych (chociaż automatyczne codzienne kopie zapasowe są niezbędną sprawdzoną metodą w przypadku każdej prawdziwej produkcyjnej bazy danych).

📝 Zanotuj adres URL Cloud Run: zastosowanie Terraform powinno się powieść i wyświetlić dane wyjściowe infrastruktury. Zanotuj cloud_run_url (lub skopiuj go do schowka) – będzie Ci potrzebny w dalszych krokach podczas weryfikacji usługi na żywo.
3. Automatyczna weryfikacja na etapie 1 (opcjonalna)
Sprawdź, czy wymagania wstępne i konfiguracje z kroku 1 są spełnione:
just workshop-eval 1
⏱️ Uwaga: ta ocena sprawdza aktywne zasoby w chmurze i może potrwać kilka minut. Jest to całkowicie opcjonalne – podczas gdy skrypt działa w terminalu, możesz od razu przejść do następnego kroku bez czekania.
4. Krok 2. Lokalny punkt odniesienia, Mailpit i wprowadzenie administratora
Zaczynamy od czystej, nowoczesnej aplikacji blogowej Rails 8 działającej na hoście lokalnym z bazą danych SQLite, przechwytywaniem e-maili Mailpit i ActiveStorage na dysku.
1. Lokalne uruchamianie aplikacji
📁 Uważaj na katalog! W tym repozytorium znajduje się aplikacja Rails w blog/ i Terraform w iac/. Po wykonaniu kroku 1 znajdziesz się w katalogu głównym repozytorium, więc każde polecenie w kroku 2 będzie wykonywane z
blog/ – Gemfile, bin/rails i compose.yaml mieszkają w tym samym miejscu. Uruchomienie ich z katalogu głównego kończy się niepowodzeniem z błędem no configuration file provided: not found lub brakiem Gemfile.
Przejdź do aplikacji Rails, sprawdź, czy używasz przypiętej wersji Ruby, a następnie zainstaluj gemy i skonfiguruj bazę danych:
cd blog
ruby -v # must print 3.4.5 — see Step 0 if it does not
bundle install
bin/rails db:setup
Błąd uprawnień podczas zapisywania w
/var/lib/gems/
lub
ruby -v
pokazuje systemową wersję Ruby (np. 3.3.x)? Ruby w czystym systemie Linux całkowicie ignoruje pliki .ruby-version i próbuje zainstalować gemy w całym systemie. Sprawdź, czy w aktywnej powłoce terminala wczytano rbenv:
eval "$(rbenv init - bash)" # or: eval "$(rbenv init - zsh)"
ruby -v # confirm it now outputs 3.4.5!
Uwaga: Jeśli w kroku 0 pominięto instalację wersji 3.4.5, uruchom rbenv install 3.4.5. Możesz też użyć trybu A (Docker Compose) poniżej (just compose-up), który uruchamia przypięty stos Ruby w całości w kontenerach bez dotykania gemów hosta.
💡 Nie chcesz o tym myśleć? just install i just compose-up z katalogu głównego repozytorium wykonują za Ciebie cd blog.
2. 🌱 Automatyczne wykrywanie węzłów początkowych i inicjowanie administratora (problemy 21 i 25)
Baza danych (db/seeds.rb) zawiera automatyczne wykrywanie inteligentnego środowiska:
- Sprawdza aktywny adapter bazy danych (SQLite lub Postgres) i konfigurację pamięci.
- Wykrywa etap 0 (localhost) i automatycznie tworzy początkowego użytkownika administracyjnego oraz wypełnia post pedagogiczny:
[LOCAL BASELINE] Welcome to Rails 8 on Localhost!- Gotowy lokalny załącznik z obrazem smutnej buźki (
local_sad_image.png) ze znakiem wodnym informującym, że lokalna pamięć dyskowa jest efemeryczna.
- Automatycznie wysyła e-maila z prośbą o zresetowanie hasła za pomocą ActionMailera.
Sprawdź lub ponownie uruchom prompt (automatycznie używa Twojego promptu GOOGLE_CLOUD_ACCOUNT z .env):
bin/rails db:seed # or from repo root: just seed
Uruchom lokalny stos technologiczny za pomocą Docker Compose:
docker compose up -d # from blog/ — or `just compose-up` from the repo root

Aplikacja, lokalny serwer SMTP Mailpit i przeglądarka bazy danych Adminer działają teraz razem w odizolowanych kontenerach:
- Aplikacja Rails: http://localhost:3000
- Interfejs internetowy Mailpit: http://localhost:8025
- Interfejs bazy danych Adminer: http://localhost:8081
🧯 Konflikt portu 3000 lub
server.pid
błąd? Jeśli wcześniej uruchomiono natywny serwer deweloperski (bin/dev), zatrzymaj go za pomocą polecenia Ctrl+C. Jeśli Docker zgłosi, że port 3000 jest już przydzielony, lub znajdzie pozostałościserver.pid po poprzednim uruchomieniu, zwalniaj miejsce za pomocą tego polecenia:
just compose-down
rm -f blog/tmp/pids/server.pid
just compose-up
3. Korzystanie z Mailpita i logowanie administratora
- Przechwytywanie wychodzących e-maili za pomocą Mailpit: otwórz
http://localhost:8025w przeglądarce. Sprawdź lokalną skrzynkę odbiorczą. Podczasdb:seedActionMailer wysłał e-maila z informacjami o wprowadzeniu administratora, który Mailpit bezpiecznie przechwycił lokalnie bez dotykania zewnętrznych serwerów poczty e-mail ani danych logowania:
2. Zaloguj się na blogu: otwórz http://localhost:3000 w przeglądarce.
- Aby ustawić hasło, możesz kliknąć link do resetowania hasła bezpośrednio w e-mailu z Mailpita.
- Możesz też zalogować się, używając adresu e-mail konta Google Cloud (z domeny
.env) i domyślnego hasła początkowego:Ch4ng3m3!!1.
- Obserwuj plakietki telemetrii wizualnej:
- Zwróć uwagę na żółty baner środowiska i odznaki w interfejsie:
Notice: Ephemeral Database Active (POSTGRESQL)i[EPHEMERAL DB / STORAGE] 💾 Local. - Zwróć uwagę na znak wodny posta: stempel 🏠 (
nanobanana_stamp_local.pngw prawym dolnym rogu obrazu okładki). Dzięki temu od razu zobaczysz, że zasoby i baza danych są obecnie powiązane z tymczasową pamięcią lokalną.
- Zwróć uwagę na żółty baner środowiska i odznaki w interfejsie:

💡 Opcjonalna wskazówka: ćwiczenia w konsoli Rails Chcesz się dowiedzieć, jak Rails wchodzi w interakcję z danymi początkowymi z interfejsu CLI? Przejdź do konsoli interaktywnej:
bin/rails console
Dynamicznie sprawdź zainicjowanego użytkownika z uprawnieniami administracyjnymi za pomocą zmiennej środowiskowej:
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. Automatyczna weryfikacja w kroku 2
Sprawdź lokalny poziom odniesienia i konfigurację administratora:
just workshop-eval 2

5. Problem: kontenery bezstanowe
Kontenery Cloud Run są bezstanowe i krótkotrwałe. Jeśli wdrożymy bazę danych SQLite i lokalny katalog storage/ bezpośrednio w Cloud Run, wszystkie posty i przesłane obrazy zostaną trwale usunięte za każdym razem, gdy kontener zostanie przeskalowany do zera lub ponownie uruchomiony.
W następnym kroku celowo wdrożymy tę tymczasową konfigurację w Cloud Run, aby na własne oczy zobaczyć Stateless Shock.
5. Krok 3. Wdróż 1 – The Stateless Shock (wczesny efekt WOW w 3 minuty!)
Zamiast czekać 15–20 minut na bazy danych w chmurze, zanim cokolwiek pojawi się w internecie, nowoczesne tworzenie aplikacji bezserwerowych zaczyna się od szybkiego sukcesu: wdrożenia aplikacji Rails z jednym kontenerem bezpośrednio w Google Cloud Run w mniej niż 3 minuty.
1. Powrót do przeszłości
Aby zagwarantować, że nasza konfiguracja początkowa jest w 100% efemeryczna (lokalna baza danych SQLite i lokalna pamięć masowa plików), użyj silnika Zero-Branch Time-Machine:
just workshop-rewind 1
💡 Co się stało?workshop-rewind 1 zastosował nakładkę konfiguracji stage-1-stateless do blog/config/ bez opuszczania gałęzi main. Aplikacja jest skonfigurowana z bazą danych SQLite na dysku kontenera i ActiveStorage w lokalnym systemie plików.
2. Wdrażanie PUMY w jednym kontenerze w Cloud Run
wdrażać bezpośrednio z kodu źródłowego w Cloud Run; Nowoczesny Rails 8 automatycznie generuje oficjalny, gotowy do wdrożenia w środowisku produkcyjnym Dockerfile od razu po zainstalowaniu (z wieloetapowymi kompilacjami, jemalloc i zabezpieczeniami dla użytkowników bez uprawnień roota). Gdy wdrożysz aplikację z folderu blog/, Google Cloud Build wykryje natywny plik Dockerfile i udostępni zarządzaną usługę bezserwerową:
# 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
Powinny pojawić się dane wyjściowe podobne do tych:

⏳ Powinno to potrwać kilka minut, podczas których Cloud Build spakuje kontener i udostępni wersję Cloud Run.
🧯 Rozwiązywanie problemów i najczęstsze pułapki
PERMISSION_DENIED: Build failed because the default service account is missing required IAM permissions
? Ten sam błąd może mieć 2 różne przyczyny:
- gcloud właśnie włączył interfejs API. Jeśli wdrożenie wyświetliło
The following APIs are not enabled ... cloudbuild.googleapis.com, a Ty odpowiedziałeś(-aś)Y, kompilacja mogła się rozpocząć, zanim nowe uprawnienia zostały w pełni rozpowszechnione. W wyskakującym okienku gcloud pojawia się ostrzeżenie „To może potrwać kilka minut”. Odczekaj minutę i uruchom ponownie to samo polecenie. Zwykle działa ono poprawnie. Krok 1terraform applyzwykle włącza ten interfejs API, więc nie powinno się wyświetlać żadne okno. - Domyślne konto usługi Compute rzeczywiście nie ma przypisanych ról. Nowoczesne projekty GCP wymuszają w nim zasadę jak najmniejszych uprawnień, co powoduje przerwanie wdrożeń źródłowych. Rozwiąż problem za pomocą:
just project-status # grants storage.admin, logging.logWriter, artifactregistry.writer, cloudbuild.builds.builderjust workshop-testteż teraz to zgłasza, więc warto ponownie uruchomić proces, jeśli wdrożenie nadal się nie udaje.
Podczas wdrażania:
- Cloud Run skompiluje obraz kontenera Rails.
- Przypisuje publiczną, bezpieczną domenę TLS:
https://blog-[hash]-[region].a.run.app. - Ruch zacznie być kierowany do Pumy na porcie 8080.
3. ✨ Wczesny moment WOW
Otwórz wygenerowany adres URL Cloud Run w przeglądarce.
- Nowoczesna aplikacja Rails 8 jest już dostępna w Google Cloud.
- Zaloguj się, używając danych logowania administratora (
GOOGLE_CLOUD_ACCOUNTiAPP_ADMIN_PASSWORD). Jeśli nie widzisz przycisku logowania, kliknij „Nowy post”. Najpierw pojawi się prośba o podanie nazwy użytkownika i hasła:
- Kliknij „Nowy post”, napisz artykuł zatytułowany „Mój pierwszy post w Cloud Run”, dołącz zdjęcie i kliknij Utwórz post.
- Post zostanie opublikowany z pełnym formatowaniem, a obraz zostanie wyrenderowany.
- Zwróć uwagę na telemetrię wizualną:
- Plakietka w nagłówku:
[EPHEMERAL DB / STORAGE] 💾 Local - Graficzny znak wodny na obrazie: stempel 🏠 (
127.0.0.1plakietka dysku tymczasowego w prawym dolnym rogu).
- Plakietka w nagłówku:
🐝 Dołącz do tabeli wyników warsztatów na żywo! Jeśli jesteś online, a osoba nadzorująca wyświetla tablicę wyników i chcesz do niej dołączyć, dodaj tutaj adres URL Cloud Run: 👉 zarejestruj Cloud Run na tablicy wyników.

4. 💥 The Catch: The Stateless Shock & The "Puma Workaround" Trap
Cloud Run to bezstanowa platforma bezserwerowa. Gdy ruch w internecie spada do zera, Cloud Run skaluje się w dół do zera instancji kontenera, aby zaoszczędzić pieniądze. Gdy nadejdzie nowe żądanie HTTP lub zostanie wdrożona nowa wersja kontenera, Cloud Run uruchomi zupełnie nowy, czysty obraz kontenera.
Baner z zablokowanymi zadaniami
Gdy tworzysz posta lub dołączasz obraz w przypadku wdrożenia w jednym kontenerze, Rails umieszcza w kolejce zadania ActiveJob (np. analizę wymiarów obrazu lub indeksowanie metadanych). Ponieważ nikt nie uruchamia procesu w tle, zobaczysz baner z ostrzeżeniem:

Kuszące rozwiązanie: uruchamianie Solid Queue w Pumie
Sprytny deweloper może powiedzieć: „Czekaj! Rails 8 umożliwia uruchamianie Solid Queue bezpośrednio w procesie serwera WWW Puma przez włączenie
SOLID_QUEUE_IN_PUMA=true
zmienna środowiskowa!
Przetestujmy to obejście w 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
Teraz wróć do przeglądarki i odśwież stronę:
💥 The Stateless Shock:
- Dobra wiadomość: proces Solid Queue jest już aktywny w Pumie. Wszystkie nowe zadania są natychmiast wyczerpywane.
- The Cold Shower (The Catch!):
- Cloud Run wdrożył nową wersję, więc poprzednia instancja kontenera została zastąpiona.
- Artykuł, który napisałeś, i plik bazy danych SQLite na dysku zostały całkowicie usunięte.
- Lekcja z architektury: uruchamianie procesów w tle w Pumie zużywa cenne zasoby procesora i pamięci RAM wątków internetowych i nie rozwiązuje problemu z trwałością.
5. Automatyczna weryfikacja na etapie 3
Sprawdź wdrożenie Cloud Run i obsługę alertów:
just workshop-eval 3
✨ Lekcja: obejścia z jednym kontenerem, takie jak SOLID_QUEUE_IN_PUMA, są przydatne w przypadku programowania lokalnego, ale w nowoczesnej architekturze chmury:
- Pliki multimedialne wymagają Google Cloud Storage (GCS) (krok 4).
- Dane relacyjne i kolejki zadań wymagają zarządzanej usługi Google Cloud SQL (krok 5).
- Pracownicy działający w tle, którzy zużywają dużo zasobów, powinni znajdować się w osobnym kontenerze pomocniczym (krok 6).
6. Krok 4. Wdróż 3 – trwałe przechowywanie w GCS i ostrzeżenie POLA
W tym kroku odłączamy pamięć masową plików multimedialnych i innych od dysku kontenera, przełączając ActiveStorage na Google Cloud Storage (GCS) i używając krótkotrwałych podpisanych adresów URL za pomocą interfejsu IAM Credentials API (iam: true).
Zanim wprowadzisz jakiekolwiek zmiany w konfiguracji, zapoznaj się z 3 elementami, których Rails potrzebuje do komunikacji z GCS:
① Identyfikator projektu + nazwa zasobnika – Rails musi wiedzieć, gdzie przechowywać obiekty blob. Aplikacja odczytuje wartość GOOGLE_CLOUD_PROJECT ze środowiska i wyznacza nazwę zasobnika jako ${GOOGLE_CLOUD_PROJECT}-activestorage-prod. Terraform z kroku 1 utworzył już ten zasobnik, więc nie musisz niczego więcej robić.
② Konto usługi z odpowiednimi uprawnieniami – Cloud Run działa jako domyślne konto usługi Compute Engine (PROJECT_NUMBER-compute@developer.gserviceaccount.com). To konto usługi musi mieć w zasobniku 2 role uprawnień:
roles/storage.objectAdmin– do przesyłania i udostępniania obiektów binarnych.roles/iam.serviceAccountTokenCreator– do wywoływania interfejsu IAM CredentialssignBlobAPI i generowania krótkotrwałych podpisanych adresów URL.
⚠️ Kuszący skrót
public: true Najszybszym sposobem na uruchomienie GCS jest ustawienie public: true w storage.yml i przyznanie allUsers:objectViewer w zasobniku. Obrazy wczytują się natychmiast i nie wymagają logowania. Nie rób tego. Publiczny zasobnik udostępnia wszystkie przesłane przez użytkowników multimedia w otwartym internecie na zawsze. Nasz projekt wykorzystuje iam: true, aby zachować 100% prywatność zasobnika – każdy adres URL obrazu to podpisany, wygasający token generowany na bieżąco przez interfejs IAM Credentials API.
③
ACTIVE_STORAGE_SERVICE=google – pojedyncza zmienna środowiskowa, która w czasie działania przełącza Rails z dysku lokalnego na GCS. Nie wymaga to zmiany kodu ani ponownego wdrażania logiki aplikacji – wystarczy przełączyć jedną zmienną środowiskową.
1. Powrót do przeszłości
Przejdź do etapu 2 wehikułu czasu:
just workshop-rewind 2
Sprawdź blog/config/storage.yml – zobaczysz, że aplikacja definiuje 3 nazwane środowiska GCS (dev / test / prod), które korzystają z tego samego bezpiecznego wzorca:
<% 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. Przyznawanie uprawnień do przechowywania i podpisywania w IAM
Sprawdź, czy wykonawcze konto usługi Cloud Run ma uprawnienia do podpisywania adresów URL i przesyłania obiektów:
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. Trzecie wdrożenie w Cloud Run z dołączonym GCS
Ponownie wdróż z włączoną usługą GCS. Upewnij się, że znajdujesz się w folderze blog/ (w przeciwnym razie Cloud Run spróbuje utworzyć kompilację za pomocą Buildpacks zamiast Rails 8 Dockerfile, co spowoduje błędy kompilacji).
Użyj znaku --update-env-vars (nie --set-env-vars), aby zachować istniejące zmienne środowiskowe (klucz główny, konfiguracja IAP itp.):
cd blog
gcloud run deploy blog \
--source . \
--region $GOOGLE_CLOUD_REGION \
--update-env-vars ACTIVE_STORAGE_SERVICE=google
💡 Wskazówka: jeśli wdrożenie się nie powiedzie, kliknij link do logów Cloud Build, który jest wygodnie dostępny w danych wyjściowych terminala (jak pokazano na ilustracji poniżej). Możesz też poprosić Antigravity o pomoc w rozszyfrowaniu i naprawieniu błędu.

4. ✨ The Surviving Image & The Cloud Stamp
- Odśwież adres URL bloga.
- Utwórz nowy post na blogu zatytułowany „Przetrwanie w chmurze” i prześlij zdjęcie.
- Spójrz na prawy dolny róg obrazu:
- Znaczek 🏠 zniknął.
- Zastąpiono go kolorową pieczątką Cloud GCS (
nanobanana_stamp_cloud.png).
- Wymuś ponowne uruchomienie innego kontenera (co powinno spowodować wdrożenie czwartej wersji):
gcloud run services update blog --region $GOOGLE_CLOUD_REGION --update-env-vars RESTART_TRIGGER=$(date +%s) - Odśwież stronę: podczas resetowania bazy danych SQLite binarny plik obrazu jest bezpiecznie przechowywany w Google Cloud Storage. Weryfikacja za pomocą interfejsu wiersza poleceń:
gcloud storage ls -l -r gs://$GCS_BUCKET/
Oto lista przesłanych obiektów binarnych i multimediów, które możesz zobaczyć w konsoli przeglądarki Google Cloud Storage w zasobniku produkcyjnym (gs://$GCS_BUCKET):

5. ⚠️ Problem: baner ostrzegawczy dotyczący utkniętych zadań
Gdy przesyłasz obraz, ActiveStorage umieszcza w kolejce zadanie analizy (ActiveStorage::AnalyzeJob), aby wyodrębnić wymiary i metadane.
Cloud Run uruchamia jednak obecnie tylko jeden kontener internetowy (puma). W Rails 8 Solid Queue przechowuje zadania w tle w bazie danych, ale nikt ich nie wykonuje bundle exec rails solid_queue:start!
Spójrz na górę strony bloga: zobaczysz jasny baner ostrzegawczy wyrenderowany przez blog/app/views/layouts/_check_stuck_jobs.html.erb.
Rozwiążemy ten problem w kroku 6, gdy przejdziemy na architekturę wielokontenerową klasy produkcyjnej z kontenerem pomocniczym i dedykowanym kontenerem worker, w którym kolejka Solid Queue będzie działać niezależnie od ruchu w internecie.
6. Automatyczna weryfikacja kroku 4
Sprawdź konfigurację GCS i telemetrię zablokowanych zadań:
just workshop-eval 4
7. Krok 5. Lista kontrolna przed wdrożeniem: Cloud SQL, Secrets i łączność z bazą danych
W krokach 3 i 4 udało Ci się opanować kontenery bezstanowe i Google Cloud Storage, a Terraform w tym czasie przygotował w tle backend produkcyjny.
Przed wdrożeniem pełnej architektury 3 kontenerów w produkcyjnym kontenerze pomocniczym (wdrożenie 4 w kroku 6) ten krok służy jako szybka kontrola przed lotem, która pozwala sprawdzić stan bazy danych, łączność i dostęp do kluczy tajnych.
0. Zmienne środowiskowe wczytywania
Wyeksportuj wszystkie wymagane zmienne powłoki bezpośrednio z danych wyjściowych Terraform:
# 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. Sprawdzanie stanu Cloud SQL
Sprawdź, czy zarządzana instancja PostgreSQL zakończyła wstępną obsługę administracyjną i jest w dobrym stanie:
echo "Checking instance: $SQL_INSTANCE_NAME"
gcloud sql instances describe $SQL_INSTANCE_NAME --format="value(state)"
Dane wyjściowe muszą mieć postać RUNNABLE.
2. (Opcjonalnie) Testowanie połączenia z bazą danych z laptopa
W środowisku produkcyjnym kontenery Cloud Run łączą się bezpiecznie z Cloud SQL za pomocą zaszyfrowanego pomocniczego proxy (127.0.0.1:5432), nie udostępniając bazy danych publicznemu internetowi (0.0.0.0/0).
ℹ️ Uwaga: ten krok jest całkowicie opcjonalny. W Cloud Run oficjalny kontener pomocniczy serwera proxy uwierzytelniania Cloud SQL automatycznie obsługuje połączenia mTLS. Aby wziąć udział w warsztatach, nie musisz niczego instalować lokalnie.
Jeśli na komputerze masz zainstalowane cloud-sql-proxy i psql i chcesz sprawdzić bezpośrednie połączenie z laptopa:
# Optional: test connectivity via Google-managed mTLS proxy
gcloud sql connect $SQL_INSTANCE_NAME --user=rails_user --database=rails_production
(Jeśli pojawi się prośba o hasło, wpisz
$DB_PASSWORD
W przeciwnym razie możesz przejść bezpośrednio do kroku 3 poniżej).
3. Sprawdzanie obiektów tajnych obsługiwanych przez Terraform
Nigdy nie przechowuj haseł do baz danych, kluczy interfejsu API ani kluczy głównych Rails w postaci zwykłego tekstu w systemie Git ani w zmiennych środowiskowych kontenera. W nowoczesnej architekturze chmury do wstrzykiwania w czasie działania w modelu zero-trust używamy Google Cloud Secret Manager.
ℹ️ Terraform zrobił to za Ciebie w kroku 1:
rails-master-key– do odszyfrowywania danych logowania Rails w czasie wykonywania.rails-db-password– kryptograficznie bezpieczne losowe hasło pasujące do użytkownika Cloud SQL.rails-admin-password– bezpieczne hasło dla początkowego administratora.
Sprawdź, czy obiekty tajne są obecne i aktywne w usłudze Secret Manager:
gcloud secrets list --filter="name:rails-"

🔑 Synchronizowanie master.key z laptopem (synchronizacja lokalna)
Ze względów bezpieczeństwa plik blog/config/master.key jest ignorowany przez Git, więc może go jeszcze nie być w Twoim lokalnym klonie. Uruchom ten przyjazny fragment kodu samonaprawczego, aby pobrać go z usługi Secret Manager, dzięki czemu lokalne narzędzia Rails będą mogły odszyfrować dane logowania:
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
🧪 Plac zabaw: chcesz utworzyć niestandardowy tajny klucz, aby sprawdzić, jak łatwo to zrobić? Secret Manager nie jest przeznaczony tylko dla Rails. Możesz utworzyć dowolny obiekt tajny za pomocą prostego polecenia interfejsu wiersza poleceń:
echo -n "MySuperSecretValue123!" | gcloud secrets create workshop-fun-secret --data-file=-
echo "✨ Created workshop-fun-secret in Secret Manager! 🪄"
4. Weryfikowanie uprawnień do uzyskiwania dostępu do obiektów tajnych
Aby kontenery Cloud Run mogły montować te obiekty tajne jako zmienne środowiskowe lub punkty montowania woluminów podczas uruchamiania, wykonawcze konto usługi ($RUN_SA) musi mieć rolę roles/secretmanager.secretAccessor w przypadku każdego obiektu tajnego.
Terraform przyznał już to uprawnienie w kroku 1. Sprawdź powiązanie zasady uprawnień w rails-master-key:
# 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"
Zobaczysz, że:
ROLE MEMBERS
roles/secretmanager.secretAccessor serviceAccount:PROJECT_NUMBER-compute@developer.gserviceaccount.com

5. Automatyczna weryfikacja przed publikacją
Uruchom automatyczny pakiet testów z kroku 5, aby potwierdzić, że baza danych jest uruchomiona, wpisy tajne nie są puste, a uprawnienia są prawidłowe:
just workshop-eval 5
8. Krok 6. Wdróż 4 – Enterprise Multi-Container Sidecars (złoty standard)
Teraz tworzymy najlepszą architekturę referencyjną: Cloud Run z wieloma kontenerami.
1. Przywracanie standardu złota
Przywróć konfigurację repozytorium do stanu kanonicznego main:
just workshop-restore-gold
2. Sprawdzanie schematu produkcyjnego z 3 kontenerami
Otwórz plik blog/compose.prod.yaml i sprawdź 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)]
Wdrożenie produkcyjne uruchamia 3 skoordynowane kontenery korzystające z tej samej sieci lokalnej:
web: obsługuje ruch HTTP na porcie 8080 za pomocą serwera Puma.worker: dedykowany kontener przetwarzania w tle z uruchomionymbundle exec rails solid_queue:start.cloudsql-proxy: oficjalny kontener dodatkowy serwera proxy uwierzytelniania Google Cloud SQL (gcr.io/cloud-sql-connectors/cloud-sql-proxy:2) powiązany z127.0.0.1:5432.
3. Uruchamianie migracji baz danych za pomocą zadania Cloud Run
Zanim przekierujemy ruch internetowy do nowego wdrożenia, musimy przeprowadzić migrację bazy danych i początkowe wypełnienie bazy danych w Cloud SQL.
⚖️ Jak przeprowadzać migracje w kontenerach: 2 strategie
W środowiskach chmurowych opartych na kontenerach istnieją 2 powszechne sposoby przeprowadzania migracji baz danych:
- Opcja A. Automatyczne w punkcie wejścia Dockera (
entrypoint.shwykonujedb:migratepodczas uruchamiania kontenera)- Zalety: w pełni zautomatyzowane; deweloperzy nie muszą pamiętać o uruchamianiu polecenia.
- Wady: niebezpieczne w przypadku autoskalowania bez serwera. Gdy Cloud Run skaluje się do 10 instancji jednocześnie przy dużym natężeniu ruchu, 10 kontenerów konkuruje o równoczesne uruchomienie migracji, co powoduje blokowanie bazy danych, warunki wyścigu schematu lub przekroczenie limitu czasu rozruchu.
- Opcja B. Jawne za pomocą zadania Cloud Run (nasz wybór architektury)
- Zalety: pełna kontrola, bezpieczeństwo transakcji i brak warunków wyścigu. Działa jako dedykowane jednorazowe zadanie kontenera całkowicie odłączone od obsługi ruchu internetowego. Jeśli migracja się nie powiedzie, wyświetlanie reklam w internecie nie zostanie naruszone.
- Wady: przed wdrożeniem wymaga uruchomienia zadania interfejsu wiersza poleceń lub kroku CI/CD.
Wybieramy opcję B, aby zapewnić maksymalną niezawodność produkcji.
⚠️ Krytyczny: DATABASE_URL Format & Ruby 3.4.5 RFC 3986 Strictness
Usługi Cloud Run Jobs łączą się z Cloud SQL za pomocą natywnego serwera proxy gniazda Unix (/cloudsql/PROJECT:REGION:INSTANCE). DATABASE_URL musi używać formatu z trzema ukośnikami:
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: aplikacja korzysta z 4 baz danych (głównej, kolejki, pamięci podręcznej i kablowej) na database.yml. Wszystkie 4 zmienne środowiskowe DATABASE_*_URL muszą wskazywać tę samą instancję Cloud SQL. W przeciwnym razie tabele Solid Queue/Cache/Cable nie zostaną utworzone.
Po db:prepare wczytaj schematy Solid Queue/Cache/Cable:
# 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
Na powyższym rysunku widać możliwe wyniki
gcloud run jobs executions describe $JOBNAME
Konsola zadań Google Cloud Run
rails-migrate
wykonanie zakończone
4. Czwarte wdrożenie: wdrażanie Cloud Run z wieloma kontenerami za pomocą Docker Compose
Teraz wdróż prawdziwy 3-kontenerowy stos produkcyjny (web, worker, cloudsql-proxy) bezpośrednio z compose.prod.yaml:
# 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
Konsola Google Cloud Run: karta „Kontenery” z wyświetlonymi 3 kontenerami pomocniczymi (
cloudsql-proxy
,
web
,
worker
)
💡 Ciekawostka dotycząca interfejsu / błąd konsoli: w menu konsoli możesz zauważyć, że Cloud Run oznacza pierwszy wpis jako Ingress container: cloudsql-proxy. Bez obaw, Jest to tylko błąd wizualny interfejsu w konsoli Google Cloud (śledzony w #149) spowodowany kolejnością zależności kontenera. W rzeczywistości tylko kontener web nasłuchuje na porcie HTTP 8080 i obsługuje 100% ruchu internetowego przychodzącego, a kontener cloudsql-proxy obsługuje wyłącznie prywatny ruch PostgreSQL na porcie 5432.
5. ✨ Wow Moment: zero ostrzeżeń i pełna trwałość w chmurze!
Weź głęboki oddech i spójrz na ekran: wszystkie banery ostrzegawcze zniknęły! 🪄
Blog o produkcyjnej wersji Rails 8: przejrzysty interfejs, brak banerów z ostrzeżeniami i trwały stan Cloud SQL
Aplikacja jest teraz oficjalnie gotowa do wdrożenia w środowisku produkcyjnym i chmurowym:
- Obsługiwane przez zarządzaną usługę Google Cloud SQL (PostgreSQL) za pomocą bezpiecznego tunelowania mTLS.
- Media są bezpiecznie przechowywane w prywatnym Google Cloud Storage z podpisywaniem obiektów binarnych IAM.
- Brak ostrzeżeń o zerowej ilości pamięci tymczasowej i brak alertów o zablokowanych zadaniach.
Otwórz adres URL Cloud Run:
- Sprawdź plakietki telemetrii:
[CLOUD PERSISTENT 🐘 ☁️]został zweryfikowany w Twoim pliku początkowym bazy danych.- W stopce oba oznaczenia Google Cloud Run i GCS świecą na zielono.
- Baner z ostrzeżeniem o zablokowanych zadaniach zniknął.
- tworzyć posty na blogu i komentarze;
- Uruchamiaj ponownie i wdrażaj tyle razy, ile chcesz: Twoje dane, posty, komentarze i zasoby będą zawsze przechowywane w Cloud SQL i GCS.
6. Automatyczna weryfikacja kroku 6
Sprawdź konfigurację wielu kontenerów:
just workshop-eval 6
9. Krok 7. Potoki generatywnej AI, Podcastifier i poszukiwanie skarbów w GCS 🏴☠️
Dzięki Solid Queue działającemu w dedykowanym kontenerze i aktywnemu Google Cloud Storage możemy uwolnić asynchroniczną generatywną AI.
1. Generator okładek w stylu retro NanoBanana (gotowa do użycia platforma generatywnej AI)

Dobra wiadomość: ta funkcja jest już w pełni zaimplementowana w bazie kodu. Nie musisz pisać żadnego kodu – Twoim zadaniem jest uruchomienie i obserwowanie działania asynchronicznego potoku GenAI w chmurze.
🧠 Jak to działa za kulisami
- Uwierzytelnianie: nie wymaga kluczy interfejsu API. Automatycznie używa domyślnego uwierzytelniania aplikacji (
roles/aiplatform.userw Vertex AI) automatycznie za pomocą konta usługi środowiska wykonawczego Cloud Run. (Jeśli podanoGEMINI_API_KEY, wywołuje bezpośrednio interfejs Gemini API). - Potok: gdy artykuł zostanie utworzony bez obrazu w tle, wywołanie zwrotne
after_commitumieści w kolejceGenerateCoverImageJobw Solid Queue. - Model: model multimodalny Google (Gemini 2.5 Flash Image / Imagen w Vertex AI) generuje autentyczny plakat włoskiego filmu z lat 60. XX wieku („Locandina di un film 1960”) z bananem i błyszczącym rubinem w kształcie cyfry 8.
- Dynamiczny znak wodny dotyczący pochodzenia: używa
libvipsdo dynamicznego umieszczania wizualnej plakietki w rogu (kolorowa chmurka w GCS). - Szybka wymiana strumienia: gdy obraz jest załączony,
Turbo::StreamsChannel.broadcast_refresh_to(post)aktualizuje przeglądarkę czytelnika na żywo bez ręcznego ponownego wczytywania strony.

📐 Wyświetl źródło diagramu sekwencji Mermaid
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!
🧪 Wypróbuj na żywo
Możesz go wywołać na 2 sposoby:
- Opcja A (interfejs internetowy): kliknij Nowy post, wpisz tytuł, np. „Architektura bezserwerowa z Ruby on Rails 8”, napisz treść i pozostaw pole wejściowe pliku obrazu okładki puste. Kliknij Utwórz posta.
- Opcja B (CLI Runner): uruchom z terminala:
bin/rails runner 'Post.create!(title: "Serverless Architecture with Ruby on Rails 8", body: "Exploring asynchronous AI pipelines with Solid Queue and NanoBanana!")'
Odczekaj około 15–30 sekund: obserwuj logi instancji roboczej Solid Queue w Cloud Run. Plakat w stylu retro pojawi się bezpośrednio w Twoim poście.
📸 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. Wyzwanie „Dwujęzyczny podcast” (praktyczne ćwiczenie z kodowania antygrawitacyjnego)
⚠️ Ważna uwaga: w przeciwieństwie do generatora okładek powyżej ta funkcja NIE jest jeszcze wdrożona!
Jeśli otworzysz blog/app/jobs/podcastifier_job.rb, zobaczysz pusty szkielet:
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
Twoim zadaniem w tym praktycznym ćwiczeniu jest współpraca z Google Antigravity w celu ukończenia tej funkcji:
- Prompt Antigravity:„Pomóż mi wdrożyć PodcastifierJob w
app/jobs/podcastifier_job.rb. Powinien pobrać post, przetłumaczyć go lub wygenerować włoskie podsumowanie audio za pomocą usługi Google Cloud Text-to-Speech (głos „it-IT-Wavenet-A” z kodem języka „it-IT” za pomocą danych logowania ADC) i dołączyć plik audio dopost.podcast_audio_itza pomocą ActiveStorage! - Dodaj odtwarzacz do widoku: w
app/views/posts/show.html.erbdodaj odtwarzacz HTML5, gdy@post.podcast_audio_it.attached?. - Wywołaj syntezę: po zapisaniu Solid Queue wykona zadanie zamiany tekstu na mowę asynchronicznie w tle.

🎧 Przykładowe wyniki działania narzędzia Podcastifier:
💡 Potrzebujesz pomocy lub masz problem? Kompletne, sprawdzone w praktyce rozwiązanie referencyjne jest dostępne w gałęzi solutions/podcastifier. W każdej chwili możesz sprawdzić tę informację, klikając git diff solutions/podcastifier.
3. [OPCJONALNIE] 🏴☠️ Poszukiwanie skarbów w GCS (odzyskiwanie obiektu w konsoli)
ℹ️ Sprawdzenie wymagań wstępnych: lokalne
cloud-sql-proxy
Wymagany interfejs CLI To opcjonalne ćwiczenie umożliwia bezpośrednie połączenie lokalnego laptopa z Google Cloud SQL za pomocą zaszyfrowanego tunelu mTLS. Sprawdź, czy masz zainstalowany serwer proxy interfejsu wiersza poleceń:
which cloud-sql-proxy
- Jeśli jest zainstalowana: przejdź do dalszej części instrukcji.
- Jeśli nie masz zainstalowanej aplikacji i chcesz wykonać to zadanie: zainstaluj ją, wykonując te czynności:
# 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 - W innym przypadku: możesz przejść do automatycznej weryfikacji w kroku 7.
Pamiętasz zdjęcie, które zostało przesłane w kroku 4, zanim ponowne uruchomienie kontenera usunęło tymczasową bazę danych SQLite? Ten plik obrazu nadal znajduje się bezpiecznie w Twoim prywatnym zasobniku GCS jako „osierocony obiekt blob”.
Użyjemy konsoli Rails, aby odzyskać ten plik i dołączyć go do posta w Cloud SQL:
# 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
W konsoli Rails:
# 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
Odśwież bloga: zdjęcie przesłane w kroku 4 w sekcji Stateless Shock zostanie przywrócone i na stałe dołączone do posta w Cloud SQL.
4. Automatyczna weryfikacja kroku 7
Weryfikacja zadań i komponentów generatywnej AI:
just workshop-eval 7
10. Krok 8. Wybierz własną przygodę / zaawansowane zadania 🏆
Teraz, gdy masz już opanowaną kanoniczną architekturę referencyjną, wybierz zadanie końcowe.
🛡️ Quest 1. Zero-Trust Google IAP (Identity-Aware Proxy)
- Trudność: średnia (zabezpieczenia klasy korporacyjnej)
- Cel: zabezpiecz aplikację Cloud Run, aby dostęp do niej miały tylko zweryfikowane konta Google lub Gmail, całkowicie eliminując logowanie za pomocą hasła.
- Jak to działa:
- Zewnętrzny system równoważenia obciążenia aplikacji HTTPS kończy uwierzytelnianie Google OAuth i weryfikuje tożsamość, zanim ruch dotrze do Cloud Run.
- Google przekazuje nagłówki zweryfikowanej tożsamości (
X-Goog-Authenticated-User-Email). - Rails automatycznie loguje zweryfikowaną tożsamość Google za pomocą:
blog/app/controllers/concerns/iap_authenticatable.rbmodule 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 - Włącz moduł Terraform w
iac/iap.tfza pomocąenable_iap = truei określ dozwolone konta Google:iap_allowed_users = [var.google_cloud_account]

📊 Kurs 2. Telemetria SRE w środowisku produkcyjnym i Cloud Logging
- Poziom trudności: średni (dostrzegalność)
- Cel: przesyłanie strumieniowe logów aplikacji w formacie JSON z identyfikatorami korelacji śledzenia bezpośrednio do Cloud Logging i wykrywanie wyjątków w środowisku produkcyjnym w czasie rzeczywistym za pomocą Cloud Error Reporting.
- Jak to działa:
- Skonfiguruj
blog/config/environments/production.rb, aby emitował uporządkowane dzienniki JSON z etykietami śledzenia GCP. - Wywołaj celowo wyjątek testowy i obserwuj, jak Raportowanie błędów w Google Cloud grupuje błędy i natychmiast Cię o nich powiadamia.
- Skonfiguruj
📸 TODO(riccardo): dodaj zrzut ekranu usługi Google Cloud Error Reporting pokazujący pogrupowane wyjątki produkcyjne i strukturalny ładunek JSON usługi Cloud Logging z etykietami śledzenia
🧠 Quest 3. pgvector Wyszukiwanie semantyczne i RAG w Gemini
- Poziom trudności: trudny (projekt końcowy z zakresu generatywnej AI)
- Cel: wyszukiwanie artykułów na podstawie koncepcji przy użyciu wektorów dystrybucyjnych przechowywanych w PostgreSQL w Cloud SQL.
- Jak to działa:
- Włącz rozszerzenie
vectorw instancji Cloud SQL PostgreSQL:CREATE EXTENSION IF NOT EXISTS vector; - Dodaj gniazdo
neighbordoblog/Gemfilei wygeneruj wektory dystrybucyjne tekstu za pomocą Gemini (text-embedding-004) naPost#after_save. - Wykonywanie zapytań o odległość kosinusową (
<=>) w celu obsługi paska wyszukiwania semantycznego za pomocą Turbo Streams.
- Włącz rozszerzenie
📸 TODO(riccardo): dodać zrzut ekranu paska wyszukiwania semantycznego na blogu na żywo, który zwraca dopasowania koncepcyjne z wynikami podobieństwa kosinusowego
⚡ Quest 4. Asystent audytu SEO i wydajności
- Trudność: łatwe / przyjemne (dla deweloperów)
- Cel: przeprowadź audyt Core Web Vitals, największego wyrenderowania treści (LCP) oraz wskaźników czytelności Flescha-Kincaida i Foga za pomocą narzędzi Antigravity i Speedgrapher.
📸 TODO(riccardo): add screenshot of Speedgrapher / Lighthouse SEO and Core Web Vitals audit summary
🤔 Curiosity Box: Getting a Live Rails Console on Cloud Run
💡 Pytanie: na tradycyjnych maszynach wirtualnych lub platformach PaaS w stylu Heroku programiści często łączą się przez SSH z działającą instancją lub używają heroku run rails console, aby na żywo sprawdzać lub poprawiać dane produkcyjne. Jaki jest odpowiednik natywny Cloud Run i jak go zabezpieczyć?
Dlaczego
gcloud run exec
nie istnieje w przypadku usług Cloud Run
Cloud Run to platforma bezserwerowa: kontener może działać jako zero, jedna lub setki identycznych instancji bez stabilnej tożsamości ani adresu powłoki. Różni się to zasadniczo od Kubernetes (kubectl exec), gdzie konkretny pod ma nazwane gniazdo, do którego można się podłączyć.
# ❌ 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
4 wzorce natywne GCP
Wzór | Polecenie | Interaktywny? | Bezpieczeństwo |
1. Lokalny serwer proxy + zdalna baza danych |
| ✅ Pełna | 🔒 Wzajemne uwierzytelnianie TLS serwera proxy uwierzytelniania Cloud SQL |
2. Zadanie Cloud Run (jednorazowe) |
| ❌ Tylko skrypt | 🔒 Wymagana rola uprawnień |
3. Gem konsoli sieciowej + zakupy w aplikacji | Przeglądarka → | ✅ Pełna | 🛡️ IAP Zero-Trust |
4. Cloud Shell + Proxy | Cloud Shell → | ✅ Pełna | 🔒 Tożsamość Google |
Wzorzec 1 (zalecany do sprawdzania danych): uruchom lokalną konsolę Rails, która komunikuje się bezpośrednio z Cloud SQL PostgreSQL za pomocą serwera proxy uwierzytelniania Cloud SQL:
# 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
Zyskujesz pełną interaktywność IRB bez narażania sieci na zagrożenia – serwer proxy Cloud SQL używa mTLS przez gniazdo domeny Unix lub interfejs zwrotny.
Wzorzec 3 (konsola internetowa + IAP Zero-Trust, ścieżka wzmocnionej przeglądarki):
web-consoleGem zapewnia sesję IRB w przeglądarce. Bez ochrony jest to krytyczna luka w zabezpieczeniach – nigdy nie udostępniaj jej publicznie. W połączeniu z płatnościami w aplikacji Google (Quest 1) obszar ataku się zmniejsza: tylko zweryfikowane tożsamości Google na liście dozwolonych mogą uzyskać dostęp do punktu końcowego /rails/console.
# 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
⚠️ Wzorzec 3 wymaga wcześniejszego włączenia misji 1 (zakupy w aplikacji). Bez niego /rails/console na publicznym adresie URL jest jak pozostawienie serwerowni bez zabezpieczeń. Dzięki IAP staje się on potężnym narzędziem dla operatorów, zabezpieczonym przez Zero-Trust na poziomie Google.
Zapytaj Antigravity: „Pokaż mi, jak uruchomić
rails console --sandbox
w bezpieczny sposób w odniesieniu do mojej produkcyjnej bazy danych Cloud SQL za pomocą serwera proxy uwierzytelniania Cloud SQL."
🏆 Ukończenie The Hive: dowód pracy zweryfikowany przez nadzorującego
Po ukończeniu wybranego zadania odbierz trofeum za ukończenie kroku 8 🏆 na tablicy wyników The Hive:
- Prześlij zadanie w GitHubie:
- Otwórz nowy problem w oficjalnym repozytorium: github.com/palladius/rails8-app-on-gcp/issues/new
- Format tytułu:
🎓 [Step 8 Completed]: - W treści podaj krótki opis tego, co udało Ci się osiągnąć, oraz link do wdrożenia w Cloud Run.
- Połącz aplikację Cloud Run z problemem:
- Zanotuj numer problemu (np.
88lub pełny adres URLhttps://github.com/palladius/rails8-app-on-gcp/issues/88). - Wstrzyknij zmienną środowiskową
STEP_8_GHIdo usługi Cloud Run:gcloud run services update blog \ --region europe-west1 \ --update-env-vars STEP_8_GHI=<YOUR_ISSUE_NUMBER> - Sprawdź, czy punkt końcowy
/status.jsonzgłasza teraz Twoje zadanie: Powinno pojawić się: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" }
- Zanotuj numer problemu (np.
- Uzyskaj weryfikację przez nadzorującego i odblokuj złote trofeum:
- Sprawdź tablicę wyników The Hive: w Twoim wierszu pojawi się teraz bursztynowa plakietka:
⏳ GHI #XX review pending. - Poproś prowadzących warsztaty (@palladius, @emilianodellacasa lub @ricc) o sprawdzenie wdrożenia.
- Gdy tylko egzaminator skomentuje Twój problem
LGTM, The Hive automatycznie zmieni Twój postęp na 8/8 🏆, a przy Twoim profilu pojawi się złoto-fioletowa świecąca odznaka i trofeum z linkiem do Twojego problemu końcowego.
- Sprawdź tablicę wyników The Hive: w Twoim wierszu pojawi się teraz bursztynowa plakietka:
11. Podsumowanie i czyszczenie 🎓
Gratulacje! 🎉
Masz utworzoną i wdrożoną w Google Cloud Platform aplikację Rails 8 klasy produkcyjnej, gotową do użycia w firmie:
- Zero-Branch Progression: opanowanie nowoczesnych przepływów pracy z nakładkami Time-Machine na
main. - Cloud Storage: skalowalne, prywatne miejsce na obiekty z podpisywaniem obiektów binarnych IAM (
iam: true). - Cloud SQL: zarządzana usługa PostgreSQL zabezpieczona tunelami mTLS serwera proxy uwierzytelniania Cloud SQL.
- Secret Manager: brak wycieków danych logowania w postaci zwykłego tekstu lub plików
.env. - Cloud Run Multi-Container: odizolowane kontenery pomocnicze Puma Web, Solid Queue Worker i proxy.
- Generatywna AI: asynchroniczne generowanie plakatów w stylu vintage i synteza podcastów TTS za pomocą Vertex AI.
- Quests: Zero-Trust IAP, SRE Observability, and pgvector embeddings!
🧹 Czyszczenie zasobów
Aby uniknąć dalszych opłat po zakończeniu warsztatów, pamiętaj o zwolnieniu miejsca na zasobach Google Cloud. Wybierz podejście, które najlepiej pasuje do Twojego środowiska:
Opcja 1. Terraform Teardown (zalecana / domyślna 🟢)
Użyj tej opcji, jeśli korzystasz z istniejącego lub udostępnionego projektu w chmurze Google, w którym znajdują się inne zasoby lub dane. Usuwa tylko zasoby udostępnione podczas tych warsztatów (Cloud Run, Cloud SQL, Secret Manager, zasobniki GCS), pozostawiając resztę projektu bez zmian.
cd iac
terraform destroy -auto-approve
Opcja 2. Całkowite usunięcie projektu (bez śladu 🌪️)
Użyj tej opcji, jeśli utworzysz dedykowany projekt warsztatowy (np. korzystając z kredytów warsztatowych lub piaskownicy) i chcesz mieć pewność, że nie pozostanie po nim żaden ślad, w tym logi, metadane, konta usług i linki do rozliczeń.
gcloud projects delete $GOOGLE_CLOUD_PROJECT --quiet