← Blog
Kubernetes15 min czytania

Online Boutique — poliglotowa demonstracja mikroserwisów na GKE

Dziesięć serwisów aplikacyjnych w sześciu językach, rozmawiających przez gRPC, wdrażanych jednym plikiem YAML o rozmiarze dwudziestu dwóch kilobajtów. Do sprawdzania klastra — siatki usług, polityk sieciowych, autoskalowania i obserwowalności — jest to najlepszy dostępny wzorzec obciążenia. Wyjaśniamy też, dlaczego tej architektury nie wolno kopiować do sklepu klienta.

Zbudowanie klastra to jedno, a udowodnienie, że działa — drugie. Postawiłeś siatkę usług, polityki sieciowe, kontroler wejścia, zbieranie metryk i autoskalowanie. Teraz potrzebujesz obciążenia, na którym da się to sprawdzić: ruchu między kilkoma serwisami, wywołań przechodzących przez granice, czegoś, co zacznie generować metryki i śledzenia.

Napisanie takiej aplikacji testowej jest projektem samym w sobie, a napisanie jej w kilku językach — projektem na tydzień. I dokładnie tę dziurę zapełnia Online Boutique (github.com/GoogleCloudPlatform/microservices-demo): kompletny sklep internetowy złożony z dziesięciu serwisów w sześciu językach, rozmawiających przez gRPC, wdrażany jednym poleceniem.

Jest w tym jednak druga strona, którą trzeba powiedzieć od razu, bo to najczęstsze nieporozumienie wokół tego repozytorium: jest to narzędzie do sprawdzania infrastruktury, a nie wzorzec architektury do skopiowania. Wrócę do tego w osobnej sekcji, bo pomyłka w tę stronę bywa kosztowna.

Stan projektu

Dane z API GitHuba na 15 października 2026:

  • 20 911 gwiazdek i — liczba, która mówi tu najwięcej — 10 433 forki. Stosunek forków do gwiazdek bliski połowie jest podpisem materiału, który ludzie klonują i przerabiają, a nie tylko obserwują,
  • repozytorium założone 3 sierpnia 2018 — osiem lat, licencja Apache-2.0,
  • ostatni push dwa dni przed napisaniem tego tekstu, wersja 0.10.6 z 13 lipca 2026,
  • zaledwie 63 otwarte zgłoszenia przy tej skali popularności,
  • utrzymanie widać w commitach: automatyczne aktualizacje zależności, w tym aktualizacja biblioteki gRPC oznaczona jako poprawka bezpieczeństwa, podniesienie obrazu Javy i modułów Terraforma.

Jedno zdanie z README warto podkreślić, bo przeczy nazwie tematu: „aplikacja działa na dowolnym klastrze Kubernetesa". Google używa jej do prezentowania własnych usług i przewodnik startowy prowadzi przez GKE, ale przewodnik rozwojowy opisuje uruchomienie na Minikube i Kindzie. To nie jest demonstracja zamknięta w jednej chmurze.

Dziesięć serwisów, sześć języków, jeden protokół

Tabela w README ma jedenaście pozycji, z czego dziesięć to serwisy aplikacyjne, a jedenasta to generator obciążenia. Po wdrożeniu w klastrze widać dwanaście podów, bo Redis dla koszyka stoi osobno. Podział na języki jest celowo nierówny:

  • Go — frontend (serwer HTTP z witryną), productcatalogservice (katalog z pliku JSON wraz z wyszukiwaniem), shippingservice (wycena i „wysyłka") oraz checkoutservice, który orkiestruje płatność, wysyłkę i powiadomienie,
  • C# — cartservice, trzymający koszyk w Redisie,
  • Node.js — currencyservice oraz paymentservice (obciążenie karty, atrapa),
  • Python — emailservice (potwierdzenie zamówienia, atrapa) i recommendationservice (rekomendacje na podstawie koszyka),
  • Java — adservice, dobierający reklamy tekstowe do słów kontekstowych,
  • Python z Locustem — generator obciążenia.

Wszystko rozmawia przez gRPC, a opisy w Protocol Buffers leżą w osobnym katalogu repozytorium — co samo w sobie jest dobrym materiałem do nauki, bo pokazuje kompletny zestaw kontraktów dla działającego systemu, nie pojedynczy przykład.

Dwa szczegóły z tabeli zasługują na wyróżnienie. Serwis walutowy pobiera prawdziwe kursy z Europejskiego Banku Centralnego i jest opisany jako serwis o najwyższej liczbie zapytań na sekundę — czyli w tym systemie najgorętszym punktem jest przeliczanie walut, co jest realistyczne i wcale nieoczywiste. Drugi: frontend nie ma rejestracji ani logowania, a identyfikatory sesji generuje automatycznie dla każdego użytkownika. Znika w ten sposób cała warstwa uwierzytelniania — dla demonstracji infrastruktury zbędna, ale to jedna z rzeczy, o których trzeba pamiętać przy ocenie, czym ta aplikacja jest.

Cały kontrakt w sześciu kilobajtach

Zajrzałem do katalogu z opisami interfejsów i wynik jest wart podania, bo działa jako lekcja sam w sobie. Kompletny kontrakt tego systemu to jeden plik o rozmiarze sześciu kilobajtów, w którym zdefiniowano dziewięć usług i piętnaście metod zdalnych.

Piętnaście wywołań na dziesięć serwisów — czyli średnio półtora na serwis. Serwis rekomendacji ma dokładnie jedną metodę, katalog produktów kilka, a większość pozostałych po jednej albo dwie. Warto się przy tej liczbie zatrzymać, bo jest w niej dobra rada projektowa: granice między serwisami zostały wyznaczone tak, żeby przez każdą przechodziło bardzo mało operacji. Serwis, do którego prowadzi jedno wywołanie, jest zrozumiały i wymienialny; serwis z trzydziestoma metodami jest rozproszonym monolitem z dodatkowym opóźnieniem sieciowym.

Dla kogoś, kto uczy się gRPC, ten plik jest zresztą lepszym materiałem niż dokumentacja: pokazuje kompletny, spójny zestaw kontraktów działającego systemu — z typami żądań i odpowiedzi, wspólnymi strukturami pieniędzy i adresów — a nie oderwany przykład jednej usługi.

Dwadzieścia dwa kilobajty YAML-a

Największą praktyczną zaletą tego repozytorium jest to, jak mało trzeba zrobić, żeby je uruchomić. Cały sklep — dwanaście podów, serwisy, konfiguracja — jest jednym plikiem manifestu o rozmiarze dwudziestu dwóch kilobajtów:

kubectl apply -f ./release/kubernetes-manifests.yaml
kubectl get pods

Po kilku minutach dwanaście podów jest w stanie działającym, a adres zewnętrzny frontendu wyciąga się z jednego serwisu. Repozytorium klonuje się przy tym z gałęzi głównej wersji i bez historii, co przy ośmiu latach commitów oszczędza sporo transferu:

git clone --depth 1 --branch v0 https://github.com/GoogleCloudPlatform/microservices-demo.git

Do tego dochodzi wariant wdrożenia przez Terraform oraz — dla klastra na GKE — polecenie tworzące klaster w trybie automatycznym. Ale sam manifest działa wszędzie i to jest ta droga, którą bym szedł: klaster mam swój, aplikacja jest tylko obciążeniem.

Prawdziwy produkt: piętnaście komponentów Kustomize

Tu jest sedno użyteczności tego repozytorium dla kogoś, kto utrzymuje klastry. Aplikacja jest bazą, a wartość leży w piętnastu komponentach Kustomize, którymi się ją modyfikuje. Kilka z nich odpowiada dokładnie na pytania, które przy odbiorze klastra trzeba sobie zadać:

  • network-policies — wdrożenie z politykami sieciowymi. Najprostszy sposób, żeby sprawdzić, czy wtyczka sieciowa w klastrze faktycznie je wymusza, a nie tylko przyjmuje obiekty,
  • service-mesh-istio — wariant dla siatki usług, wraz z osobnym manifestem dla Istio,
  • non-public-frontend — bez publicznego równoważnika obciążenia. Przydatne, gdy klaster testowy nie ma wychodzić do internetu,
  • container-images-registry oraz warianty ustawiające znacznik i przyrostek obrazów — czyli przestawienie całości na własny rejestr. To jest komponent, którego szuka każdy, kto testuje klaster odcięty od internetu albo z wymuszonym skanowaniem obrazów,
  • without-loadgenerator — bez generatora ruchu, gdy chcemy podać własny,
  • google-cloud-operations — śledzenie i profilowanie w usługach Google,
  • single-shared-session — jedna wspólna sesja zamiast osobnej dla każdego użytkownika,
  • oraz warianty podmieniające magazyny danych na usługi zarządzane — Spanner, AlloyDB i Memorystore — a także zmieniające markę witryny i adres bazowy.

Ta lista tłumaczy, dlaczego repozytorium ma dziesięć tysięcy forków. Nie jest to aplikacja z kilkoma opcjami, a stanowisko badawcze z wymiennymi elementami — i każdy, kto potrzebował sprawdzić jedną konkretną rzecz w klastrze, brał je i przerabiał pod siebie.

Generator obciążenia, czyli najbardziej niedoceniana część

Jedenasty element zestawu jest tym, który najczęściej decyduje o użyteczności całości: generator oparty na Locuście, wysyłający nieprzerwanie żądania imitujące realistyczne zachowania kupujących.

Znaczenie tego jest bardzo praktyczne. Autoskalowanie na pustym klastrze nie skaluje niczego. Pulpit siatki usług bez ruchu pokazuje zera. Śledzenie rozproszone bez żądań nie ma czego śledzić. Do sprawdzenia, czy te mechanizmy są poprawnie skonfigurowane, potrzebny jest ruch — i to nie ruch w postaci pętli z narzędziem obciążającym pojedynczy adres, a przechodzący przez kilka serwisów w sposób przypominający prawdziwe sesje.

Dlatego domyślne wdrożenie startuje z generatorem włączonym, a wyłączenie go jest osobnym komponentem — właściwa kolejność domyślnych zachowań. Jeśli klaster ma pokazać metryki od pierwszej minuty, ruch musi się pojawić bez dodatkowej pracy.

Uruchomienie lokalne i jego cena

Wdrożenie gotowego manifestu to jedna sprawa, a praca nad kodem — druga. Przewodnik rozwojowy prowadzi przez Skaffolda w wersji 2.0.2 lub nowszej, który buduje i wdraża wszystkie obrazy hurtowo. Dwa polecenia obsługują cały cykl: jedno wdraża, a drugie przebudowuje i wdraża automatycznie w trakcie wprowadzania zmian w kodzie.

Warto jednak znać liczby, zanim ktoś to odpali na laptopie. Przewodnik podaje dla Minikube konkretne wymagania: cztery rdzenie, 4 GB pamięci i 32 GB miejsca na dysku. A pierwsze uruchomienie budujące obrazy dla dziesięciu serwisów w sześciu językach zajmuje około dwudziestu minut — co przewodnik uczciwie zapowiada.

Praktyczny wniosek: do sprawdzania infrastruktury bierz gotowy manifest, a Skaffolda tylko wtedy, gdy faktycznie modyfikujesz kod serwisów. Różnica to kilka minut wobec pół godziny i kilkunastu gigabajtów obrazów na dysku. Alternatywą dla Minikube jest Kind, uruchamiany jednym poleceniem — lżejszy, jeśli nie potrzebujemy pełnej maszyny wirtualnej.

Jest tu jeszcze jeden szczegół dla kogoś, kto chce z tego zrobić stanowisko badawcze na dłużej: przewodnik ma osobną sekcję o dodawaniu nowego mikroserwisu. Czyli da się dołożyć własny serwis w wybranym języku i zobaczyć, jak wpisuje się w siatkę usług, obserwowalność i polityki — na systemie, o którym wiemy, że działa poprawnie.

Czego z tego nie wolno kopiować

Ta sekcja jest w moim odczuciu najważniejsza, bo dotyczy pomyłki popełnianej z dobrą wolą. „Referencyjny sklep w mikroserwisach od Google" brzmi jak wzorzec do naśladowania — i nim nie jest.

Dowody są w samym repozytorium. Płatność, wysyłka i wysyłanie wiadomości są atrapami, wprost tak opisanymi w tabeli. Katalog produktów pochodzi z pliku JSON. Nie ma rejestracji ani logowania. Nie ma trwałego magazynu zamówień. Koszyk żyje w Redisie. Innymi słowy: nie ma tu żadnego z elementów, które w prawdziwym sklepie stanowią większość pracy — a jest jedenaście osobnych procesów, żeby pokazać komunikację między nimi.

Podział na dziesięć serwisów w sześciu językach jest tu celowym wyostrzeniem dydaktycznym. Ma pokazać ruch między granicami, wielojęzyczność, kontrakty gRPC i to, jak siatka usług radzi sobie z takim systemem. Zastosowanie tego samego podziału w sklepie klienta byłoby błędem: sześć języków znaczy sześć zestawów zależności do aktualizowania, sześć kultur pisania testów i sześć sposobów logowania — przy funkcjonalności, którą jedna aplikacja z kolejką obsłuży taniej i pewniej.

Jest to o tyle warte powiedzenia, że argument „przecież Google robi to tak" pada w rozmowach o architekturze regularnie. Odpowiedź brzmi: Google robi tak w aplikacji, której zadaniem jest demonstrowanie infrastruktury, a nie sprzedawanie rzeczy. Jeśli ktoś chce dowodu, wystarczy pokazać, że serwis płatności zwraca zmyślony identyfikator transakcji.

Wariant z asystentem opartym na modelu

Wśród komponentów jest jeden nowszy i wart odnotowania: asystent zakupowy napędzany modelem Gemini, sugerujący produkty na podstawie zdjęcia. Wdraża się go jak każdy inny wariant, przez komponent Kustomize.

Dla nas ma to podwójną wartość. Po pierwsze, jest to gotowy przykład wpięcia funkcji opartej na modelu w istniejący system mikroserwisowy — z widocznym miejscem, w którym wywołanie modelu wchodzi w przepływ zakupowy. Po drugie, pokazuje realne zapotrzebowanie takiej funkcji na infrastrukturę, bo można ją włączyć i zobaczyć w śledzeniu, ile czasu dokłada do żądania. Jest to jednak wariant związany z konkretną chmurą, więc do klastra u innego dostawcy nie przeniesie się bez zmian.

Materiały poboczne warte więcej niż aplikacja

README kończy się długą listą materiałów zbudowanych na tej aplikacji i część z nich jest wartościowsza niż samo repozytorium, bo odpowiada na pytania, które zadaje się przy każdym wdrożeniu:

  • utwardzanie bezpieczeństwa obrazów kontenerów na przykładzie tej właśnie aplikacji,
  • porównanie obrazów bazowych — czy zaczynać od Alpine, od obrazu bez powłoki, czy od zupełnie pustego,
  • sondy stanu zdrowia gRPC w nowszych wersjach Kubernetesa — temat, na którym potyka się każdy, kto pierwszy raz wdraża usługę gRPC,
  • optymalizacja i zabezpieczanie kontenerów .NET pod Kubernetesa,
  • szyfrowanie ruchu do Redisa w siatce usług, wystawianie aplikacji siatkowych przez kontroler wejścia GKE oraz wdrożenia wieloregionowe.

Wspólną zaletą tych materiałów jest to, że opisują konkretne problemy na obciążeniu, które można uruchomić u siebie w pięć minut — czyli da się je przeczytać i natychmiast sprawdzić, zamiast wierzyć na słowo.

Pułapki

  • To demonstracja, nie wzorzec architektury. Płatność, wysyłka i poczta są atrapami, katalog jest w pliku JSON, uwierzytelniania nie ma,
  • Dwanaście podów kosztuje. Na klastrze rozliczanym za zasoby ciągle działający generator obciążenia to stała pozycja w rachunku — pamiętaj o usunięciu klastra po testach,
  • Generator obciążenia działa domyślnie, więc każdy pomiar wydajności czegokolwiek innego na tym klastrze jest nim zaburzony,
  • Przewodnik startowy prowadzi przez GKE i tworzy klaster jednym poleceniem — łatwo zostawić działający klaster i zapłacić za weekend,
  • Część wariantów jest związana z jedną chmurą: Spanner, AlloyDB, Memorystore, operacje w chmurze Google i asystent oparty na modelu,
  • Sześć języków to sześć łańcuchów zależności — przy własnym forku aktualizowanie tego jest realną pracą, którą w oryginale wykonuje automat,
  • Opis repozytorium mówi o dziesięciu serwisach, a sekcja architektury o jedenastu — rozbieżność wynika z tego, czy generator obciążenia liczyć jako serwis,
  • Serwis walutowy pobiera prawdziwe kursy z zewnątrz, więc w klastrze odciętym od internetu zachowa się inaczej niż w dokumentacji.

Gdzie to ma sens w naszej pracy

  • Odbiór klastra. Postawiony klaster u klienta trzeba czymś obciążyć, zanim wjedzie na niego produkcja. Jeden manifest, dwanaście podów, ruch od pierwszej minuty,
  • Sprawdzenie polityk sieciowych. Komponent z politykami odpowiada na pytanie, czy wtyczka sieciowa faktycznie je wymusza — a nie tylko przyjmuje bez błędu,
  • Wdrożenie siatki usług. Zanim wpuścimy w siatkę aplikację klienta, warto zobaczyć ją na systemie, o którym wiemy, że działa,
  • Test rejestru prywatnego i skanowania obrazów. Komponent przestawiający rejestr pozwala przepchnąć dwanaście obrazów przez procedurę klienta i sprawdzić, gdzie się zatrzyma,
  • Nauka gRPC w praktyce. Katalog z opisami Protocol Buffers dla działającego systemu jest lepszym materiałem niż pojedynczy przykład z dokumentacji,
  • Materiał do rozmowy o architekturze — jako przeciwwaga. Pokazanie, że referencyjny sklep w mikroserwisach ma zmyśloną płatność, bywa najskuteczniejszym argumentem przeciw dzieleniu aplikacji klienta na jedenaście części.

Podsumowanie

  • Dziesięć serwisów aplikacyjnych w sześciu językach, gRPC, plus generator obciążenia i Redis — razem dwanaście podów,
  • Jeden manifest o rozmiarze 22 kilobajtów i kilka minut do działającego systemu,
  • Działa na dowolnym klastrze, nie tylko na GKE,
  • Piętnaście komponentów Kustomize to prawdziwa wartość: polityki sieciowe, siatka usług, własny rejestr, brak publicznego wejścia,
  • Generator obciążenia jest włączony domyślnie — bez ruchu nie sprawdzisz ani autoskalowania, ani obserwowalności,
  • Serwis walutowy pobiera prawdziwe kursy i jest najgorętszym punktem systemu,
  • Płatność, wysyłka i poczta to atrapy, a uwierzytelniania nie ma wcale,
  • Nie kopiuj tej architektury do sklepu klienta — podział jest dydaktyczny, nie produkcyjny,
  • Usuń klaster po testach, bo dwanaście podów z generatorem ruchu kosztuje,
  • Cały kontrakt to dziewięć usług i piętnaście metod w jednym pliku — dobra lekcja o wyznaczaniu granic serwisów,
  • Do pracy nad kodem Skaffold, ale pierwsze budowanie to około dwudziestu minut i wymagania 4 rdzeni oraz 4 GB pamięci,
  • Materiały poboczne o utwardzaniu obrazów i sondach gRPC są warte przeczytania niezależnie od aplikacji.

Licencja: repozytorium jest na Apache-2.0 — wolno używać komercyjnie, modyfikować, wdrażać u klientów i redystrybuować, przy zachowaniu noty licencyjnej, pliku NOTICE, jeśli występuje, i odnotowaniu istotnych zmian w modyfikowanych plikach, wraz z jawną licencją patentową od kontrybutorów. Przy materiale, którego naturalnym trybem użycia jest fork i przeróbka — a forków jest ponad dziesięć tysięcy — jest to licencja właściwa i nie stawia żadnych przeszkód: wolno wziąć manifesty, przerobić je pod klaster klienta i zostawić w jego repozytorium, także w projekcie zamkniętym. Dwie rzeczy warto natomiast rozdzielić. Po pierwsze, licencja obejmuje kod i manifesty, ale nie usługi, do których część wariantów się podłącza: Spanner, AlloyDB, Memorystore, operacje w chmurze i asystent oparty na modelu to usługi płatne, rozliczane według cenników dostawcy — swobodna licencja nie znaczy tu darmowego wdrożenia. Po drugie, obrazy kontenerów publikowane przez projekt są wygodą, nie zobowiązaniem: dla wdrożenia, które ma przejść przeglądem bezpieczeństwa u klienta, właściwą drogą jest zbudowanie ich samodzielnie i wypchnięcie do własnego rejestru — do czego repozytorium zresztą przewiduje osobny komponent. Osobno warto pamiętać, że marka i grafiki witryny należą do jej właściciela, a wariant zmieniający oznaczenia istnieje właśnie po to, żeby demonstracja nie udawała cudzego sklepu.