Przejdź do głównej zawartości

Wzorce Pipeline CI/CD

Twoje wdrożenie przeszło wszystkie sprawdzenia i mimo to położyło produkcję. Testy jednostkowe były zielone, build Dockera się powiódł, kubectl set image zwróciło 0 - ale obraz wypuścił CRITICAL CVE w zależności przechodniej, bo nic w pipeline jej nigdy nie przeskanowało. CI mówiło ci, że wszystko jest w porządku, dokładnie do chwili, w której pager powiedział ci, że nie jest.

Rozwiązaniem nie jest „napisz lepszy YAML ręcznie”. Rozwiązaniem jest użycie narzędzia AI do wygenerowania pipeline’u, który ma już bramki, jakie dodałby starszy inżynier platformowy - cachowanie zależności, skan podatności, który faktycznie wywala build, oraz wdrożenie produkcyjne czekające na prawdziwy health check - a następnie przejrzenie tego, co powstało, zamiast pisania 200 linii boilerplate’u od zera.

  • Gotowy do wklejenia prompt, który zamienia istniejący package.json + Dockerfile w kompletny workflow GitHub Actions z matrycą wersji Node, cachowaniem zależności i skanem Trivy, który bramkuje build.
  • Prompt, który zamienia czerwony log CI w diagnozę przyczyny źródłowej plus konkretną poprawkę, abyś przestał ręcznie bisekować nieudane uruchomienia.
  • Prompt do dodania bramkowanego metrykami rolloutu canary do istniejącego wdrożenia kubectl.
  • Trójnarzędziowy workflow (Cursor, Claude Code, Codex) do generowania, przeglądania i uruchamiania zmian w pipeline - łącznie z oficjalnymi GitHub Actions dla Claude Code i Codex, dzięki czemu ten sam model, który napisał pipeline, może przeglądać twoje PR-y.
  • Mapę „Gdy to się zepsuje” obejmującą tryby awarii, na które generowane pipeline’y wpadają najpierw: cache misses, błędy OIDC przy assume role, timeouty rolloutu i fałszywe alarmy skanera.

Pułapka promptów typu „stwórz pipeline CI/CD” polega na tym, że produkują one prawdopodobnie wyglądający workflow oderwany od twojego rzeczywistego projektu - zły menedżer pakietów, zmyślone skrypty testowe, wersja Node, której nie używasz. Zakotwicz prompt w plikach, które już są w repo, aby wynik odpowiadał rzeczywistości.

Otwórz repo w Cursorze, dodaj package.json, Dockerfile oraz dowolne istniejące .github/workflows/* do kontekstu Agenta przez @, a następnie uruchom poniższy prompt w trybie Agent. Cursor edytuje plik workflow w miejscu, a ty przeglądasz diff w edytorze przed zaakceptowaniem. Trzymaj package.json w kontekście, aby czytał twój prawdziwy blok scripts zamiast zgadywać npm test.

Dobry wygenerowany wynik wygląda jak ten szkielet - zwróć uwagę na krok skanu, który faktycznie bramkuje build, czyli część, o której zapominają ręcznie pisane pipeline’y:

.github/workflows/ci.yml
name: CI
on:
push: { branches: [main] }
pull_request:
release: { types: [published] }
permissions:
contents: read
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix: { node: [20, 22] }
steps:
- uses: actions/checkout@v6
- uses: actions/setup-node@v6
with:
node-version: ${{ matrix.node }}
cache: 'npm'
- run: npm ci
- run: npm test # the real script, read from package.json
build:
needs: test
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
id-token: write # OIDC, no stored registry password
steps:
- uses: actions/checkout@v6
- uses: docker/setup-buildx-action@v4
- uses: docker/login-action@v4
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- uses: docker/build-push-action@v7
id: build
with:
push: true
tags: ghcr.io/${{ github.repository }}:${{ github.sha }}
cache-from: type=gha
cache-to: type=gha,mode=max
- name: Scan image (fails build on CRITICAL/HIGH)
uses: aquasecurity/trivy-action@v0.36.0
with:
image-ref: ghcr.io/${{ github.repository }}:${{ github.sha }}
severity: 'CRITICAL,HIGH'
exit-code: '1'
ignore-unfixed: true
deploy-prod:
needs: build
if: github.event_name == 'release'
runs-on: ubuntu-latest
environment: production # required reviewers enforce the gate
steps:
- uses: actions/checkout@v6
# ... cloud auth + rollout below

Decyzją do przejrzenia jest tutaj exit-code: '1' w kroku Trivy. Bez niej skan tworzy raport, którego nikt nie czyta, a build pozostaje zielony. Z nią podatny obraz bazowy blokuje wdrożenie. Ta jedna linia to różnica między zepsutym pipeline’em z wstępu a bezpiecznym.

Wygenerowanie pipeline’u to łatwiejsza połowa. Połowa, która zżera twoje popołudnie, to uruchomienie, które wywala się w linii 1 z 400-liniowego logu z npm ci kończącym się kodem 1 i bez oczywistego powodu. Wklej log do narzędzia AI, zamiast go przewijać.

Sformułowanie „działa lokalnie, ale wywala się w CI” ma znaczenie: popycha model w stronę przyczyn specyficznych dla środowiska - nieaktualnego klucza actions/cache przywracającego node_modules zbudowane pod złą wersją Node, lockfile’a zacommitowanego niezgodnie z package.json, brakującego kontenera serwisowego - zamiast ogólnikowych porad „sprawdź swoje testy”.

Gdy podstawowe wdrożenie już działa, kolejna prośba brzmi zwykle „wypuść na 10% ruchu, obserwuj error rate, automatycznie promuj albo wycofaj”. To właśnie tutaj wygenerowany blok kubectl jest niebezpieczny, jeśli nie jest bramkowany prawdziwym sygnałem - więc uczyń bramkę jawną w prompcie.

Nalegaj na „plain shell with explicit thresholds”. Canary, który promuje na podstawie nieprzejrzystego inputu akcji, jest nieaudytowalny; taki, w którym próg error rate 0.01 jest widoczny w workflow, to coś, co twój zespół może zrozumieć i dostroić.

Ta sama pętla generuj-i-przeglądaj dotyczy innych platform - zmienia się tylko plik docelowy. Powyższe prompty działają dosłownie, jeśli podmienisz „GitHub Actions / .github/workflows/ci.yml” na „etapy .gitlab-ci.yml” lub „deklaratywny Jenkinsfile”. Dwie uwagi specyficzne dla platform, które warto przekazać AI:

  • GitLab CI: poproś o wbudowane szablony bezpieczeństwa (include: - template: Security/SAST.gitlab-ci.yml oraz Container-Scanning.gitlab-ci.yml) zamiast ręcznie sklejanych zadań skanera - są utrzymywane przez GitLab i podłączają wyniki do widgetu MR. Przypnij obrazy zadań do prawdziwego tagu (node:22-alpine) i użyj cache:key:files: [package-lock.json], aby cache unieważniał się przy zmianie lockfile’a.
  • Jenkins: poproś o Jenkinsfile używający równoległych etapów quality-gate (parallel) i agentów Docker, oraz wywołujący withSonarQubeEnv + waitForQualityGate abortPipeline: true, tak by niezaliczona bramka jakości faktycznie zatrzymywała pipeline. Trzymaj logikę wdrożenia w bibliotece współdzielonej, nie inline.

Domknięcie pętli: AI, które przegląda własne pipeline’y

Dział zatytułowany „Domknięcie pętli: AI, które przegląda własne pipeline’y”

Najmocniejszy wzorzec to pozwolenie, by ten sam model, który napisał pipeline, przejrzał PR, który go zmienia. Obaj dostawcy dostarczają natywną GitHub Action, więc nie musisz schodzić do npm install -g i ręcznie scrapować git diff.

Cursor nie dostarcza akcji CI - to IDE. Podział pracy: użyj Agenta Cursora oraz agenta w tle (background agent) do napisania i iterowania workflow lokalnie z pełnym kontekstem edytora, a następnie pozwól, by GitHub Action Claude Code albo Codeksa obsłużyła krok przeglądu w CI. Generuj lokalnie, przeglądaj w CI.

  1. Cache się przywraca, ale build i tak rekompiluje wszystko. Klucz actions/cache się nie zmienił, ale zawartość jest błędna - zwykle node_modules zacachowane pod inną wersją Node albo klucz pozbawiony hasha lockfile’a. Użyj klucza w stylu ${{ runner.os }}-node${{ matrix.node }}-${{ hashFiles('**/package-lock.json') }} i preferuj wbudowane cache: 'npm' z actions/setup-node (które cachuje cache pobrań npm, a nie node_modules) zamiast cachowania node_modules bezpośrednio.

  2. Wdrożenie OIDC wywala się z „Not authorized to perform sts:AssumeRoleWithWebIdentity”. Zadanie ma permissions: id-token: write, ale polityka zaufania po stronie chmury nie dopuszcza tego repo/brancha. Poprawka jest po stronie trust relationship roli IAM (warunek sub musi pasować do repo:org/name:ref:refs/heads/main lub twojego środowiska), a nie w YAML-u. Poproś AI o wygenerowanie polityki zaufania na podstawie permissions i wyzwalacza workflow, a następnie zweryfikuj, że claim sub się zgadza.

  3. kubectl rollout status wisi aż zadanie wpadnie w timeout. Nowe pody nie przechodzą w Ready - niedziałający readiness probe, błąd pobrania obrazu albo niewystarczające zasoby klastra. Dodaj --timeout=120s, aby szybko wywaliło, a następnie kubectl describe deployment/app -n <ns> i kubectl get events --sort-by=.lastTimestamp, by zobaczyć dlaczego. Rollout, który nigdy się nie kończy, to zablokowane wdrożenie, a nie powolne.

  4. Trivy wywala build na CVE, którego nie możesz naprawić. CRITICAL w zależności przechodniej bez jeszcze załatanej wersji. Nie usuwaj kroku skanu - tak właśnie wydarzył się scenariusz ze wstępu. Użyj ignore-unfixed: true (już jest w szkielecie), aby pominąć CVE bez poprawki, oraz przejrzanego .trivyignore z konkretnym ID CVE i notatką o wygaśnięciu dla reszty. Hurtowe wyłączenie bramki to zła poprawka.

  5. Wygenerowany workflow przypina akcje do @master lub @main. To najczęstsza wada w pipeline’ach generowanych przez AI: ryzyko supply-chain i brak powtarzalności. Przypnij każdą akcję firm trzecich do wydanego tagu (albo commit SHA dla ścieżek wysokiego zaufania). Poproś ponownie z „pin all actions to released tags, no floating refs” lub popraw to przy przeglądzie.