Anleitung

Docker für PrestaShop: Entwicklungsumgebung einrichten

Docker für PrestaShop einrichten: Multi-Versions-Tests, Modul-Workflow, Datenbankverwaltung, Xdebug-Debugging und Produktionsüberlegungen.

Warum wir jeden PrestaShop-Shop auf Docker betreiben

Unsere gesamte Entwicklungs- und Staging-Infrastruktur bei mypresta.rocks läuft auf Docker, ein TrueNAS-Host, dedizierte Container wie ps176-dev, ps178-dev, ps8-dev und ps9-dev, ein gemeinsam genutztes ps-redis, ein Nginx Proxy Manager als vorgeschaltete Instanz. Jeden Fehler auf dieser Seite haben wir mindestens einmal selbst gemacht.

Das Problem: PS 1.7 verlangt PHP 7.1, PS 8.x verlangt 8.1, PS 9.x verlangt 8.3+. MySQL 5.7 gegenüber 8.0 ändert das Authentifizierungs-Plugin. Das nativ zu installieren ist der sichere Weg, einen Samstag mit Fehlersuche zu verbringen, statt Module zu schreiben. Jeder Container liefert exakt die Laufzeitumgebung mit, die sein PrestaShop erwartet.

  • Tests über mehrere Versionen. PS 1.6, 1.7, 8.x und 9.x gleichzeitig. Ein Modul-Audit ist eine Sache von einem Nachmittag, nicht von einer Woche, in der LAMP-Stacks neu aufgebaut werden.
  • Isolation. Jeder Shop hat sein eigenes PHP, MySQL und Dateisystem. Eine misslungene Installation kann nicht auf einen anderen übergreifen.
  • Reproduzierbarkeit. Alles steckt in der docker-compose.yml. Laptop, Staging, der Rechner eines Kollegen, dieselbe Einrichtung.
  • Einfaches Aufräumen. docker compose down -v und alles ist weg.
Wir betreiben separate PrestaShop-Container von 1.6 bis 9.1 auf einer einzigen TrueNAS-Box. Die folgenden Muster sind das, was wir nach einem Jahrzehnt der Verfeinerung beibehalten haben.

Voraussetzungen

Docker installieren

Ubuntu/Debian: curl -fsSL https://get.docker.com | sh, anschließend sudo usermod -aG docker $USER. macOS: Docker Desktop: die Implementierung der Dateifreigabe in den Einstellungen auf VirtioFS umstellen. Windows: zuerst WSL2, dann Docker Desktop mit dem WSL2-Backend. Der Hyper-V-Modus ist langsamer; wir würden ihn meiden.

Die vier Konzepte, auf die es ankommt

  • Image: schreibgeschützte Vorlage. Das offizielle ist prestashop/prestashop auf Docker Hub.
  • Container: eine laufende Instanz. Mehrere aus einem Image, genau so funktionieren Einrichtungen mit mehreren Versionen.
  • Volume: persistenter Speicher. Kein Volume, keine Daten nach dem Entfernen des Containers. Wir haben Testdaten verloren, weil wir das vergessen hatten.
  • Netzwerk: virtuelles Netzwerk, damit Container sich gegenseitig erreichen können (PrestaShop ↔ MySQL).

Hardware

Rechnen Sie mit 1,5–2 GB RAM pro PrestaShop-Instanz. 16 GB sind auf einem Entwickler-Laptop für 2–3 Versionen angenehm. Unsere Entwicklungsmaschine hat 64 GB und NVMe, weil wir mehrere versionierte Container gleichzeitig betreiben. Mit drehenden Festplatten werden Sie Docker hassen, versuchen Sie es gar nicht erst.

Einrichtung mit zwei Containern

Legen Sie dies in eine docker-compose.yml:

version: '3.8'
services:
  prestashop:
    image: prestashop/prestashop:8.2
    container_name: <your-shop>
    ports:
      - "8080:80"
    environment:
      - DB_SERVER=db
      - DB_USER=prestashop
      - DB_PASSWD=prestashop_password
      - DB_NAME=prestashop
      - PS_DOMAIN=localhost:8080
      - PS_FOLDER_ADMIN=admin-dev
      - PS_FOLDER_INSTALL=disabled
      - ADMIN_MAIL=admin@yourshop.com
      - ADMIN_PASSWD=admin_password_123
    volumes:
      - shop-data:/var/www/html
    depends_on:
      - db

  db:
    image: mysql:8.0
    container_name: <your-shop>-db
    environment:
      - MYSQL_ROOT_PASSWORD=root_password
      - MYSQL_DATABASE=prestashop
      - MYSQL_USER=prestashop
      - MYSQL_PASSWORD=prestashop_password
    volumes:
      - shop-db-data:/var/lib/mysql

volumes:
  shop-data:
  shop-db-data:

DB_SERVER muss exakt mit dem Dienstnamen (db) übereinstimmen, der mit Abstand häufigste Grund, warum ein frisches Compose-Setup scheitert. PS_FOLDER_INSTALL=disabled verhindert, dass der Installer bei jedem Neustart erneut läuft. docker compose up -d, dann mit docker compose logs -f prestashop beobachten; beim ersten Mal 1–2 Minuten einplanen.

Shop unter http://localhost:8080, Back Office unter http://localhost:8080/admin-dev.

Verwenden Sie für die Datenbank immer benannte Volumes. Ohne ein solches zerstört das Entfernen des Containers jedes Produkt, jede Bestellung und jeden Kunden. Wir haben einen halben Tag an Testdaten verloren, weil wir das bei einem „schnellen“ Wegwerf-Container vergessen hatten.

Tests über mehrere Versionen

Das ist der Fall, für den Docker gemacht wurde. Drei PrestaShop-Versionen nebeneinander, jede auf ihrem eigenen Port und ihrer eigenen Datenbank:

version: '3.8'
services:
  ps176-dev:
    image: prestashop/prestashop:1.7.6
    container_name: ps176-dev
    ports: ["8076:80"]
    environment:
      - DB_SERVER=<your-db-176>
      - PS_DOMAIN=localhost:8076
      # ... gleiches Muster wie oben
    volumes:
      - ps176-data:/var/www/html
    networks: [ps-network]

  <your-db-176>:
    image: mysql:5.7
    volumes: [your-db-176-data:/var/lib/mysql]
    networks: [ps-network]

  ps8-dev:
    image: prestashop/prestashop:8.2
    container_name: ps8-dev
    ports: ["8082:80"]
    environment:
      - DB_SERVER=<your-db-8>
      - PS_DOMAIN=localhost:8082
    volumes:
      - ps8-data:/var/www/html
    networks: [ps-network]

  <your-db-8>:
    image: mysql:8.0
    command: --default-authentication-plugin=mysql_native_password
    volumes: [your-db-8-data:/var/lib/mysql]
    networks: [ps-network]

  ps9-dev:
    image: prestashop/prestashop:9.0
    container_name: ps9-dev
    ports: ["8083:80"]
    environment:
      - DB_SERVER=<your-db-9>
      - PS_DOMAIN=localhost:8083
    volumes:
      - ps9-data:/var/www/html
    networks: [ps-network]

  <your-db-9>:
    image: mysql:8.0
    command: --default-authentication-plugin=mysql_native_password
    volumes: [your-db-9-data:/var/lib/mysql]
    networks: [ps-network]

networks:
  ps-network:
    driver: bridge

Wählen Sie ein Port-Schema. Unseres ist 8178 für PS 1.7.8, 8082 für 8.2, 8090 für 9.0. Jenseits von zehn Containern sind Portnummern nicht mehr einprägsam; ab da haben wir Nginx Proxy Manager davorgeschaltet und jedem Shop einen Hostnamen wie ps8-dev.mypresta.rocks gegeben. Tun Sie das am ersten Tag, wenn Sie über eine Handvoll hinausgehen.

Immer getrennte Datenbanken. Das Schema weicht zwischen den Hauptversionen voneinander ab; Migrationen würden sich gegenseitig beschädigen.

Warnung: docker network connect / disconnect auf einem laufenden Container schreibt die Port-Zuordnung neu. Wir haben zugesehen, wie es auf unserem NPM-Container stillschweigend Port 443 lahmgelegt und damit alle Seiten auf einen Schlag offline genommen hat. Definieren Sie das Netzwerk im Compose und erstellen Sie den Container neu, wenn Sie es ändern müssen.

Workflow für die Modulentwicklung

Binden Sie Ihr Modulverzeichnis per Bind-Mount ein. Jede Änderung ist sofort live. Der größte einzelne Vorteil, den Docker Ihnen für die Modularbeit verschafft:

volumes:
  - ps8-data:/var/www/html
  - /home/user/modules/my_module:/var/www/html/modules/my_module

Für Tests über mehrere Versionen binden Sie dasselbe Host-Verzeichnis in jeden Container ein. Eine Datei bearbeiten, drei Tabs aktualisieren. Wir binden jedes ~/modules/mpr* in alle Container ps178-dev, ps8-dev und ps9-dev ein, genau zu diesem Zweck.

Berechtigungen: die wiederkehrende Falle

Host-Dateien gehören Ihnen (UID 1000); Apache läuft als www-data (UID 33). PrestaShop versucht, in var/cache, img und modules zu schreiben, und bekommt eine Zugriffsverweigerung, deshalb scheitern Modul-Uploads bei frischen Setups.

# Interaktive MySQL-Sitzung
docker exec -it <your-shop>-db mysql -u root -p'root' prestashop

# Eine einzelne Abfrage ausführen
docker exec <your-shop>-db mysql -u root -p'root' -e "SELECT COUNT(*) FROM ps_product;" prestashop

Halten Sie ein fix-container-perms.sh bereit. Wir führen unseres häufiger aus, als uns lieb ist, besonders nachdem Module per rsync hineinkopiert wurden.

Cache

docker exec ps8-dev rm -rf /var/www/html/var/cache/*

Oder deaktivieren Sie den Template-Cache unter Erweiterte Parameter → Leistung während der aktiven Arbeit. Aktivieren Sie ihn wieder, bevor Sie die Arbeit als erledigt betrachten, cache-bezogene Fehler treten nur bei eingeschaltetem Cache zutage. Wenn die Produktion Redis verwendet, fügen Sie denselben Dienst lokal hinzu; Redis Dashboard & Key Manager ist nützlich, wenn Sie möchten, dass die PrestaShop-seitige Cache-Verdrahtung der Produktion entspricht, statt sie mit Filesystem-Cache vorzutäuschen.

Datenbankverwaltung

Halten Sie Testdatenbanken klein genug, um sie hin- und herzubewegen. Bevor Sie einen Live-Shop in Docker exportieren, bereinigen Sie veraltete Warenkörbe, Logs und temporäre Daten mit Database Cleanup oder einem gleichwertigen SQL-Bereinigungsdurchlauf, und ziehen Sie dann den Dump.

  phpmyadmin:
    image: phpmyadmin:latest
    ports: ["9090:80"]
    environment:
      - PMA_HOSTS=<your-db-176>,<your-db-8>,<your-db-9>
      - PMA_USER=root
      - PMA_PASSWORD=root
    networks: [ps-network]

phpMyAdmin

Der phpMyAdmin-Dienst oben verbindet sich mit jeder Datenbank im Netzwerk; die folgenden Befehle exportieren und importieren eine Datenbank:

# Export
docker exec <your-shop>-db mysqldump -u root -p'root' prestashop > backup.sql

# Import
docker exec -i <your-shop>-db mysql -u root -p'root' prestashop < backup.sql

Import und Export

  mailpit:
    image: axllent/mailpit
    ports:
      - "8025:8025"  # Web-UI
      - "1025:1025"  # SMTP
    networks: [ps-network]

Zwei Stolperfallen aus der Praxis: Bei komprimierten Dumps durch gunzip leiten, und beim Wiederherstellen über docker exec immer SET NAMES utf8mb4 an den Anfang setzen. Sonst landen UTF-8-Produktnamen doppelt kodiert, und die Behebung ist hässlicher als die Vorbeugung.

Persistent oder flüchtig

Persistent (benannte Volumes): alles, dessen Verlust Sie bedauern würden. Flüchtig: Installer-Tests. Wir halten einen flüchtigen PS-9.0-Container für die Frage „Installiert sich dieses Modul sauber auf einem leeren Shop?“ bereit, bei jedem Durchlauf frisch.

E-Mail-Tests mit Mailpit

Mailpit fängt ausgehende E-Mails ab, die über Mailpit gesendet werden, und zeigt sie mit der Dienstkonfiguration oben in einer Web-UI an. Das folgende Dockerfile ergänzt PrestaShop um Xdebug:

FROM prestashop/prestashop:8.2
RUN pecl install xdebug && docker-php-ext-enable xdebug
COPY xdebug.ini /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini

Back Office → Erweiterte Parameter → E-Mail: SMTP mailpit, Port 1025, keine Verschlüsselung, keine Authentifizierung. Abgefangene Mails unter http://localhost:8025. Ein einziges gemeinsam genutztes Mailpit bedient jeden Entwicklungs-Shop in unserem Netzwerk.

Debugging mit Xdebug

Das offizielle Image bringt Xdebug nicht mit. Bauen Sie den Wrapper mit dem Dockerfile oben und konfigurieren Sie anschließend xdebug.ini und VS Code wie unten gezeigt:

[xdebug]
xdebug.mode=debug
xdebug.start_with_request=yes
xdebug.client_host=host.docker.internal
xdebug.client_port=9003
xdebug.idekey=VSCODE
{
  "version": "0.2.0",
  "configurations": [{
    "name": "Listen for Xdebug (Docker)",
    "type": "php",
    "request": "launch",
    "port": 9003,
    "pathMappings": {
      "/var/www/html/modules/my_module": "${workspaceFolder}"
    }
  }]
}

Unter Linux existiert host.docker.internal standardmäßig nicht, fügen Sie extra_hosts: ["host.docker.internal:host-gateway"] hinzu. Wir haben dafür eine halbe Stunde verloren.

VS Code

Installieren Sie PHP Debug und fügen Sie die oben gezeigte JSON-Konfiguration in .vscode/launch.json ein. Die folgenden Befehle korrigieren die Container-Berechtigungen:

docker exec <your-shop> chown -R www-data:www-data /var/www/html/var
docker exec <your-shop> chown -R www-data:www-data /var/www/html/img
docker exec <your-shop> chown -R www-data:www-data /var/www/html/modules

pathMappings ist das, was den Breakpoint auslöst. Ohne es tut VS Code stillschweigend gar nichts.

PHPStorm

Einstellungen → PHP → Server: localhost + Container-Port, /var/www/html auf das Projekt abbilden. Xdebug-Port 9003 unter PHP → Debug, „Überwachung starten.“

Nützliche Befehle

AufgabeBefehl
Alle Container startendocker compose up -d
Alle Container stoppendocker compose down
Stoppen und alle Daten löschendocker compose down -v
Logs ansehendocker compose logs -f
PS-Cache leerendocker exec CONTAINER rm -rf /var/www/html/var/cache/*
MySQL-CLIdocker exec -it CONTAINER-db mysql -u root -p'PASS' prestashop
Datenbank exportierendocker exec CONTAINER-db mysqldump -u root -p'PASS' prestashop > backup.sql
Datenbank importierendocker exec -i CONTAINER-db mysql -u root -p'PASS' prestashop < backup.sql
Eine Shell im Container öffnendocker exec -it CONTAINER bash
Ressourcenverbrauch prüfendocker stats --no-stream
Nach Dockerfile-Änderungen neu bauendocker compose up -d --build
PrestaShop-Konsole ausführendocker exec CONTAINER php bin/console cache:clear --env=prod
Composer im Modul ausführendocker exec -w /var/www/html/modules/my_module CONTAINER composer install

Produktion: unsere ehrliche Meinung

Für die meisten Händler ist Docker ein Entwicklungswerkzeug. Die Produktion läuft in der Regel besser auf herkömmlichem Hosting, ein einzelner LAMP-Stack lässt sich leichter überwachen und übergeben, native Datei-I/O schlägt Docker-Volumes (PrestaShop lädt Tausende PHP-Dateien pro Anfrage), und die meisten PrestaShop-freundlichen Hoster geben Ihnen cPanel, nicht einen Docker-Daemon.

Docker macht sich in der Produktion bezahlt bei CI/CD, Kapazitätsspitzen bei Verkaufsaktionen, zehn oder mehr Shops oder Deployments ohne Ausfallzeit.

Compose vs. Kubernetes vs. Swarm. Compose bewältigt 20–30 Container auf einem einzigen Host, das, was wir betreiben, völlig ausreichend. Kubernetes bringt Auto-Scaling und Multi-Node-Orchestrierung mit, um den Preis eines echten Infrastruktur-Teams; bei PrestaShop haben wir bislang keinen Fall erlebt, in dem es die richtige Wahl war. Docker Swarm ist ein unbequemer Mittelweg, den wir auslassen würden. Die Community hat sich davon abgewandt. Und kompose (das Werkzeug zum „Umwandeln von Compose in k8s“) klingt großartig, bis Sie es ausprobieren und feststellen, dass die Ausgabe ebenso viel Handarbeit erfordert wie eine Neuerstellung von Grund auf.

Zwei Host-Einstellungen, die sich lohnen

  • live-restore: true in /etc/docker/daemon.json. Neustarts des Daemons töten laufende Container nicht mehr.
  • Benutzerdefinierter data-root auf einem schnellen SSD-Pool, nicht auf der Betriebssystem-Festplatte. Images und MySQL-Volumes wachsen; Systemfestplatten füllen sich unbemerkt.

Dinge, die schiefgehen

„Kann keine Verbindung zur Datenbank herstellen“

  • DB_SERVER stimmt nicht mit dem MySQL-Dienstnamen überein (identisch, Bindestriche inklusive).
  • MySQL hat den Start noch nicht abgeschlossen. Verwenden Sie einen Healthcheck und depends_on: condition: service_healthy.
  • Container in unterschiedlichen Netzwerken: beide in eine benannte Bridge legen.
  • MySQL 8.0 verwendet standardmäßig caching_sha2_password; das mysqli von PrestaShop benötigt mysql_native_password. Fügen Sie command: --default-authentication-plugin=mysql_native_password hinzu.

Langsame I/O unter macOS

Bind-Mounts unter macOS waren früher quälend langsam (10–30 s pro Seitenaufruf). Drei Lösungen: VirtioFS in den Einstellungen von Docker Desktop (der größte einzelne Gewinn), weniger einbinden (nur das Modulverzeichnis, der Rest auf einem benannten Volume), Mutagen (bidirektionale Dateisynchronisation, die die Mount-Schicht umgeht, Holzhammer, funktioniert).

SSL in der Entwicklung

Zahlungsmodule und Social Login verweigern reines HTTP. Nginx Proxy Manager beendet SSL für jeden Container, das, was wir nutzen, die sauberste Option. mkcert für lokal vertrauenswürdige Zertifikate. Traefik für automatische Erkennung und Bereitstellung.

MySQL frisst Ihren gesamten RAM

command: >
  --innodb-buffer-pool-size=128M
  --max-connections=50

Heben Sie bei Docker Desktop das Speicherlimit unter Einstellungen → Ressourcen auf mindestens 6 GB an, sobald Sie mehrere Container haben. Stoppen Sie die, die Sie nicht verwenden: docker stop ps178-dev.

Endlosschleifen bei der Neuinstallation

Wenn PrestaShop sich bei jedem Neustart neu installiert, wird entweder das Volume /var/www/html nicht persistiert oder PS_FOLDER_INSTALL=disabled wird nicht gelesen. Prüfen Sie, ob docker volume ls ein echtes (kein anonymes) Volume anzeigt.

Mixed Content nach einer Port-Änderung

docker exec <your-shop>-db mysql -u root -p'root' -e "
  UPDATE ps_configuration SET value='localhost:8080'
    WHERE name IN ('PS_SHOP_DOMAIN','PS_SHOP_DOMAIN_SSL');
  UPDATE ps_shop_url SET domain='localhost:8080', domain_ssl='localhost:8080';
" prestashop

Eine Warnung: Führen Sie diese Abfrage niemals ohne Backup auf einem Live-Shop eines Kunden aus. Wir haben zugesehen, wie sie mitten am Nachmittag ein Produktions-Frontend lahmgelegt hat.

Weiterführende Lektüre

Passende Fragen

Lade ...
Nach oben