Modul 9 — CI/CD

43. Stavba CI pipeline (GitHub Actions nebo GitLab CI) — základy

Praktická stavba první CI pipeline v GitHub Actions — syntaxe workflow souboru, joby, kroky a triggery.

Odhadovaná délka studia: 55 minut · Stav: nehotovo

Technologie: CI/CD

Úvod a kontext

Minulá lekce vysvětlila principy CI/CD na koncepční úrovni. Teď je čas
postavit skutečnou pipeline. Použijeme GitHub Actions, protože je
vestavěná přímo do GitHubu (nejrozšířenější platformy pro hostování
Gitu) a nevyžaduje žádnou externí infrastrukturu — vše, co potřebujete,
je YAML soubor v repozitáři. Principy popsané zde (workflow, joby,
kroky, triggery) jsou koncepčně stejné i v GitLab CI/CD, liší se hlavně
syntaxe.

Teorie

Základní pojmy GitHub Actions

  • Workflow — celá automatizace definovaná jedním YAML souborem v
    .github/workflows/. Repozitář může mít víc workflow souborů (např.
    jeden pro testy, jeden pro nasazení).
  • Trigger (on) — událost, která workflow spustí: push do větve,
    otevření pull requestu, ruční spuštění, plánovaný čas (cron).
  • Job — sada kroků, která běží na jednom runneru (izolovaném
    virtuálním stroji). Workflow může mít víc jobů, které běží paralelně
    nebo v definovaném pořadí (needs).
  • Step — jednotlivý krok uvnitř jobu — buď spuštění shellového
    příkazu (run), nebo použití hotové znovupoužitelné akce (uses),
    např. pro checkout repozitáře nebo instalaci konkrétní verze
    interpretu.
  • Runner — stroj, na kterém job běží; GitHub poskytuje hostované
    runnery (ubuntu-latest, windows-latest apod.) nebo lze provozovat
    vlastní (self-hosted).

Struktura workflow souboru

# .github/workflows/ci.yml
name: CI

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout repozitáře
        uses: actions/checkout@v4

      - name: Instalace Pythonu
        uses: actions/setup-python@v5
        with:
          python-version: "3.12"

      - name: Instalace závislostí
        run: pip install -r requirements.txt

      - name: Spuštění lintingu
        run: flake8 .

      - name: Spuštění testů
        run: pytest --maxfail=1

Tento workflow se spustí při každém push do main a při každém pull
requestu směřujícím do main — takže se ověří jak přímé změny hlavní
větve, tak navrhované změny ještě před sloučením.

Proměnné prostředí a tajemství

Citlivé hodnoty (API klíče, přihlašovací údaje) se nikdy nezapisují
přímo do YAML souboru (ten je ve veřejném/sdíleném repozitáři vidět
komukoliv s přístupem) — používají se GitHub Secrets, uložené
zašifrovaně v nastavení repozitáře a zpřístupněné jako proměnné
prostředí:

      - name: Nasazení
        env:
          API_TOKEN: ${{ secrets.DEPLOY_API_TOKEN }}
        run: ./deploy.sh

Více jobů a závislosti mezi nimi

Joby ve výchozím stavu běží paralelně (na oddělených runnerech).
Explicitní závislost (např. "nejdřív build, pak teprve deploy") se
zapisuje pomocí needs:

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Sestavení Docker image
        run: docker build -t myapp:${{ github.sha }} .

  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: pytest

  deploy:
    needs: [build, test]
    runs-on: ubuntu-latest
    steps:
      - run: echo "Nasazuji jen pokud build i test uspěly"

deploy se spustí, jen pokud oba joby v needs (build i test)
skončí úspěšně — tím se v pipeline vynucuje pořadí a podmínka.

Matice (matrix) — testování ve více konfiguracích

Když potřebujete stejný job spustit s víc kombinacemi parametrů
(např. verze Pythonu), místo kopírování jobu se použije strategy.matrix:

jobs:
  test:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        python-version: ["3.10", "3.11", "3.12"]
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with:
          python-version: ${{ matrix.python-version }}
      - run: pip install -r requirements.txt
      - run: pytest

GitHub Actions tento job spustí třikrát paralelně, jednou pro každou
verzi Pythonu z matice.

Praktický příklad

Kompletní minimální workflow pro projekt s Dockerem — od checkoutu po
sestavení image (bez samotného nasazení, to je předmět další lekce):

name: Build a testy

on:
  push:
    branches: [main]

jobs:
  build-and-test:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Instalace závislostí
        run: pip install -r requirements.txt

      - name: Testy
        run: pytest

      - name: Sestavení Docker image
        run: docker build -t myapp:${{ github.sha }} .

      - name: Uložení image jako artefakt (pro pozdější stage)
        run: docker save myapp:${{ github.sha }} -o image.tar

      - uses: actions/upload-artifact@v4
        with:
          name: docker-image
          path: image.tar

Po commitnutí tohoto souboru do .github/workflows/ci.yml a jeho
pushnutí GitHub workflow automaticky spustí; průběh a logy jsou vidět
v záložce "Actions" repozitáře.

Shrnutí

CI pipeline v GitHub Actions se skládá z workflow (celá automatizace),
spouštěného triggerem (on), obsahujícího joby (běžící na runnerech),
z nichž každý má sekvenci kroků (run/uses). Joby lze provázat přes
needs, aby na sebe navazovaly v definovaném pořadí, a násobit přes
strategy.matrix pro testování víc konfigurací najednou. Citlivé
hodnoty patří do GitHub Secrets, nikdy přímo do YAML. Tento princip
(trigger → joby → kroky) je koncepčně stejný i v GitLab CI/CD, jen s
jinou syntaxí (.gitlab-ci.yml, stages, script).

Kontrolní otázky

  1. Jaký je rozdíl mezi jobem a krokem (step) ve workflow?
  2. Jak zajistíte, aby se job deploy spustil až po úspěšném dokončení
    jobů build a test?
  3. Proč se citlivé hodnoty jako API klíče neukládají přímo do YAML
    souboru workflow?
  4. Mini cvičení: v existujícím (nebo novém) GitHub repozitáři vytvořte
    .github/workflows/ci.yml, který se spustí při každém push a
    spustí alespoň jeden triviální příkaz (např. echo "Ahoj CI"), pak
    ověřte v záložce Actions, že workflow proběhl úspěšně.

Lekce na sebe nejsou zamčené — libovolnou lekci můžete otevřít i označit jako hotovou v jakémkoliv pořadí.