In questo articolo, Docker Compose – Creazione di un ambiente con Apache, PHP, MySQL e phpMyAdmin, vediamo come utilizzare Docker Compose per creare un ambiente di sviluppo con Apache, PHP, MySQL e phpMyAdmin.

In questo articolo, Docker Compose – Creazione di un ambiente con Apache, PHP, MySQL e phpMyAdmin, vediamo come utilizzare Docker Compose per creare un ambiente di sviluppo con Apache, PHP, MySQL e phpMyAdmin.

Introduzione a Docker e Docker Compose

Cos’è Docker Compose?

Docker Compose è uno strumento che consente di definire e gestire applicazioni multi-container. Con un singolo file YAML (docker-compose.yml), è possibile configurare, eseguire e gestire più contenitori contemporaneamente, semplificando notevolmente la gestione di ambienti complessi. Docker Compose è particolarmente utile quando si lavora con applicazioni che richiedono più servizi, come database, server web e applicazioni frontend.

Il file docker-compose.yml è un file di configurazione scritto in formato YAML (YAML acronimo di “YAML Ain’t Markup Language” è un linguaggio di serializzazione dei dati utilizzato per scrivere file di configurazione per il deployment dell’infrastruttura) che consente di definire, gestire e avviare più container Docker in maniera coordinata, come se fossero un’unica applicazione multi-servizio.

Vantaggi di usare Docker Compose

  • Gestione semplificata di più container: Docker Compose permette di avviare e gestire facilmente più container con un singolo comando.
  • Definizione delle dipendenze: Le dipendenze tra i servizi sono esplicitamente definite nel file docker-compose.yml, semplificando la configurazione.
  • Facilità di scalabilità: È possibile scalare i servizi aggiungendo o rimuovendo container con un solo comando.
  • Ambientazioni riproducibili: Docker Compose consente di creare ambienti che possono essere facilmente replicati su altre macchine, assicurando che i team di sviluppo lavorino con la stessa configurazione.

Teoria di Docker Compose

File docker-compose.yml

Il cuore di Docker Compose è il file docker-compose.yml, che descrive i servizi, le reti e i volumi utilizzati dall’applicazione. Ecco una panoramica della sintassi del file:

version: "xxx"
services:
  servizio 1:
    image: immagine:tag
    ports:
      - "porta_host:porta_container"
    volumes:
      - locale:container
    environment:
      VARIABILE: valore
  servizio 2:
   image: immagine:tag
    ports:
      - "porta_host:porta_container"
    volumes:
      - locale:container
    environment:
      VARIABILE: valore
  servizio n:
    ......
networs:
  ......

Concetto di Servizi, Reti e Volumi

  • Servizi: Ogni contenitore che esegue un’applicazione o una parte di essa è definito come un “servizio”. In questo caso, apache-php, mysql e phpmyadmin sono tutti servizi.
  • Reti: Docker Compose crea automaticamente una rete privata per ogni applicazione, a meno che non venga configurato diversamente.
  • Volumi: I volumi sono utilizzati per persistere i dati tra i riavvii dei contenitori. In questo esempio, il volume ./html è montato su /var/www/html per permettere la modifica dei file PHP in locale.

Per quanto riguarda Servizi e Volumi i concetti sono già stati esplicitati nelle GUIDE PRECEDENTI. Esplicitiamo il concetto di RETE

Il concetto di reti in Docker Compose riguarda la gestione della comunicazione tra i contenitori (container) che fanno parte della stessa applicazione. Quando si avvia un’applicazione multi-container tramite Docker Compose, Docker crea automaticamente una rete virtuale privata in cui i container possono comunicare tra di loro. Questo isolamento è utile per garantire che i contenitori di un’applicazione non interferiscano con quelli di altre applicazioni che potrebbero essere in esecuzione sulla stessa macchina.

Cos’è una rete in Docker Compose?

Una rete in Docker Compose è un’entità virtuale che consente ai contenitori di comunicare tra loro. Ogni contenitore che appartiene alla stessa rete può “vedere” e comunicare con gli altri contenitori della stessa rete utilizzando i loro nomi di servizio (definiti nel file docker-compose.yml), come se fossero nomi host.

Se non viene configurata esplicitamente una rete, Docker Compose crea automaticamente una rete privata e di default per ogni applicazione. La rete sarà visibile solo ai contenitori definiti nel file docker-compose.yml di quell’applicazione, impedendo la comunicazione con altre applicazioni in esecuzione sulla stessa macchina.

Comportamento di Default

Quando si usa Docker Compose senza configurare reti esplicitamente, Docker crea una rete privata con il nome del progetto, a cui i container sono automaticamente connessi. Questo significa che i contenitori possono comunicare tra loro, ma non con i contenitori di altre applicazioni.

Esempio di un file docker-compose.yml con la configurazione di rete di default:

version: "3"
services:
  web:
    image: nginx
    ports:
      - "8080:80"
  db:
    image: mysql
    environment:
      MYSQL_ROOT_PASSWORD: example

In questo caso, Docker Compose crea una rete chiamata nomeprogetto_default (dove “nomeprogetto” è il nome della cartella o del progetto) e connette i contenitori web e db a questa rete. Entrambi i container possono comunicare tra loro utilizzando i nomi di servizio (web e db), come nel caso di una connessione al database MySQL dal container web usando db come hostname.

Come personalizzare le reti in Docker Compose?

Docker Compose consente anche di definire reti personalizzate, che danno un maggiore controllo sul comportamento di rete tra i contenitori. Si può definire una rete con un nome specifico, decidere se utilizzare una rete bridge (la rete predefinita di Docker) o altre tipologie di rete, e collegare i tuoi contenitori a queste reti.

Ecco un esempio di configurazione di rete personalizzata:

version: "3"
services:
  web:
    image: nginx
    networks:
      - frontend
  db:
    image: mysql
    environment:
      MYSQL_ROOT_PASSWORD: example
    networks:
      - backend
  phpmyadmin:
    image: phpmyadmin
    environment:
      PMA_HOST: db
    networks:
      - frontend
      - backend

networks:
  frontend:
  backend:

In questo esempio, sono state create due reti personalizzate: frontend e backend. I contenitori web e phpmyadmin sono collegati alla rete frontend, mentre db è collegato alla rete backend. Inoltre, phpmyadmin è connesso sia alla rete frontend che alla rete backend.

Cosa accade con le reti personalizzate?

  • I contenitori sulla stessa rete (ad esempio, web e phpmyadmin nella rete frontend) possono comunicare facilmente tra loro.
  • I contenitori su reti diverse (ad esempio, web sulla rete frontend e db sulla rete backend) non possono comunicare direttamente tra di loro, a meno che non venga configurato un collegamento esplicito tra le reti.
  • Nel caso del servizio phpmyadmin, esso è connesso sia alla rete frontend che a quella backend, quindi può comunicare sia con il contenitore web che con db.

Esempio pratico: comunicazione tra servizi

Immaginiamo di voler creare un’applicazione che include un server web (Apache con PHP), un database (MySQL) e una interfaccia di gestione (phpMyAdmin). Si può utilizzare Docker Compose per definire i servizi e le reti. Se non si specifica una rete personalizzata, Docker Compose creerà automaticamente una rete privata.

Tuttavia, se si ha bisogno di configurare una rete separata per isolare la comunicazione tra i servizi, si può fare come mostrato nell’esempio precedente.

Scenario senza rete personalizzata:

  • I servizi possono comunicare tra di loro tramite il nome del servizio, ma tutti sono sulla stessa rete, quindi sono più “esposti”.

Scenario con reti personalizzate:

  • I contenitori web e phpmyadmin sono sulla stessa rete (frontend) e possono comunicare facilmente tra loro, ma non possono comunicare direttamente con db, a meno che non si colleghino alla rete backend o non venga creato un link esplicito.
  • Rete di default: Docker Compose crea automaticamente una rete per ogni applicazione, a meno che non venga configurato diversamente.
  • Reti personalizzate: Si possono definire reti personalizzate per un controllo più granulare sulla comunicazione tra i contenitori.
  • Sicurezza e isolamento: Le reti personalizzate possono essere utilizzate per isolare i contenitori, migliorando la sicurezza e l’affidabilità dell’applicazione.
  • Comunicazione tra i contenitori: I contenitori sulla stessa rete possono comunicare tra di loro tramite i loro nomi di servizio.

Questo approccio rende Docker Compose uno strumento potente per gestire applicazioni complesse e sicure.

Creazione dell’ambiente con Apache – PHP, MySQL e phpMyAdmin

Ci proponiamo di creare un ambiente con il Web Server Apache-PHP, l’ RDBMS MySQL e l’interfaccia di gestione phpMyAdmin. Tutti servizi sono containerizzati attraverso Docker Compose

Vediamo inizialmente come creare un ambiente senza phpMyAdmin, ne testiamo il funzionamento e solo dopo integriamo il servizio phpMyAdmin nostro file docker-compose.yml.

Vedremo come sarà semplice arricchire la nostra applicazione con UN SOLO COMANDO e SENZA INSTALLARE ALCUN SOFTWARE!

Step 1: Creazione di un ambiente di base con Apache-PHP e MySQL

Iniziamo creando un’applicazione con Apache, PHP e MySQL utilizzando Docker Compose. Creiamo una nuova directory (Apache-PHP-MySQL-phpMyAdmin) per il progetto e ci posizioniamo al suo interno.

Tasto destro del mouse -> Apri nel Terminale (si aprirà PowerShell) e scriviamo
code . (Si aprirà Visual Studio Code nella cartella di progetto)

creiamo il file docker-compose.yml con il seguente contenuto:

version: '3'
services:
  web:
    build: .
    image: php:8.2-apache
    container_name: apache_php
    ports:
      - "8080:80"
    volumes:
      - ./sorgenti:/var/www/html
    networks:
      - app-network

  db:
    image: mysql:8.0
    container_name: mysql_db
    environment:
      MYSQL_ROOT_PASSWORD: root
      MYSQL_DATABASE: testdb
    ports:
      - "3306:3306"
    networks:
      - app-network

networks:
  app-network:
    driver: bridge

Analizziamo il contenuto del file:

  • La versione del file docker-compose.yml indica quale schema di configurazione viene utilizzato. In questo caso, version: '3' è una delle versioni più comuni per Docker Compose e rappresenta una sintassi che è compatibile con Docker 1.13.0 e versioni successive. La versione 3 supporta la gestione di servizi, reti, volumi e altre risorse.
  • Servizio web (Apache-PHP):
    • image: php:8.4.6-apache-bullseye: Questo campo definisce l’immagine Docker da usare per il servizio. In questo caso, l’immagine è basata su PHP 8.4.6 con Apache. Questa immagine è già preconfigurata per eseguire PHP con un server Apache.
    • build: . consente di indicare a Docker che la costruzione dell’immagine deve partire da un Dockerfile anzichè dall’immagine originaria. Il Dockerfile ci consentirà di montare un nuovo layer sull’immagine originaria: l’estensione mysqli
    • container_name: apache_php: Imposta un nome personalizzato per il contenitore, che in questo caso sarà apache_php. Questo nome può essere utilizzato per riferirsi al contenitore da altre parti del sistema, come per fermarlo o eseguire comandi specifici.
    • ports: – “8080:80”: Mappa la porta 80 del contenitore (la porta predefinita di Apache) sulla porta 8080 della macchina host. Ciò significa che potremo accedere all’applicazione web tramite http://localhost:8080.
    • volumes: – ./src:/var/www/html: Monta una cartella locale (./sorgenti) all’interno del contenitore nella directory /var/www/html, che è la directory predefinita per i file web di Apache (per capire qual è la WORKDIR basta fare il docker inspect oppure direttamente nella documentazione dell’immagine da Docker Hub). In pratica, i file PHP che mettiamo nella cartella ./sorgenti sulla nostra macchina locale saranno visibili e accessibili all’interno del contenitore.
    • networks: – app-network: Specifica che il servizio web sarà collegato alla rete app-network, che viene definita più in basso nel file. Questo permette al contenitore web di comunicare con altri contenitori sulla stessa rete, come il contenitore del database MySQL.
  • Servizio db (MySQL)
    • image: mysql:5.7: Specifica l’immagine Docker da usare per il servizio. In questo caso, si usa l’immagine ufficiale di MySQL 5.7. Questa immagine è preconfigurata per eseguire MySQL.
    • container_name: mysql_db: Imposta un nome personalizzato per il contenitore MySQL, che in questo caso sarà mysql_db.
    • environment: La sezione environment definisce le variabili di ambiente da passare al contenitore MySQL.
    • MYSQL_ROOT_PASSWORD: rootpassword: Nella documentazione dell’immagine di mysql è esplicitato che è NECESSARIO esplicitare il valore di questa variabile di ambiente. In questo caso il valore (quindi la password di root) è root.
    • MYSQL_DATABASE: testdb: Crea un database chiamato testdb durante l’avvio del contenitore. Questo è utile per iniziare con un database già configurato.
    • ports: – “3306:3306”: Mappa la porta 3306 del contenitore (la porta predefinita di MySQL) sulla porta 3306 della macchina host. Ciò significa che MySQL sarà accessibile sulla nostra macchina locale tramite localhost:3306.
    • networks: – app-network: Specifica che il servizio MySQL sarà collegato alla rete app-network, permettendo la comunicazione con il contenitore Apache-PHP e altri contenitori sulla stessa rete.
  • Reti

networks: La sezione networks definisce le reti che i contenitori useranno per comunicare tra loro.

  • app-network: Questa è la rete personalizzata definita nel file. Viene creata per i contenitori web e db, che possono quindi scambiarsi dati tramite questa rete privata.
  • driver: bridge: Il driver bridge è il driver predefinito per la rete, che consente ai contenitori di comunicare tra loro sulla stessa macchina host tramite una rete privata.

Step 2: Creazione del Dockerfile

All’interno della cartella di progetto creiamo il Dockerfile:

FROM php:8.2-apache

# Abilitare l'estensione mysqli
RUN docker-php-ext-install mysqli

# Impostare la directory di lavoro
WORKDIR /var/www/html

Non ci dilunghiamo nella spiegazione poichè la teoria (e la pratica) sul Dockerfile è stata spiegata nella guida: https://profgiagnotti.it/dockerfile-personalizzazione-di-immagini-e-push-su-docker-hub/

Step 3: Creazione della cartella sorgenti per i file PHP

Creiamo la cartella sorgenti all’interno della cartella del progetto e aggiungiamo un file PHP di esempio. All’interno di sorgenti, creiamo un file chiamato index.php:

<?php
$servername = "db";
$username = "root";
$password = "root";
$dbname = "testdb";

// Crea connessione
$conn = new mysqli($servername, $username, $password, $dbname);

// Verifica connessione
if ($conn->connect_error) {
    die("Connection failed: " . $conn->connect_error);
}

echo "Connessione a MySQL stabilita con successo!";

// Chiudi la connessione
$conn->close();
?>

Questo script PHP si connette al database MySQL e stampa un messaggio di successo se la connessione è riuscita.

Step 4: Avvio dell’applicazione

Ora che abbiamo creato la configurazione di Docker Compose e il nostro file PHP, possiamo avviare i servizi. Apri il terminale nella directory del progetto (o direttamente da Visual Studio Code) e lanciare il comando:

docker-compose up --build -d

Questo comando avvierà i container in background.

Al termine del processo di avvio possiamo verificare che i contenitori siano in esecuzione con: docker ps -a oppure da Docker Desktop

Nota: Se si effettuano modifiche nel Dockerfile conviene vermare i container con:

docker compose down

e forzare la ricostruzione delle immagini con:

docker-compose up --build

Step 5: Testare il Funzionamento

Una volta che i container sono attivi, apriamo il browser e visitiamo http://localhost:8080. Vediamo la pagina con il messaggio “Connessione a MySQL stabilita con successo!” che indica che la connessione al database MySQL è stata stabilita con successo.

Step 6: Aggiungere phpMyAdmin per la gestione del database

A questo punto, l’applicazione è funzionante con Apache-PHP e MySQL. Ora, aggiungiamo phpMyAdmin al file docker-compose.yml per semplificare la gestione del database MySQL tramite una interfaccia web.

Aggiornare il file docker-compose.yml aggiungendo il servizio phpmyadmin come segue:

version: '3'
services:
  web:
    build: .
    image: php:8.2-apache
    container_name: apache_php
    ports:
      - "8080:80"
    volumes:
      - ./sorgenti:/var/www/html
    networks:
      - app-network

  db:
    image: mysql:8.0
    container_name: mysql_db
    environment:
      MYSQL_ROOT_PASSWORD: root
      MYSQL_DATABASE: testdb
    ports:
      - "3306:3306"
    networks:
      - app-network
      
  phpmyadmin:
    image: phpmyadmin
    container_name: phpmyadmin
    environment:
      PMA_HOST: db
      PMA_PORT: 3306
    ports:
      - "8081:80"
    networks:
      - app-network

networks:
  app-network:
    driver: bridge
  • Servizio phpmyadmin
    • image: phpmyadmin: Specifica l’immagine Docker da usare per il servizio. In questo caso, si usa l’immagine ufficiale di phpmyadmin.
    • container_name: phpmyadmin: Imposta un nome personalizzato per il contenitore phpMyAdmin, che in questo caso sarà phpmyadmin.
    • environment: La sezione environment definisce le variabili di ambiente da passare al contenitore phpmyadmin.
    • PMA_HOST: db: Nella documentazione dell’immagine di phpmyadmin è esplicitato che è, per un uso con un DB server esterno, è NECESSARIO esplicitare il nome del DB esterno (nel nostro caso il servizio db di mysql)
    • PMA_PORT: 3306: Nella documentazione dell’immagine di phpmyadmin è esplicitato che è, per un uso con un DB server esterno, è NECESSARIO esplicitare la porta che espone il servizio esterno (nel nostro caso la 3306 di mysql)
    • ports: – “8081:80”: Mappa la porta 80 del contenitore sulla porta 8081 della macchina host. Ciò significa che phpmyadmin sarà accessibile sulla nostra macchina locale tramite localhost:8081.
    • networks: – app-network: Specifica che il servizio sarà collegato alla rete app-network, permettendo la comunicazione con il contenitore Apache-PHP e MySQL

Step 7: Rilanciare Docker Compose

Per aggiungere il nuovo servizio senza fermare gli altri, eseguire il seguente comando:

docker-compose up -d

Step 8: Testare phpMyAdmin

Ora, apriamo il browser e visitiamo http://localhost:8081. Vediamo l’interfaccia di phpMyAdmin. Accediamo con le seguenti credenziali:

  • Username: root
  • Password: root (impostata in precedenza)

Possiamo ora gestire facilmente il database MySQL tramite l’interfaccia grafica di phpMyAdmin.

Test completo dell’applicazione

Proviamo ora a testare l’applicazione nel suo complesso:

creiamo un nuovo db da phpmyadmin “test_completo”, una nuova tabella “utenti” e lo popoliamo la tabella con 2 record

modifichiamo il nome di index.php in connessione.php e lo modifichiamo in questo modo: (sostituiamo il dbname ed eliminiamo il messaggio di successo)

<?php
$servername = "db";
$username = "root";
$password = "root";
$dbname = "test_completo";

// Crea connessione
$conn = new mysqli($servername, $username, $password, $dbname);

// Verifica connessione
if ($conn->connect_error) {
    die("Connection failed: " . $conn->connect_error);
}
?>

Scriviamo il nuovo index.html come segue:

<?php
//includiamo la connessione al database
include 'connessione.php';

//selezioniamo gli utenti dalla tabella "utenti" del database "test_completo"
$sql = "SELECT * FROM utenti";
$result = $conn->query($sql);

//verifichiamo se ci sono risultati, estraiamo i dati e li visualizziamo in formato tabellare
if ($result->num_rows > 0) {    
    echo "<table border='1'><tr><th>ID</th><th>Cognome</th><th>Nome</th></tr>";
    // output data of each row
    while($row = $result->fetch_assoc()) {
        echo "<tr><td>" . $row["id"]. "</td><td>" . $row["Cognome"]. "</td><td>" . $row["Nome"]. "</td></tr>";
    }
    echo "</table>";
} else {
    echo "0 risultati";
}
$conn->close();
?>

Questo script seleziona i record di “utenti” e li visualizza in formato tabellare.

Non ci resta che tornare sul browser all’URL: localhot:8080, aggiornare e….

verificare che la nostra App funziona correttamente con semplici step e senza installare software aggiuntivo

Vantaggi di Docker Compose: Un Solo Comando per Ampliare l’Applicazione

L’aspetto più interessante di Docker Compose è la sua capacità di ampliare l’applicazione rapidamente con un solo comando. In pochi passaggi, abbiamo aggiunto un nuovo servizio (phpMyAdmin) al nostro ambiente, senza dover modificare manualmente configurazioni complesse o riavviare i contenitori precedenti.

Conclusione

In questo articolo, abbiamo creato un ambiente di sviluppo con Docker Compose utilizzando Apache-PHP e MySQL. Successivamente, abbiamo aggiunto phpMyAdmin per una gestione più semplice del database. Questo processo dimostra quanto sia facile estendere un’applicazione con Docker Compose, rendendo la gestione delle dipendenze e l’ampliamento dei servizi veloce e senza problemi.

Utilizzare Docker Compose permette di automatizzare la configurazione di ambienti complessi, risparmiando tempo e riducendo la possibilità di errori. Con un solo comando, è possibile lanciare, modificare e aggiornare intere applicazioni.

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *