Nessun risultato. Prova con un altro termine.
Guide
Notizie
Software
Tutorial

Kubernetes, realizzare un'applicazione: il Web layer

Un esempio di applicazione Web basata su PHP e MySQL utilizzando Kubernetes per l'orchestrazione e Docker per i container
Un esempio di applicazione Web basata su PHP e MySQL utilizzando Kubernetes per l'orchestrazione e Docker per i container
Link copiato negli appunti

Nella lezione precedente abbiamo iniziato a parlare di un'applicazione su Kubernetes in grado di mettere al lavoro i concetti visti sinora ed attivare i principali ingranaggi di questa splendida piattaforma.

Si tratta di una semplice applicazione Web in PHP che accede ad un database MySQL: quest'ultimo verrà precaricato con un database di prova creato in fase di inizializzazione mentre la prima consisterà in una semplice pagina che offrirà i dati letti in una tabella.

Nonostante il caso non appaia particolarmente complicato ci aiuterà ad imparare ad organizzare un'applicazione (avrà due livelli: un data layer con MySQL ed un Web layer con Apache/PHP), ad impiegare immagini Docker personalizzate nonché a sperimentare il service discovery, meccanismo innato che permette a servizi della stessa applicazione di trovarsi tra loro senza conoscere esplicitamente i reciproci indirizzi IP.

Riepiloghiamo i principi fondanti su cui ci stiamo muovendo:

  • ogni layer sarà costituito da un Deployment che gestirà i Pod necessari mentre la sua esposizione verso il resto dell'applicazione sarà offerta da un Service. Come si vedrà, per prima cosa, andremo a definire le immagini Docker che definiranno i container da attivare;
  • visto che il database MySQL fornirà accesso mediante password quest'ultima sarà conservata in un Secret cui dovrà fare accesso sia il data layer sia il Web layer. Nel primo caso, abbiamo già visto, la password non sarà altro che la password dell'utente root
  • l'applicazione Web potrà connettersi al database conoscendo il nome del Service che lo rappresenta e lo userà come suo indirizzo. Mediante il service discovery, Kubernetes stabilirà i contatti.

Gestione della password

Per prima cosa, ricordiamo, come già visto nella lezione precedente, che per i nostri scopi creeremo in modalità imperativa un Secret che conterrà la password. Questo il comando da noi utilizzato che viene riportato qui per comodità:

kubectl create secret generic \
       passwd-secret --from-literal=password=topolino

Creazione delle immagini

Parliamo ora delle immagini che definiremo. Visto che vogliamo precaricare il database da leggere, abbiamo scelto (non era l'unica soluzione) di immettere nell'immagine un file SQL di inizializzazione di nome init.sql. Eccone il testo:

CREATE DATABASE IF NOT EXISTS scuola;
USE scuola;
CREATE TABLE allievi(
      nome varchar(50),
      cognome varchar(50),
      classe int);
INSERT INTO allievi (nome,cognome,classe) VALUES ('Silvia', 'Rossi', 1);
INSERT INTO allievi (nome,cognome,classe) VALUES ('Elena', 'Neri', 1);
INSERT INTO allievi (nome,cognome,classe) VALUES ('Michele', 'Bianchi', 2);
INSERT INTO allievi (nome,cognome,classe) VALUES ('Simone', 'Azzurri', 2);
INSERT INTO allievi (nome,cognome,classe) VALUES ('Sergio', 'Rossi', 3);
INSERT INTO allievi (nome,cognome,classe) VALUES ('Ilenia', 'Gialli', 3);

Il Dockerfile che lo trasformerà in un'immagine è questo:

FROM mysql:5.6
COPY init.sql /docker-entrypoint-initdb.d/

Per quanto riguarda il Web layer abbiamo un Dockerfile che si basa su un'immagine Docker per PHP su server Apache. Aggiungeremo solo l'accortezza di chiedere l'installazione della libreria mysqli per accedere a MySQL:

FROM php:8.0-apache
RUN docker-php-ext-install mysqli
WORKDIR /var/www/html
COPY index.php index.php
EXPOSE 80

Il file index.php conterrà il codice per eseguire una query sull'unica tabella del database e mostrarla in una griglia: ne riportiamo uno stralcio limitandoci al codice PHP evitando il testo del CSS non indispensabile al nostro scopo:

<?php
    $hostname = "data-layer-service";
    $username = "root";
    $password = getenv('MYSQL_ROOT_PASSWORD');
    $dbname = "scuola";
    $con = mysqli_connect($hostname, $username, $password, $dbname);
    if(!$con)
    {
        die("Connessione fallita! Verificare parametri del server di database: " . mysqli_connect_error());
    }
    $sql = "SELECT nome,cognome,classe FROM allievi";
    $risultato = mysqli_query($con, $sql);
    if(mysqli_num_rows($risultato) > 0)
    {
       echo '<table> <tr> <th> Nome </th> <th> Cognome </th> <th> Classe </th> </tr>';
       while($riga = mysqli_fetch_assoc($risultato)){
           echo '<tr > <td>' . $riga["nome"] . '</td>
           <td>' . $riga["cognome"] . '</td>
           <td> ' . $riga["classe"] . '</td></tr>';
       }
       echo '</table>';
    }
    else
    {
        echo "Nessun risultato!";
    }
    mysqli_close($con);
?>

Il risultato che otterremo è quello che si vede nella figura seguente.

Figura 1. Risultato visualizzato nella pagina Web

In questo codice notiamo un paio di aspetti molto importanti:

  • l'indirizzo del database corrisponde a data-layer-service ovvero il nome del Service Kubernetes che espone il database (lo si verifichi nel prossimo paragrafo);
  • la password del database verrà immessa nel Deployment come variabile d'ambiente di nome MYSQL_ROOT_PASSWORD (verificare anche questo nel prossimo paragrafo) quindi dovrà essere letta dal codice PHP accedendovi con getenv('MYSQL_ROOT_PASSWORD').

Solitamente, le immagini di questo tipo vengono create ed immagazzinate in un registry (tipicamente disponibile in Cloud) ma in questo caso stiamo sperimentando su minikube quindi, affinché questo tool abbia a disposizione le immagini, dobbiamo farle compilare a lui con i comandi che seguono. Lanceremo questo dalla cartella in cui si trova il Dockerfile dell'immagine del database:

$ minikube image build -t data-layer-custom .

Questo dalla cartella in cui si trova il Dockerfile dell'immagine del Web layer:

$ minikube image build -t web-layer-custom .

Infine potremo verificare la loro presenza negli asset di minikube con il seguente comando:

$ minikube image ls
...
docker.io/library/web-layer-custom:latest
docker.io/library/php:8.0-apache
docker.io/library/mysql:5.6
docker.io/library/data-layer-custom:latest
...

Componenti Kubernetes

Siamo ora pronti per lanciare le componenti Kubernetes necessarie. Riportiamo anche il data layer, già provato nella lezione precedente, sia per comodità sia per mostrare come impiegare la nuova immagine di cui abbiamo parlato qui:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: data-layer-deployment
spec:
  selector:
    matchLabels:
      app: mysqlsrv
  template:
    metadata:
      labels:
        app: mysqlsrv
    spec:
      containers:
        - name: mysql-server
          image: data-layer-custom
          imagePullPolicy: Never
          env:
          - name: MYSQL_ROOT_PASSWORD
            valueFrom:
              secretKeyRef:
                name: passwd-secret
                key: password
          volumeMounts:
            - name: data-storage
              mountPath: /var/lib/mysql
      volumes:
        - name: data-storage
          hostPath:
             path: /dbstorage
---
apiVersion: v1
kind: Service
metadata:
  name: data-layer-service
spec:
  ports:
  - port: 3306
  selector:
    app: mysqlsrv

Il Web layer avrà una struttura simile e sarà predisposto per essere contattato da utenza esterna mentre il data layer è a uso esclusivo interno.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-layer-deployment
  labels:
    server: web-layer
spec:
  selector:
   matchLabels:
     server: web-layer
  template:
    metadata:
     labels:
       server: web-layer
    spec:
      containers:
      - name: web-layer
        imagePullPolicy: Never
        image: web-layer-custom
        env:
        - name: MYSQL_ROOT_PASSWORD
          valueFrom:
              secretKeyRef:
                name: passwd-secret
                key: password
---
apiVersion: v1
kind: Service
metadata:
  name: web-layer-service
spec:
  type: NodePort
  ports:
  - port: 80
  selector:
    app: web-layer

A questo punto potremo avviare il data layer:

kubectl apply -f data-layer.yaml

ed il Web layer:

kubectl apply -f web-service.yaml

per poi verificarne l'effettiva operatività grazie a kubectl:

$ kubectl get svc
NAME                 TYPE        CLUSTER-IP     EXTERNAL-IP    PORT(S)       AGE
data-layer-service   ClusterIP   10.100.19.62   <none>   3306/TCP      68s
kubernetes           ClusterIP   10.96.0.1      <none>   443/TCP       7m1s
web-layer-service    NodePort    10.96.53.253   <none>   80:31427/TCP  31s
$ kubectl get deploy
NAME                    READY   UP-TO-DATE   AVAILABLE   AGE
data-layer-deployment   1/1     1            1           90s
web-layer-deployment    1/1     1            1           53s

A questo punto, si potrà visualizzare la tabella mostrata all'inizio di questa lezione invocando il Service del Web layer dal browser con le modalità mostrate durante la guida ed in dipendenza dell'installazione di minikube o Kubernetes che si è scelta.

Da qui potete scaricare il codice della lezione.

Ti consigliamo anche