Docker ist ein Container Management System, mit dem man Code auf jeder Maschine unabhängig vom Betriebssystem ausführen kann. Mehr über Docker kannst du in der offiziellen [Docker Dokumentation](https://docs.docker.com/manuals/) finden
[TOC]
## Dockerfile
Dockerfiles beschreiben die Schritte, die für das erstellen eines Containers befolgt werden. In diesem Repository sind zwei Dockerfiles. Wie diese erweitert werden können, findet man in der [offiziellen Dockerfile Referenz](https://docs.docker.com/reference/dockerfile/).
### Datenbank
Diese Dockerfile startet eine [Postgres Datenbank](https://www.postgresql.org). Im moment wird das `postgres:16-alpine` image genommen. Beim start wird das Password auf `password` gesetzt und der Standardport `5432` erreichbar gemacht. Solltest du diesen Container öffentlich zugänglich machen, änder **unbedingt** das Password. Als letzten Schritt kopiert die Dockerfile die `schema.sql` Datei in `/docker-entrypoint-initdb.d/`, wo beim Containerstart alle SQL Befehle ausgeführt werden.
### API
Die Dockerfile für die API benutzt das neuste `node` image, kopier `package.json` und `package-lock.json` in den Container und installiert damit dann die dependencies. Danach wird jede Datei, die nicht von der `.dockerignore` ingoriert wird in den Container kopiert um ihn dann mit `node . ` zu starten. Standardmäßig macht die Dockerfile den Port `3000` zugänglich, solltest du das ändern wollen, musst du das dann auch in der `index.js` tun.
## docker-compose.yaml
Docker Compose Dateien haben feste Anweisungen, wie Container und ihre Umgebung erstellt werden sollen. Mit ihnen kann man Container in geteilte Netzwerke packen, ihnen namen geben, Ports öffnen und Healthchecks definieren.
### Netzwerk
Compose erstellt ein Netzwerk, welches die API mit der Datenbank für Kommunikation verknüpft, ohne sie öffentlich zugänglich zu machen
```yaml
networks:
evaluation-network:
diver:bridge
```
### Bauen
Container werden mit dem `services:` Schlüssel erstellt
```yaml
services:
database:
build:
context:./
dockerfile:Dockerfile
api:
build:
context:./api
dockerfile:Dockerfile
```
Der `context` Schlüssel gibt Docker den Path unter dem es die Dockerfile erwarten kann um das image zu bauen.
### Health check
Um sicherzugehen, dass die Datenbank vollständig funktioniert, wird ein Healthcheck erstellt. Dieser ruft alle 10 Sekunden `pg_isready` auf, bis die Abfrage erfolgreich war. `pg_isready` ist eine Funktion von Postgres selbst, welche nur erfolgreich endet, falls die Datenbank richtig gestartet wurde und Verbindungen akzeptiert.
```yaml
healthcheck:
test:["CMD","pg_isready"]
interval:10s
timeout:1s
retries:3
```
Der API container kann dann auf diesen Healthcheck warten, bevor er startet.
```yaml
depends_on:
database:
condition:service_healthy
```
### Umgebungsvariablen
Wenn die API manuell gestartet wird, liest diese die `.env` Datei aus. Damit die API dasselbe in Docker kann, müssen die gleichen Umgebungsvariablen mit dem `environment` Schlüssel angegeben werden.
```yaml
environment:
-DB_HOST=database
-DB_USER=postgres
-DB_PASS=password
-DB_DATABASE=evaluation
```
Solltest du diese Daten irgendwo beim erstellen des Datenbank Containers verändert haben, musst du diese auch hier ändern.
### Port
Da beide Container isoliert auf einem Netzwerk liegen, muss die API extra anfragbar gemacht werden. Dafür muss einfach nur der `ports` Schlüssel konfiguriert werden:
```yaml
ports:
-"50000:3000"
```
Solltest du in der API Dockerfile den Port veränder haben, musst du die `3000` hier durch diesen ersetzten. Solltest du deine API auf einem anderen Port als `50000` erreichen wollen, musst du diese hier mit einer anderen Zahl ersetzen. Denk aber dran, dass nicht alle Ports verfügbar sind, wie auf [dieser Liste](https://de.wikipedia.org/wiki/Liste_der_Portnummern) zu finden ist.