Nelle lezioni precedenti abbiamo esplorato i fondamenti di Docker, configurato un ambiente di sviluppo "Dockerizzato" e creato il nostro primo container per il database MySQL. Ora è giunto il momento di creare un ambiente per eseguire il nostro codice PHP, utilizzando Docker, che ci consentirà di sviluppare e testare applicazioni Laravel in un ambiente isolato e riproducibile.
Cosa faremo e cosa vogliamo ottenere
In questa lezione, ci concentreremo sulla creazione del nostro container PHP. Lo configureremo per eseguire correttamente le nostre applicazioni Laravel. Utilizzeremo immagini ufficiali di PHP fornite da Docker Hub e le modificheremo secondo le nostre esigenze per supportare dipendenze specifiche del framework.
Prima di iniziare, assicurati di aver già installato Docker sul tuo sistema e di avere una conoscenza di base dei concetti di containerizzazione. Se hai seguito le lezioni precedenti, sei già a buon punto per continuare.
Senza ulteriori indugi, procediamo alla creazione del nostro container PHP per Laravel!
Configurazione del servizio PHP nel docker-compose.yml
Riapriamo il file docker-compose.yml
ed aggiungiamo le seguenti righe:
# PHP services
php:
build:
context: .
target: php
args:
- APP_ENV=${APP_ENV}
environment:
- APP_ENV=${APP_ENV}
- CONTAINER_ROLE=app
working_dir: /var/www/
volumes:
- ./:/var/www
ports:
- 8000:8000
depends_on:
- database
dove in:
# PHP services
php:
Definiamo i servizi PHP all'interno del file docker-compose.yml
. Quindi configuriamo la build:
build:
context: .
target: php
args:
- APP_ENV=${APP_ENV}
Specifichiamo le variabili d'ambiente per il nostro servizio PHP:
environment:
- APP_ENV=${APP_ENV}
- CONTAINER_ROLE=app
Impostiamo poi la directory di lavoro all'interno del container:
working_dir: /var/www/
Montiamo il codice sorgente all'interno del container:
volumes:
- ./:/var/www
Esponiamo quindi la porta 8000
del container. Sarà utilizzata per accedere all'applicazione:
ports:
- 8000:8000
Specifichiamo che il servizio dipende da quello del database, quindi dovrà essere avviato dopo di esso:
depends_on:
- database
Il file docker-compose.yml completo
version: "3.9"
services:
# PHP services
php:
build:
context: .
target: php
args:
- APP_ENV=${APP_ENV}
environment:
- APP_ENV=${APP_ENV}
- CONTAINER_ROLE=app
working_dir: /var/www/
volumes:
- ./:/var/www
ports:
- 8000:8000
depends_on:
- database
command: php -S 0.0.0.0:8000 -t public
# Database service
database:
image: mysql:latest
ports:
- "3306:3306"
environment:
- MYSQL_DATABASE=${DB_DATABASE}
- MYSQL_PASSWORD=${DB_PASSWORD}
- MYSQL_ROOT_PASSWORD=${DB_PASSWORD}
volumes:
- db-data:/var/lib/mysql
volumes:
db-data: ~
Dockerfile per il servizio PHP
Apriamo il file Dockerfile e modifichiamolo come di seguito:
FROM php:8.3 as php
# Aggiorniamo il gestore pacchetti
RUN apt-get update -y
# Installiamo le dipendenze necessarie
RUN apt-get install -y unzip libpq-dev libcurl4-gnutls-dev
# Installiamo le estensioni PHP richieste per Laravel
RUN docker-php-ext-install pdo pdo_mysql
RUN docker-php-ext-enable pdo pdo_mysql
# Installiamo l'estensione bcmath
RUN docker-php-ext-install bcmath
# Installiamo e abilitiamo Xdebug per il debug delle nostre applicazioni PHP
RUN pecl install xdebug && docker-php-ext-enable xdebug
Il Dockerfile fornisce istruzioni per la creazione dell'immagine del servizio PHP nell'ambiente Docker. Definisce una serie di passaggi per creare un'immagine PHP personalizzata. Iniziamo con l'immagine base di PHP versione 8.3 e quindi:
- aggiorniamo il gestore pacchetti.
- Installiamo le dipendenze necessarie per supportare le estensioni PHP e altre librerie utilizzate da Laravel.
- Utilizziamo
docker-php-ext-install
per installare le estensioni PHP richieste da Laravel, come PDO, PDO MySQL e BCMATH. - Installiamo Xdebug tramite PECL per consentire il debug delle applicazioni PHP e abilitiamolo con
docker-php-ext-enable
.
Creeremo così un'immagine PHP personalizzata con tutte le dipendenze necessarie per eseguire applicazioni Laravel nel container.
Lanciare il Comando Docker-Compose
Per avviare l'ambiente Docker con le nuove configurazioni, incluso il Dockerfile appena creato, eseguiamo il comando:
docker-compose up --build -d
Questo comando avvierà tutti i servizi definiti in docker-compose.yml
. Stavolta però, grazie alla flag --build
, esso costruirà nuovamente le immagini dei servizi, applicando le modifiche apportate al Dockerfile. La flag -d
avvierà invece i container in background.
Una volta finito digitiamo docker-compose ps
nel terminale per verificare che non ci siamo contenitori in errore. Noterete che il database parte regolarmente mentre il server php
no:
$ docker compose ps
NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS
project10-database-1 mysql:latest "docker-entrypoint.s…" database 15 minutes ago Up 15 minutes 0.0.0.0:3306->3306/tcp, 33060/tcp
Se lanciamo:
docker compose ps -a
abbiamo tutti i container, anche quelli non in esecuzione:
$ docker compose ps -a
NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS
project10-database-1 mysql:latest "docker-entrypoint.s…" database 17 minutes ago Up 17 minutes 0.0.0.0:3306->3306/tcp, 33060/tcp
project10-php-1 project10-php "docker-php-entrypoi…" php About a minute ago Exited (0) About a minute ago
E' evidente php
che non è in esecuzione. Approfondiamo e digitiamo:
$ docker compose logs php
php-1 | Interactive shell
php-1 |
Il risultato del comando docker compose logs php
indica che il container PHP ha avviato una shell interattiva invece di eseguire il comando predefinito o quello specificato nel Dockerfile. Per cui riapriamo il Dockerfile e alla fine dello stesso scriviamo:
...
WORKDIR /var/www
COPY . .
COPY --from=composer:2.7.6 /user/bin/composer usr/bin/composer
ENTRYPOINT [ "Docker/entrypoint.sh" ]
Modifiche al Dockerfile
WORKDIR /var/www
: imposta la directory di lavoro nel container. Tutti i comandi successivi nel Dockerfile verranno eseguiti relativamente a questa directory. In questo caso, la directory di lavoro è impostata su/var/www
.COPY . .
: copia tutti i file e le directory dal contesto di build (solitamente la directory del progetto locale) nella directory corrente del container, cioè la directory di lavoro impostata in precedenza conWORKDIR
. Questo comando consente di copiare tutto il contenuto del progetto nel container.COPY --from=composer:2.7.6 /user/bin/composer usr/bin/composer
: copia il binario di Composer dalla fase di build dell'immagine Composer (specificata con--from=composer:2.7.6
) nella directory/usr/bin/composer
all'interno del container. Questo binario di Composer sarà disponibile per l'uso all'interno del container.ENTRYPOINT [ "Docker/entrypoint.sh" ]
: imposta il punto di ingresso del container. Quando il container viene avviato, il comando specificato è eseguito.Docker/entrypoint.sh
è il file di script di ingresso che verrà eseguito quando il container viene avviato.
In breve, queste istruzioni nel Dockerfile configurano il container per:
- impostare la directory di lavoro su
/var/www
. - Copiare tutto il contenuto del progetto nel container.
- Copiare il binario di Composer nel container.
- Eseguire uno script di ingresso quando il container viene avviato.
Ora non resta che implementare il file relativo al punto di ingresso del container: Docker/entrypoint.sh
.
Implementare il file entrypoint.sh
Apriamo il file Docker/entrypoint.sh
e digitiamo quanto di seguito (questo file scrive i comandi che andrebbero scritti nella shell):
#!/bin/bash
if [ ! -f "vendor/autoload.php" ]; then
composer install --no-progress --no-interaction
fi
if [ ! -f ".env" ]; then
echo "Creating env file for env $APP_ENV"
cp .env.example .env
else
echo "env file exists"
fi
php artisan migrate
php artisan key:generate
php artisan cache:clear
php artisan config:clear
php artisan route:clear
php artisan serve --port=$PORT --host=0.0.0.0 --env=.env
Questo è uno script bash che viene eseguito all'avvio del container PHP. Ecco cosa fa passo dopo passo.
Verifica l'esistenza di vendor/autoload.php
- Controlla se il file
vendor/autoload.php
esiste. Questo file è generato da Composer e contiene l'autoload delle classi PHP del progetto. - Se il file non esiste, esegue
composer install --no-progress --no-interaction
per installare le dipendenze del progetto senza mostrare la barra di avanzamento e senza interazioni dell'utente.
Verifica l'esistenza di .env
- Controlla se il file
.env
esiste. Questo file contiene le variabili d'ambiente necessarie per configurare l'applicazione Laravel. - Se il file non esiste, esegue
cp .env.example .env
per copiare il file.env.example
nel file.env
.
Esecuzione dei comandi di Artisan
php artisan migrate
: applica le migrazioni del database.php artisan key:generate
: genera una nuova chiave per l'applicazione.php artisan cache:clear
: cancella la cache dell'applicazione.php artisan config:clear
: cancella la cache delle configurazioni dell'applicazione.php artisan route:clear
: cancella la cache delle route dell'applicazione.
Avvio del server di sviluppo di Laravel
- Esegue
php artisan serve --port=$PORT --host=0.0.0.0 --env=.env
per avviare il server di sviluppo di Laravel. Imposta la porta e l'host specificati dalle variabili d'ambiente$PORT
e$APP_ENV
. - La variabile d'ambiente
.env
specifica il file di configurazione da utilizzare.
Questo script è utile per automatizzare alcune operazioni comuni che devono essere eseguite ogni volta che il container PHP viene avviato, come l'installazione delle dipendenze, l'applicazione delle migrazioni del database e l'avvio del server di sviluppo di Laravel.
Riavviare i servizi
Una volta implementato il file Dockerfile con il Composer ed il punto di ingresso relativo al server dobbiamo buildare (ricostruire l'immagine) ed avviare il server. Da terminale ridigitiamo:
docker-compose up --build -d
in modo tale che Docker si scarichi e mandi in esecuzione gli ultimi package inseriti. Una volta terminato navighiamo all'indirizzo
http://localhost:8000
Se tutto dovesse andare a buon fine dovremmo vedere la home di Laravel:
Un errore relativo al server come:
L'errore "SQLSTATE[HY000] [2002] No such file or directory...."
indica che Laravel non riesce a connettersi al database MySQL. Per risolvere proviamo a modificare il file .env
:
DB_CONNECTION=mysql
DB_HOST=database
DB_PORT=3306
DB_DATABASE=project1.0
DB_USERNAME=root
DB_PASSWORD=secret
Esso assegna all'host il nome del contenitore del database, in questo caso database
, quindi riavvia i servizi.
Conclusione: il container Docker per il server
In questa lezione, ci siamo concentrati sulla creazione del nostro container PHP utilizzando Docker e lo abbiamo configurato per eseguire correttamente applicazioni Laravel. Nel nostro percorso, abbiamo definito il servizio PHP nel file docker-compose.yml
, configurando la build, le variabili d'ambiente, i volumi e le porte necessarie per il funzionamento dell'ambiente di sviluppo.
Abbiamo creato poi un Dockerfile per il servizio PHP con le istruzioni per creare un'immagine personalizzata e le dipendenze per eseguire applicazioni nel container. Questo Dockerfile è stato modificato per installare le estensioni PHP richieste da Laravel e abilitare Xdebug per il debug.
Infine, abbiamo implementato uno script di ingresso (entrypoint.sh
) per il container che automatizza alcune operazioni come l'installazione delle dipendenze, l'applicazione delle migrazioni del database e l'avvio del server di sviluppo di Laravel.
Con l'ambiente Docker completamente configurato, possiamo sviluppare applicazioni Laravel in modo rapido, riproducibile e isolato da altri ambienti. Utilizzando Docker possiamo garantire che le applicazioni funzionino correttamente ovunque, semplificando il processo di sviluppo, test e distribuzione.
Ora sei pronto per sperimentare con Docker e Laravel. Ci auguriamo che questa serie di lezioni ti abbia fornito una solida base per iniziare il tuo viaggio nello sviluppo di applicazioni web moderne. Buon coding!