LW IT Solutions logo LW IT Solutions logo LW IT Solutions
« Przegląd bloga /Cloud & AI/Tutorials / Bezserwerowe mikrousługi: Skalowanie w Google Cloud Run...
Ten artykuł w innych językach:

Bezserwerowe mikrousługi: Skalowanie w Google Cloud Run z GitHub Actions

Bezserwerowe mikrousługi: Skalowanie w Google Cloud Run z GitHub Actions

Management Summary

Google Cloud Run uruchamia aplikacje w chmurze i dopasowuje liczbę działających kopii do ruchu. Ogranicza to pracę przy utrzymaniu serwerów i przydaje się usługom o zmiennym obciążeniu. GitHub Actions automatyzuje przygotowanie oraz dostarczanie nowych wersji, ułatwiając powtarzalne wydania. Nadal potrzebne są rozsądne limity wydajności i kosztów: automatyczne skalowanie nie zastępuje monitoringu, a pamięć masowa i powiązane usługi mogą kosztować także podczas bezczynności.

Spis treści
  1. 1. Wymagania i oddzielne tożsamości
  2. 2. Ograniczenie WIF do właściciela, repozytorium i gałęzi main
  3. 3. Budowanie obrazu, uwierzytelnienie i przygotowanie rewizji
  4. 4. Skalowanie i koszty dopasowane do aplikacji
  5. Pytania i odpowiedzi
  6. Źródła

Google Cloud Run obsługuje kontenerowe usługi WWW bez utrzymywania własnego serwera lub klastra Kubernetes. Przy odpowiedniej konfiguracji usługa bez żądań może zmniejszyć liczbę instancji do zera. Wzrost ruchu uruchamia kolejne instancje w granicach dostępnych limitów i kwot. Instancja to działająca kopia aplikacji. Uruchomienie nowej kopii trwa; takie opóźnienie nazywa się zimnym startem. Nadal potrzebne jest utrzymanie aplikacji i opłacanie pozostałych usług.

Obraz zawiera aplikację i pliki potrzebne do działania. Rewizja to wdrożona wersja z określonym obrazem i ustawieniami. GitHub Actions może budować obrazy i wdrażać przez Workload Identity Federation (WIF). WIF zastępuje stale zapisany klucz konta usługi Google krótkotrwałymi poświadczeniami. Przejęte przepływy pracy, nadmierne uprawnienia i przypadkowo dołączone poświadczenia pozostają ryzykiem. Dlatego przykład wykonuje build przed uwierzytelnieniem w chmurze, a nową rewizję początkowo wdraża bez zwykłego ruchu.

1. Wymagania i oddzielne tożsamości

Projekt, rozliczenia, wymagane API, repozytorium Artifact Registry services, konto wdrożeniowe i oddzielne konto wykonawcze muszą już istnieć. Przykład aktualizuje istniejącą usługę api-service w us-central1. Usługa ma włączoną kontrolę wywołań IAM i nie ma publicznych uprawnień wywołania. Pierwsza konfiguracja oraz zmiany dostępu publicznego wymagają odpowiednich uprawnień administracyjnych poza potokiem.

  • Konto wdrożeniowe: ci-cd-deployer wymaga Artifact Registry Writer na repozytorium obrazów, Cloud Run Developer na istniejącej usłudze oraz Service Account User na koncie wykonawczym. Writer obejmuje również odczyt obrazów potrzebny do wdrożenia.
  • Konto wykonawcze: api-runtime otrzymuje tylko uprawnienia aplikacji, na przykład dostęp do konkretnego magazynu danych. Uprawnienia wdrożeniowe nie należą do tej roli.
  • Aplikacja: Kontener musi nasłuchiwać na 0.0.0.0:$PORT i przechowywać sesje lub trwałe dane poza nietrwałym kontenerem. Wymagane są Dockerfile oraz wykonywalny, właściwy dla projektu skrypt ci/test.sh.
Build przed uwierzytelnieniem, wdrożenie digestu obrazu, testy i udostępnienie
Build odbywa się przed utworzeniem pliku poświadczeń chmurowych. WIF ogranicza dostęp; testy aplikacji i jawne przełączenie ruchu kończą wydanie.

2. Ograniczenie WIF do właściciela, repozytorium i gałęzi main

Polecenia tworzą nową relację zaufania. Wszystkie przykładowe identyfikatory wymagają wcześniejszego zastąpienia. PROJECT_NUMBER jest numerycznym numerem projektu Google, a nie identyfikatorem projektu. OWNER_ID i REPOSITORY_ID są numerycznymi identyfikatorami GitHub. Dzięki temu ponowne zajęcie usuniętej nazwy organizacji lub repozytorium przez inne konto nie odtwarza zaufanej tożsamości.

Shell
#!/usr/bin/env bash
set -euo pipefail
# Replace all example identifiers before administrative setup.
PROJECT_ID="enterprise-ai-project"
PROJECT_NUMBER="1234567890"
OWNER_ID="11111111"
REPOSITORY_ID="22222222"
DEPLOYER="ci-cd-deployer@${PROJECT_ID}.iam.gserviceaccount.com"

gcloud iam workload-identity-pools create github-actions-pool \
  --project="$PROJECT_ID" --location=global \
  --display-name="GitHub Actions Pool"

gcloud iam workload-identity-pools providers create-oidc github-provider \
  --project="$PROJECT_ID" --location=global \
  --workload-identity-pool=github-actions-pool \
  --issuer-uri="https://token.actions.githubusercontent.com" \
  --attribute-mapping="google.subject=assertion.sub,attribute.repository_id=assertion.repository_id,attribute.repository_owner_id=assertion.repository_owner_id,attribute.ref=assertion.ref,attribute.event_name=assertion.event_name" \
  --attribute-condition="assertion.repository_owner_id == '${OWNER_ID}' && assertion.repository_id == '${REPOSITORY_ID}' && assertion.ref == 'refs/heads/main' && assertion.event_name == 'push'"

gcloud iam service-accounts add-iam-policy-binding "$DEPLOYER" \
  --project="$PROJECT_ID" --role=roles/iam.workloadIdentityUser \
  --member="principalSet://iam.googleapis.com/projects/${PROJECT_NUMBER}/locations/global/workloadIdentityPools/github-actions-pool/attribute.repository_id/${REPOSITORY_ID}"

Warunek dostawcy dopuszcza tylko zdarzenia push z ustalonego repozytorium na main. Sam wyzwalacz workflow nie ogranicza dostępu po stronie Google Cloud. Propagacja zmian WIF i IAM może potrwać. Powiązanie roles/iam.workloadIdentityUser pozwala użyć tożsamości konta wdrożeniowego; uprawnienia do zasobów nadal są wymagane oddzielnie.

Ochrona gałęzi i przegląd zmian plików workflow pozostają ważne: inny uprawniony workflow na main także może spełnić te warunki. Środowisko GitHub production wymaga właściwych reguł ochrony. Sama nazwa środowiska w YAML nie tworzy obowiązku zatwierdzenia.

3. Budowanie obrazu, uwierzytelnienie i przygotowanie rewizji

Przed pierwszym uruchomieniem wzorzec gha-creds-*.json należy umieścić w .gitignore, a poniższe wykluczenia w .dockerignore. Pozostałe pliki sekretów oraz pliki ignore przypisane do Dockerfile wymagają dopasowania do projektu; późniejsze wyjątki nie mogą ponownie włączać poświadczeń.

Tekst
gha-creds-*.json
.git
.env
.env.*

Akcja auth domyślnie zapisuje plik krótkotrwałych poświadczeń w katalogu roboczym. Późniejsze docker build z szerokim COPY mogłoby dołączyć ten plik do obrazu. Dlatego testy i budowanie odbywają się przed uwierzytelnieniem w chmurze. Wersje akcji wskazują konkretne, sprawdzone commity; aktualizacje nadal wymagają przeglądu.

YAML
name: Build and stage a Cloud Run revision

on:
  push:
    branches: [main]

permissions:
  contents: read
  id-token: write

concurrency:
  group: cloud-run-api-service
  cancel-in-progress: false

env:
  PROJECT_ID: enterprise-ai-project
  REGION: us-central1
  IMAGE: us-central1-docker.pkg.dev/enterprise-ai-project/services/api-service
  PROVIDER: projects/1234567890/locations/global/workloadIdentityPools/github-actions-pool/providers/github-provider
  DEPLOYER: ci-cd-deployer@enterprise-ai-project.iam.gserviceaccount.com
  RUNTIME: api-runtime@enterprise-ai-project.iam.gserviceaccount.com

jobs:
  stage:
    runs-on: ubuntu-latest
    timeout-minutes: 30
    environment: production
    defaults:
      run:
        shell: bash
    steps:
      - name: Checkout
        uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
        with:
          persist-credentials: false

      - name: Application tests and build before cloud authentication
        run: |
          set -euo pipefail
          ./ci/test.sh
          docker build --tag "$IMAGE:$GITHUB_SHA" .

      - name: Authenticate for image push
        uses: google-github-actions/auth@7c6bc770dae815cd3e89ee6cdf493a5fab2cc093 # v3
        with:
          workload_identity_provider: ${{ env.PROVIDER }}
          service_account: ${{ env.DEPLOYER }}
          project_id: ${{ env.PROJECT_ID }}

      - name: Set up gcloud
        uses: google-github-actions/setup-gcloud@aa5489c8933f4cc7a4f7d45035b3b1440c9c10db # v3

      - name: Push image
        run: |
          set -euo pipefail
          gcloud auth configure-docker "$REGION-docker.pkg.dev" --quiet
          docker push "$IMAGE:$GITHUB_SHA"

      - name: Refresh authentication before deployment
        uses: google-github-actions/auth@7c6bc770dae815cd3e89ee6cdf493a5fab2cc093 # v3
        with:
          workload_identity_provider: ${{ env.PROVIDER }}
          service_account: ${{ env.DEPLOYER }}
          project_id: ${{ env.PROJECT_ID }}

      - name: Configure refreshed gcloud credentials
        uses: google-github-actions/setup-gcloud@aa5489c8933f4cc7a4f7d45035b3b1440c9c10db # v3

      - name: Stage revision without changing traffic
        run: |
          set -euo pipefail
          gcloud run services describe api-service \
            --project="$PROJECT_ID" --region="$REGION" >/dev/null
          DIGEST="$(gcloud artifacts docker images describe "$IMAGE:$GITHUB_SHA" \
            --project="$PROJECT_ID" --format='value(image_summary.digest)')"
          [[ "$DIGEST" =~ ^sha256:[0-9a-f]{64}$ ]]
          gcloud run deploy api-service \
            --project="$PROJECT_ID" --region="$REGION" \
            --image="$IMAGE@$DIGEST" --service-account="$RUNTIME" \
            --no-traffic --tag=candidate \
            --min-instances=0 --max-instances=50 \
            --concurrency=80 --memory=512Mi --cpu=1 --cpu-throttling \
            --quiet

Potok wysyła obraz z tagiem commita, a następnie wdraża ustalony digest. Digest identyfikuje zawartość obrazu; sam tag może się zmienić. Uwierzytelnienie jest odnawiane przed wdrożeniem, aby czas budowania i wysyłania nie zużywał niepotrzebnie krótkiego okresu ważności. Bardzo długi upload lub deployment nadal może wymagać ponownego uwierzytelnienia i kontrolowanej próby.

--no-traffic pozostawia zwykły ruch przy wcześniejszych rewizjach. Tag candidate tworzy osobny adres testowy i przy następnym przebiegu wskazuje nową rewizję. Adres nadal podlega zasadom dostępu usługi. Podstawowe testy funkcjonalne sprawdzają na przykład typowe żądanie API. Wymagają konta uprawnionego do wywołania usługi, zwykle z Cloud Run Invoker i odpowiednim tokenem ID. Sam poprawny start nie dowodzi poprawnego działania aplikacji.

Po testach i sprawdzeniu dokładnego identyfikatora rewizji ruch można przełączyć jawnie. Placeholder poniżej wymaga zastąpienia faktycznie sprawdzoną rewizją. Wycofanie analogicznie wskazuje wcześniejszą zweryfikowaną rewizję. Zmiany tabel bazy danych i już wykonane działania w innych systemach pozostają w mocy. Na przykład wysłana wiadomość nie zostaje cofnięta przez przywrócenie poprzedniej rewizji.

Shell
# After authenticated smoke tests and approval of this exact revision:
gcloud run services update-traffic api-service \
  --project=enterprise-ai-project --region=us-central1 \
  --to-revisions=REVIEWED_REVISION_NAME=100

4. Skalowanie i koszty dopasowane do aplikacji

  • Współbieżność 80: To maksymalna liczba jednoczesnych żądań na instancję w przykładzie, a nie próg wymagający pełnego wypełnienia. Autoskalowanie uwzględnia między innymi wykorzystanie CPU i współbieżności. Żądania intensywnie używające CPU lub pamięci często wymagają niższych wartości; większa równoległość nie zmniejsza automatycznie zużycia pamięci.
  • Zero minimalnych instancji: --min-instances=0 dotyczy nowej rewizji. Minimalną liczbę na poziomie usługi również trzeba sprawdzić. Przy rozliczaniu według żądań zwykłe bezczynne instancje bez minimalnego utrzymywania nie generują opłat za bezczynne zasoby obliczeniowe; start, zamykanie i żądania nadal mogą kosztować. Dochodzą obrazy w rejestrze, sieć, logi i GitHub Actions.
  • Maksimum 50: --max-instances=50 jest tutaj limitem rewizji. Wiele rewizji i chwilowe przekroczenia mogą zwiększyć sumę. Odpowiedni dodatkowy limit usługi lepiej chroni zależne systemy; żadne z tych ustawień nie stanowi twardego limitu rachunku.
  • Praca w tle: --cpu-throttling wybiera przydział CPU związany z żądaniami. Rozliczanie instancjowe ze stale przydzielonym CPU i minimalnymi instancjami umożliwia pracę w tle, lecz nie gwarantuje nieprzerwanego procesu. Instancje mogą zostać zakończone. Zadania z możliwością ponowienia mogą korzystać z trwałej kolejki Cloud Tasks lub odpowiednich Cloud Run Jobs.

Wartości 80, 50 i 512 MiB są ustawieniami początkowymi przykładu. Testy obciążeniowe powinny mierzyć opóźnienia, błędy, zużycie pamięci i połączenia z bazą. Cloud Run może przełączać rewizje bez planowanej przerwy, ale błędny kod, niezgodne migracje lub wyczerpane kwoty nadal mogą powodować awarie.

Trzy składane stoły mieszczą tę samą największą liczbę talerzy, a czwarty stoi złożony przy ścianie. Tak samo concurrency określa, ile zapytań instancja obsługuje naraz, a nieużywane nic nie kosztują.
Trzy składane stoły mieszczą tę samą największą liczbę talerzy, a czwarty stoi złożony przy ścianie. Tak samo concurrency określa, ile zapytań instancja obsługuje naraz, a nieużywane nic nie kosztują.

Pytania i odpowiedzi

Czy wdrażanie bez klucza jest bezobsługowe?

Nie. WIF usuwa z tego procesu stale zapisany klucz Google. Krótkotrwałe tokeny, dostęp do GitHub i uprawnienia wykonawcze nadal wymagają ochrony. Zależności, obrazy bazowe, commity akcji i reguły IAM wymagają utrzymania.

Dlaczego brakuje –allow-unauthenticated?

Flaga nadaje publiczne prawo wywołania i wymaga dodatkowych uprawnień IAM. Przykład zakłada już prywatną usługę i zachowuje zasady wywołania. Pominięcie flagi nie zmienia istniejącej usługi publicznej w prywatną.

Co kosztuje po zatrzymaniu wszystkich instancji?

Między innymi zapisane obrazy i pozostałe używane usługi chmurowe. Reguła czyszczenia rejestru powinna zachowywać potrzebne obrazy wydań i wycofania. Skalowanie do zera nie oznacza darmowych wdrożeń ani darmowej całej infrastruktury.

Lukas Wójcik

Lukas Wójcik

Systems architect and technology enthusiast specializing in scalable tracking solutions, GMP Stack (GA4 & GTM), and robust backend architectures. Advocate for clean code and privacy-first design.

Kontakt

Masz pytanie lub pomysł na projekt internetowy? Napisz krótko, o co chodzi. Formularz korzysta z reCAPTCHA i formconfirmed do ochrony przed spamem.

Napisanie komentarza

Doświadczenia z innymi modelami lub dostawcami oraz pytania o wdrożenie są tu mile widziane.

Adres e-mail nie jest publikowany. Pola obowiązkowe oznaczono gwiazdką.

LUKASWOJCIK.COM · NEWSLETTER

Nowe pomysły w skrzynce

Nowe artykuły, praktyczne narzędzia i informacje o projektach.

Wybierz tematy (opcjonalnie)
Bez wyboru: wszystkie tematy.

Zapis wymaga potwierdzenia e-mailem. · Prywatność

Prywatność · Newsletter

Adres e-mail, język, wybrane tematy oraz daty zapisu i potwierdzenia są przechowywane w celu wysyłki newslettera. Wymagane jest potwierdzenie zapisu. Każda wiadomość zawiera link do natychmiastowej rezygnacji. Formconfirmed chroni formularz przed spamem. Brak śledzenia otwarć i kliknięć.

Pełna polityka prywatności ↗