1. Wprowadzenie
Last Updated: 2024-11-01
Jak zmodernizować starą aplikację PHP, aby działała w Google Cloud?
(📽️ obejrzyj 7-minutowy film wprowadzający do tego ćwiczenia z programowania)
Często zdarza się, że starsze aplikacje działają lokalnie i wymagają modernizacji. Oznacza to, że muszą być skalowalne, bezpieczne i możliwe do wdrożenia w różnych środowiskach.
W tym warsztacie:
- Skonteneryzuj aplikację PHP.
- Przejdź na zarządzaną usługę baz danych ( Cloud SQL).
- Wdrażanie w Cloud Run (alternatywa dla GKE/Kubernetes, która nie wymaga żadnych operacji).
- Zabezpiecz aplikację za pomocą usługi Identity and Access Management (IAM) i Secret Manager.
- Zdefiniuj potok CI/CD za pomocą Cloud Build. Cloud Build można połączyć z repozytorium Git hostowanym u popularnych dostawców Git, takich jak GitHub czy GitLab, i uruchamiać przy każdym przesłaniu do głównego repozytorium.
- Przechowuj zdjęcia aplikacji w Cloud Storage. Można to osiągnąć przez zamontowanie, a zmiana aplikacji nie wymaga kodu.
- Wprowadzenie funkcji generatywnej AI w Gemini, koordynowanych za pomocą Cloud Functions (bezserwerowych).
- Zapoznaj się z SLO i obsługą odświeżonej aplikacji.
Wykonując te czynności, możesz stopniowo modernizować aplikację PHP, zwiększając jej skalowalność, bezpieczeństwo i elastyczność wdrażania. Przeniesienie aplikacji do Google Cloud umożliwia korzystanie z potężnej infrastruktury i usług, które zapewniają jej płynne działanie w środowisku natywnym dla chmury.
Uważamy, że wiedzę zdobytą dzięki tym prostym krokom możesz wykorzystać w przypadku własnej aplikacji i organizacji, w których używasz innego języka lub stosu technologicznego oraz innych przypadków użycia.
Informacje o aplikacji
Aplikacja ( kod na licencji MIT), którą sklonujesz, to podstawowa aplikacja PHP 5.7 z uwierzytelnianiem MySQL. Głównym założeniem aplikacji jest udostępnienie platformy, na której użytkownicy mogą przesyłać zdjęcia, a administratorzy mogą oznaczać nieodpowiednie obrazy. Aplikacja ma 2 tabele:
- Użytkownicy Wstępnie skompilowane z administratorami. Nowi użytkownicy mogą się rejestrować.
- Grafika Zawiera kilka przykładowych obrazów. Zalogowani użytkownicy mogą przesyłać nowe zdjęcia. Dodamy tu trochę magii.
Twój cel
Chcemy zmodernizować starą aplikację, aby działała w Google Cloud. Wykorzystamy jego narzędzia i usługi, aby zwiększyć skalowalność, poprawić bezpieczeństwo, zautomatyzować zarządzanie infrastrukturą i zintegrować zaawansowane funkcje, takie jak przetwarzanie obrazów, monitorowanie i przechowywanie danych, przy użyciu usług takich jak Cloud SQL, Cloud Run, Cloud Build, Secret Manager i innych.

Co ważniejsze, chcemy to zrobić krok po kroku, abyś mógł nauczyć się, jakie jest uzasadnienie każdego z nich. Zwykle każdy krok otwiera nowe możliwości dla kolejnych (np. moduły 2–3 i 6–7).
Nadal się wahasz? Obejrzyj ten 7-minutowy film w YouTube.
Czego potrzebujesz
- Komputer z przeglądarką i połączeniem internetowym.
- niektóre środki GCP; Zobacz następny krok.
- Będziesz używać Cloud Shell. Zawiera wszystkie preinstalowane polecenia, których będziesz potrzebować, oraz zintegrowane środowisko programistyczne.
- Konto GitHub. Jest to potrzebne do rozwidlenia oryginalnego kodu 🧑🏻💻 gdgpescara/app-mod-workshop za pomocą własnego repozytorium Git. Jest to potrzebne do utworzenia własnego potoku CI/CD (automatyczne zatwierdzanie –> kompilacja –> wdrażanie).
Przykładowe rozwiązania znajdziesz tutaj:
- Repozytorium autora: https://github.com/Friends-of-Ricc/app-mod-workshop
- Oryginalne repozytorium warsztatów w folderach
.solutions/, w podziale na rozdziały.
Te warsztaty są przeznaczone do przeprowadzenia w Cloud Shell (w przeglądarce).
Możesz jednak spróbować zrobić to na komputerze lokalnym.
2. Konfigurowanie środków i Fork

Wykorzystaj środki w GCP i skonfiguruj środowisko GCP [opcjonalnie]
Aby przeprowadzić te warsztaty, musisz mieć konto rozliczeniowe z określonymi środkami. Aby rozpocząć, użyj środków z banera u góry tego modułu. Jeśli masz już połączenie z kontem rozliczeniowym, możesz pominąć ten krok.
Po zakończeniu otwórz konsolę Google Cloud i utwórz nowy projekt, klikając selektor projektu w lewym górnym rogu menu, w którym wyświetla się „Brak organizacji”. Szczegółowe informacje znajdziesz poniżej

Jeśli nie masz projektu, utwórz nowy, jak pokazano na zrzucie ekranu poniżej. W prawym górnym rogu znajduje się opcja „NOWY PROJEKT”.

Pamiętaj, aby powiązać nowy projekt z kontem rozliczeniowym w ramach okresu próbnego GCP w ten sposób:

Możesz już korzystać z Google Cloud Platform. Jeśli jesteś początkującym użytkownikiem lub chcesz wszystko robić w środowisku chmurowym, możesz uzyskać dostęp do Cloud Shell i jego edytora, klikając przycisk w lewym górnym rogu, jak pokazano poniżej.

Sprawdź, czy w lewym górnym rogu wybrany jest nowy projekt:
Nie wybrano (źle):

Wybrano (dobrze):

Utwórz rozwidlenie aplikacji z GitHuba
- Otwórz aplikację w wersji demonstracyjnej: https://github.com/gdgpescara/app-mod-workshop
- Kliknij 🍴 fork.
- Jeśli nie masz konta GitHub, musisz utworzyć nowe.
- Edytuj elementy w dowolny sposób.

- Sklonuj kod aplikacji za pomocą
git clonehttps://github.com/YOUR-GITHUB-USER/YOUR-REPO-NAME
- Otwórz sklonowany folder projektu w ulubionym edytorze. Jeśli wybierzesz Cloud Shell, możesz to zrobić, klikając „Otwórz edytor”, jak pokazano poniżej.

Wszystko, czego potrzebujesz, znajdziesz w edytorze Google Cloud Shell, jak pokazano na ilustracji poniżej.

Możesz to zrobić wizualnie, klikając „Otwórz folder” i wybierając folder, prawdopodobnie app-mod-workshop w folderze głównym.
3. Moduł 1. Tworzenie instancji SQL
Utwórz instancję Google Cloud SQL
Nasza aplikacja PHP będzie łączyć się z bazą danych MySQL, dlatego musimy ją zreplikować w Google Cloud, aby przeprowadzić migrację bez żadnych problemów. Cloud SQL to idealne rozwiązanie, ponieważ umożliwia uruchamianie w pełni zarządzanej bazy danych MySQL w chmurze. Aby to zrobić:
- Otwórz stronę Cloud SQL: https://console.cloud.google.com/sql/instances
- Kliknij „Utwórz instancję”.
- Włącz API (w razie potrzeby). Może to potrwać kilka sekund.
- Wybierz MySQL.
- (Staramy się znaleźć najtańszą wersję, aby dłużej działała):
- Wersja: Enterprise
- Wstępnie ustawione: development (próbowaliśmy piaskownicy, ale nie sprawdziła się w naszym przypadku)
- Wersja MySQL: 5.7 (wow, to już historia!)
- Identyfikator instancji: wybierz
appmod-phpapp(jeśli to zmienisz, pamiętaj, aby odpowiednio zmodyfikować też przyszłe skrypty i rozwiązania). - Hasło: dowolne, ale zapisz je jako CLOUDSQL_INSTANCE_PASSWORD.
- Region: pozostaw ten sam, który został wybrany dla reszty aplikacji (np. Mediolan =
europe-west8). - Dostępność strefowa: 1 strefa (oszczędzamy pieniądze na potrzeby wersji demonstracyjnej)
Kliknij przycisk Utwórz instancję, aby wdrożyć bazę danych Cloud SQL. ⌛ Zajmie to około 10 minut⌛. W międzyczasie czytaj dalej dokumentację. Możesz też zacząć rozwiązywać zadania z następnego modułu („Konteneryzacja aplikacji PHP”), ponieważ w pierwszej części (do momentu naprawienia połączenia z bazą danych) nie jest on zależny od tego modułu.
Uwaga. Ta instancja powinna kosztować około 7 PLN dziennie. Po warsztatach pamiętaj o odłączeniu go.
Tworzenie bazy danych image_catalog i użytkownika w Cloud SQL
Projekt aplikacji zawiera folder db/, w którym znajdują się 2 pliki SQL:
- 01_schema.sql : zawiera kod SQL do utworzenia 2 tabel z danymi o użytkownikach i obrazach.
- 02_seed.sql: zawiera kod SQL do wypełniania danych w utworzonych wcześniej tabelach.
Pliki te zostaną użyte później, po utworzeniu bazy danych image_catalog. Aby to zrobić:
- Otwórz instancję i kliknij kartę Bazy danych:
- kliknij „Utwórz bazę danych”;
- nazwij go
image_catalog(jak w konfiguracji aplikacji PHP).

Następnie tworzymy użytkownika bazy danych. Dzięki temu możemy uwierzytelnić się w bazie danych image_catalog.
- Teraz kliknij kartę Użytkownicy.
- Kliknij „Dodaj konto użytkownika”.
- Użytkownik: utwórzmy go:
- Nazwa użytkownika:
appmod-phpapp-user - Hasło: wybierz coś, co łatwo zapamiętać, lub kliknij „Wygeneruj”.
- Wybierz „Zezwalaj na dowolnego hosta (%)”.
- kliknij DODAJ.
Otwórz bazę danych znanych adresów IP.
Pamiętaj, że wszystkie bazy danych w Cloud SQL są „izolowane”. Musisz wyraźnie skonfigurować sieć, z której ma być dostępna.
- Kliknij instancję.
- Otwórz menu „Połączenia”.
- Kliknij kartę „Sieci”.
- Kliknij w sekcji „Autoryzowane sieci”. Teraz dodaj sieć (czyli podsieć).
- Na razie wybierzmy szybkie, ale NIEBEZPIECZNE ustawienia, aby aplikacja działała. Później możesz ograniczyć dostęp do zaufanych adresów IP:
- Nazwa: „Everyone in the world - INSECURE” (Wszyscy na świecie – NIEZABEZPIECZONE).
- Sieć: „
0.0.0.0/0"(uwaga: to jest NIEZABEZPIECZONA część!) - Kliknij GOTOWE.
- Kliknij Zapisz.
Powinien pojawić się ekran podobny do tego:

Uwaga. To rozwiązanie jest dobrym kompromisem, który pozwala ukończyć warsztaty w czasie O(godziny). Zapoznaj się jednak z dokumentem SECURITY, aby zabezpieczyć rozwiązanie na potrzeby wdrożenia w wersji produkcyjnej.
Czas przetestować połączenie z bazą danych.
Sprawdźmy, czy utworzony wcześniej użytkownik image_catalog działa.
Otwórz „Cloud SQL Studio” w instancji i wpisz nazwę bazy danych, nazwę użytkownika i hasło, aby się uwierzytelnić, jak pokazano poniżej:

Teraz możesz otworzyć edytor SQL i przejść do następnej sekcji.
Importowanie bazy danych z bazy kodu
Użyj edytora SQL, aby zaimportować tabele image_catalog wraz z danymi. Skopiuj kod SQL z plików w repozytorium ( 01_schema.sql, a potem 02_seed.sql) i wykonaj je kolejno.
Następnie w katalogu image_catalog powinny pojawić się 2 tabele: users i images, jak pokazano poniżej:

Możesz to sprawdzić, uruchamiając w edytorze to polecenie: select * from images;
Zanotuj też publiczny adres IP instancji Cloud SQL, ponieważ będzie Ci potrzebny później. Aby uzyskać adres IP, otwórz stronę główną instancji Cloud SQL na stronie Przegląd. (Przegląd > Połącz z tą instancją > Publiczny adres IP).
4. Moduł 2. Konteneryzowanie aplikacji w PHP

Chcemy stworzyć tę aplikację na potrzeby chmury.
Oznacza to spakowanie kodu w pliku ZIP, który zawiera wszystkie informacje potrzebne do stosowania go w chmurze.
Możesz to zrobić na kilka sposobów:
- Docker. Bardzo popularne, ale dość skomplikowane w prawidłowej konfiguracji.
- Buildpacki Mniej popularny, ale zwykle „automatycznie zgaduje”, co zbudować i co uruchomić. Często po prostu działa.
Na potrzeby tych warsztatów założymy, że używasz Dockera.
Jeśli zdecydujesz się użyć Cloud Shell, otwórz go ponownie (kliknij w prawym górnym rogu konsoli Cloud).

W dolnej części strony powinien się otworzyć wygodny shell, w którym w kroku konfiguracji nastąpiło rozwidlenie kodu.

Docker
Jeśli chcesz mieć kontrolę, to jest to odpowiednie rozwiązanie dla Ciebie. Ma to sens, gdy musisz skonfigurować określone biblioteki i wstrzyknąć pewne nieoczywiste zachowania (chmod w przypadku przesyłania, niestandardowy plik wykonywalny w aplikacji itp.).
Chcemy wdrożyć skonteneryzowaną aplikację w Cloud Run, więc zapoznaj się z tą dokumentacją. Jak przenieść go z PHP 8 do PHP 5.7? Możesz do tego użyć Gemini. Możesz też użyć tej gotowej wersji:
# Use the official PHP image: https://hub.docker.com/_/php
FROM php:5.6-apache
# Configure PHP for Cloud Run.
# Precompile PHP code with opcache.
# Install PHP's extension for MySQL
RUN docker-php-ext-install -j "$(nproc)" opcache mysqli pdo pdo_mysql && docker-php-ext-enable pdo_mysql
RUN set -ex; \
{ \
echo "; Cloud Run enforces memory & timeouts"; \
echo "memory_limit = -1"; \
echo "max_execution_time = 0"; \
echo "; File upload at Cloud Run network limit"; \
echo "upload_max_filesize = 32M"; \
echo "post_max_size = 32M"; \
echo "; Configure Opcache for Containers"; \
echo "opcache.enable = On"; \
echo "opcache.validate_timestamps = Off"; \
echo "; Configure Opcache Memory (Application-specific)"; \
echo "opcache.memory_consumption = 32"; \
} > "$PHP_INI_DIR/conf.d/cloud-run.ini"
# Copy in custom code from the host machine.
WORKDIR /var/www/html
COPY . .
# Setup the PORT environment variable in Apache configuration files: https://cloud.google.com/run/docs/reference/container-contract#port
ENV PORT=8080
# Tell Apache to use 8080 instead of 80.
RUN sed -i 's/80/${PORT}/g' /etc/apache2/sites-available/000-default.conf /etc/apache2/ports.conf
# Note: This is quite insecure and opens security breaches. See last chapter for hardening ideas.
# Uncomment at your own risk:
#RUN chmod 777 /var/www/html/uploads/
# Configure PHP for development.
# Switch to the production php.ini for production operations.
# RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini"
# https://github.com/docker-library/docs/blob/master/php/README.md#configuration
RUN mv "$PHP_INI_DIR/php.ini-development" "$PHP_INI_DIR/php.ini"
# Expose the port
EXPOSE 8080
Najnowsza wersja Dockerfile jest dostępna tutaj.
Aby przetestować aplikację lokalnie, musimy zmienić plik config.php w taki sposób, aby aplikacja PHP łączyła się z bazą danych MySQL dostępną w Google Cloud SQL. Na podstawie wcześniejszych ustawień wypełnij puste pola:
<?php
// Database configuration
$db_host = '____________';
$db_name = '____________';
$db_user = '____________';
$db_pass = '____________';
try {
$pdo = new PDO("mysql:host=$db_host;dbname=$db_name", $db_user, $db_pass);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
die("Errore di connessione: " . $e->getMessage());
}
session_start();
?>
DB_HOSTto publiczny adres IP Cloud SQL. Znajdziesz go w konsoli SQL:

DB_NAMEshould be unchanged:image_catalog- Wartość
DB_USERpowinna wynosićappmod-phpapp-user DB_PASSto coś, co wybrałeś(-aś). Ustaw go w pojedynczych cudzysłowach i w razie potrzeby użyj znaku ucieczki.
Możesz też przetłumaczyć kilka 🇮🇹 włoskich fragmentów na język angielski za pomocą Gemini.
OK. Skoro masz już Dockerfile i skonfigurowałeś(-aś) aplikację PHP tak, aby łączyła się z bazą danych, spróbujmy to zrobić.
Zainstaluj Dockera, jeśli jeszcze go nie masz ( link). Nie jest to potrzebne, jeśli używasz Cloud Shell (jakie to fajne!).
Teraz spróbuj skompilować i uruchomić skonteneryzowaną aplikację PHP za pomocą odpowiednich poleceń docker build i run.
# Build command - don't forget the final . This works if Dockerfile is inside the code folder:
$ docker build -t my-php-app-docker .
# Local Run command: most likely ports will be 8080:8080
$ docker run -it -p <CONTAINER_PORT>:<LOCAL_MACHINE_PORT> my-php-app-docker
Jeśli wszystko działa, po połączeniu z hostem lokalnym powinna wyświetlić się ta strona internetowa. Aplikacja działa teraz na porcie 8080. Kliknij ikonę „Podgląd w przeglądarce” (przeglądarka z okiem), a następnie Podejrzyj na porcie 8080 (lub „Zmień port”, aby użyć innego portu).

Testowanie wyniku w przeglądarce
Aplikacja powinna teraz wyglądać mniej więcej tak:

Jeśli zalogujesz się za pomocą danych Admin/admin123, zobaczysz coś takiego:

Świetnie! Poza włoskim tekstem wszystko działa. 🎉🎉🎉
Jeśli konteneryzacja jest prawidłowa, ale dane logowania do bazy danych są nieprawidłowe, możesz zobaczyć taki komunikat:

Spróbuj jeszcze raz. Prawie się udało.
Zapisywanie w Artifact Registry [opcjonalnie]
Powinna już być dostępna działająca skonteneryzowana aplikacja PHP gotowa do wdrożenia w chmurze. Następnie potrzebujemy miejsca w chmurze, w którym będziemy przechowywać obraz Dockera i udostępniać go na potrzeby wdrażania w usługach Google Cloud, takich jak Cloud Run. To rozwiązanie do przechowywania nosi nazwę Artifact Registry i jest w pełni zarządzaną usługą Google Cloud przeznaczoną do przechowywania artefaktów aplikacji, w tym obrazów kontenerów Dockera, pakietów Maven, modułów npm i innych.
Utwórzmy repozytorium w Google Cloud Artifact Registry za pomocą odpowiedniego przycisku.

Wybierz prawidłową nazwę, format i region odpowiedni do przechowywania artefaktów.

Wróć do lokalnego środowiska programistycznego, dodaj tag do obrazu kontenera aplikacji i prześlij go do utworzonego przed chwilą repozytorium Artifact Registry. Aby to zrobić, wykonaj te polecenia.
- docker tag OBRAZ_ŹRÓDŁOWY[:TAG] OBRAZ_DOCELOWY[:TAG]
- docker push TARGET_IMAGE[:TAG]
Wynik powinien wyglądać jak na zrzucie ekranu poniżej.

Hurra 🎉🎉🎉 możesz przejść na kolejny poziom. Wcześniej poświęć 2 minuty na wypróbowanie przesyłania, logowania i wylogowywania oraz zapoznanie się z punktami końcowymi aplikacji.Będą Ci potrzebne później.
Możliwe błędy
Jeśli pojawią się błędy związane z konteneryzacją, poproś Gemini o wyjaśnienie i naprawienie błędu, podając:
- Twój obecny plik Dockerfile
- otrzymany błąd,
- [w razie potrzeby] wykonywany kod PHP.
Uprawnienia do przesyłania. Spróbuj też użyć punktu końcowego /upload.php i prześlij zdjęcie. Możesz zobaczyć błąd podany poniżej. W takim przypadku musisz chmod/chownnaprawićDockerfile.
Ostrzeżenie: move_uploaded_file(uploads/image (3).png): nie udało się otworzyć strumienia: Permission denied w /var/www/html/upload.php w wierszu 11
PDOException „nie udało się znaleźć sterownika” (lub „Errore di connessione: could not find driver”). Upewnij się, że plik Dockerfile zawiera odpowiednie biblioteki PDO dla MySQL (pdo_mysql), aby można było połączyć się z bazą danych. Inspirację znajdziesz tutaj.
Nie udało się przekazać prośby do systemu backendowego. Nie udało się połączyć z serwerem na porcie 8080. Oznacza to, że prawdopodobnie udostępniasz nieprawidłowy port. Upewnij się, że udostępniasz port, z którego serwery Apache/Nginx faktycznie obsługują żądania. To nie jest proste. Jeśli to możliwe, ustaw port na 8080 (ułatwi to korzystanie z Cloud Run). Jeśli chcesz zachować port 80 (np. dlatego, że Apache tego wymaga), użyj innego polecenia:
$ docker run -it -p 8080:80 # force 80
# Use the PORT environment variable in Apache configuration files.
# https://cloud.google.com/run/docs/reference/container-contract#port
RUN sed -i 's/80/${PORT}/g' /etc/apache2/sites-available/000-default.conf /etc/apache2/ports.conf
5. Moduł 3. Wdrażanie aplikacji w Cloud Run

Dlaczego warto wybrać Cloud Run?
Słuszne pytanie. Jeszcze kilka lat temu z pewnością wybrałbyś Google App Engine.
Mówiąc wprost, Cloud Run ma nowszy stos technologiczny, jest łatwiejsza we wdrożeniu, tańsza i skaluje się do 0, gdy nie jest używana. Dzięki elastyczności, która pozwala na uruchamianie dowolnych kontenerów bezstanowych, oraz integracji z różnymi usługami Google Cloud idealnie nadaje się do wdrażania mikroserwisów i nowoczesnych aplikacji przy minimalnym narzucie i maksymalnej wydajności.
Cloud Run to w pełni zarządzana platforma Google Cloud, która umożliwia uruchamianie bezstanowych aplikacji skonteneryzowanych w środowisku bezserwerowym. Automatycznie obsługuje całą infrastrukturę, skalując się od zera, aby sprostać przychodzącemu ruchowi, i zmniejszając skalę, gdy jest bezczynna, co czyni ją opłacalną i wydajną. Cloud Run obsługuje dowolny język lub bibliotekę, o ile są one spakowane w kontenerze, co zapewnia dużą elastyczność podczas programowania. Usługa dobrze integruje się z innymi usługami Google Cloud i nadaje się do tworzenia mikroserwisów, interfejsów API, witryn i aplikacji opartych na zdarzeniach bez konieczności zarządzania infrastrukturą serwerową.
Wymagania wstępne
Aby wykonać to zadanie, musisz mieć zainstalowany program gcloud na komputerze lokalnym. Jeśli nie, zapoznaj się z instrukcjami tutaj. Jeśli korzystasz z Google Cloud Shell, nie musisz nic robić.
Przed wdrożeniem...
Jeśli pracujesz w środowisku lokalnym, uwierzytelnij się w Google Cloud za pomocą tego polecenia:
$ gcloud auth login –update-adc # not needed in Cloud Shell
Powinno to uwierzytelnić Cię za pomocą loginu OAuth w przeglądarce. Zaloguj się w Chrome jako ten sam użytkownik (np. vattelapesca@gmail.com), który jest zalogowany w Google Cloud z włączonym rozliczeniem.
Włącz Cloud Run API za pomocą tego polecenia:
$ gcloud services enable run.googleapis.com cloudbuild.googleapis.com
Na tym etapie wszystko jest gotowe do wdrożenia w Cloud Run.
Wdrażanie aplikacji w Cloud Run za pomocą gcloud
Polecenie, które umożliwia wdrożenie aplikacji w Cloud Run, to gcloud run deploy. Aby osiągnąć cel, możesz ustawić kilka opcji. Minimalny zestaw opcji (które możesz podać w wierszu poleceń lub o które narzędzie poprosi Cię w interaktywnym prompcie) obejmuje:
- Nazwa usługi Cloud Run, którą chcesz wdrożyć w aplikacji. Usługa Cloud Run zwróci adres URL, który będzie punktem końcowym aplikacji.
- Region Google Cloud, w którym będzie działać aplikacja. (
--regionREGION) - Obraz kontenera, który zawiera Twoją aplikację.
- Zmienne środowiskowe, których aplikacja potrzebuje podczas wykonywania.
- Flaga Allow-Unauthenticated, która umożliwia wszystkim dostęp do aplikacji bez dodatkowego uwierzytelniania.
Zapoznaj się z dokumentacją (lub przewiń w dół, aby znaleźć możliwe rozwiązanie), aby dowiedzieć się, jak zastosować tę opcję w wierszu poleceń.
Wdrażanie potrwa kilka minut. Jeśli wszystko jest w porządku, w konsoli Google Cloud zobaczysz coś takiego:


Kliknij adres URL podany przez Cloud Run i przetestuj aplikację. Po uwierzytelnieniu powinien pojawić się ekran podobny do tego.

„gcloud run deploy” bez argumentów
Możesz zauważyć, że gcloud run deploy zadaje Ci odpowiednie pytania i wypełnia pozostawione przez Ciebie puste pola. Jest niesamowicie!
W kilku modułach dodamy to polecenie do aktywatora kompilacji Cloud Build, więc nie możemy sobie pozwolić na interaktywne pytania. Musimy wypełnić wszystkie opcje w poleceniu. Chcesz stworzyć złotą gcloud run deploy --option1 blah --foo bar --region your-fav-region. Jak to zrobisz?
- powtarzaj kroki 2–3–4, aż gcloud przestanie zadawać pytania:
- [LOOP]
gcloud run deployz dotychczas znalezionymi opcjami - [LOOP] systemy proszą o opcję X
- [LOOP] Wyszukaj w dokumentach publicznych informacje o tym, jak skonfigurować X z interfejsu wiersza poleceń, dodając opcję
--my-option [my-value]. - Wróć do kroku 2, chyba że gcloud zakończy działanie bez dalszych pytań.
- This gcloud run deploy BLAH BLAH BLAH rocks! Zapisz polecenie, ponieważ będzie Ci potrzebne później w kroku Cloud Build.
Możliwe rozwiązanie znajdziesz tutaj. Dokumenty znajdziesz tutaj.
Gratulacje 🎉🎉🎉 udało Ci się wdrożyć aplikację w Google Cloud, co jest pierwszym krokiem w procesie modernizacji.
6. Moduł 4. Czyszczenie hasła za pomocą usługi Secret Manager

W poprzednim kroku udało nam się wdrożyć i uruchomić aplikację w Cloud Run. Zrobiliśmy to jednak w sposób niezgodny z zasadami bezpieczeństwa: przekazaliśmy niektóre tajne informacje w postaci zwykłego tekstu.
Pierwsza iteracja: zaktualizuj plik config.php, aby używać zmiennej ENV
Być może zauważyliście, że hasło do bazy danych umieściliśmy bezpośrednio w kodzie w pliku config.php. Jest to wystarczające do celów testowych i sprawdzenia, czy aplikacja działa. Nie możesz jednak zatwierdzać ani używać kodu w taki sposób w środowisku produkcyjnym. Hasło (i inne parametry połączenia z bazą danych) powinno być odczytywane dynamicznie i przekazywane do aplikacji w czasie działania. Zmodyfikuj plik config.php, aby odczytywał parametry bazy danych ze zmiennych środowiskowych. Jeśli się nie powiedzie, rozważ ustawienie wartości domyślnych. Jest to przydatne w przypadku niepowodzenia wczytywania zmiennych środowiskowych. W takiej sytuacji dane wyjściowe strony poinformują Cię, czy używane są wartości domyślne. Wypełnij puste pola i zastąp kod w pliku config.php.
<?php
// Database configuration with ENV variables. Set default values as well
$db_host = getenv('DB_HOST') ?: 'localhost';
$db_name = getenv('DB_NAME') ?: 'image_catalog';
$db_user = getenv('DB_USER') ?: 'appmod-phpapp-user';
$db_pass = getenv('DB_PASS') ?: 'wrong_password';
// Note getenv() is PHP 5.3 compatible
try {
$pdo = new PDO("mysql:host=$db_host;dbname=$db_name", $db_user, $db_pass);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
die("Errore di connessione: " . $e->getMessage());
}
session_start();
?>
Ponieważ aplikacja jest kontenerowa, musisz podać sposób dostarczania zmiennych środowiskowych do aplikacji. Można to zrobić na kilka sposobów:
- W czasie kompilacji w pliku Dockerfile. Dodaj do poprzedniego pliku Dockerfile 4 parametry, używając składni ENV DB_VAR=ENV_VAR_VALUE. Spowoduje to ustawienie wartości domyślnych, które można zastąpić w czasie działania programu. Na przykład wartości „DB_NAME” i „DB_USER” można ustawić tylko tutaj.
- W czasie wykonywania. Możesz skonfigurować te zmienne dla Cloud Run, zarówno w interfejsie wiersza poleceń, jak i w interfejsie. To odpowiednie miejsce na umieszczenie wszystkich 4 zmiennych (chyba że chcesz zachować wartości domyślne ustawione w pliku Dockerfile).
W środowisku localhost możesz umieścić zmienne środowiskowe w pliku .env (sprawdź folder solutions).
Upewnij się też, że plik .env jest dodany do .gitignore – nie chcesz przecież przesyłać swoich danych logowania do GitHub.
echo .env >> .gitignore
Następnie możesz przetestować instancję lokalnie:
docker run -it -p 8080:8080 --env-file .env my-php-app-docker
Udało Ci się:
- Aplikacja będzie dynamicznie odczytywać zmienną z ENV
- Zwiększono bezpieczeństwo, ponieważ hasło do bazy danych zostało usunięte z kodu.
Możesz teraz wdrożyć nową wersję w Cloud Run. Przejdźmy do interfejsu i ręcznie ustawmy zmienne środowiskowe:
- Wejdź na https://console.cloud.google.com/run.
- Kliknij aplikację
- Kliknij „Edytuj i wdróż nową wersję”.
- Na pierwszej karcie „Kontenery” kliknij dolną kartę „Zmienne i obiekty tajne”.
- Kliknij „+ Dodaj zmienną” i dodaj wszystkie potrzebne zmienne. Powinno to wyglądać mniej więcej tak:


Czy to idealne rozwiązanie? Nie. Twój PASS jest nadal widoczny dla większości operatorów. Można temu zapobiec, korzystając z usługi Google Cloud Secret Manager.
Druga iteracja: Secret Manager
Hasła zniknęły z Twojego kodu: sukces! Ale zaraz – czy jesteśmy już bezpieczni?
Hasła są nadal widoczne dla każdego, kto ma dostęp do konsoli Google Cloud. W rzeczywistości możesz go pobrać, jeśli uzyskasz dostęp do pliku YAML wdrożenia Cloud Run. Jeśli spróbujesz edytować lub wdrożyć nową wersję Cloud Run, hasło będzie widoczne w sekcji Zmienne i tajne dane, jak pokazano na zrzutach ekranu poniżej.
Secret Manager w Google Cloud to bezpieczna, scentralizowana usługa do zarządzania informacjami wrażliwymi, takimi jak klucze interfejsu API, hasła, certyfikaty i inne obiekty tajne.
Umożliwia przechowywanie obiektów tajnych, zarządzanie nimi i uzyskiwanie do nich dostępu przy użyciu szczegółowych uprawnień i zaawansowanego szyfrowania. Menedżer obiektów tajnych jest zintegrowany z usługą Google Cloud Identity and Access Management (IAM), dzięki czemu możesz kontrolować, kto ma dostęp do określonych obiektów tajnych, co zapewnia bezpieczeństwo danych i zgodność z przepisami.
Obsługuje też automatyczne rotowanie i obsługa wersji obiektów tajnych, co upraszcza zarządzanie cyklem życia obiektów tajnych i zwiększa bezpieczeństwo aplikacji w usługach Google Cloud.
Aby uzyskać dostęp do Secret Managera, w menu hamburgera otwórz usługi Bezpieczeństwo i znajdź go w sekcji Ochrona danych, jak pokazano na zrzucie ekranu poniżej.

Włącz interfejs Secret Manager API, jak pokazano na poniższym obrazie.

- Teraz kliknij Utwórz obiekt tajny. Nazwijmy go racjonalnie:
- Nazwa:
php-amarcord-db-pass - Wartość obiektu tajnego: „hasło do bazy danych” (zignoruj część „prześlij plik”).
- dodaj adnotację do tego tajnego linku, która powinna wyglądać tak:
projects/123456789012/secrets/php-amarcord-db-pass. Jest to unikalny wskaźnik do obiektu tajnego (w przypadku Terraform, Cloud Run i innych usług). Jest to Twój unikalny numer projektu.
Wskazówka: staraj się stosować spójne konwencje nazewnictwa w przypadku kluczy tajnych, specjalizując się od lewej do prawej, np. cloud-devrel-phpamarcord-dbpass
- Organizacja (z firmą)
- Zespół (w organizacji)
- Zastosowanie (w zespole)
- Nazwa zmiennej (w aplikacji)
Dzięki temu możesz łatwo tworzyć wyrażenia regularne, aby znajdować wszystkie tajne informacje w jednej aplikacji.
Utwórz nową wersję Cloud Run
Teraz, gdy mamy już nowy klucz Secret, musimy pozbyć się zmiennej środowiskowej DB_PASS i zastąpić ją nowym kluczem Secret. Przykłady:
- Dostęp do Cloud Run za pomocą konsoli Google Cloud
- Wybierz aplikację.
- Kliknij „Edytuj i wdróż nową wersję”.
- znajdź kartę „Zmienne i obiekty tajne”;
- Aby zresetować zmienną środowiskową DB_PASS, użyj przycisku „+ Odwołaj się do obiektu tajnego”.
- Użyj tego samego hasła „DB_PASS” w przypadku odwoływanych się do niego obiektów tajnych i użyj najnowszej wersji.

Gdy to zrobisz, powinien pojawić się ten błąd:

Spróbuj znaleźć rozwiązanie. Aby rozwiązać ten problem, otwórz sekcję Administracja i zmień uprawnienia do przyznawania. Miłego debugowania!
Gdy to zrobisz, wróć do Cloud Run i wdroż nową wersję. Wynik powinien wyglądać jak na ilustracji poniżej:

Wskazówka: Konsola programisty (interfejs) doskonale wykrywa problemy z uprawnieniami. Poświęć trochę czasu na przejrzenie wszystkich linków do swoich podmiotów w chmurze.
7. Moduł 5. Konfigurowanie CI/CD za pomocą Cloud Build

Dlaczego warto używać potoku CI/CD?
Do tej pory powinnaś(-eś) kilka razy wpisać gcloud run deploy, być może odpowiadając na to samo pytanie.
Masz dość ręcznego wdrażania aplikacji za pomocą gcloud run deploy? Czy nie byłoby wspaniale, gdyby Twoja aplikacja mogła wdrażać się automatycznie za każdym razem, gdy przenosisz nową zmianę do repozytorium Git?
Aby korzystać z potoku CI/CD, musisz mieć 2 rzeczy:
- Osobiste repozytorium Git: na szczęście w kroku 2 utworzono już rozwidlenie repozytorium warsztatowego na koncie GitHub. Jeśli nie, wróć i wykonaj ten krok. Rozwidlone repozytorium powinno wyglądać tak:
https://github.com/<YOUR_GITHUB_USER>/app-mod-workshop - Cloud Build. Ta niesamowita i tania usługa umożliwia skonfigurowanie automatyzacji kompilacji niemal wszystkiego: Terraform, aplikacji w kontenerach Dockera itp.
Ta sekcja dotyczy konfigurowania Cloud Build.
Witaj w Cloud Build!
W tym celu użyjemy Cloud Build:
- skompilować źródło (za pomocą pliku Dockerfile); Można go traktować jako „duży plik ZIP”, który zawiera wszystko, co jest potrzebne do jego utworzenia i uruchomienia (czyli „artefakt kompilacji”).
- przesłać ten artefakt do Artifact Registry (AR).
- Następnie wdróż aplikację „php-amarcord” z AR w Cloud Run.
- Spowoduje to utworzenie nowej wersji („rewizji”) istniejącej aplikacji (pomyśl o warstwie z nowym kodem). Skonfigurujemy ją tak, aby w przypadku powodzenia wysyłania powiadomień kierować ruch do nowej wersji.
Oto przykłady niektórych wersji mojej aplikacji php-amarcord:

Jak to wszystko robimy?
- Tworząc jeden idealny plik YAML:
cloudbuild.yaml - Tworząc aktywator kompilacji w Cloud Build.
- Połączenie z repozytorium GitHub przez interfejs Cloud Build.
Utwórz wyzwalacz (i połącz repozytorium)
- Otwórz stronę https://console.cloud.google.com/cloud-build/triggers.
- Kliknij „Utwórz aktywator”.
- Kompilacja:
- Nazwa: coś znaczącego, np.
on-git-commit-build-php-app - Zdarzenie: wypchnięcie do gałęzi
- Źródło: „Połącz nowe repozytorium”

- Po prawej stronie otworzy się okno „Połącz repozytorium”.
- Dostawca źródłowy: „Github” (pierwszy)
- „Kontynuuj”
- Uwierzytelnianie otworzy okno w GitHubie, w którym będzie można przeprowadzić uwierzytelnianie krzyżowe. Postępuj zgodnie z instrukcjami i zachowaj cierpliwość. Jeśli masz dużo repozytoriów, może to zająć trochę czasu.
- „Wybierz repozytorium” Wybierz konto lub repozytorium i zaznacz pole „Rozumiem...”.
- Jeśli pojawi się błąd: aplikacja na GitHubie nie jest zainstalowana w żadnym Twoim repozytorium, kliknij „Zainstaluj Google Cloud Build” i postępuj zgodnie z instrukcjami.
Kliknij Połącz.
- Bingo! Twoje repozytorium jest teraz połączone.
- Wróć do części Aktywator…
- Konfiguracja: wykryta automatycznie (*)
- Zaawansowane: wybierz konto usługi „[PROJECT_NUMBER]- compute@developer.gserviceaccount.com”
- xxxxx to identyfikator Twojego projektu.
- Domyślne konto usługi Compute jest odpowiednie w przypadku podejścia laboratoryjnego – nie używaj go w środowisku produkcyjnym. ( więcej informacji).
- pozostawić wszystko inne bez zmian.
- Kliknij przycisk „Utwórz”.
(*) To najprostszy sposób, ponieważ sprawdza, czy w repozytorium znajduje się plik Dockerfile lub cloudbuild.yaml. Jednak cloudbuild.yaml daje Ci prawdziwą możliwość decydowania, co zrobić na danym etapie.
Mam moc!
Teraz aktywator nie będzie działać, dopóki nie przyznasz kontu usługi Cloud Build (co to jest konto usługi? Adres e-mail „robota”, który wykonuje zadanie w Twoim imieniu – w tym przypadku tworzy elementy w chmurze.
Jeśli nie przyznasz SA uprawnień do tworzenia i wdrażania, nie będzie on w stanie tego zrobić. Na szczęście to proste.
- kliknij „Cloud Build” > „Ustawienia”.
- Konto usługi „[PROJECT_NUMBER]- compute@developer.gserviceaccount.com”
- Zaznacz te pola:
- Cloud Run
- Secret Manager
- Konta usługi
- Cloud Build
- Zaznacz też pole „Ustaw jako preferowane konto usługi”.

Gdzie jest plik YAML Cloud Build?
Zdecydowanie zachęcamy do poświęcenia czasu na utworzenie własnego pliku YAML Cloud Build.
Jeśli jednak nie masz czasu lub nie chcesz go poświęcać, możesz poszukać inspiracji w tym folderze rozwiązań: .solutions
Teraz możesz przesłać zmianę do GitHub i obserwować, jak Cloud Build wykonuje swoją część zadania.
Skonfigurowanie Cloud Build może być trudne. Oczekuj wymiany informacji przez:
- Sprawdzanie logów na stronie https://console.cloud.google.com/cloud-build/builds;region=global
- Znajdź swój błąd.
- Poprawienie kodu i ponowne wydanie polecenia git commit / git push.
- Czasami błąd nie występuje w kodzie, ale w konfiguracji. W takim przypadku możesz wydać nową kompilację z interfejsu (Cloud Build > „Triggery” > Uruchom).

Pamiętaj, że jeśli użyjesz tego rozwiązania, nadal musisz wykonać pewne czynności. Na przykład musisz ustawić zmienne środowiskowe dla nowo utworzonych punktów końcowych środowiska deweloperskiego i produkcyjnego:

Można to zrobić na dwa sposoby:
- Za pomocą interfejsu – przez ponowne ustawienie zmiennych środowiskowych.
- Za pomocą CLI, tworząc dla Ciebie „idealny” skrypt. Przykład znajdziesz tutaj: gcloud-run-deploy.sh . Musisz wprowadzić kilka zmian, np. w punkcie końcowym i numerze projektu. Numer projektu znajdziesz w przeglądzie Cloud.
Jak przesłać kod do GitHub?
Wykracza to poza zakres tego warsztatu.git push Jeśli jednak utkniesz i będziesz w Cloud Shell, możesz to zrobić na 2 sposoby:
- CLI. Dodaj lokalnie klucz SSH i dodaj zdalne repozytorium za pomocą adresu git@github.com:YOUR_USER/app-mod-workshop.git (zamiast http).
- VSCode. Jeśli używasz edytora Cloud Shell, możesz otworzyć kartę Kontrola źródła (Ctrl+Shift+G), kliknąć „Synchronizuj zmiany” i postępować zgodnie z instrukcjami. Powinno być możliwe uwierzytelnienie konta GitHub w VS Code, a pobieranie i wysyłanie zmian będzie od tego momentu bardzo proste.

Pamiętaj, aby git add clodubuild.yaml wśród innych plików, w przeciwnym razie nie będzie działać.
Głębokie a płytkie „równoległe środowiska deweloperskie i produkcyjne” [opcjonalnie]
Jeśli wersja modelu została skopiowana stąd, będziesz mieć 2 identyczne wersje DEV i PROD. To świetne rozwiązanie, które jest zgodne z regułą 10 aplikacji dwunastoczynnikowej.
Używamy jednak 2 różnych punktów końcowych sieci, aby aplikacja wskazywała tę samą bazę danych. W przypadku warsztatów to wystarczy, ale w rzeczywistości warto poświęcić trochę czasu na utworzenie odpowiedniego środowiska produkcyjnego. Oznacza to posiadanie 2 baz danych (jednej na potrzeby programowania, a drugiej na potrzeby produkcji) oraz wybranie miejsca, w którym będą one przechowywane na potrzeby odtwarzania awaryjnego i wysokiej dostępności. To wykracza poza zakres tych warsztatów, ale warto o tym pomyśleć.
Jeśli masz czas na przygotowanie „zaawansowanej” wersji produkcji, pamiętaj o wszystkich zasobach, które musisz powielić, takich jak:
- baza danych Cloud SQL (i prawdopodobnie instancja SQL);
- Zasobnik GCS
- funkcji w Cloud Functions.
- Możesz używać Gemini 1.5 Flash jako modelu w środowisku deweloperskim (tańszy, szybszy) i Gemini 1.5 Pro (bardziej wydajny).
Zastanów się, czy wartość ta powinna być taka sama w wersji produkcyjnej. Jeśli nie, powtórz te działania. Jest to oczywiście znacznie łatwiejsze w przypadku Terraform, gdzie możesz wstawić środowisko (-dev, -prod) jako sufiks do zasobów.
8. Moduł 6. Przenoszenie do Google Cloud Storage

Miejsce na dane

Obecnie aplikacja przechowuje stan w kontenerze Dockera. Jeśli urządzenie się zepsuje, aplikacja ulegnie awarii lub po prostu wdrożysz nową wersję, zostanie zaplanowana nowa wersja z nowym, pustym miejscem na dane: 🙈
Jak to naprawić? Istnieje kilka sposobów.
- przechowywanie obrazów w bazie danych, Tak zrobiłem w przypadku poprzedniej aplikacji PHP. To najprostsze rozwiązanie, które nie komplikuje sprawy. Ale na pewno zwiększa to opóźnienie i obciążenie bazy danych.
- Przenieś aplikację Cloud Run do rozwiązania przyjaznego dla pamięci masowej: GCE + dysk stały? Może GKE + Storage? Uwaga: to, co zyskujesz w zakresie kontroli, tracisz w zakresie elastyczności.
- Przejdź do GCS. Google Cloud Storage to najlepsza w swojej klasie usługa przechowywania danych w całym Google Cloud, która jest najbardziej typowym rozwiązaniem chmurowym. Wymaga to jednak użycia bibliotek PHP. Czy mamy biblioteki PHP 5.7 dla GCS? Czy
PHP 5.7obsługujeComposer(wygląda na to, że PHP 5.3.2 to najstarsza wersja obsługiwana przez Composer)? - Może użyć kontenera dodatkowego Dockera?
- Możesz też użyć montowania woluminów Cloud Run w GCS. Brzmi świetnie.
🤔 Migracja miejsca na dane (pytanie otwarte)
[Open Ended] W tym ćwiczeniu chcemy, abyś znalazł(-a) rozwiązanie, które pozwoli przenieść obrazy w taki sposób, aby zmiany zostały zachowane.
Test akceptacyjny
Nie chcę Ci podawać rozwiązania, ale chcę, żeby stało się to:
- Przesyłasz
newpic.jpg. Zobaczysz je w aplikacji. - Uaktualniasz aplikację do nowej wersji.
newpic.jpgnadal jest widoczny.
💡 Możliwe rozwiązanie (montowanie woluminów GCS w Cloud Run)
To bardzo eleganckie rozwiązanie, które pozwala nam osiągnąć stanowe przesyłanie plików bez dotykania kodu (poza wyświetlaniem opisu obrazu, ale to jest trywialne i służy tylko zadowoleniu oka).
Powinno to umożliwić zamontowanie folderu z Cloud Run w GCS, więc:
- Wszystkie przesłane pliki będą widoczne w aplikacji.
- Wszystkie pliki przesyłane do aplikacji będą w rzeczywistości przesyłane do GCS.
- Magia będzie działać na obiekty przesłane do GCS (rozdział 7).
Uwaga. Zapoznaj się z zapisami drobnym drukiem dotyczącymi FUSE. Jeśli wydajność jest problemem, NIE jest to w porządku.
Tworzenie zasobnika GCS
GCS to wszechobecna usługa przechowywania danych w Google Cloud. Jest to sprawdzone rozwiązanie, z którego korzystają wszystkie usługi GCP wymagające miejsca na dane.
Pamiętaj, że Cloud Shell eksportuje PROJECT_ID jako GOOGLE_CLOUD_PROJECT:
$ export PROJECT_ID=$GOOGLE_CLOUD_PROJECT
#!/bin/bash
set -euo pipefail
# Your Cloud Run Service Name, eg php-amarcord-dev
SERVICE_NAME='php-amarcord-dev'
BUCKET="${PROJECT_ID}-public-images"
GS_BUCKET="gs://${BUCKET}"
# Create bucket
gsutil mb -l "$GCP_REGION" -p "$PROJECT_ID" "$GS_BUCKET/"
# Copy original pictures there - better if you add an image of YOURS before.
gsutil cp ./uploads/*.png "$GS_BUCKET/"
Skonfiguruj Cloud Run tak, aby zamontować zasobnik w folderze /uploads/
Teraz przejdźmy do eleganckiej części. Tworzymy wolumin php_uploads i instruujemy Cloud Run, aby wykonał podłączenie FUSE w MOUNT_PATH (np. /var/www/html/uploads/):
#!/bin/bash
set -euo pipefail
# .. keep variables from previous script..
# Uploads folder within your docker container.
# Tweak it for your app code.
MOUNT_PATH='/var/www/html/uploads/'
# Inject a volume mount to your GCS bucket in the right folder.
gcloud --project "$PROJECT_ID" beta run services update "$SERVICE_NAME" \
--region $GCP_REGION \
--execution-environment gen2 \
--add-volume=name=php_uploads,type=cloud-storage,bucket="$BUCKET" \
--add-volume-mount=volume=php_uploads,mount-path="$MOUNT_PATH"
Teraz powtórz ten krok w przypadku wszystkich punktów końcowych, które chcesz przekierować do Cloud Storage.
Możesz to też zrobić w interfejsie.
- Na karcie „Woluminy” utwórz punkty montowania woluminu wskazujące Twój zasobnik typu „Zasobnik Cloud Storage”, np. o nazwie „php_uploads”.
- W sekcji Kontenery > Podłączenia woluminów podłącz utworzony wolumin do punktu woluminu wymaganego przez aplikację. Zależy to od pliku Dockerfile, ale może wyglądać tak:
var/www/html/uploads/.
Jeśli wszystko działa, po edytowaniu nowej wersji Cloud Run powinna pojawić się mniej więcej taka informacja:

Teraz przetestuj nową aplikację, przesyłając 1 nowy obraz do punktu końcowego /upload.php.
Obrazy powinny być płynnie przesyłane w GCS bez konieczności pisania ani jednej linii kodu PHP:

Co się właśnie stało?
Stało się coś magicznego.
Stara aplikacja ze starym kodem nadal działa. Nowy, zmodernizowany stos umożliwia nam przechowywanie wszystkich obrazów i zdjęć w aplikacji w zasobniku Cloud Bucket z zachowaniem stanu. Teraz nie ma już ograniczeń:
- Chcesz wysyłać e-maile za każdym razem, gdy otrzymasz obraz z treściami „niebezpiecznymi” lub „przedstawiającymi nagość”? Możesz to zrobić bez modyfikowania kodu PHP.
- Chcesz używać modelu multimodalnego Gemini za każdym razem, gdy pojawi się obraz, aby go opisać, i przesyłać bazę danych z opisem? Możesz to zrobić bez modyfikowania kodu PHP. Nie wierzysz mi? Czytaj dalej w rozdziale 7.
Otworzyliśmy sobie tutaj duże pole możliwości.
9. Moduł 7. Wzbogacanie aplikacji o funkcje Google Gemini

Masz teraz nowoczesną, odświeżoną aplikację PHP (jak Fiat 126 z 2024 r.) z pamięcią masową w chmurze.
Do czego służy
Wymagania wstępne
W poprzednim rozdziale modelowe rozwiązanie pozwoliło nam zamontować obrazy /uploads/ w GCS, de facto oddzielając logikę aplikacji od pamięci obrazów.
To ćwiczenie wymaga:
- Ukończ ćwiczenie w rozdziale 6 (pamięć).
- Musisz mieć zasobnik GCS z przesłanymi obrazami, do którego użytkownicy przesyłają zdjęcia w Twojej aplikacji.
Konfigurowanie funkcji w Cloud Functions (w Pythonie)
Zastanawiasz się, jak wdrożyć aplikację opartą na zdarzeniach? Na przykład:
- gdy nastąpi <zdarzenie> => wyślij e-maila
- gdy nastąpi <zdarzenie> => jeśli <warunek> jest spełniony, zaktualizuj bazę danych.
Wydarzenie może być dowolne, np. nowy rekord dostępny w BigQuery, nowy obiekt zmieniony w folderze w GCS lub nowa wiadomość oczekująca w kolejce w Pub/Sub.
Google Cloud obsługuje wiele paradygmatów, które umożliwiają osiągnięcie tego celu. W szczególności:
- EventArc Dowiedz się, jak otrzymywać zdarzenia GCS. Świetnie nadaje się do tworzenia DAG-ów i orkiestrowania działań na podstawie instrukcji warunkowych w chmurze.
- Cloud Scheduler Sprawdza się na przykład w przypadku zadania crona o północy w chmurze.
- Cloud Workflows Podobnie jak Event Arc, umożliwia
- Funkcje Cloud Run (znane też jako
lambdas). - Cloud Composer. Jest to w zasadzie wersja Apache Airflow od Google, która świetnie sprawdza się też w przypadku DAG.
W tym ćwiczeniu przyjrzymy się funkcji w Cloud Functions, aby osiągnąć spektakularny rezultat. Zapewnimy Ci też opcjonalne ćwiczenia.
Pamiętaj, że przykładowy kod jest dostępny w katalogu .solutions/.
Konfigurowanie funkcji w Cloud Functions (🐍 Python)
Próbujemy stworzyć bardzo ambitny GCF.
- Gdy w GCS zostanie utworzony nowy obraz… (prawdopodobnie dlatego, że ktoś przesłał go w aplikacji – ale nie tylko)
- .. wywołać Gemini, aby opisać obraz i uzyskać jego opis tekstowy .. (warto sprawdzić typ MIME i upewnić się, że jest to obraz, a nie plik PDF, MP3 lub tekstowy)
- .. i zaktualizować bazę danych tym opisem. (może to wymagać wprowadzenia poprawek w bazie danych, aby dodać kolumnę
descriptiondo tabeliimages).
Popraw bazę danych, aby dodać description do obrazów
- Otwórz Cloud SQL Studio:

- Wpisz nazwę użytkownika i hasło do bazy danych obrazów.
- Wstrzyknij ten kod SQL, który dodaje kolumnę z opisem obrazu:
ALTER TABLE images ADD COLUMN description TEXT;

I bingo! Sprawdź teraz, czy to zadziałało:
SELECT * FROM images;
Powinna się wyświetlić nowa kolumna z opisem:

Napisz Gemini f(x)
Uwaga. Ta funkcja została utworzona z pomocą Gemini Code Assist.
Uwaga. Podczas tworzenia tej funkcji mogą wystąpić błędy uprawnień. Niektóre z nich zostały opisane poniżej w sekcji „Możliwe błędy”.
- Włączanie interfejsów API
- Otwórz stronę https://console.cloud.google.com/functions/list.
- Kliknij „Utwórz funkcję”.
- Włączanie interfejsów API za pomocą kreatora interfejsów API:

Możesz utworzyć GCF w interfejsie lub w wierszu poleceń. W tym przypadku użyjemy wiersza poleceń.
Możliwy kod znajdziesz w sekcji .solutions/.
- Utwórz folder na swój kod, np. „gcf/”. Otwórz folder.
- Utwórz plik
requirements.txt:
google-cloud-storage
google-cloud-aiplatform
pymysql
- Utwórz funkcję w Pythonie. Przykładowy kod znajdziesz tutaj: gcf/main.py.
#!/usr/bin/env python
"""Complete this"""
from google.cloud import storage
from google.cloud import aiplatform
import vertexai
from vertexai.generative_models import GenerativeModel, Part
import os
import pymysql
import pymysql.cursors
# Replace with your project ID
PROJECT_ID = "your-project-id"
GEMINI_MODEL = "gemini-1.5-pro-002"
DEFAULT_PROMPT = "Generate a caption for this image: "
def gemini_describe_image_from_gcs(gcs_url, image_prompt=DEFAULT_PROMPT):
pass
def update_db_with_description(image_filename, caption, db_user, db_pass, db_host, db_name):
pass
def generate_caption(event, context):
"""
Cloud Function triggered by a GCS event.
Args:
event (dict): The dictionary with data specific to this type of event.
context (google.cloud.functions.Context): The context parameter contains
event metadata such as event ID
and timestamp.
"""
pass
- Wypchnij funkcję. Możesz użyć skryptu podobnego do tego: gcf/push-to-gcf.sh.
Uwaga 1. Upewnij się, że zmienne środowiskowe mają odpowiednie wartości, lub po prostu dodaj je na górze (GS_BUCKET=blah, ..):
Uwaga 2. Spowoduje to przesłanie całego kodu lokalnego (.), więc umieść kod w określonym folderze i używaj .gcloudignore jak profesjonalista, aby uniknąć przesyłania dużych bibliotek. ( przykład).
#!/bin/bash
set -euo pipefail
# add your logic here, for instance:
source .env || exit 2
echo "Pushing ☁️ f(x)☁ to 🪣 $GS_BUCKET, along with DB config.. (DB_PASS=$DB_PASS)"
gcloud --project "$PROJECT_ID" functions deploy php_amarcord_generate_caption \
--runtime python310 \
--region "$GCP_REGION" \
--trigger-event google.cloud.storage.object.v1.finalized \
--trigger-resource "$BUCKET" \
--set-env-vars "DB_HOST=$DB_HOST,DB_NAME=$DB_NAME,DB_PASS=$DB_PASS,DB_USER=$DB_USER" \
--source . \
--entry-point generate_caption \
--gen2
Uwaga: w tym przykładzie wywoływana będzie metoda generate_caption, a funkcja Cloud Function przekaże do niej zdarzenie GCS ze wszystkimi odpowiednimi informacjami (nazwą zasobnika, nazwą obiektu itp.). Poświęć trochę czasu na debugowanie tego słownika zdarzeń w Pythonie.
Testowanie funkcji
Testy jednostkowe
Funkcja ma wiele ruchomych części. Możesz chcieć przetestować wszystkie pojedyncze elementy.
Przykład znajdziesz w pliku gcf/test.py.
Interfejs Cloud Functions
Poświęć też trochę czasu na zapoznanie się z funkcją w interfejsie. Warto przejrzeć wszystkie karty, zwłaszcza Source (moja ulubiona), Variables, Trigger i Logs. Na karcie Logs spędzisz dużo czasu, rozwiązując problemy (możliwe błędy znajdziesz też na dole tej strony). Nie zapomnij też sprawdzić Permissions.

Test E2E
Czas ręcznie przetestować funkcję.
- Otwórz aplikację i zaloguj się.
- Prześlij zdjęcie (nie za duże, bo duże obrazy mogą powodować problemy).
- sprawdź w interfejsie, czy zdjęcie zostało przesłane.
- Sprawdź w Cloud SQL Studio, czy opis został zaktualizowany. Zaloguj się i uruchom to zapytanie:
SELECT * FROM images.

To działa! Możemy też zaktualizować interfejs, aby wyświetlać ten opis.
Aktualizacja PHP, aby wyświetlać [opcjonalnie]
Udowodniliśmy, że aplikacja działa. Dobrze byłoby jednak, gdyby użytkownicy też mogli zobaczyć ten opis.
Nie musimy być ekspertami w zakresie PHP, aby dodać opis do index.php. Ten kod powinien (tak, Gemini też mi go napisał!):
<?php if (!empty($image['description'])): ?>
<p class="font-bold">Gemini Caption:</p>
<p class="italic"><?php echo $image['description']; ?></p>
<?php endif; ?>
Umieść ten kod w tagu foreach w dowolnym miejscu.
W kolejnych krokach widzimy też ładniejszą wersję interfejsu dzięki Gemini Code Assist. Wersja z ładnym formatowaniem może wyglądać tak:

Wnioski
Masz funkcję w Cloud Functions, która jest aktywowana, gdy w GCS pojawiają się nowe obiekty. Potrafi ona opisywać zawartość obrazu tak jak człowiek i automatycznie aktualizować bazę danych. Niesamowite!
Co dalej? Możesz zastosować to samo rozumowanie, aby uzyskać 2 przydatne funkcje.
[opcjonalnie] Dodaj kolejne funkcje w Cloud Functions [otwarte]
Przychodzą mi na myśl jeszcze 2 dodatkowe funkcje.
📩 Aktywator e-mail
Wywoływacz e-mail, który wysyła e-maila za każdym razem, gdy ktoś wyśle zdjęcie.
- Za często? Dodaj kolejne ograniczenie: duże zdjęcie lub zdjęcie, którego treść w Gemini zawiera słowa „nude/nudity/violent” (nagość/przemoc).
- Sprawdź
EventArc.
🚫 Automatyczna moderacja nieodpowiednich zdjęć
Obecnie administratorzy oznaczają obrazy jako „nieodpowiednie”. A może powierzyć Gemini moderowanie pokoju? Dodaj test, który będzie oznaczać nieodpowiednie treści wywołujące, i zaktualizuj bazę danych, tak jak w przypadku poprzedniej funkcji. Oznacza to w zasadzie użycie poprzedniej funkcji, zmianę promptu i zaktualizowanie bazy danych na podstawie odpowiedzi.
Zastrzeżenie: Generatywna AI ma nieprzewidywalne dane wyjściowe. Upewnij się, że „wyniki kreatywne” Gemini są „pod kontrolą”. Możesz poprosić o odpowiedź deterministyczną, np. wynik ufności od 0 do 1, kod JSON itp. Możesz to zrobić na wiele sposobów, np.: * używając bibliotek Pythona pydantic, langchain itp.; * korzystając z ustrukturyzowanych danych wyjściowych Gemini.
Wskazówka: Możesz mieć WIELE funkcji lub jeden prompt, który wymusza odpowiedź w formacie JSON (świetnie sprawdza się w przypadku „Gemini Structured Output”, jak wspomnieliśmy powyżej), np.:
Jakiego prompta należy użyć, aby wygenerować ten obraz?
{
"description": "This is the picture of an arrosticino",
"suitable": TRUE
}
Możesz dodać do promptu dodatkowe pola, aby uzyskać informacje, np. czy jest w nim coś dobrego. Co w tym złego? Czy rozpoznajesz to miejsce? Czy na zdjęciu znajduje się tekst (OCR nigdy nie był łatwiejszy):
goods: „Wygląda na pyszne jedzenie”bads: „Wygląda na niezdrowe jedzenie”OCR: "Da consumare preferibilmente prima del 10 Novembre 2024"location: "Pescara, Lungomare"
Zwykle lepiej jest mieć funkcję N dla N wyników, ale wykonanie funkcji, która robi 10 rzeczy, jest niezwykle satysfakcjonujące. Więcej informacji znajdziesz w tym artykule Riccardo.
Możliwe błędy (głównie związane z IAM lub uprawnieniami)
Gdy po raz pierwszy opracowałem to rozwiązanie, napotkałem problemy z uprawnieniami IAM. Dodam je tutaj, aby okazać empatię i podsunąć pomysły na ich rozwiązanie.
Błąd: konto usługi ma niewystarczające uprawnienia
- Pamiętaj, że aby wdrożyć funkcję GCF, która nasłuchuje zasobnika GCS, musisz skonfigurować odpowiednie uprawnienia dla konta usługi używanego w tym zadaniu, jak na rysunku:

Może też być konieczne włączenie interfejsów API EventArc, co może potrwać kilka minut, zanim staną się one w pełni dostępne.
Błąd: brak wywołującego Cloud Run
- Kolejny komentarz z interfejsu do zarządzania uprawnieniami GCF: Rola wywołującego Cloud Run.

Ten błąd można naprawić, uruchamiając w obrazie polecenie podobne do fix-permissions.sh.
Ten problem został opisany tutaj: https://cloud.google.com/functions/docs/securing/authenticating
Błąd: przekroczono limit pamięci
Gdy uruchomiłem go po raz pierwszy, w logach pojawił się komunikat: „Przekroczono limit pamięci 244 MiB, wykorzystano 270 MiB. Rozważ zwiększenie limitu pamięci. Więcej informacji znajdziesz na stronie https://cloud.google.com/functions/docs/configuring/memory. Ponownie dodaj pamięć RAM do GCF. Możesz to łatwo zrobić w interfejsie. Oto możliwy wzrost:

Możesz też poprawić skrypt wdrażania Cloud Run, aby zwiększyć MEM/CPU. Potrwa to nieco dłużej.
Błąd: opublikowano w PubSub
Podczas tworzenia aktywatora za pomocą GCF w wersji 1 wystąpił ten błąd:

Możesz to łatwo naprawić, przechodząc do IAM i przypisując do konta usługi rolę „Publikujący w Pub/Sub”.
Błąd: Vertex AI nie był używany
Jeśli pojawi się ten błąd:
Odmowa dostępu: 403. Interfejs Vertex AI API nie był wcześniej używany w projekcie YOUR_PROJECT lub jest wyłączony. Aby go włączyć, wejdź na https://console.developers.google.com/apis/api/aiplatform.googleapis.com/overview?project=YOR_PROJECT
Wystarczy włączyć interfejsy Vertex AI API. Najprostszy sposób na włączenie WSZYSTKICH potrzebnych interfejsów API:
- https://console.cloud.google.com/vertex-ai
- Kliknij „Włącz wszystkie zalecane interfejsy API”.

Błąd: nie znaleziono aktywatora EventArc.
Jeśli pojawi się ten komunikat, ponownie wdróż funkcję.

Błąd: 400 – agenci usługi są udostępniani
400 – trwa udostępnianie agentów usługi ( https://cloud.google.com/vertex-ai/docs/general/access-control#service-agents ). Agenci usługi są potrzebni do odczytania podanego pliku Cloud Storage. Spróbuj ponownie za kilka minut.
Jeśli tak się stanie, odczekaj trochę lub poproś o pomoc pracownika Google.
10. Moduł 8. Tworzenie celów SLO dotyczących dostępności
W tym rozdziale staramy się to osiągnąć:
- Tworzenie wskaźników poziomu usług
- Tworzenie poziomów SLO na podstawie wskaźników SLI
- Tworzenie alertów na podstawie docelowych poziomów usług

Jest to bardzo ważny temat dla autora, ponieważ Riccardo pracuje w Google Cloud w obszarze SRE / DevOps.
(otwarte) Utwórz wskaźniki poziomu usług i docelowe poziomy usług dla tej aplikacji
Jak dobra jest aplikacja, jeśli nie wiesz, kiedy nie działa?
Co to jest SLO?
O rany! Google wymyśliło docelowe poziomy usług. Więcej informacji na ten temat znajdziesz w tych artykułach:
- Książka SRE – rozdział 2. Wdrażanie docelowych poziomów usług ( 👉 więcej książek o SRE)
- Art of SLOs ( świetny film). To świetne szkolenie, które pomoże Ci dowiedzieć się więcej o tym, jak opracować idealny poziom SLO dla Twojej usługi.
- Kurs SRE w serwisie Coursera Przyłożyłem do tego rękę.
Krok 1. Utwórz wskaźnik SLI/SLO dostępności
Zacznijmy od SLO dostępności, ponieważ jest to najprostszy i prawdopodobnie najważniejszy parametr, który chcesz mierzyć.
Na szczęście Cloud Run ma wbudowaną obsługę SLO dzięki Istio.
Gdy aplikacja jest już w Cloud Run, jest to bardzo proste. Zajmuje mi to 30 sekund.
- Otwórz stronę Cloud Run.
- Kliknij/wybierz aplikację.
- Wybierz kartę
SLOs. - Kliknij „+ Utwórz SLO”.
- Dostępność, na żądanie
- Dalej
- Miesiąc kalendarzowy / 99%.
- kliknij „Utwórz SLO”;

Krok 2. Skonfiguruj alerty dotyczące tego docelowego poziomu usług
Proponuję utworzyć 2 alerty:
- Jeden z niskim tempem wykorzystania środków („Slowburn”), który będzie wysyłać Ci alerty e-mailem (symuluje zgłoszenie o niskim priorytecie).
- jeden z wysokim tempem wykorzystania środków („Fastburn”), który będzie Cię powiadamiać SMS-em (symuluje zgłoszenie o wysokim priorytecie / pager);
Wróć do SLO tab.
Zrób to 2 razy:

- Kliknij „Utwórz alert docelowego poziomu usług” (przycisk 🔔 z plusem w środku po prawej stronie).
- Okres wyszukiwania wstecz, próg tempa wykorzystania:
- [FAST]. Pierwsze:
60min /10x - [SLOW]. Sekunda:
720min /2x - Kanał powiadomień: kliknij Zarządzaj kanałami powiadomień.
- Najpierw „Email” -> Dodaj nowe -> ..
- Po drugie, „SMS” –> Dodaj nowy –> Zweryfikuj na telefonie.
- Wskazówka: lubię używać emotikonów w nazwach. To świetna zabawa podczas prezentacji.
- Gdy skończysz, kliknij duży znak X w prawym górnym rogu.
- Najpierw wybierz telefon (szybko), a potem e-mail (wolno).
- Dodaj przykładową dokumentację, np.:
[PHP Amarcord] Riccardo told me to type sudo reboot or to check documentation in http://example.com/playbooks/1.php but I guess he was joking.
Bingo!
Wynik końcowy
To ćwiczenie możemy uznać za zakończone, gdy będziesz mieć 1 działający SLO i 2 alerty dotyczące dostępności, a powiadomienia będą wysyłane na Twój adres e-mail i telefon.
Możesz dodać opóźnienie (bardzo do tego zachęcam) lub nawet bardziej złożone. W przypadku opóźnienia wybierz wartość, która Twoim zdaniem jest odpowiednia. Jeśli masz wątpliwości, wybierz 200 ms.
11. Dalsze kroki
Ukończono WSZYSTKO. Czego brakuje?
Kilka kwestii do przemyślenia:
Wypróbuj Gemini
Możesz korzystać z Gemini w 2 wersjach:
- Vertex AI „Sposób Enterprise” powiązany z GCP, który omówiliśmy w rozdziale 7 (GCF+Gemini). Całe uwierzytelnianie działa magicznie, a usługi są ze sobą doskonale połączone.
- AI od Google „Ścieżka konsumenta”. Klucz interfejsu Gemini API możesz uzyskać tutaj. Następnie możesz zacząć tworzyć małe skrypty, które można powiązać z dowolnym zadaniem, które już masz (prace zastrzeżone, inne chmury, localhost itp.). Wystarczy, że zastąpisz klucz interfejsu API, a kod zacznie magicznie działać.
Zachęcamy do wypróbowania (2) w ramach własnych projektów.
Ulepszenia interfejsu
Nie znam się na interfejsach. Ale Gemini tak! Możesz po prostu wziąć jedną stronę PHP i napisać coś takiego:
I have a VERY old PHP application. I want to touch it as little as possible. Can you help me:
1. add some nice CSS to it, a single static include for tailwind or similar, whatever you prefer
2. Transform the image print with description into cards, which fit 4 per line in the canvas?
Here's the code:
-----------------------------------
[Paste your PHP page, for instance index.php - mind the token limit!]
Możesz to łatwo zrobić w mniej niż 5 minut, korzystając z Cloud Build. :)
Odpowiedź Gemini była idealna (nie musiałem niczego zmieniać):

A oto nowy układ w osobistej aplikacji autora:

Uwaga: kod jest wklejony jako obraz, ponieważ nie chcemy zachęcać Cię do jego kopiowania. Chcemy, aby Gemini napisał go za Ciebie, uwzględniając Twoje własne kreatywne ograniczenia interfejsu użytkownika lub interfejsu. Zaufaj nam, po tym procesie pozostaną Ci bardzo drobne zmiany.
Bezpieczeństwo
Odpowiednie zabezpieczenie tej aplikacji nie jest celem tych 4-godzinnych warsztatów, ponieważ wydłużyłoby czas ich ukończenia o 1–2 rzędy wielkości.
Ten temat jest jednak bardzo ważny. Zebraliśmy kilka pomysłów w SECURITY.
12. Gratulacje!
Gratulacje 🎉🎉🎉 , udało Ci się zmodernizować starszą aplikację PHP za pomocą Google Cloud.

Podsumowując, z tego ćwiczenia dowiesz się:
- Jak wdrożyć bazę danych w Google Cloud SQL i przenieść do niej istniejącą bazę danych.
- Jak skonteneryzować aplikację PHP za pomocą Dockera i Buildpacków oraz zapisać jej obraz w Google Cloud Artifact Registry
- Jak wdrożyć skonteneryzowaną aplikację w Cloud Run i uruchomić ją w Cloud SQL
- Jak bezpiecznie przechowywać i używać poufnych parametrów konfiguracji (np. hasła do bazy danych) za pomocą usługi Google Secret Manager
- Jak skonfigurować potok CI/CD za pomocą Google Cloud Build, aby automatycznie kompilować i wdrażać aplikację PHP przy każdym przeniesieniu kodu do repozytorium GitHub.
- Jak używać Cloud Storage do „przenoszenia” zasobów aplikacji do chmury
- Jak wykorzystać technologie bezserwerowe do tworzenia niesamowitych przepływów pracy w Google Cloud bez modyfikowania kodu aplikacji.
- Wykorzystaj możliwości multimodalne Gemini w odpowiednim przypadku użycia.
- Wdrażanie zasad SRE w Google Cloud
To świetny początek Twojej przygody z modernizacją aplikacji w Google Cloud.
🔁 Opinie
Jeśli chcesz podzielić się z nami opinią na temat tych warsztatów, wypełnij ten formularz opinii.
Chętnie poznamy Twoją opinię, a także prośby o scalenie dotyczące fragmentów kodu, z których jesteś szczególnie dumny(-a).
🙏 Pozdrawiamy
Autor dziękuje Mirko Gilioli i Maurizio Ipsale z firmy Datatonic za pomoc w opracowaniu i testowaniu rozwiązania.
