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
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-deployerwymaga 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-runtimeotrzymuje 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:$PORTi przechowywać sesje lub trwałe dane poza nietrwałym kontenerem. Wymagane są Dockerfile oraz wykonywalny, właściwy dla projektu skryptci/test.sh.

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.
#!/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ń.
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.
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 \
--quietPotok 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.
# 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=1004. 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=0dotyczy 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=50jest 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-throttlingwybiera 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.

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.
Źródła
- Dokumentacja Cloud Run
- Dokumentacja Docker
- WIF w procesach wdrażania
- Akcja auth: poświadczenia w wynikach budowania
- Uwierzytelnianie Google Cloud w GitHub Actions
- Współbieżność w Cloud Run
- Ustawienia rozliczeń Cloud Run
- Maksymalna liczba instancji
- Testowanie rewizji, przełączanie ruchu i wycofywanie wersji
- Uprawnienia do wdrażania w Cloud Run
- Wymagania wykonawcze kontenerów Cloud Run
- Przypinanie GitHub Actions do konkretnych commitów


