für Datenbanken in Docker-Dev-Containern
Seed-Daten unterscheiden sich fundamental von reinen Init-Skripten: Init-Skripte legen das Schema an, Seed-Daten füllen es mit realistischen, wiederholbaren Testdaten. Wer beide Konzepte vermischt, endet entweder mit leeren Entwicklungsdatenbanken oder mit inkonsistenten Testständen zwischen Teammitgliedern.
Inhaltsverzeichnis
- 1. Warum Seed-Daten etwas anderes sind als Init-Skripte
- 2. Seed-Strategie: anonymisierter Produktions-Dump
- 3. Seed-Strategie: programmatische Seeder mit Faker
- 4. Idempotente Seed-Skripte richtig schreiben
- 5. Seed-Daten als eigener Service mit docker compose run
- 6. Schnelles Reset über Volume-Snapshots statt Neu-Seed
- 7. Seed-Daten für Magento-spezifische Testszenarien
- 8. Seeds in CI-Pipelines konsistent halten
- 9. Seed-Strategien im Vergleich
- 10. Zusammenfassung
- 11. FAQ
1. Warum Seed-Daten etwas anderes sind als Init-Skripte
Init-Skripte im offiziellen MySQL- oder PostgreSQL-Image legen beim ersten Start des Containers das Datenbankschema an, erzeugen Tabellen und Indizes und laufen üblicherweise genau einmal. Seed-Daten sind davon konzeptionell getrennt: sie füllen ein bereits existierendes Schema mit realistischen, für Entwicklung und manuelle Tests brauchbaren Datensätzen, und sollen im Gegensatz zu Init-Skripten beliebig oft wiederholbar sein, etwa wenn ein Entwickler versehentlich Testdaten kaputt gemacht hat und einen sauberen Ausgangszustand braucht.
Der Unterschied wird besonders bei Magento-Projekten sichtbar: das Schema mit all seinen EAV-Tabellen entsteht durch setup:install beziehungsweise Init-Skripte, aber realistische Seed-Daten mit hunderten Produkten, Kategorien und Testkunden müssen separat eingespielt werden, um Checkout-Flows, Suchfunktionen oder Rabattregeln sinnvoll manuell testen zu können. Ohne durchdachte Seed-Daten arbeitet jeder Entwickler mit einer fast leeren Datenbank, was Bugs verschleiert, die erst bei realistischen Datenmengen auftreten.
Dieser Artikel zeigt verschiedene Strategien für Seed-Daten in Docker-Dev-Containern, von anonymisierten Produktions-Dumps über programmatische Seeder bis zu schnellen Volume-Snapshots, die einen kompletten Reset in Sekunden statt Minuten ermöglichen.
2. Seed-Strategie: anonymisierter Produktions-Dump
Die realistischste Quelle für Seed-Daten ist ein Export der tatsächlichen Produktionsdatenbank, allerdings niemals unverändert, sondern immer mit anonymisierten personenbezogenen Daten. Namen, E-Mail-Adressen, Telefonnummern und Zahlungsinformationen müssen vor der Nutzung als lokale Seed-Daten zwingend durch Platzhalter oder generierte Fake-Werte ersetzt werden, sowohl aus Datenschutzgründen als auch, um Entwickler nicht versehentlich mit echten Kundendaten hantieren zu lassen.
#!/usr/bin/env bash
# anonymize-and-export.sh — create anonymized seed data from production
set -euo pipefail
PROD_DB="shop_production"
SEED_FILE="./seed/anonymized-dump.sql"
mysqldump --single-transaction --no-tablespaces "$PROD_DB" > /tmp/raw-dump.sql
# Anonymize personal data before it ever leaves the secure environment
mysql "$PROD_DB" <<'SQL'
UPDATE customer_entity
SET email = CONCAT('customer', entity_id, '@example.test'),
firstname = 'Test',
lastname = CONCAT('User', entity_id);
UPDATE sales_order_address
SET telephone = '000000000', street = 'Test Street 1';
SQL
mysqldump --single-transaction --no-tablespaces "$PROD_DB" > "$SEED_FILE"
echo "[OK] Anonymized seed data written to $SEED_FILE"
Wichtig für diese Strategie: die Anonymisierung muss vor dem Export erfolgen, niemals danach, weil ein bereits exportierter Dump mit echten Daten schon außerhalb der geschützten Produktionsumgebung existiert. Ein solcher anonymisierter Dump als Seed-Daten-Quelle liefert realistische Datenverteilungen und Kantenfälle, die synthetische Generatoren oft übersehen, etwa besonders lange Produktnamen oder ungewöhnliche Preiskombinationen.
3. Seed-Strategie: programmatische Seeder mit Faker
Wo kein Produktions-Dump verfügbar ist, etwa bei neuen Projekten ohne Live-Daten, übernehmen programmatische Seeder mit Bibliotheken wie Faker die Generierung von Seed-Daten. Der Vorteil gegenüber einem statischen SQL-Dump: die Menge und Struktur der Testdaten lässt sich flexibel parametrisieren, etwa "erzeuge 500 Produkte in 10 Kategorien mit 50 Testkunden", ohne eine feste Datei pflegen zu müssen.
<?php
declare(strict_types=1);
namespace Mironsoft\DevTools\Console\Command;
use Faker\Factory as FakerFactory;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
/**
* Seeds the development database with realistic, reproducible test data.
* Intended to run inside the app container against the local dev database.
*/
final class SeedTestDataCommand extends Command
{
protected static $defaultName = 'dev:seed';
protected function execute(InputInterface $input, OutputInterface $output): int
{
// Fixed seed value keeps generated data identical across every run
$faker = FakerFactory::create('de_DE');
$faker->seed(42);
$pdo = new \PDO('mysql:host=db;dbname=shop_dev', 'root', 'secret');
for ($i = 0; $i < 500; $i++) {
$stmt = $pdo->prepare(
'INSERT INTO catalog_product_seed (sku, name, price) VALUES (?, ?, ?)'
);
$stmt->execute([
sprintf('SEED-%04d', $i),
$faker->words(3, true),
$faker->randomFloat(2, 5, 500),
]);
}
$output->writeln('[OK] Seeded 500 products with deterministic Faker data');
return Command::SUCCESS;
}
}
Der entscheidende Kniff bei diesem Ansatz ist $faker->seed(42): durch den festen Seed-Wert erzeugt Faker bei jedem Lauf exakt dieselben Seed-Daten, statt bei jedem Aufruf zufällige neue Werte zu liefern. Das macht Bugreports reproduzierbar, weil ein Kollege mit demselben Seed-Skript exakt dieselben Testdaten erhält, statt raten zu müssen, welches zufällig generierte Produkt den beobachteten Fehler ausgelöst hat.
4. Idempotente Seed-Skripte richtig schreiben
Ein häufiger Fehler bei Seed-Daten-Skripten: sie funktionieren nur beim ersten Ausführen und schlagen bei jedem weiteren Aufruf mit Duplicate-Key-Fehlern fehl, weil sie stumpf INSERT-Anweisungen ohne Berücksichtigung bereits vorhandener Daten ausführen. Ein idempotentes Seed-Skript muss dagegen beliebig oft ausführbar sein und immer im selben, definierten Endzustand landen, unabhängig davon, wie oft es zuvor gelaufen ist.
-- WRONG: fails with duplicate key error on every run after the first
INSERT INTO catalog_product_seed (sku, name, price)
VALUES ('SEED-0001', 'Test Product', 19.99);
-- RIGHT: idempotent via TRUNCATE before re-seeding
TRUNCATE TABLE catalog_product_seed;
INSERT INTO catalog_product_seed (sku, name, price)
VALUES ('SEED-0001', 'Test Product', 19.99);
-- ALTERNATIVE: idempotent via upsert when truncation is not desired
INSERT INTO catalog_product_seed (sku, name, price)
VALUES ('SEED-0001', 'Test Product', 19.99)
ON DUPLICATE KEY UPDATE
name = VALUES(name),
price = VALUES(price);
Für Seed-Daten, die vollständig kontrolliert und reproduzierbar sein sollen, ist TRUNCATE vor dem erneuten Einfügen meist die robustere Wahl, weil sie garantiert einen exakt definierten Endzustand herstellt. Der Upsert-Ansatz mit ON DUPLICATE KEY UPDATE eignet sich besser, wenn zusätzliche, manuell angelegte Testdaten neben den generierten Seed-Daten erhalten bleiben sollen.
5. Seed-Daten als eigener Service mit docker compose run
Statt Seed-Logik manuell in einen laufenden Container zu exec-en, lohnt sich ein dedizierter Compose-Service, der ausschließlich für das Einspielen von Seed-Daten zuständig ist und danach beendet wird. Dieser Service teilt sich Netzwerk und Datenbankzugriff mit dem Hauptstack, läuft aber nicht dauerhaft mit, sondern wird gezielt über docker compose run gestartet.
# docker-compose.yml — dedicated seeding service, not started with "up"
services:
app:
build: .
depends_on:
db:
condition: service_healthy
db:
image: mysql:8.4
environment:
MYSQL_ROOT_PASSWORD: secret
MYSQL_DATABASE: shop_dev
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
interval: 5s
retries: 10
seed:
build: .
depends_on:
db:
condition: service_healthy
command: ["bin/console", "dev:seed"]
profiles: ["seed"]
# Start the stack normally without seeding
docker compose up -d
# Run seed data explicitly, only when actually needed
docker compose run --rm seed
Der Profil-Schlüssel seed stellt sicher, dass dieser Service niemals versehentlich bei einem normalen docker compose up mitgestartet wird. Stattdessen läuft er nur explizit über docker compose run --rm seed, was Seed-Daten-Läufe zu einer bewussten, klar sichtbaren Aktion macht statt eines unsichtbaren Nebeneffekts beim normalen Hochfahren des Stacks.
6. Schnelles Reset über Volume-Snapshots statt Neu-Seed
Bei größeren Datenmengen kann das komplette Neu-Seeden mehrere Minuten dauern, was im Entwicklungsalltag störend ist, wenn ein Entwickler nur schnell zu einem sauberen Ausgangszustand zurück möchte. Deutlich schneller ist, einmal geseedete Seed-Daten als Volume-Snapshot zu sichern und bei Bedarf einfach das Volume zurückzuspielen, statt das komplette Seed-Skript erneut auszuführen.
#!/usr/bin/env bash
# snapshot-seed-data.sh — back up an already-seeded volume for instant restore
set -euo pipefail
VOLUME_NAME="shop-dev_db_data"
SNAPSHOT_DIR="./seed/snapshots"
mkdir -p "$SNAPSHOT_DIR"
echo "[INFO] Creating snapshot of seeded volume..."
docker run --rm \
-v "${VOLUME_NAME}:/source:ro" \
-v "$(pwd)/${SNAPSHOT_DIR}:/backup" \
alpine tar czf /backup/seeded-baseline.tar.gz -C /source .
echo "[OK] Snapshot saved to ${SNAPSHOT_DIR}/seeded-baseline.tar.gz"
#!/usr/bin/env bash
# restore-seed-data.sh — instant reset to the seeded baseline, seconds not minutes
set -euo pipefail
docker compose down
docker volume rm shop-dev_db_data || true
docker volume create shop-dev_db_data
docker run --rm \
-v "shop-dev_db_data:/target" \
-v "$(pwd)/seed/snapshots:/backup:ro" \
alpine tar xzf /backup/seeded-baseline.tar.gz -C /target
docker compose up -d
echo "[OK] Restored to seeded baseline in seconds"
Dieser Ansatz trennt bewusst zwei unterschiedliche Operationen: das einmalige, unter Umständen langsame Erzeugen der Seed-Daten, und das häufige, immer schnelle Zurücksetzen auf genau diesen Zustand. Für Entwickler, die mehrmals täglich einen sauberen Datenbankstand brauchen, etwa während intensiver manueller Tests, spart dieses Muster erhebliche Wartezeit gegenüber einem kompletten Neu-Seed.
7. Seed-Daten für Magento-spezifische Testszenarien
Magento bringt mit den Sample-Data-Paketen bereits eine Grundmenge an Seed-Daten mit, die für einen ersten Eindruck ausreicht, aber selten die spezifischen Testszenarien eines echten Projekts abdeckt. Für realistische Tests von Rabattregeln, mehrstufigen Kategoriebäumen oder Multi-Website-Setups sind projektspezifische Seed-Daten nötig, die über eigene Data Patches oder CLI-Befehle eingespielt werden, statt sich auf die generischen Sample-Daten zu verlassen.
Ein bewährtes Muster ist ein eigener bin/magento-Befehl, der gezielt Testkunden mit unterschiedlichen Kundengruppen, Produkte mit Sonderpreisen und Bestellungen in verschiedenen Status anlegt. Diese projektspezifischen Seed-Daten spiegeln reale Geschäftslogik wider, etwa gestaffelte B2B-Rabatte oder saisonale Angebote, und decken damit Bugs auf, die mit den generischen Magento-Beispieldaten niemals sichtbar würden.
8. Seeds in CI-Pipelines konsistent halten
Dieselben Seed-Daten, die lokal für manuelle Tests genutzt werden, sollten idealerweise auch in der CI-Pipeline für automatisierte End-to-End-Tests zum Einsatz kommen. Ein zentrales Seed-Skript, das sowohl lokal als auch im CI-Runner identisch ausgeführt wird, verhindert die Situation, in der ein Test lokal grün ist, aber in der CI fehlschlägt, weil dort andere Testdaten vorliegen als auf dem Entwicklerrechner.
Wichtig dabei: CI-Umgebungen sollten niemals den vollständigen anonymisierten Produktions-Dump nutzen, weil dieser für schnelle CI-Läufe zu groß und zu langsam ist. Für CI eignet sich stattdessen eine kompaktere Teilmenge der Seed-Daten, generiert über denselben Faker-Seeder mit denselben festen Seed-Werten, aber mit deutlich reduzierter Datenmenge, etwa 50 statt 500 Produkten, um Pipeline-Laufzeiten kurz zu halten.
9. Seed-Strategien im Vergleich
Die Wahl der passenden Seed-Strategie hängt stark vom Projektstand und den verfügbaren Datenquellen ab.
| Strategie | Realismus | Setup-Aufwand | Geschwindigkeit |
|---|---|---|---|
| Anonymisierter Produktions-Dump | Sehr hoch | Hoch (Anonymisierung nötig) | Langsam bei großen Dumps |
| Faker-Seeder | Mittel | Mittel | Schnell und parametrisierbar |
| Volume-Snapshot | Wie Quelle des Snapshots | Niedrig nach Ersteinrichtung | Sehr schnell (Sekunden) |
Für maximale Realitätsnähe bei komplexen Bugreports ist der anonymisierte Produktions-Dump unschlagbar, kostet aber den größten Einrichtungsaufwand wegen der Anonymisierungspflicht. Faker-Seeder liefern schnell parametrisierbare Seed-Daten für neue Projekte ohne Produktionshistorie. Volume-Snapshots sind kein eigenständiger Datengenerator, sondern eine Geschwindigkeitsoptimierung für häufige Resets bereits vorhandener Seed-Daten.
Mironsoft
Seed-Skripte, Testdaten-Strategien und Docker-Entwicklungsumgebungen für Magento
Realistische Testdaten für euer gesamtes Team?
Wir bauen anonymisierte Dump-Pipelines, idempotente Faker-Seeder und Volume-Snapshot-Workflows für eure Magento- und PHP-Projekte, damit jeder Entwickler dieselben, reproduzierbaren Seed-Daten nutzt.
Anonymisierungs-Pipeline
Sichere, DSGVO-konforme Erstellung von Seed-Daten aus Produktionsdaten
Faker-Seeder-Entwicklung
Idempotente, parametrisierbare Seed-Skripte für neue Projekte ohne Produktionshistorie
Volume-Snapshot-Workflow
Sekundenschnelle Resets auf einen sauberen, geseedeten Ausgangszustand
10. Zusammenfassung
Seed-Daten lösen ein anderes Problem als Init-Skripte: statt Schema anzulegen, füllen sie eine Datenbank mit realistischen, wiederholbaren Testdaten für Entwicklung und manuelle Prüfung. Anonymisierte Produktions-Dumps liefern maximalen Realismus, programmatische Faker-Seeder mit festem Seed-Wert liefern reproduzierbare, parametrisierbare Datenmengen ohne Produktionshistorie, und idempotente Skripte mit TRUNCATE oder Upsert stellen sicher, dass wiederholtes Seeding niemals mit Duplicate-Key-Fehlern scheitert.
Volume-Snapshots ergänzen diese Strategien um schnelle Resets in Sekunden statt Minuten, während dedizierte Compose-Services mit Profile-Flag Seed-Daten-Läufe zu einer bewussten, sichtbaren Aktion machen statt eines unsichtbaren Nebeneffekts. Wer dieselben Seed-Mechanismen konsistent zwischen lokaler Entwicklung und CI-Pipeline einsetzt, vermeidet die frustrierende Situation, dass ein Test lokal grün, in der CI aber rot ist, nur weil unterschiedliche Seed-Daten zugrunde lagen.
Seed-Daten für Docker-Dev-Container — Das Wichtigste auf einen Blick
Init vs. Seed
Init-Skripte legen das Schema an, Seed-Daten füllen es mit realistischen, wiederholbar einspielbaren Testdaten.
Anonymisierung
Personenbezogene Daten immer vor dem Export ersetzen, niemals einen ungeschützten Dump verteilen.
Idempotenz
TRUNCATE vor dem Neuseeden oder ON DUPLICATE KEY UPDATE verhindert Fehler bei wiederholten Läufen.
Volume-Snapshots
Einmal geseedete Volumes sichern und in Sekunden zurückspielen, statt jedes Mal neu zu seeden.