Docker per PrestaShop: Configurazione ambiente di sviluppo
Docker per lo sviluppo PrestaShop: test multi-versione, workflow moduli, gestione database, debug con Xdebug e considerazioni per la produzione.
Perché eseguiamo ogni PrestaShop su Docker
La nostra intera infrastruttura di sviluppo e staging su mypresta.rocks è basata su Docker: un singolo host TrueNAS, container dedicati come ps176-dev, ps178-dev, ps8-dev e ps9-dev, un ps-redis condiviso, Nginx Proxy Manager davanti a tutto. Ogni errore descritto in questa pagina lo abbiamo commesso almeno una volta.
Il problema: PS 1.7 richiede PHP 7.1, PS 8.x richiede 8.1, PS 9.x richiede 8.3 o superiore. MySQL 5.7 rispetto a 8.0 cambia il plugin di autenticazione. Installare tutto questo in modo nativo è il modo migliore per passare un sabato a fare risoluzione dei problemi invece di scrivere moduli. Ogni container porta con sé esattamente il runtime che il suo PrestaShop si aspetta.
- Test multi-versione. PS 1.6, 1.7, 8.x e 9.x contemporaneamente. Un audit di un modulo diventa il lavoro di un pomeriggio, non di una settimana passata a ricostruire stack LAMP.
- Isolamento. Ogni negozio ha il proprio PHP, MySQL, filesystem. Un'installazione andata male non può contaminarne un'altra.
- Riproducibilità. Tutto è in
docker-compose.yml. Portatile, staging, macchina di un collega: la stessa configurazione. - Pulizia semplice.
docker compose down -ve tutto sparisce.
Eseguiamo container PrestaShop separati dalla 1.6 fino alla 9.1 su un'unica macchina TrueNAS. Gli schemi descritti qui sotto sono ciò che abbiamo conservato dopo un decennio di perfezionamenti.
Prerequisiti
Installazione di Docker
Ubuntu/Debian: curl -fsSL https://get.docker.com | sh, poi sudo usermod -aG docker $USER. macOS: Docker Desktop: nelle impostazioni conviene impostare l'implementazione della condivisione file su VirtioFS. Windows: prima WSL2, poi Docker Desktop con il backend WSL2. La modalità Hyper-V è più lenta; noi la eviteremmo.
I quattro concetti che contano
- Immagine: modello di sola lettura. Quella ufficiale è
prestashop/prestashopsu Docker Hub. - Container: un'istanza in esecuzione. Più container da una sola immagine: è così che funzionano le configurazioni multi-versione.
- Volume: archiviazione persistente. Senza volume, niente dati dopo la rimozione del container. Abbiamo perso dati di test dimenticando questo punto.
- Rete: rete virtuale che permette ai container di raggiungersi a vicenda (PrestaShop ↔ MySQL).
Hardware
Conviene prevedere 1,5-2GB di RAM per ogni istanza PrestaShop. 16GB sono comodi su un portatile da sviluppatore per 2-3 versioni. La nostra macchina di sviluppo ha 64GB e NVMe perché eseguiamo diversi container versionati contemporaneamente. I dischi meccanici ti faranno odiare Docker: non ci provare nemmeno.
Configurazione a due container
Inserisci questo in un file 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 deve corrispondere esattamente al nome del servizio (db): è il motivo più frequente per cui un nuovo compose fallisce. PS_FOLDER_INSTALL=disabled impedisce che l'installatore venga rieseguito a ogni riavvio. Esegui docker compose up -d, poi osserva l'avvio con docker compose logs -f prestashop; concedi 1-2 minuti alla prima esecuzione.
Il negozio è all'indirizzo http://localhost:8080, il Back Office è su http://localhost:8080/admin-dev.
Utilizza sempre volumi con nome per il database. Senza un volume, rimuovere il container distrugge ogni prodotto, ordine e cliente. Abbiamo perso mezza giornata di dati di test dimenticando questo su un container "usa e getta" creato in fretta.
Test multi-versione
Questo è lo scenario per cui Docker è stato pensato. Tre versioni di PrestaShop affiancate, ciascuna sulla propria porta e sul proprio database:
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
# ... stesso schema visto sopra
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
Scegli uno schema di porte: il nostro è 8178 per PS 1.7.8, 8082 per la 8.2, 8090 per la 9.0. Superati i dieci container, i numeri di porta smettono di essere memorizzabili; a quel punto abbiamo messo Nginx Proxy Manager davanti e abbiamo assegnato a ogni negozio un hostname come ps8-dev.mypresta.rocks. Conviene farlo fin dal primo giorno se prevedi di andare oltre una manciata di container.
Separa sempre i database. Lo schema diverge tra le versioni maggiori; le migrazioni si corromperebbero a vicenda.
Attenzione: docker network connect / disconnect su un container in esecuzione riscrive la mappatura delle porte. Lo abbiamo visto disattivare silenziosamente la porta 443 sul nostro container NPM, mettendo offline tutti i siti in un colpo solo. Definisci la rete nel compose e ricrea il container se hai bisogno di modificarla.
Flusso di lavoro per lo sviluppo dei moduli
Esegui il bind-mount della directory del tuo modulo: ogni modifica è subito attiva. È il singolo vantaggio più grande che Docker offre per il lavoro sui moduli:
volumes:
- ps8-data:/var/www/html
- /home/user/modules/my_module:/var/www/html/modules/my_module
Per il test multi-versione, monta la stessa directory dell'host in ogni container. Modifica un file, aggiorna tre schede. Montiamo ogni ~/modules/mpr* in tutti i container ps178-dev, ps8-dev e ps9-dev proprio per questo.
Permessi: la trappola ricorrente
I file dell'host appartengono a te (UID 1000); Apache gira come www-data (UID 33). PrestaShop tenta di scrivere su var/cache, img, modules e si vede negare l'accesso: è per questo che il caricamento dei moduli fallisce sulle configurazioni appena create.
# Sessione MySQL interattiva
docker exec -it <your-shop>-db mysql -u root -p'root' prestashop
# Esegue una singola query
docker exec <your-shop>-db mysql -u root -p'root' -e "SELECT COUNT(*) FROM ps_product;" prestashop
Conviene tenere a portata di mano uno script fix-container-perms.sh. Il nostro lo eseguiamo più spesso di quanto vorremmo, soprattutto dopo aver fatto rsync dei moduli.
Cache
docker exec ps8-dev rm -rf /var/www/html/var/cache/*
Oppure disabilita la cache dei modelli in Parametri Avanzati → Prestazioni durante il lavoro attivo. Riabilitala prima di considerare concluso il lavoro: i bug legati alla cache si manifestano solo con la cache attiva. Se la produzione usa Redis, aggiungi lo stesso servizio anche in locale; Redis Dashboard & Key Manager è utile quando vuoi che il cablaggio della cache lato PrestaShop corrisponda alla produzione invece di simularlo con la cache su filesystem.
Gestione del database
Mantieni i database di test abbastanza piccoli da poterli spostare facilmente. Prima di esportare un negozio live in Docker, ripulisci carrelli abbandonati, log e dati temporanei con Database Cleanup o un'equivalente operazione di pulizia SQL, poi esegui il 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
Il servizio phpMyAdmin qui sopra si collega a ogni database presente sulla rete; i comandi qui sotto esportano e importano un database:
# Esportazione
docker exec <your-shop>-db mysqldump -u root -p'root' prestashop > backup.sql
# Importazione
docker exec -i <your-shop>-db mysql -u root -p'root' prestashop < backup.sql
Importazione ed esportazione
mailpit:
image: axllent/mailpit
ports:
- "8025:8025" # Interfaccia web
- "1025:1025" # SMTP
networks: [ps-network]
Due insidie tipiche della produzione: passa i dump compressi attraverso gunzip e indica sempre SET NAMES utf8mb4 all'inizio di qualsiasi ripristino eseguito via docker exec; altrimenti i nomi dei prodotti in UTF-8 finiscono con doppia codifica e correggerlo è più sgradevole che prevenirlo.
Persistente o effimero
Persistente (volumi con nome): qualsiasi cosa ti dispiacerebbe perdere. Effimero: i test di installazione. Teniamo un container PS 9.0 effimero per la domanda "questo modulo si installa senza problemi su un negozio vuoto?": ricreato da zero a ogni esecuzione.
Test delle email con Mailpit
Mailpit intercetta le email in uscita inviate tramite il suo servizio e le mostra in un'interfaccia web, utilizzando la configurazione del servizio riportata sopra. Il Dockerfile qui sotto aggiunge Xdebug a PrestaShop:
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 → Parametri Avanzati → E-mail: SMTP mailpit, porta 1025, nessuna crittografia, nessuna autenticazione. La posta intercettata è su http://localhost:8025. Un unico Mailpit condiviso serve ogni negozio di sviluppo sulla nostra rete.
Debug con Xdebug
L'immagine ufficiale non include Xdebug. Costruisci il wrapper utilizzando il Dockerfile qui sopra, poi configura xdebug.ini e VS Code come mostrato qui sotto:
[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}"
}
}]
}
Su Linux, host.docker.internal non esiste in modo predefinito: aggiungi extra_hosts: ["host.docker.internal:host-gateway"]. Abbiamo perso mezz'ora su questo dettaglio.
VS Code
Installa PHP Debug e aggiungi la configurazione JSON mostrata sopra al file .vscode/launch.json. I comandi qui sotto correggono i permessi del container:
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 è ciò che fa scattare il breakpoint. Senza, VS Code non fa nulla in silenzio.
PHPStorm
Impostazioni → PHP → Server: localhost + porta del container, mappa /var/www/html sul progetto. Porta Xdebug 9003 in PHP → Debug, "Avvia ascolto".
Comandi utili
| Attività | Comando |
|---|---|
| Avviare tutti i container | docker compose up -d |
| Arrestare tutti i container | docker compose down |
| Arrestare ed eliminare tutti i dati | docker compose down -v |
| Visualizzare i log | docker compose logs -f |
| Svuotare la cache di PS | docker exec CONTAINER rm -rf /var/www/html/var/cache/* |
| CLI di MySQL | docker exec -it CONTAINER-db mysql -u root -p'PASS' prestashop |
| Esportare il database | docker exec CONTAINER-db mysqldump -u root -p'PASS' prestashop > backup.sql |
| Importare il database | docker exec -i CONTAINER-db mysql -u root -p'PASS' prestashop < backup.sql |
| Aprire una shell nel container | docker exec -it CONTAINER bash |
| Controllare l'uso delle risorse | docker stats --no-stream |
| Ricostruire dopo modifiche al Dockerfile | docker compose up -d --build |
| Eseguire la console di PrestaShop | docker exec CONTAINER php bin/console cache:clear --env=prod |
| Eseguire Composer in un modulo | docker exec -w /var/www/html/modules/my_module CONTAINER composer install |
Produzione: la nostra opinione sincera
Per la maggior parte dei commercianti, Docker è uno strumento di sviluppo. La produzione di solito gira meglio su hosting tradizionale: un singolo stack LAMP è più facile da monitorare e da passare ad altri, l'I/O nativo dei file batte i volumi Docker (PrestaShop carica migliaia di file PHP a ogni richiesta) e la maggior parte degli host adatti a PrestaShop offre cPanel, non un demone Docker.
Docker in produzione vale lo sforzo con CI/CD, picchi di capacità per eventi di vendita, dieci o più negozi, oppure deployment a zero tempo di inattività.
Compose, Kubernetes o Swarm. Compose gestisce 20-30 container su un singolo host: è quello che eseguiamo noi, ed è più che sufficiente. Kubernetes aggiunge auto-scaling e orchestrazione multi-nodo al costo di un vero team infrastrutturale; per PrestaShop non abbiamo ancora visto un caso in cui fosse la scelta giusta. Docker Swarm è una scomoda via di mezzo che eviteremmo: la community è andata oltre. E kompose (lo strumento "converti compose in k8s") sembra ottimo finché non lo provi e scopri che l'output richiede tante modifiche manuali quante ne richiederebbe scriverlo da zero.
Due impostazioni dell'host che vale la pena configurare
live-restore: truein/etc/docker/daemon.json. I riavvii del demone smettono di terminare i container in esecuzione.- Un
data-rootpersonalizzato su un pool SSD veloce, non sul disco del sistema operativo. Le immagini e i volumi MySQL crescono; i dischi di sistema si riempiono silenziosamente.
Cosa può andare storto
"Impossibile connettersi al database"
DB_SERVERnon corrisponde al nome del servizio MySQL (identico, trattini compresi).- MySQL non ha finito di avviarsi. Usa un healthcheck e
depends_on: condition: service_healthy. - I container sono su reti diverse: mettili entrambi su un bridge con nome.
- MySQL 8.0 usa per impostazione predefinita
caching_sha2_password; il mysqli di PrestaShop richiedemysql_native_password. Aggiungicommand: --default-authentication-plugin=mysql_native_password.
I/O lento su macOS
I bind mount su macOS un tempo erano lentissimi (10-30s per caricamento di pagina). Tre soluzioni: VirtioFS nelle impostazioni di Docker Desktop (il singolo miglioramento più grande), montare di meno (solo la directory del modulo, il resto su un volume con nome), Mutagen (sincronizzazione bidirezionale dei file che aggira lo strato di mount: è una soluzione drastica, ma funziona).
SSL in sviluppo
I moduli di pagamento e il social login rifiutano il semplice HTTP. Nginx Proxy Manager termina l'SSL per ogni container: è quello che usiamo noi, l'opzione più pulita. mkcert per certificati attendibili in locale. Traefik per il rilevamento e il provisioning automatici.
MySQL che consuma tutta la RAM
command: >
--innodb-buffer-pool-size=128M
--max-connections=50
Su Docker Desktop, alza il limite di memoria in Impostazioni → Risorse ad almeno 6GB quando hai diversi container attivi. Arresta quelli che non stai usando: docker stop ps178-dev.
Cicli di reinstallazione
Se PrestaShop si reinstalla a ogni riavvio, il volume /var/www/html non sta persistendo oppure PS_FOLDER_INSTALL=disabled non viene letto. Verifica che docker volume ls mostri un volume reale (non anonimo).
Contenuto misto dopo un cambio di porta
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
Un avvertimento: non eseguire mai quella query su un negozio cliente live senza un backup. L'abbiamo vista mandare in tilt il frontend di una produzione nel bel mezzo del pomeriggio.
Letture correlate
- Sviluppo locale di PrestaShop: configurazione con XAMPP, WAMP, Docker e Linux: Docker a confronto con le alternative
- Strumenti essenziali per lo sviluppo PrestaShop: cosa teniamo accanto a Docker
- Come creare un sito di staging PrestaShop: estendere questi schemi allo staging
- Guida alla risoluzione dei problemi: quando il container gira ma il negozio continua a comportarsi male
- Ottimizzazione delle prestazioni e Performance Revolution: la tappa successiva dopo "funziona"
- Il repository Docker ufficiale di PrestaShop