GitLab Pipelines · Workshop Lektion 7 / services

services – eine echte Datenbank im Test

Integrationstests gegen Postgres, direkt in der Pipeline.

Warum das zählt
Unsere Tasks-API speichert Aufgaben in einer Datenbank. Unit-Tests mit Mocks reichen nicht – du willst gegen ein echtes Postgres testen. Mit services startet GitLab dir eine Wegwerf-DB neben dem Job. Das ist der Schritt von „Spielzeug-Pipeline" zu „testet wie in echt".

Kurzer Rückruf

Welche Variable nennt den Default-Branch des Projekts?

Die Idee: ein Begleit-Container

services startet zusätzlich zum Job-Container einen weiteren Container – z. B. Postgres. Beide laufen im selben Netzwerk; der Job erreicht den Service über einen Hostnamen. Der Hostname ist standardmässig vom Image abgeleitet – am klarsten setzt man ihn per alias.

Job-Container

pytest
verbindet zu →

Service-Container

postgres:16
Host: postgres
Zwei Container, ein Netzwerk. Der Test erreicht die DB unter dem Hostnamen postgres.

Die .gitlab-ci.yml

integration-test:
  stage: test
  image: python:3.12-slim
  services:
    - name: postgres:16
      alias: postgres        # Hostname für den Job
  variables:
    POSTGRES_DB: tasks_test
    POSTGRES_USER: tasks
    POSTGRES_PASSWORD: secret
    # die App liest ihre Verbindung aus DATABASE_URL:
    DATABASE_URL: "postgresql://tasks:secret@postgres:5432/tasks_test"
  script:
    - pip install -r requirements.txt pytest
    - pytest tests/integration -q

Die POSTGRES_*-Variablen werden an beide Container übergeben: Postgres initialisiert damit Datenbank und Benutzer, und der Job nutzt dieselben Werte in DATABASE_URL – Hostname postgres, Port 5432.

Dein Win Deine Pipeline testet jetzt gegen eine echte Postgres-Instanz – frisch, isoliert, und nach dem Job weg.

Besonderheiten & Stolperfallen

Der Service braucht einen Moment Postgres ist nicht sofort bereit, wenn der Container startet. Verbindet sich dein Test zu früh, scheitert er mit „connection refused". Robuste Pipelines warten kurz – z. B. mit pg_isready in einer Schleife im before_script, bevor die Tests starten.
Hostname = Image-Name oder alias Ohne alias wäre der Host vom Image-Namen abgeleitet (Doppelpunkt-Teil weg, Slashes zu Sonderzeichen). Ein expliziter alias: postgres ist vorhersehbar und lesbar – immer setzen.
Passwort-Pflicht Ohne POSTGRES_PASSWORD (oder POSTGRES_HOST_AUTH_METHOD: trust) weigert sich das offizielle Postgres-Image zu starten. Im Test ist ein simples Passwort okay – es ist eine Wegwerf-DB.
Services sind nicht nur Datenbanken Dasselbe Muster gilt für Redis, MySQL, ein Mock-API-Image, sogar docker:dind (nächste Lektion). „Service" heisst einfach: ein Begleit-Container, den dein Job über einen Hostnamen erreicht.

Übung für Teilnehmende

Übung 1 · Verbindung lesen

Frage: Der Service hat alias: db. Wie lautet die DATABASE_URL für Benutzer app, Passwort pw, DB shop?

Lösung anzeigen

postgresql://app:pw@db:5432/shop – Hostname ist der alias, Port 5432.

Übung 2 · Robustheit

Aufgabe: Ergänze ein before_script, das wartet, bis Postgres bereit ist, bevor die Tests laufen. (Tipp: pg_isready -h postgres.)

Lösung anzeigen
before_script:
  - apt-get update && apt-get install -y postgresql-client
  - until pg_isready -h postgres -U tasks; do sleep 1; done

Die Schleife blockiert, bis die DB Verbindungen annimmt – das beseitigt sporadische „connection refused"-Fehler.

Übung 3 · Redis dazu

Frage: Du brauchst zusätzlich Redis. Wie viele Einträge unter services: und wie erreichst du Redis?

Lösung anzeigen

Zwei Service-Einträge (Postgres + name: redis:7, alias: redis). Redis erreichst du unter Host redis, Port 6379. Mehrere Services sind völlig normal.

Kurz prüfen (aus dem Kopf)

Wie erreicht ein Job seinen Service-Container?

Warum scheitern Tests manchmal direkt am Start?

Primärquelle zum Lesen GitLab Docs – Services und das PostgreSQL-Beispiel.
Frag deinen Teacher. Brauchst du ein vollständiges FastAPI-Integrationstest-Setup? Sag Bescheid.
← Lektion 6 Lektion 8 · Container Registry →