Come Installare e Configurare Laravel con Docker Compose su Ubuntu 22.04
Introduzione
Con containerizzare un'applicazione si intende il processo di adattare un'applicazione e i suoi componenti in modo da poterla eseguire in ambienti leggeri noti come container. Tali ambienti sono isolati e usa e getta, e possono essere utilizzati per sviluppare, testare e distribuire applicazioni in produzione.
In questa guida, useremo Docker Compose per containerizzare un'applicazione Laravel per lo sviluppo. Quando avrai terminato, avrai un'applicazione Laravel di esempio in esecuzione su tre contenitori di servizio separati:
- Un servizio
appche esegue PHP7.4-FPM; - Un servizio
dbche esegue MySQL 8.0; - Un servizio
nginxche utilizza il servizioappper eseguire il parsing del codice PHP prima di servire l'applicazione Laravel all'utente finale.
Per consentire un processo di sviluppo semplificato e facilitare il debug delle applicazioni, manterremo i file dell'applicazione sincronizzati utilizzando volumi condivisi. Vedremo anche come usare i comandi docker compose exec per eseguire Composer e Artisan sul container app.
Distribuisci le tue applicazioni frontend da GitHub utilizzando la piattaforma App di Linux-Console.net. Lascia che Linux-Console.net si occupi della scalabilità della tua app.
Punti Chiave:
- La containerizzazione rende lo sviluppo prevedibile: Eseguire Laravel su Docker garantisce ambienti coerenti su tutte le macchine, eliminando i problemi del tipo "funziona sul mio computer" e rendendo più facile la collaborazione.
- La separazione dei servizi migliora la manutenibilità: suddividere PHP, MySQL e Nginx in container separati aiuta a isolare i problemi, semplifica gli aggiornamenti e rispecchia le configurazioni reali di produzione.
- Le variabili d'ambiente sono fondamentali per una configurazione flessibile: utilizzare un file
.envpermette agli sviluppatori di modificare le credenziali del database e altre impostazioni senza toccare il codice dell'applicazione. - Le immagini Docker personalizzate migliorano controllo e sicurezza: Creare la propria immagine PHP garantisce l'installazione solo di ciò che il progetto richiede, mantenendo l'ambiente leggero e sicuro.
- Le autorizzazioni dei file devono corrispondere agli utenti del container: Impostare la proprietà e le autorizzazioni corrette per le directory scrivibili di Laravel previene errori durante l'esecuzione e supporta uno sviluppo locale senza intoppi.
- L'uso dei file di override supporta più ambienti:
docker-compose.override.ymlconsente modifiche locali—come il live reloading—senza alterare le configurazioni di produzione. Questo mantiene lo sviluppo e il deployment chiaramente separati. - La risoluzione dei problemi inizia con la comprensione del comportamento dei container: Sapere come ispezionare i log, controllare i servizi in esecuzione e testare la connettività è fondamentale per risolvere rapidamente la maggior parte dei problemi nelle configurazioni containerizzate.
- Una configurazione basata su Docker si adatta al tuo flusso di lavoro: Una volta creata, la stessa configurazione può alimentare ambienti locali, di staging o di produzione, creando una base stabile e riutilizzabile per futuri progetti Laravel.
Prerequisiti
- Accesso a una macchina locale Ubuntu o a un server di sviluppo come utente non root con privilegi sudo. Se stai usando un server remoto, è consigliabile avere un firewall attivo. Per configurare questi elementi, fai riferimento alla nostra Guida alla Configurazione Iniziale del Server per Ubuntu.
- Docker installato sul tuo server, seguendo i Passaggi 1 e 2 di Come Installare e Usare Docker su Ubuntu.
- Docker Compose installato sul tuo server, seguendo il Passo 1 di Come Installare e Usare Docker Compose su Ubuntu.
Passo 1 — Ottenere l'applicazione demo
Per iniziare, recupereremo l'applicazione demo Laravel dal suo repository Github. Siamo interessati al branch tutorial-01, che contiene l'applicazione Laravel di base che abbiamo creato nella guida Come Installare e Configurare Laravel con Nginx su Ubuntu 22.04 (LEMP).
Per ottenere il codice dell'applicazione compatibile con questo tutorial, scarica la release tutorial-1.0.1 nella tua directory home con:
cd ~
curl -L https://github.com/do-community/travellist-laravel-demo/archive/tutorial-1.0.1.zip -o travellist.zipAvremo bisogno del comando unzip per estrarre il codice dell'applicazione. Nel caso non abbiate mai installato questo pacchetto, fatelo ora con:
sudo apt update
sudo apt install unzipOra, decomprimi i contenuti dell'applicazione e rinomina la cartella estratta per un accesso più semplice:
unzip travellist.zip
mv travellist-laravel-demo-tutorial-1.0.1 travellist-demoVai alla directory travellist-demo:
cd travellist-demoNel passaggio successivo, creeremo un file di configurazione .env per configurare l'applicazione.
Passo 2 — Configurazione del file .env dell’applicazione
I file di configurazione di Laravel si trovano in una directory chiamata config, all'interno della directory principale dell'applicazione. Inoltre, un file .env viene utilizzato per impostare la configurazione dipendente dall'ambiente, come le credenziali e qualsiasi informazione che potrebbe variare tra i diversi deploy. Questo file non è incluso nel controllo della versione.
Avvertenza: Il file di configurazione dell'ambiente contiene informazioni sensibili sul tuo server, incluse le credenziali del database e le chiavi di sicurezza. Per questo motivo, non dovresti mai condividere questo file pubblicamente.
I valori contenuti nel file .env avranno la precedenza sui valori impostati nei normali file di configurazione situati nella directory config. Ogni installazione in un nuovo ambiente richiede un file di ambiente personalizzato per definire elementi come le impostazioni di connessione al database, le opzioni di debug, l'URL dell'applicazione, tra le altre cose che possono variare a seconda dell'ambiente in cui l'applicazione viene eseguita.
Ora creeremo un nuovo file .env per personalizzare le opzioni di configurazione per l'ambiente di sviluppo che stiamo configurando. Laravel include un file .env di esempio che possiamo copiare per creare il nostro:
cp .env.example .envApri questo file usando nano o l'editor di testo che preferisci:
nano .envIl file .env attuale dell'applicazione demo travellist contiene impostazioni per utilizzare un database MySQL locale, con 127.0.0.1 come host del database. Dobbiamo aggiornare la variabile DB_HOST in modo che punti al servizio database che creeremo nel nostro ambiente Docker. In questa guida, chiameremo il nostro servizio database db. Procedi e sostituisci il valore indicato di DB_HOST con il nome del servizio database:
APP_NAME=Travellist
APP_ENV=dev
APP_KEY=
APP_DEBUG=true
APP_URL=http://localhost:8000
LOG_CHANNEL=stack
DB_CONNECTION=mysql
DB_HOST=db
DB_PORT=3306
DB_DATABASE=travellist
DB_USERNAME=travellist_user
DB_PASSWORD=password
...Sentiti libero di cambiare anche il nome del database, il nome utente e la password, se lo desideri. Queste variabili saranno utilizzate in un passaggio successivo, quando configureremo il file docker-compose.yml per impostare i nostri servizi.
Salva il file quando hai finito di modificare. Se hai usato nano, puoi farlo premendo Ctrl+x, poi Y e Invio per confermare.
Passo 3 – Configurazione del Dockerfile dell'applicazione
Sebbene sia i nostri servizi MySQL che Nginx saranno basati su immagini predefinite ottenute da Docker Hub, dobbiamo comunque creare un'immagine personalizzata per il contenitore dell'applicazione. Creeremo un nuovo Dockerfile per questo.
La nostra immagine travellist sarà basata sull'immagine ufficiale PHP php:7.4-fpm di Docker Hub. Su questo ambiente PHP-FPM di base, installeremo alcuni moduli PHP aggiuntivi e lo strumento di gestione delle dipendenze Composer.
Creeremo anche un nuovo utente di sistema; questo è necessario per eseguire i comandi artisan e composer durante lo sviluppo dell'applicazione. L'impostazione uid garantisce che l'utente all'interno del container abbia lo stesso uid del tuo utente di sistema sulla macchina host, dove stai eseguendo Docker. In questo modo, qualsiasi file creato da questi comandi viene replicato nell'host con le autorizzazioni corrette. Questo significa anche che sarai in grado di utilizzare l'editor di codice che preferisci sulla macchina host per sviluppare l'applicazione in esecuzione all'interno dei container.
Crea un nuovo Dockerfile con:
nano DockerfileCopia i seguenti contenuti nel tuo Dockerfile:
FROM php:7.4-fpm
# Arguments defined in docker-compose.yml
ARG user
ARG uid
# Install system dependencies
RUN apt-get update && apt-get install -y \
git \
curl \
libpng-dev \
libonig-dev \
libxml2-dev \
zip \
unzip
# Clear cache
RUN apt-get clean && rm -rf /var/lib/apt/lists/*
# Install PHP extensions
RUN docker-php-ext-install pdo_mysql mbstring exif pcntl bcmath gd
# Get latest Composer
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
# Create system user to run Composer and Artisan Commands
RUN useradd -G www-data,root -u $uid -d /home/$user $user
RUN mkdir -p /home/$user/.composer && \
chown -R $user:$user /home/$user
# Set working directory
WORKDIR /var/www
USER $user
Non dimenticare di salvare il file quando hai finito.
Il nostro Dockerfile inizia definendo l'immagine di base che stiamo utilizzando: php:7.4-fpm.
Dopo aver installato i pacchetti di sistema e le estensioni PHP, installiamo Composer copiando l'eseguibile composer dalla sua ultima immagine ufficiale alla nostra immagine dell'applicazione.
Viene quindi creato e configurato un nuovo utente di sistema utilizzando gli argomenti user e uid dichiarati all'inizio del Dockerfile. Questi valori verranno inseriti da Docker Compose al momento della build.
Infine, impostiamo la directory di lavoro predefinita come /var/www e passiamo all'utente appena creato. Questo assicurerà che ti connetta come utente normale e che ti trovi nella directory corretta quando esegui i comandi composer e artisan sul contenitore dell'applicazione.
Passo 4 — Configurazione di Nginx e File di Dump del Database
Quando si creano ambienti di sviluppo con Docker Compose, è spesso necessario condividere file di configurazione o di inizializzazione con i container di servizio, al fine di configurare o avviare tali servizi. Questa pratica facilita l'apportare modifiche ai file di configurazione per affinare l'ambiente di sviluppo mentre si sviluppa l'applicazione.
Ora configureremo una cartella con i file che saranno utilizzati per configurare e inizializzare i nostri container di servizio.
Per configurare Nginx, condivideremo un file travellist.conf che definirà come viene servita l'applicazione. Crea la cartella docker-compose/nginx con:
mkdir -p docker-compose/nginxApri un nuovo file chiamato travellist.conf all'interno di quella directory:
nano docker-compose/nginx/travellist.confCopia la seguente configurazione Nginx in quel file:
server {
listen 80;
index index.php index.html;
error_log /var/log/nginx/error.log;
access_log /var/log/nginx/access.log;
root /var/www/public;
location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass app:9000;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
}
location / {
try_files $uri $uri/ /index.php?$query_string;
gzip_static on;
}
}Questo file configurerà Nginx per ascoltare sulla porta 80 e utilizzare index.php come pagina indice predefinita. Imposterà la root dei documenti su /var/www/public e successivamente configurerà Nginx per usare il servizio app sulla porta 9000 per elaborare i file *.php.
Salva e chiudi il file quando hai finito di modificare.
Per configurare il database MySQL, condivideremo un dump del database che verrà importato quando il container sarà inizializzato. Questa è una funzione fornita dall'immagine MySQL 8.0 che useremo su quel container.
Crea una nuova cartella per i tuoi file di inizializzazione MySQL all'interno della cartella docker-compose:
mkdir docker-compose/mysqlApri un nuovo file .sql:
nano docker-compose/mysql/init_db.sqlIl seguente dump di MySQL si basa sul database che abbiamo impostato nella nostra guida Laravel su LEMP. Creerà una nuova tabella chiamata places. Successivamente, popolerà la tabella con un insieme di luoghi di esempio.
Aggiungi il seguente codice al file:
DROP TABLE IF EXISTS `places`;
CREATE TABLE `places` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
`visited` tinyint(1) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=12 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
INSERT INTO `places` (name, visited) VALUES ('Berlin',0),('Budapest',0),('Cincinnati',1),('Denver',0),('Helsinki',0),('Lisbon',0),('Moscow',1),('Nairobi',0),('Oslo',1),('Rio',0),('Tokyo',0);La tabella places contiene tre campi: id, name e visited. Il campo visited è un indicatore utilizzato per identificare i luoghi che sono ancora da visitare. Sentiti libero di modificare i luoghi di esempio o di aggiungerne di nuovi. Salva e chiudi il file quando hai finito.
Abbiamo finito di configurare il Dockerfile dell'applicazione e i file di configurazione dei servizi. Successivamente, configureremo Docker Compose per utilizzare questi file quando creiamo i nostri servizi.
Passo 5 — Creazione di un ambiente multi-contenitore con Docker Compose
Docker Compose ti permette di creare ambienti multi-container per applicazioni che girano su Docker. Utilizza le definizioni di servizio per costruire ambienti completamente personalizzabili con più container che possono condividere reti e volumi di dati. Questo consente un'integrazione senza soluzione di continuità tra i componenti dell'applicazione.
Per configurare le definizioni dei nostri servizi, creeremo un nuovo file chiamato docker-compose.yml. Solitamente, questo file si trova nella cartella principale dell'applicazione e definisce il tuo ambiente containerizzato, comprese le immagini di base che utilizzerai per costruire i tuoi container e come i tuoi servizi interagiranno tra loro.
Definiremo tre diversi servizi nel nostro file docker-compose.yml: app, db e nginx.
Il servizio app creerà un'immagine chiamata travellist, basata sul Dockerfile che abbiamo precedentemente creato. Il container definito da questo servizio eseguirà un server php-fpm per interpretare il codice PHP e inviare i risultati al servizio nginx, che sarà in esecuzione su un container separato. Il servizio mysql definisce un container che esegue un server MySQL 8.0. I nostri servizi condivideranno una rete bridge chiamata travellist.
I file dell'applicazione saranno sincronizzati sia sul servizio app che sul servizio nginx tramite bind mount. I bind mount sono utili negli ambienti di sviluppo perché permettono una sincronizzazione bidirezionale efficiente tra la macchina host e i container.
Crea un nuovo file docker-compose.yml nella cartella principale dell'applicazione:
nano docker-compose.ymlUn tipico file docker-compose.yml inizia con una definizione di versione, seguita da un nodo services, sotto il quale sono definiti tutti i servizi. Le reti condivise sono di solito definite alla fine di quel file.
Per iniziare, copia questo codice di base nel tuo file docker-compose.yml:
version: "3.9"
services:
networks:
travellist:
driver: bridgeModificheremo ora il nodo services per includere i servizi app, db e nginx.
Il servizio app
Il servizio app creerà un container denominato travellist-app. Costruisce una nuova immagine Docker basata su un Dockerfile situato nello stesso percorso del file docker-compose.yml. La nuova immagine verrà salvata localmente con il nome travellist.
Anche se la root del documento servita come applicazione si trova nel contenitore nginx, abbiamo bisogno dei file dell'applicazione anche all'interno del contenitore app, così da poter eseguire i comandi tramite lo strumento Laravel Artisan.
Copia la seguente definizione di servizio sotto il tuo nodo services, all'interno del file docker-compose.yml:
app:
build:
args:
user: sammy
uid: 1000
context: ./
dockerfile: Dockerfile
image: travellist
container_name: travellist-app
restart: unless-stopped
working_dir: /var/www/
volumes:
- ./:/var/www
networks:
- travellistQueste impostazioni fanno quanto segue:
build: Questa configurazione indica a Docker Compose di creare un'immagine locale per il servizioapp, utilizzando il percorso specificato (context) e il Dockerfile per le istruzioni. Gli argomentiusereuidvengono inseriti nel Dockerfile per personalizzare i comandi di creazione dell'utente durante la build.image: Il nome che verrà utilizzato per l'immagine in fase di creazione.container_name: Imposta il nome del container per questo servizio.restart: Riavvia sempre, a meno che il servizio non sia fermo.working_dir: Imposta la directory predefinita per questo servizio come/var/www.volumes: Crea un volume condiviso che sincronizzerà i contenuti dalla directory corrente a/var/wwwall'interno del container. Nota che questa non è la tua root dei documenti, poiché quella si troverà nel containernginx.networks: Configura questo servizio per utilizzare una rete chiamatatravellist.
Il servizio db
Il servizio db utilizza un'immagine predefinita di MySQL 8.0 da Docker Hub. Poiché Docker Compose carica automaticamente i file di variabili .env presenti nella stessa directory del file docker-compose.yml, possiamo ottenere le impostazioni del nostro database dal file .env di Laravel che abbiamo creato in un passaggio precedente.
Includi la seguente definizione di servizio nel nodo services, subito dopo il servizio app:
db:
image: mysql:8.0
container_name: travellist-db
restart: unless-stopped
environment:
MYSQL_DATABASE: ${DB_DATABASE}
MYSQL_ROOT_PASSWORD: ${DB_PASSWORD}
MYSQL_PASSWORD: ${DB_PASSWORD}
MYSQL_USER: ${DB_USERNAME}
SERVICE_TAGS: dev
SERVICE_NAME: mysql
volumes:
- ./docker-compose/mysql:/docker-entrypoint-initdb.d
networks:
- travellistQueste impostazioni fanno quanto segue:
image: Definisce l'immagine Docker che dovrebbe essere utilizzata per questo container. In questo caso, stiamo usando un'immagine MySQL 8.0 da Docker Hub.container_name: Imposta il nome del container per questo servizio:travellist-db.restart: Riavvia sempre questo servizio, a meno che non sia stato esplicitamente interrotto.environment: Definisce le variabili d'ambiente nel nuovo container. Stiamo utilizzando i valori ottenuti dal file.envdi Laravel per configurare il nostro servizio MySQL, che creerà automaticamente un nuovo database e utente in base alle variabili d'ambiente fornite.volumes: Crea un volume per condividere un dump di database.sqlche sarà utilizzato per inizializzare il database dell'applicazione. L'immagine MySQL importerà automaticamente i file.sqlinseriti nella directory/docker-entrypoint-initdb.dall'interno del container.networks: Configura questo servizio per utilizzare una rete chiamatatravellist.
Il servizio nginx
Il servizio nginx utilizza un'immagine Nginx predefinita basata su Alpine, una distribuzione Linux leggera. Crea un container chiamato travellist-nginx e utilizza la definizione ports per creare una reindirizzazione dalla porta 8000 sul sistema host alla porta 80 all'interno del container.
Includi la seguente definizione di servizio nel nodo services, subito dopo il servizio db:
nginx:
image: nginx:1.17-alpine
container_name: travellist-nginx
restart: unless-stopped
ports:
- 8000:80
volumes:
- ./:/var/www
- ./docker-compose/nginx:/etc/nginx/conf.d
networks:
- travellistQueste impostazioni fanno quanto segue:
image: Definisce l'immagine Docker che dovrebbe essere utilizzata per questo container. In questo caso, stiamo usando l'immagine Alpine Nginx 1.17.container_name: Imposta il nome del contenitore per questo servizio: travellist-nginx.restart: Riavvia sempre questo servizio, a meno che non sia stato esplicitamente interrotto.ports: Configura un reindirizzamento delle porte che consentirà l'accesso esterno tramite la porta8000al server web in esecuzione sulla porta80all'interno del container.volumi: Crea due volumi condivisi. Il primo sincronizzerà i contenuti dalla directory corrente a/var/wwwall'interno del container. In questo modo, quando apporterai modifiche locali ai file dell'applicazione, queste saranno rapidamente riflesse nell'applicazione servita da Nginx all'interno del container. Il secondo volume garantirà che il nostro file di configurazione di Nginx, situato indocker-compose/nginx/travellist.conf, venga copiato nella cartella di configurazione di Nginx del container.networks: Configura questo servizio per utilizzare una rete chiamatatravellist.
File docker-compose.yml completato
Ecco come appare il nostro file docker-compose.yml completato:
version: "3.9"
services:
app:
build:
args:
user: sammy
uid: 1000
context: ./
dockerfile: Dockerfile
image: travellist
container_name: travellist-app
restart: unless-stopped
working_dir: /var/www/
volumes:
- ./:/var/www
networks:
- travellist
db:
image: mysql:8.0
container_name: travellist-db
restart: unless-stopped
environment:
MYSQL_DATABASE: ${DB_DATABASE}
MYSQL_ROOT_PASSWORD: ${DB_PASSWORD}
MYSQL_PASSWORD: ${DB_PASSWORD}
MYSQL_USER: ${DB_USERNAME}
SERVICE_TAGS: dev
SERVICE_NAME: mysql
volumes:
- ./docker-compose/mysql:/docker-entrypoint-initdb.d
networks:
- travellist
nginx:
image: nginx:1.17-alpine
container_name: travellist-nginx
restart: unless-stopped
ports:
- 8000:80
volumes:
- ./:/var/www
- ./docker-compose/nginx:/etc/nginx/conf.d/
networks:
- travellist
networks:
travellist:
driver: bridgeAssicurati di salvare il file quando hai finito.
Passo 6 — Eseguire l'applicazione con Docker Compose
Ora useremo i comandi docker compose per creare l'immagine dell'applicazione ed eseguire i servizi che abbiamo specificato nella nostra configurazione.
Costruisci l'immagine app con il seguente comando:
docker compose build appQuesto comando potrebbe richiedere alcuni minuti per essere completato. Vedrai un output simile a questo:
Building app
Sending build context to Docker daemon 377.3kB
Step 1/11 : FROM php:7.4-fpm
---> 8c08d993542f
Step 2/11 : ARG user
---> e3ce3af04d87
Step 3/11 : ARG uid
---> 30cb921ef7df
Step 4/11 : RUN apt-get update && apt-get install -y git curl libpng-dev libonig-dev libxml2-dev zip unzip
. . .
---> b6dbc7a02e95
Step 5/11 : RUN apt-get clean && rm -rf /var/lib/apt/lists/*
---> 10ef9dde45ad
. . .
Step 6/11 : RUN docker-php-ext-install pdo_mysql mbstring exif pcntl bcmath gd
. . .
---> 920e4f09ec75
Step 7/11 : COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
---> dbbcd44e44af
Step 8/11 : RUN useradd -G www-data,root -u $uid -d /home/$user $user
---> db98e899a69a
Step 9/11 : RUN mkdir -p /home/$user/.composer && chown -R $user:$user /home/$user
---> 5119e26ebfea
Step 10/11 : WORKDIR /var/www
---> 699c491611c0
Step 11/11 : USER $user
---> cf250fe8f1af
Successfully built cf250fe8f1af
Successfully tagged travellist:latestQuando la compilazione è terminata, puoi eseguire l'ambiente in modalità in background con:
docker compose up -dCreating travellist-db ... done
Creating travellist-app ... done
Creating travellist-nginx ... doneQuesto eseguirà i tuoi container in background. Per mostrare informazioni sullo stato dei tuoi servizi attivi, esegui:
docker compose psVedrai un output simile a questo:
Name Command State Ports
-----------------------------------------------------------------------------------------------
travellist-app docker-php-entrypoint php-fpm Up 9000/tcp
travellist-db docker-entrypoint.sh mysqld Up 3306/tcp, 33060/tcp
travellist-nginx nginx -g daemon off; Up 0.0.0.0:8000->80/tcp,:::8000->80/tcpIl tuo ambiente è ora attivo e funzionante.
Ora puoi verificare che ogni servizio containerizzato risponda correttamente utilizzando semplici comandi curl.
Per testare il servizio web Nginx:
curl -I http://localhost:8000Output previsto:
HTTP/1.1 200 OK Server: nginx/1.17.10 Content-Type: text/html; charset=UTF-8Questo conferma che il container Nginx è in esecuzione e sta fornendo risposte dalla tua applicazione Laravel.
Per testare PHP-FPM tramite Nginx:
curl -s http://localhost:8000 | grep "Berlin"Se l'applicazione funziona correttamente, questo comando restituisce l'HTML della pagina di benvenuto che include la parola Berlin.
Dobbiamo ancora eseguire un paio di comandi per completare la configurazione dell'applicazione. Puoi usare il comando docker compose exec per eseguire comandi nei container del servizio, come ad esempio un ls -l per mostrare informazioni dettagliate sui file nella directory dell'applicazione:
docker compose exec app ls -ltotal 256
-rw-r--r-- 1 sammy sammy 737 Apr 18 14:21 Dockerfile
-rw-r--r-- 1 sammy sammy 101 Jan 7 2020 README.md
drwxr-xr-x 6 sammy sammy 4096 Jan 7 2020 app
-rwxr-xr-x 1 sammy sammy 1686 Jan 7 2020 artisan
drwxr-xr-x 3 sammy sammy 4096 Jan 7 2020 bootstrap
-rw-r--r-- 1 sammy sammy 1501 Jan 7 2020 composer.json
-rw-r--r-- 1 sammy sammy 179071 Jan 7 2020 composer.lock
drwxr-xr-x 2 sammy sammy 4096 Jan 7 2020 config
drwxr-xr-x 5 sammy sammy 4096 Jan 7 2020 database
drwxr-xr-x 4 sammy sammy 4096 Apr 18 14:22 docker-compose
-rw-r--r-- 1 sammy sammy 1017 Apr 18 14:29 docker-compose.yml
-rw-r--r-- 1 sammy sammy 1013 Jan 7 2020 package.json
-rw-r--r-- 1 sammy sammy 1405 Jan 7 2020 phpunit.xml
drwxr-xr-x 2 sammy sammy 4096 Jan 7 2020 public
-rw-r--r-- 1 sammy sammy 273 Jan 7 2020 readme.md
drwxr-xr-x 6 sammy sammy 4096 Jan 7 2020 resources
drwxr-xr-x 2 sammy sammy 4096 Jan 7 2020 routes
-rw-r--r-- 1 sammy sammy 563 Jan 7 2020 server.php
drwxr-xr-x 5 sammy sammy 4096 Jan 7 2020 storage
drwxr-xr-x 4 sammy sammy 4096 Jan 7 2020 tests
-rw-r--r-- 1 sammy sammy 538 Jan 7 2020 webpack.mix.jsOra eseguiremo composer install per installare le dipendenze dell'applicazione:
docker compose exec app rm -rf vendor composer.lock
docker compose exec app composer installVedrai un output simile a questo:
No composer.lock file present. Updating dependencies to latest instead of installing from lock file. See https://getcomposer.org/install for more information.
. . .
Lock file operations: 89 installs, 0 updates, 0 removals
- Locking doctrine/inflector (2.0.4)
- Locking doctrine/instantiator (1.4.1)
- Locking doctrine/lexer (1.2.3)
- Locking dragonmantank/cron-expression (v2.3.1)
- Locking egulias/email-validator (2.1.25)
- Locking facade/flare-client-php (1.9.1)
- Locking facade/ignition (1.18.1)
- Locking facade/ignition-contracts (1.0.2)
- Locking fideloper/proxy (4.4.1)
- Locking filp/whoops (2.14.5)
. . .
Writing lock file
Installing dependencies from lock file (including require-dev)
Package operations: 89 installs, 0 updates, 0 removals
- Downloading doctrine/inflector (2.0.4)
- Downloading doctrine/lexer (1.2.3)
- Downloading dragonmantank/cron-expression (v2.3.1)
- Downloading symfony/polyfill-php80 (v1.25.0)
- Downloading symfony/polyfill-php72 (v1.25.0)
- Downloading symfony/polyfill-mbstring (v1.25.0)
- Downloading symfony/var-dumper (v4.4.39)
- Downloading symfony/deprecation-contracts (v2.5.1)
. . .
Generating optimized autoload files
> Illuminate\Foundation\ComposerScripts::postAutoloadDump
> @php artisan package:discover --ansi
Discovered Package: facade/ignition
Discovered Package: fideloper/proxy
Discovered Package: laravel/tinker
Discovered Package: nesbot/carbon
Discovered Package: nunomaduro/collision
Package manifest generated successfully.L'ultima cosa da fare prima di testare l'applicazione è generare una chiave univoca per l'applicazione con lo strumento da riga di comando artisan di Laravel. Questa chiave è utilizzata per criptare le sessioni degli utenti e altri dati sensibili:
docker compose exec app php artisan key:generateApplication key set successfully.Ora vai sul tuo browser e accedi al nome di dominio o all'indirizzo IP del tuo server sulla porta 8000:
http://server_domain_or_IP:8000Nota: Nel caso tu stia eseguendo questa demo sul tuo computer locale, usa http://localhost:8000 per accedere all'applicazione dal tuo browser.
Vedrai una pagina come questa:
Puoi anche testare l'applicazione Laravel dall'interno del container dell'app senza usare un browser:
docker compose exec app curl http://nginxSe tutto è configurato correttamente, dovresti vedere l'output HTML della pagina di benvenuto predefinita di Laravel.
<html>
<head>
<title>Travel List</title>
</head>
<body>
<h1>My Travel Bucket List</h1>
<h2>Places I'd Like to Visit</h2>
<ul>
<li>Berlin</li>
<li>Budapest</li>
<li>Denver</li>
<li>Helsinki</li>
<li>Lisbon</li>
<li>Nairobi</li>
<li>Rio</li>
<li>Tokyo</li>
</ul>
<h2>Places I've Already Been To</h2>
<ul>
<li>Cincinnati</li>
<li>Moscow</li>
<li>Oslo</li>
</ul>
</body>
</html>Puoi usare il comando logs per controllare i log generati dai tuoi servizi:
docker compose logs nginxAttaching to travellist-nginx
. . .
travellist-nginx | 172.24.9.1 - - [18/Apr/2022:14:49:16 +0000] "GET / HTTP/1.1" 200 627 "-" "curl/7.82.0"
travellist-nginx | 172.24.9.1 - - [18/Apr/2022:14:51:27 +0000] "GET / HTTP/1.1" 200 627 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:89.0) Gecko/20100101 Firefox/89.0"
travellist-nginx | 172.24.9.1 - - [18/Apr/2022:14:51:27 +0000] "GET /favicon.ico HTTP/1.1" 200 0 "http://localhost:8000/" "Mozilla/5.0 (X11; Linux x86_64; rv:89.0) Gecko/20100101 Firefox/89.0"Puoi anche usare il seguente comando curl per attivare le voci di log:
curl http://localhost:8000Poi esegui di nuovo:
docker compose logs nginxOra dovresti vedere una voce corrispondente nel registro degli accessi per la tua richiesta.
Se vuoi mettere in pausa il tuo ambiente Docker Compose mantenendo lo stato di tutti i suoi servizi, esegui:
docker compose pausePausing travellist-db ... done
Pausing travellist-nginx ... done
Pausing travellist-app ... donePuoi quindi riprendere i tuoi servizi con:
docker compose unpauseUnpausing travellist-app ... done
Unpausing travellist-nginx ... done
Unpausing travellist-db ... donePer chiudere l'ambiente Docker Compose e rimuovere tutti i suoi container, network e volumi, esegui:
docker compose downStopping travellist-nginx ... done
Stopping travellist-db ... done
Stopping travellist-app ... done
Removing travellist-nginx ... done
Removing travellist-db ... done
Removing travellist-app ... done
Removing network travellist-laravel-demo_travellistPer una panoramica di tutti i comandi di Docker Compose, si prega di consultare il riferimento ai comandi della riga di comando di Docker Compose.
Correzione dei permessi di file e directory in Laravel
Quando si esegue Laravel all'interno di container Docker, uno dei problemi più comuni che gli sviluppatori devono affrontare è legato ai permessi di file e directory. Laravel richiede che alcune directory siano scrivibili dal processo PHP-FPM all'interno del container app. Se queste directory non sono scrivibili, l'applicazione potrebbe non riuscire a registrare gli errori, memorizzare i file di configurazione nella cache o salvare correttamente i dati di sessione.
Potresti incontrare messaggi come:
The stream or file "/var/www/storage/logs/laravel.log" could not be opened in append mode: failed to open stream: Permission deniedo
file_put_contents(/var/www/bootstrap/cache/config.php): Failed to open stream: Permission deniedQuesti errori indicano che l'utente che esegue PHP all'interno del contenitore non ha il permesso di scrivere nelle directory necessarie.
I passaggi seguenti descrivono come diagnosticare e risolvere questi problemi sia negli ambienti locali che in quelli di produzione.
Regola i permessi della directory scrivibile
Laravel richiede che due directory siano scrivibili dall'utente del server web:
/var/www/storage/var/www/bootstrap/cache
Se vedi errori di permesso, puoi risolverli regolando proprietà e permessi dall'interno del container:
docker compose exec app chown -R sammy:sammy /var/www/storage /var/www/bootstrap/cache
docker compose exec app chmod -R 775 /var/www/storage /var/www/bootstrap/cacheSe il tuo Dockerfile utilizza un nome utente diverso (definito tramite l'argomento di build user), sostituisci sammy con quel nome utente.
Puoi verificare la proprietà con il seguente comando:
docker compose exec app ls -ld /var/www/storage /var/www/bootstrap/cacheL'output dovrebbe mostrare che l'utente e il gruppo corrispondono al processo PHP-FPM all'interno del container.
Se vuoi modificare i permessi direttamente dalla macchina host, esegui:
sudo chown -R $(id -u):$(id -g) storage bootstrap/cache
sudo chmod -R 775 storage bootstrap/cacheQuesto garantisce che entrambe le directory di Laravel siano scrivibili sia dal container che dall'utente del tuo host.
Imposta la proprietà della directory durante la creazione dell'immagine
Per prevenire il ripetersi di problemi di permessi dopo ogni ricostruzione, puoi impostare la proprietà delle directory durante il processo di creazione dell’immagine Docker. Apri il tuo Dockerfile e aggiungi la seguente riga vicino alla fine, prima di passare all’utente non root:
RUN chown -R $user:www-data /var/wwwQuesto comando garantisce che tutti i file e le directory sotto /var/www siano di proprietà dell'utente che hai definito nel tuo Dockerfile.
Per un approccio più mirato e sicuro, puoi modificare solo le directory in cui Laravel deve scrivere:
RUN chown -R $user:www-data /var/www/storage /var/www/bootstrap/cacheDopo aver effettuato questa modifica, ricostruisci l'immagine e riavvia i container:
docker compose build app
docker compose up -dLa prossima volta che il contenitore si avvierà, avrà già i permessi corretti.
Verifica la coerenza dell'ID utente tra host e container
Quando si utilizzano i bind mount, Docker condivide i file tra il tuo host e il container. Se l'UID numerico dell'utente dell'host differisce dall'UID definito nel container, possono verificarsi conflitti di proprietà dei file. Questo è comune sui sistemi in cui gli ID utente variano tra le macchine.
Per verificare i valori UID, esegui:
id -u $(whoami)
docker compose exec app id -uSe questi due numeri non corrispondono, aggiorna il tuo file docker-compose.yml per passare il tuo UID reale al processo di build:
build:
args:
user: sammy
uid: 1000Poi ricostruisci l'immagine:
docker compose build app
docker compose up -dQuesto garantisce che l'utente del container corrisponda al tuo utente host, prevenendo discrepanze di permessi sui file montati con bind.
Correggi i permessi della directory della cache di Composer
Composer memorizza le dipendenze scaricate e i file di cache nella directory home dell’utente all’interno del container (/home/sammy/.composer). Se questa directory non è scrivibile, potresti vedere avvisi come:
Cannot create cache directory /home/sammy/.composer/cachePuoi risolvere questo creando la directory della cache e assegnando la proprietà corretta:
docker compose exec app mkdir -p /home/sammy/.composer/cache
docker compose exec app chown -R sammy:sammy /home/sammy/.composerQuesto garantisce che Composer possa memorizzare le dipendenze e i file di cache senza errori di autorizzazione, il che accelera anche le future esecuzioni di composer install.
Pratiche consigliate per gli ambienti di produzione
In produzione, la gestione dei permessi dovrebbe essere gestita durante la creazione dell'immagine piuttosto che a runtime. Questo migliora la coerenza e la sicurezza.
Segui queste pratiche per una configurazione pronta per la produzione:
Evita i bind mount per il codice dell'applicazione: invece, copia i file dell'applicazione all'interno dell'immagine durante la build. I bind mount dovrebbero essere riservati allo sviluppo.
Imposta i permessi durante la build: Aggiungi i comandi
RUN chownechmodal tuo Dockerfile per garantire la corretta proprietà e i diritti di accesso prima della distribuzione.Usa l'utente con privilegi minimi: Assicurati che il processo PHP venga eseguito sotto un utente non root (l'attuale configurazione con
$userlo fa già).Restringere le autorizzazioni sulle directory non scrivibili: La maggior parte dei file delle applicazioni dovrebbe essere di sola lettura. Puoi farlo rispettando:
chmod -R 755 /var/www chmod -R 775 /var/www/storage /var/www/bootstrap/cacheQuesta configurazione permette a Laravel di scrivere solo dove necessario, proteggendo allo stesso tempo gli altri file dell'applicazione da modifiche.
Seguendo questi passaggi, i tuoi container Laravel avranno permessi sui file stabili e prevedibili sia negli ambienti locali che in quelli di produzione. Questo riduce gli errori ricorrenti e garantisce che Laravel possa registrare dati, memorizzare nella cache i file e scrivere le sessioni in modo affidabile.
Comprendere docker-compose.override.yml per ambienti locali e di produzione
Docker Compose ti permette di definire applicazioni multi-container usando un unico file di configurazione. Nella maggior parte dei casi, questa configurazione è memorizzata in un file chiamato docker-compose.yml. Tuttavia, gestire più ambienti come lo sviluppo locale e la produzione spesso richiede adattamenti specifici per l'ambiente. È qui che il file docker-compose.override.yml diventa utile.
Per impostazione predefinita, Docker Compose cerca automaticamente un file chiamato docker-compose.override.yml nella stessa directory del file Compose principale. Quando viene trovato, unisce le configurazioni di entrambi i file quando esegui qualsiasi comando docker compose. Questo approccio permette agli sviluppatori di mantenere una configurazione base pulita e riutilizzabile, personalizzando al contempo aspetti specifici dell'ambiente per l'uso locale o di produzione.
Il ruolo di docker-compose.override.yml
Il file docker-compose.override.yml è un'estensione della configurazione base di Compose. Modifica o aggiunge proprietà che si applicano solo a un determinato ambiente, senza richiedere modifiche al file principale docker-compose.yml. Il file di override è particolarmente utile nei flussi di lavoro di sviluppo locale, dove gli sviluppatori spesso devono montare il codice sorgente, abilitare strumenti di debug o modificare le variabili d'ambiente per i test.
Quando esegui il comando docker compose up, Docker unisce automaticamente i contenuti di docker-compose.yml e docker-compose.override.yml. Se un servizio, volume o configurazione è definito in entrambi i file, i valori presenti nel file override hanno la precedenza.
Per utilizzare un file di override diverso, ad esempio uno destinato alla produzione, puoi specificare manualmente il file usando il flag -f:
docker compose -f docker-compose.yml -f docker-compose.prod.yml up -dQuesto approccio ti permette di mantenere configurazioni separate per diversi ambienti utilizzando una struttura di comandi unica e coerente.
Strutturare per lo Sviluppo Locale
Gli ambienti di sviluppo locali richiedono generalmente modifiche frequenti, ricaricamento del codice in tempo reale e registrazione dettagliata. Il file docker-compose.override.yml consente di introdurre queste funzionalità senza influire sugli altri ambienti.
Un tipico file di override locale può includere:
- Montaggi bind per aggiornamenti live del codice
- Direttive di build locali invece di utilizzare immagini precompilate
- Variabili d'ambiente specifiche per lo sviluppo
- Servizi di debug e test
Per esempio:
version: "3.9"
services:
app:
build:
context: .
dockerfile: Dockerfile.dev
volumes:
- ./src:/app
- ./logs:/app/logs
environment:
- DATABASE_URL=postgres://postgres:postgres@db:5432/app_db
- LOG_LEVEL=debug
ports:
- "8000:8000"
depends_on:
- db
db:
environment:
- POSTGRES_PASSWORD=postgresIn questo esempio:
- Il servizio
appviene costruito direttamente da un Dockerfile locale (Dockerfile.dev), rendendo facile testare le modifiche senza dover ricostruire le immagini tramite un registry. - Il codice sorgente viene montato utilizzando bind mount, consentendo al container di riflettere in tempo reale le modifiche ai file locali.
- Le variabili d'ambiente come
LOG_LEVEL=debugvengono impostate per fornire output più dettagliati durante lo sviluppo. - Il database utilizza credenziali semplici adatte per i test locali, ma non dovrebbero essere utilizzate in produzione.
Questa configurazione offre un ambiente di sviluppo più veloce e flessibile mantenendo invariata la configurazione di base.
Prepararsi per la produzione
Gli ambienti di produzione richiedono stabilità, riproducibilità e sicurezza. I container dovrebbero essere eseguiti a partire da immagini predefinite piuttosto che essere creati localmente, e le informazioni sensibili dovrebbero essere gestite in modo sicuro. A differenza del file di override applicato automaticamente per lo sviluppo locale, gli override di produzione devono essere specificati esplicitamente.
Un file di override per la produzione (docker-compose.prod.yml) è solitamente progettato per sostituire i passaggi di build locali con riferimenti alle immagini, usare volumi denominati invece di montaggi bind e definire proprietà relative al deployment come i limiti delle risorse e la scalabilità.
Esempio:
version: "3.9"
services:
app:
image: registry.example.com/myapp:1.2.3
environment:
- DATABASE_URL=${DATABASE_URL}
- LOG_LEVEL=info
volumes:
- app-data:/var/lib/app
ports:
- "8000:8000"
restart: unless-stopped
deploy:
replicas: 3
resources:
limits:
cpus: "0.5"
memory: 512M
db:
image: postgres:15
volumes:
- db-data:/var/lib/postgresql/data
environment:
- POSTGRES_PASSWORD_FILE=/run/secrets/db_password
secrets:
db_password:
external: true
volumes:
app-data:
db-data:In questa configurazione:
Il servizio
appfa riferimento a un'immagine predefinita (myapp:1.2.3) memorizzata in un registro invece di essere creata localmente.I mount bind vengono sostituiti con volumi nominati per garantire uno storage dei dati coerente e isolato.
Le credenziali sensibili sono archiviate in modo sicuro utilizzando i segreti di Docker.
La sezione
deploydefinisce il comportamento di scaling e i limiti delle risorse per una maggiore stabilità sotto carico.La configurazione deve essere applicata esplicitamente durante il deployment:
docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d
Questa struttura garantisce che le distribuzioni di produzione siano coerenti, controllate e prive di artefatti locali dello sviluppo.
Confronto tra sovrascritture locali e di produzione
| Aspetto della configurazione | Locale (docker-compose.override.yml) | Produzione (docker-compose.prod.yml) |
|---|---|---|
| Applicato automaticamente | Sì | No (devi usare -f) |
| Gestione del codice sorgente | Mount bind per aggiornamenti in tempo reale | Immagini preconfigurate dal registro |
| Variabili d'ambiente | Valori incentrati sugli sviluppatori | Valori sicuri per la produzione |
| Registrazione | Verboso (debug) | Conciso (info o errore) |
| Gestione dei segreti | Valori semplici o .env | Segreti Docker o segreti gestiti |
| Scalatura | Contenitore singolo | Molteplici repliche |
| Ottimizzazione delle prestazioni | Non richiesto | Limiti delle risorse definiti |
| Strumenti di debug | Abilitato | Disabilitato |
| Politica di riavvio | Manuale o nessuno | |
L'utilizzo di più file Docker Compose offre un modo chiaro per separare le configurazioni specifiche dell'ambiente dalla configurazione di base. Il file base docker-compose.yml definisce la struttura comune dell'applicazione, mentre docker-compose.override.yml la adatta per lo sviluppo locale. Quando si effettua il deploy in produzione, un file di override esplicito garantisce una configurazione prevedibile e sicura.
Questo modello consente ai team di mantenere un flusso di lavoro coerente. Gli sviluppatori possono avviare l'applicazione in locale utilizzando:
docker compose upe distribuire in produzione usando:
docker compose -f docker-compose.yml -f docker-compose.prod.yml up -dEntrambi gli ambienti condividono la stessa configurazione di base pur mantenendo impostazioni indipendenti adatte ai loro requisiti specifici. Questa separazione migliora la manutenibilità, riduce gli errori di configurazione e mantiene allineati gli ambienti locali e di produzione.
Risoluzione dei problemi del tuo ambiente
Questa sezione fornisce passaggi di risoluzione dei problemi per i problemi comuni che potresti incontrare durante l'esecuzione della tua app con Docker Compose.
502 Bad Gateway (Nginx mostra risposte 502)
Sintomi:
- Il browser mostra 502 Bad Gateway quando si accede a
http://localhost:8000. - I log di Nginx contengono righe come
recv() failed (111: Connection refused)oconnect() failed (111: Connection refused) while connecting to upstream.
Cause probabili:
- PHP-FPM (il servizio
app) non è in esecuzione o non sta ascoltando sulla socket/porta prevista. - Nginx
fastcgi_passpunta all'host/porta sbagliata. - Nome del container non corrispondente o problemi di rete tra
nginxeapp. appsi è bloccato all'avvio (ad esempio, a causa di estensioni mancanti o errori di configurazione).
Come confermare:
Ispeziona i log di Nginx:
docker compose logs nginx | tail -n 100Cerca messaggi
502o errori di connessione upstream.Controlla lo stato e i log del contenitore
app:docker compose ps app docker compose logs app --tail=200Conferma che PHP-FPM stia ascoltando all'interno del container
app:docker compose exec app ss -ltnp | grep :9000 || docker compose exec app ss -lxp | grep php-fpmPrevisto: un listener TCP sulla porta
9000oppure un socket Unix usato danginx(meno comune con questo compose).Conferma che
nginxpuò risolvere e raggiungereappsulla rete compose:docker compose exec nginx ping -c 2 app docker compose exec nginx wget -qO- --timeout=2 http://app:9000/ || trueSe
pingfallisce owgetva in timeout, c'è un problema di rete o una discrepanza nel nome del servizio.
Correzioni comuni:
Se PHP-FPM non è in esecuzione, controlla i log di
appper errori PHP fatali o problemi di avvio. Risolvi l'errore di base (spesso un'estensione mancante o un problema di permessi) e riavvia:docker compose restart app docker compose logs app --tail=100Se la configurazione di Nginx utilizza un upstream diverso (ad esempio,
fastcgi_pass 127.0.0.1:9000;), aggiornadocker-compose/nginx/travellist.confinfastcgi_pass app:9000;(corrispondente al nome del servizio nel tuo compose) e ricarica Nginx:# After editing config in host docker compose exec nginx nginx -s reload docker compose logs nginx --tail=50Se PHP-FPM ascolta su un socket Unix (es.
/run/php/php7.4-fpm.sock) ma Nginx si aspetta TCP o viceversa, standardizzare su TCPapp:9000per configurazioni Compose o montare correttamente il socket tra i container (consigliato: usare TCP in Compose multi-container).
Estensioni PHP mancanti (errori durante l'esecuzione di Composer o Artisan, o malfunzionamenti a runtime)
Sintomi:
- I comandi di Composer o Laravel falliscono con messaggi come
Classe "PDO" non trovata,ext-pdo mancanteoChiamata a funzione indefinita json_encode. - Errori PHP nei log di
appche fanno riferimento a classi o funzioni non definite.
Come confermare:
Ispeziona l'elenco dei moduli PHP del container
app:docker compose exec app php -m | sortCerca i nomi delle estensioni di cui hai bisogno (per le estensioni tipiche di Laravel:
pdo_mysql,mbstring,bcmath,openssl,tokenizer,xml,ctype,json,gd).Controlla il testo dell'errore di Composer, che di solito indica le estensioni necessarie:
docker compose exec app composer install
Correzioni:
Aggiungi le estensioni mancanti nel tuo Dockerfile e ricostruisci l'immagine. Esempio (per
pdo_mysqlegd):RUN apt-get update && apt-get install -y libpng-dev libxml2-dev \ && docker-php-ext-install pdo_mysql mbstring xml gdQuindi ricostruisci e riavvia:
docker compose build app docker compose up -d app docker compose logs app --tail=100Se un'estensione richiede librerie di sistema (ad esempio
gdha bisogno dilibpng-dev), aggiungi le corrispondenti righeapt-get installprima didocker-php-ext-install.Se ti serve un'estensione PHP che non è integrata, considera di installarla tramite PECL e abilitala in
php.ini.
Errori di connessione al database (Laravel non riesce a connettersi a MySQL)
Sintomi:
- Laravel mostra errori di connessione al database (
SQLSTATE[HY000] [2002] Connessione rifiutataoAccesso negato per l'utente). - Le migrazioni falliscono oppure l'applicazione mostra una pagina vuota per le pagine basate sui dati.
Come confermare:
Controlla i log del container del DB per errori di inizializzazione:
docker compose logs db --tail=200Verifica che il contenitore DB sia avviato:
docker compose ps dbVerifica che le credenziali e l'host siano coerenti tra
.envedocker-compose.yml. Nel file.envdi Laravel,DB_HOSTdovrebbe essere il nome del servizio definito in Docker Compose (db), non127.0.0.1olocalhost:DB_HOST=db DB_PORT=3306 DB_DATABASE=travellist DB_USERNAME=travellist_user DB_PASSWORD=passwordTest dall'interno del container
db:docker compose exec db mysql -u"${DB_USERNAME}" -p"${DB_PASSWORD}" -e "SHOW DATABASES;"Oppure, esegui il test dal contenitore
appper verificare la connettività di rete:docker compose exec app sh -c 'which mysql >/dev/null 2>&1 || echo "no mysql client"; mysql -h db -u"${DB_USERNAME}" -p"${DB_PASSWORD}" -e "SELECT VERSION();"'
Cause comuni e soluzioni:
Host errato in
.env: aggiornaDB_HOST=db, ricrea i container o ricarica le variabili d'ambiente:docker compose down docker compose up -d docker compose exec app php artisan migrateDB non pronta all'avvio dell'app: usa un meccanismo di ritentativo nella tua app o aggiungi un controllo di integrità e avvia l'ordinamento. Puoi anche attendere manualmente:
docker compose exec db mysqladmin -u"${DB_USERNAME}" -p"${DB_PASSWORD}" ping # expected: mysqld is aliveInizializzazione SQL non riuscita: controlla i file sotto
./docker-compose/mysql, un errore di sintassi o di permessi può interrompere l'inizializzazione del DB. Controlla i log del DB per eventuali errori di importazione.Privilegi/credenziali errate: conferma che il database e l'utente esistano. Ricrea il database o esegui SQL per concedere i privilegi.
Utilizzo della porta a livello host: se hai provato
curl telnet://localhost:3306e il serviziodbnon espone una porta host, quella connessione verrà rifiutata per impostazione predefinita. Effettua il test dall'interno dei container, oppure esponi la porta indocker-compose.yml(ports: - "3306:3306") per il debug solo locale.
Problemi di permessi e del filesystem (archiviazione, cache, file di log)
Sintomi:
- Laravel genera eccezioni relative alla scrittura della cache o dei log:
Impossibile aprire il flusso o il file "/var/www/storage/logs/laravel.log". - I file creati dai processi del container sono di proprietà di
roote non sono modificabili dal tuo utente host.
Come confermare:
Controlla i permessi del file dall'host:
ls -l ls -l storage bootstrap/cache docker compose exec app id -u # user id inside containerIspeziona i log del contenitore per errori di autorizzazione.
Correzioni:
Assicurati che il Dockerfile imposti l'utente e l'UID che corrispondono al tuo utente host (il tuo Dockerfile crea già un utente con
ARG uid). Conferma che iluidnegli argomenti di build didocker-compose.ymlcorrisponda al tuo UID host (di solito1000).Correggi la proprietà dal host o all'interno del container:
docker compose exec app chown -R sammy:sammy /var/www/storage /var/www/bootstrap/cacheo dall'host:
sudo chown -R $(id -u):$(id -g) storage bootstrap/cachePer lo sviluppo, i mount bind possono causare discrepanze di permessi; è preferibile eseguire i comandi del container per regolare la proprietà dopo aver avviato i container.
Errori relativi al compositore o al fornitore
Sintomi:
composer installfallisce all'interno diappo la cartellavendormanca causando l'errore di classe non trovata.composersegnala esaurimento della memoria nel container.
Come confermare:
Esegui composer all'interno del contenitore
appe cattura l'output:docker compose exec app composer install --no-interaction --prefer-dist
Correzioni:
Se vengono raggiunti i limiti di memoria di
composer, consenti più memoria o imposta la variabile d'ambiente di composer:docker compose exec app php -d memory_limit=-1 /usr/bin/composer installAssicurati che l’eseguibile di Composer sia presente (il tuo Dockerfile copia Composer). In caso contrario, ricostruisci l’immagine con il layer di Composer.
Se
vendorè assente a causa dell'overlay del bind mount, assicurati che il tuo bind mount non stia nascondendo la cartellavendorcreata nell'immagine. La migliore pratica è eseguirecomposer installdopo che i container sono avviati in modo chevendorvenga creato nella cartella montata, oppure aggiungerevendoral container tramite la build dell'immagine per la produzione.
L'applicazione restituisce una pagina vuota o errori 500
Sintomi:
- Il browser mostra una risposta vuota o errore HTTP 500.
- I log di Nginx mostrano 200 ma la pagina è vuota; i log di
appmostrano eccezioni fatali.
Come confermare:
Controlla i registri dell'applicazione:
docker compose exec app tail -n 200 storage/logs/laravel.log docker compose logs app --tail=200Controlla l'ambiente:
APP_DEBUG=truein.envfarà mostrare a Laravel errori dettagliati in fase di sviluppo (non attivare in produzione).
Correzioni:
Correggi l'eccezione di base mostrata in
laravel.log.Verifica che il file
.envesista e cheAPP_KEYsia impostato:docker compose exec app php artisan key:generateEsegui le migrazioni, svuota la cache:
docker compose exec app php artisan migrate --force docker compose exec app php artisan config:cache docker compose exec app php artisan route:cache docker compose exec app php artisan view:cache
Errori nella costruzione del container (errori durante docker compose build)
Sintomi:
docker compose buildgenera errori con apt o durante le fasi di build.
Come confermare:
Esegui di nuovo la build con i log:
docker compose build app
Correzioni:
Leggi l'output del passaggio che ha fallito. Problemi tipici:
- Rete/DNS nell'ambiente di build: riprovare o assicurarsi che Docker possa accedere a Internet.
- Pacchetti mancanti o sorgente apt errata: aggiungi
apt-get updateprima dell'installazione e pulisci le liste di apt dopo. - Permessi sui file copiati nell'immagine: assicurati che i percorsi
COPYsiano corretti.
Esempio di snippet Dockerfile per installazioni robuste:
RUN apt-get update && apt-get install -y --no-install-recommends \
libpng-dev libxml2-dev zip unzip \
&& docker-php-ext-install pdo_mysql mbstring xml gd \
&& apt-get clean && rm -rf /var/lib/apt/lists/*Problemi di rete o DNS tra i container
Sintomi:
- Un contenitore non può raggiungere un altro tramite il nome del servizio (ad esempio,
appnon può raggiungeredbcondb:3306). pingtramite il nome del servizio non funziona.
Come confermare:
docker compose exec app ping -c 3 db
docker compose exec app getent hosts db
docker network inspect travellistCorrezioni:
Conferma che i servizi condividano la stessa rete in
docker-compose.yml(entrambi dovrebbero fare riferimento atravellist).Se hai cambiato i nomi dei servizi o delle reti, aggiorna di conseguenza
DB_HOSTe gli upstream di Nginx.Ricrea la rete (questo distrugge i container effimeri, quindi fai attenzione):
docker compose down docker network prune # optional and destructive docker compose up -d
Comandi diagnostici utili
Esegui questi per un'ispezione mirata:
Mostra i container in esecuzione e le porte:
docker compose psLog in tempo reale per un servizio:
docker compose logs -f --tail=200 nginxEsegui una shell all'interno di un container:
docker compose exec app sh docker compose exec db bashIspeziona le variabili d'ambiente del contenitore:
docker compose exec app env | sort docker compose exec db env | grep MYSQLControlla l'elenco dei processi del contenitore:
docker compose exec app ps aux docker compose exec app ss -ltnpControlla lo stato di salute di MySQL:
docker compose exec db mysqladmin -u"${DB_USERNAME}" -p"${DB_PASSWORD}" ping
Quando esporre le porte dell'host per il debug
Per impostazione predefinita, il servizio db in questa configurazione non è collegato alle porte dell'host. Esporre le porte solo per il debug locale. Per esporre temporaneamente MySQL sull'host, aggiungi a docker-compose.yml sotto db:
ports:
- "3306:3306"Poi riavvia:
docker compose up -d dbDopo il debug, rimuovi la mappatura ports per evitare di esporre il database alla rete.
Domande frequenti
1. Ho bisogno di avere Composer installato sull'host?
No. Puoi eseguire Composer interamente all'interno del container dell'app, che è l'approccio consigliato per questo flusso di lavoro con Compose. Il Dockerfile nel tutorial include Composer, quindi esegui comandi come docker compose exec app composer install o docker compose run --rm app composer require vendor/package. Eseguire Composer nel container garantisce l'uso della versione corretta di PHP e delle estensioni necessarie, evitando di creare file vendor con proprietà incoerenti sul sistema host.
2. Posso eseguire le migrazioni di Laravel dall'interno del container?
Sì. Esegui le migrazioni dal container dell'app in modo che utilizzino lo stesso runtime e la stessa rete della tua applicazione: docker compose exec app php artisan migrate. Per attività occasionali o CI puoi usare docker compose run --rm app php artisan migrate --force. Prima di eseguire le migrazioni assicurati che il container del database sia attivo e accetti connessioni, ad esempio con docker compose exec db mysqladmin -u$ {DB_USERNAME} -p$ {DB_PASSWORD} ping o riprovando finché non risponde.
3. Come faccio a installare estensioni PHP aggiuntive?
Aggiungi i pacchetti di sistema necessari e i comandi per le estensioni nel Dockerfile, quindi ricostruisci l'immagine. Ad esempio, installa le dipendenze e costruisci estensioni comuni con qualcosa del genere:
RUN apt-get update && apt-get install -y libpng-dev libjpeg-dev \
&& docker-php-ext-configure gd --with-jpeg \
&& docker-php-ext-install pdo_mysql mbstring gdSe hai bisogno di un'estensione PECL, usa pecl install e docker-php-ext-enable. Dopo aver modificato il Dockerfile, esegui docker compose build app e poi docker compose up -d app per applicare le modifiche.
4. Come posso esporre il container Nginx per HTTPS?
Aggiungi un blocco server HTTPS alla tua configurazione Nginx, monta il tuo certificato e la chiave nel container e pubblica la porta 443 in docker-compose. Ecco un esempio con modifiche minime in docker-compose.yml:
services:
nginx:
ports:
- "8000:80"
- "443:443"
volumes:
- ./docker-compose/nginx:/etc/nginx/conf.d
- ./certs:/etc/nginx/certs:roQuindi aggiungi un blocco server SSL che faccia riferimento a /etc/nginx/certs/fullchain.pem e /etc/nginx/certs/privkey.pem. In produzione, utilizza un reverse proxy o un gestore di certificati come Traefik o un bilanciatore di carico esterno per ottenere e rinnovare i certificati in modo sicuro invece di memorizzare le chiavi private nello stack dell'app.
5. Come ricostruisco Laravel dopo aver modificato il codice?
Dipende da cosa è cambiato. Se stai usando i bind mount per la directory del progetto, le modifiche a PHP, template, route e controller vengono riflesse immediatamente; esegui i comandi di pulizia della cache di Laravel se necessario, ad esempio:
docker compose exec app php artisan config:clear
docker compose exec app php artisan route:clear
docker compose exec app php artisan view:clearSe hai modificato le dipendenze di Composer o il Dockerfile (nuove estensioni o pacchetti di sistema), reinstalla o ricostruisci: docker compose exec app composer install per le modifiche alle dipendenze, e docker compose build app && docker compose up -d per le modifiche al Dockerfile. Riavvia il servizio interessato quando cambi la configurazione di PHP-FPM o Nginx: docker compose restart app o docker compose restart nginx.
Conclusione
In questa guida, abbiamo configurato un ambiente Docker con tre container utilizzando Docker Compose per definire la nostra infrastruttura in un file YAML.
Da questo punto in poi, puoi lavorare sulla tua applicazione Laravel senza dover installare e configurare un server web locale per lo sviluppo e i test. Inoltre, lavorerai con un ambiente usa e getta che può essere facilmente replicato e distribuito, il che può essere utile sia durante lo sviluppo della tua applicazione sia quando ti avvicini a un ambiente di produzione.
Per ulteriori tutorial su Laravel, consulta i seguenti articoli:
- Ospita la tua app Laravel su Linux-Console.net
- Come installare e configurare Laravel con Nginx su Ubuntu (Stack LEMP)
- Come creare risorse API Eloquent di Laravel per convertire i modelli in JSON
- Come Avviare una Nuova Applicazione Laravel con Docker Compose
Grazie per aver imparato con la community di Linux-Console.net.

