Docker und MySQL für React-Projekte einrichten
Docker und MySQL einrichten
~14 Min. Lesezeit Zuletzt aktualisiert am 8. August 2026
Unsere Bewertungen leben bisher nur im React-State – nach jedem Neuladen sind sie weg. In diesem und dem nächsten Kapitel bauen wir einen eigenen, kleinen Server samt Datenbank, damit Bewertungen wirklich dauerhaft gespeichert werden. Der erste Schritt: Docker und eine MySQL-Datenbank.
Was ist Docker, ganz genau?
Eine Datenbank wie MySQL ist eigentlich ein eigenständiges Programm, das Sie normalerweise aufwändig auf Ihrem Computer installieren, konfigurieren und pflegen müssten – mit Versionskonflikten, Betriebssystem-Unterschieden und viel manueller Einrichtung. Docker löst dieses Problem, indem es Programme in "Containern" verpackt: fertig konfigurierte, isolierte Mini-Umgebungen, die auf jedem Computer identisch laufen, egal ob Windows, Mac oder Linux.
| Docker-Begriff | Vergleich |
|---|---|
| Image – die "Bauanleitung"/das "Rezept" für einen Container, z. B. "MySQL Version 8" | vergleichbar mit einer .dmg/.exe-Installationsdatei, nur reproduzierbar und identisch für jeden |
| Container – eine LAUFENDE Instanz eines Images | vergleichbar mit einem laufenden Programm/Prozess – Sie können mehrere Container aus demselben Image starten |
| docker-compose.yml – eine Konfigurationsdatei, die mehrere zusammengehörige Container beschreibt | vergleichbar mit einer package.json, nur für ganze Programme/Dienste statt npm-Pakete |
docker-compose.yml anlegen
Legen Sie im Hauptordner (auf derselben Ebene wie package.json, NICHT in src/) die Datei docker-compose.yml an:
services:
mysql:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: geheimespasswort
MYSQL_DATABASE: produktkatalog
ports:
- '3306:3306'
volumes:
- mysql-daten:/var/lib/mysql
volumes:
mysql-daten:Zeile für Zeile: image: mysql:8.0 lädt automatisch das offizielle, fertig konfigurierte MySQL-Image von Docker Hub (dem "App Store" für Container-Images) herunter. environment setzt Umgebungsvariablen, die das MySQL-Image selbst auswertet, um beim allerersten Start automatisch ein Root-Passwort und eine leere Datenbank namens produktkatalog anzulegen. ports: '3306:3306' verbindet den Port 3306 IM Container mit Port 3306 AUF Ihrem Computer, damit Programme außerhalb des Containers (unser gleich folgender Node-Server) sich verbinden können. volumes sorgt dafür, dass die Datenbank-Dateien auch nach einem docker compose down erhalten bleiben, statt mit dem Container gelöscht zu werden.
MySQL starten
docker compose up -d-d ("detached") startet die Container im Hintergrund, statt Ihr Terminal zu blockieren. Prüfen Sie, ob es läuft:
docker compose psSie sollten einen Eintrag mit Status "running" oder "Up" sehen. Zum Beenden später: docker compose down (die Datenbank-DATEN bleiben dank volumes erhalten, nur der laufende Container wird gestoppt).
server/: den Grundstein für unseren Node-Server legen
Unser eigener Server lebt in einem eigenen Ordner server/, komplett getrennt von src/ (das ist React-Code, der im BROWSER läuft) – der Server-Code läuft dagegen direkt mit Node.js, ohne Browser. Legen Sie server/package.json an:
{
"name": "produktkatalog-server",
"type": "module",
"scripts": {
"start": "node server.js"
},
"dependencies": {
"express": "^4.19.0",
"mysql2": "^3.9.0",
"cors": "^2.8.5"
}
}"type": "module" aktiviert moderne import/export-Syntax statt des älteren require() – dieselbe Syntax, die Sie im gesamten src/-Ordner schon verwenden. Installieren Sie die drei Pakete:
cd server
npm install
cd ..express ist das gängigste Web-Server-Framework für Node.js (vergleichbar mit Symfony/Laravel-Routing in der PHP-Welt, nur deutlich minimalistischer). mysql2 ist der Datenbanktreiber, mit dem wir uns aus Node.js heraus mit unserem gerade gestarteten MySQL-Container verbinden. cors erlaubt unserer React-App (läuft auf localhost:5173), Anfragen an unseren Server (läuft auf einem anderen Port) zu stellen – ohne cors blockiert der Browser das standardmäßig aus Sicherheitsgründen.
server/db.js: die Datenbankverbindung
import mysql from 'mysql2/promise';
export const pool = mysql.createPool({
host: 'localhost',
user: 'root',
password: 'geheimespasswort',
database: 'produktkatalog',
});mysql2/promise statt mysql2 ist wichtig – die "promise"-Variante unterstützt async/await aus Kapitel 22, statt nur Callback-Funktionen. Ein "Pool" verwaltet automatisch mehrere wiederverwendbare Datenbankverbindungen im Hintergrund, statt für jede Anfrage eine neue Verbindung aufzubauen und wieder zu schließen – deutlich performanter.
server/server.js: das Grundgerüst
import express from 'express';
import cors from 'cors';
import { pool } from './db.js';
const app = express();
app.use(cors());
app.use(express.json());
app.get('/api/health', async (req, res) => {
const [rows] = await pool.query('SELECT 1 AS ok');
res.json({ status: 'ok', datenbankVerbunden: rows[0].ok === 1 });
});
app.listen(4000, () => {
console.log('Server läuft auf http://localhost:4000');
});app.use(express.json()) sorgt dafür, dass Express eingehende JSON-Anfragen automatisch in req.body umwandelt (das brauchen wir im nächsten Kapitel für neue Bewertungen). Starten Sie den Server und testen Sie den Gesundheitscheck:
cd server
node server.jsÖffnen Sie in einem zweiten Terminal (oder Browser-Tab) http://localhost:4000/api/health – Sie sollten {{"status":"ok","datenbankVerbunden":true}} sehen. Das bestätigt: Node-Server UND MySQL-Verbindung funktionieren beide.
Ziel-Projektstruktur (Erinnerung aus Kapitel 3) – server/ nimmt jetzt Form an
produktkatalog-web/
├── index.html
├── package.json
├── vite.config.js
├── docker-compose.yml (MySQL-Container für Bewertungen)
├── server/ (eigener Node/Express-Server)
│ ├── package.json
│ ├── server.js
│ └── db.js
└── src/
├── main.jsx
├── App.jsx (Routing)
├── index.css
├── api/
│ ├── magentoApi.js (Magento-REST-API: Produkte)
│ └── reviewsApi.js (eigener Server: Bewertungen)
├── context/
│ └── AuthContext.jsx (einfacher Login-Zustand)
├── components/
│ ├── ProductCard.jsx
│ └── ProtectedRoute.jsx
├── hooks/
│ └── useDocumentTitle.js (Custom Hook)
└── pages/
├── ProductListPage.jsx
├── ProductDetailPage.jsx
├── ReviewsPage.jsx (verschachtelte Route)
├── LoginPage.jsx
└── AccountPage.jsx (geschützte Route)Achtung: Ein echtes Passwort gehört NIEMALS direkt in den Code, wie wir es hier zur Vereinfachung tun – in einem echten Projekt würden Sie Zugangsdaten in einer .env-Datei speichern (die NICHT ins Git-Repository eingecheckt wird) und über das Paket dotenv laden. Für dieses lokale Lern-Setup ist das feste Passwort im Code eine bewusste Vereinfachung.