Lekcja 3 · Dzień 3
CI/CD GitHub Actions na flecie 20+ serwisów
To będzie konkretniejsze niż „Jenkins”. JD: reusable workflows, matrix, cache, Java/Kotlin. Plus OIDC zamiast kluczy i promocja PR → staging → prod.
Reusable workflows
Jeden kontrakt dla 20 repo (albo monorepo z 20 katalogami):
# .github/workflows/service.yml (w repo serwisu)
jobs:
build:
uses: org/platform-workflows/.github/workflows/java-service.yml@v3
with:
service: payments-api
java-version: "21"
environment: ${{ github.ref == 'refs/heads/main' && 'staging' || 'dev' }}
secrets: inherit # lepiej: named secrets albo OIDC bez secrets
permissions:
id-token: write
contents: read
Zasady, które warto powiedzieć:
- Wersjonuj workflow tagami (
v3), niemain. Breaking change = major. - Wejście:
service,java-version,environment. Nie: dowolny shell od callera. permissionsleast privilege.id-token: writetylko tam, gdzie OIDC.- Reusable workflow nie może sam wywołać reusable (jeden poziom) — dlatego grubą logikę trzymaj w actions (composite) albo w jednym grubym workflow z jobami.
Matrix (java / env / service)
strategy:
fail-fast: false
matrix:
service: [ledger, cards, limits, receipts]
java: ["17", "21"]
exclude:
- service: cards
java: "17"
fail-fast: false na flecie: jeden czerwony serwis nie ma ukrywać reszty. Pytanie z raportu: pipeline pada tylko na jednym serwisie w matrixie — pełna odpowiedź jest w pytaniach. Szkielet diagnostyki:
- Czy pada ten sam serwis lokalnie na tym samym JDKu i z czystym Gradle?
- Czy pada tylko w CI? → cache, secrets, OIDC, runner, sieć do Artifactory.
- Czy pada tylko jedna komórka matrixa? → wersja Javy, exclude, zła ścieżka.
- Czy pada flaky? → rerun ≠ fix. Test isolation, czas, testcontainers vs. niedostępny Docker layer.
Cache Gradle/Maven i kiedy kłamie
actions/setup-java + cache: gradle albo actions/cache na ~/.gradle/caches. Klucz: lockfile + OS + java version.
Kiedy cache kłamie:
- Klucz za szeroki — serwis A dostaje dirty cache serwisu B (w monorepo częste).
- Klucz za wąski — 0% hit, CI wolne, ludzie wyłączają testy.
- Zapisano cache z połowy nieudanego joba (Gradle daemon, niekompletne artifacty).
- Zmiana w
init.gradle/ lusterku repo nie jest w kluczu. - Windows vs Linux path — nie ich przypadek, ale klasyka.
Mitigacja: cache tylko dependencies (caches/modules-2), nie build/. Restore-keys ostrożnie. Przy podejrzeniu: job z cache: false jako kontrola. Dokumentuj „jak zabić cache” w runbooku — to będzie pytanie operacyjne.
OIDC do AWS zamiast long-lived keys
Przepływ:
- W AWS: OIDC provider
https://token.actions.githubusercontent.com, audiencests.amazonaws.com. - Rola z trust policy:
subograniczony dorepo:org/repo:environment:prod(albo ref). Nie do całego org. - Job:
permissions: id-token: write+aws-actions/configure-aws-credentialszrole-to-assume. - GitHub Environments: protection rules na
prod(reviewers, wait timer). OIDC claimenvironmentmusi zgadzać się z trust policy.
Dla PCI: self-hosted runner w PCI VPC, albo deploy z account CI przez assume-role do PCI z bardzo wąską polityką (ECR push + ECS update, bez RDS). Public GitHub-hosted runner nie powinien mieć roli, która czyta CHD.
Promocja: PR → staging → prod
- PR: build, test, scan (Snyk/Trivy), terraform plan jako komentarz. Zero apply na prod.
- merge do main: obraz tagowany SHA, deploy staging automatycznie.
- prod: ten sam artefakt (digest, nie
latest). Manual approval tam, gdzie trzeba — PCI, migracje RDS, destroy. Nie na każdym mikroserwisie, bo wtedy ludzie klikają w ciemno.
Promotion by digest: staging i prod palą ten sam SHA. „Na stagingu działało” bez tego samego obrazu nic nie znaczy.
Jak debugujesz pipeline, który „działa lokalnie”
- Porównaj wersje: JDK, Gradle, OS, Docker.
java -versionw logu CI. - Wymuś czysty build:
--no-build-cache --refresh-dependencies. - Sprawdź sekrety: lokalnie masz
~/.aws, w CI masz OIDC. Inny caller, inny IAM. - Sieć: runner nie widzi internal Maven, VPC endpoint, IP allow-list Artifactory.
- Timezones, locale,
line.separator— rzadziej, ale JUnit to lubi. - Akt runner vs. Twój laptop: 2 vCPU vs. 16. Test timing, Testcontainers OOM.
Ćwiczenie
Na kartce: sygnatura reusable workflow (inputs, permissions, environments). Jedna linijka trust policy OIDC z sub dla prod. Opowiedz, jak debugujesz padający jeden serwis w matrixie — zegar 3 minuty.