Drupal 9 + MySQL 5.7 su Kubernetes
Drupal è un CMS piuttosto popolare con una grande community dietro, ed è particolarmente popolare tra le grandi aziende e per i siti web complessi. Infatti, alcuni dei siti più visitati al mondo come Nokia, Wish, NASA utilizzano Drupal come CMS per i loro siti aziendali.
In questo post, andremo a vedere come configurare un’istanza di Drupal versione 9.5 con MySQL 5.7 su Kubernetes.
Spoiler: sarà più lungo l’articolo che la sua effettiva realizzazione!
Questo è lo schema di ciò che otterremo alla fine:
Persistenza
Sappiamo che i container non sono persistenti, quindi è necessario utilizzare dei Persistent Volumes per preservare i dati che Drupal dovrà salvare… Altrimenti, tutte le modifiche scritte nel database o in qualsiasi directory andranno perse dopo il riavvio del container!
Andiamo quindi a definire due PVC, supponendo che il cluster Kubernetes su cui lavoriamo abbia a disposizione un provisioner che si occupa di eseguire il binding tra le claim per lo storage e i volumi persistenti.
In questo caso richiediamo due volumi da 5 GB ciascuno, dove il primo sarà usato per i file del sito web e il secondo per il database MySQL. Chiaramente, questo dimensionamento è adatto a un ambiente di test o di demo, ma possono essere adattati!
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: drupal-pvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 5Gi
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: mysql-pvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 5Gi
Invece, per installare l’istanza di MySQL utilizzeremo un Deployment e un Service. Si noti che eseguiamo MySQL con un’utenza amministrativa, che può essere anche cambiata seguendo le indicazioni presenti nella documentazione ufficiale.
Infatti, quando lo si utilizza in produzione, utilizzare credenziali personalizzate e sicure. Peraltro, è buona pratica memorizzare questo tipo di informazioni in un Secret, per cui procediamo con la sua definizione e includiamo la password dell’utente root:
apiVersion: v1
kind: Secret
metadata:
name: mysql-creds
stringData:
MYSQL_ROOT_PASSWORD: root_password
Il Deployment di MySQL è piuttosto semplice: utilizza un’immagine mysql nella versione 5.7.8, tra le ultime disponibili e compatibili con la versione 9 di Drupal (vedi documentazione).
Inoltre, definiamo quelle che sono le variabili di ambiente che l’istanza dovrà utilizzare per configurare il database su cui l’istanza Drupal andrà a lavorare, e poi definiamo anche la porta 3306 come porta di ascolto per gli altri servizi e anche il path su cui il volume di MySQL creato in precedenza verrà montato.
apiVersion: apps/v1
kind: Deployment
metadata:
name: mysql
spec:
replicas: 1
template:
metadata:
labels:
app: mysql
spec:
containers:
- env:
- name: MYSQL_ROOT_PASSWORD
valueFrom:
secretKeyRef:
name: mysql-creds
key: MYSQL_ROOT_PASSWORD
- name: MYSQL_DATABASE
value: drupal-database
image: "mysql:5.7.8"
imagePullPolicy: IfNotPresent
name: mysql
ports:
- containerPort: 3306
name: mysql
protocol: TCP
volumeMounts:
- mountPath: /var/lib/mysql
name: drupal-pvc
subPath: dbdata
volumes:
- name: drupal-pvc
persistentVolumeClaim:
claimName: mysql-pvc
selector:
matchLabels:
app: mysql
Il Deployment di Drupal sarà basato su un container con un’immagine di Drupal dal repository Docker Hub pari all’ultima versione ad oggi disponibile, ossia la 9.5.11.
Inoltre, utilizzeremo anche un container temporaneo (ovvero, un initContainer) la cui missione sarà quella di pre-popolare lo storage persistente con i dati utilizzati da Drupal.
Questo controller esporrà la porta 80 e ugualmente monterà un proprio volume con diverse cartelle per ogni componente necessario a Drupal per lavorare, come i themes, i modules o i sites.
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: drupal
name: drupal
spec:
replicas: 1
template:
metadata:
labels:
app: drupal
spec:
initContainers:
- name: init-sites-volume
imagePullPolicy: IfNotPresent
image: drupal:9.5.11
command: ['/bin/bash', '-c']
args: ['cp -r /var/www/html/sites/ /data/; chown www-data:www-data /data/ -R']
volumeMounts:
- mountPath: /data
name: pvc-drupal
containers:
- image: drupal:9.5.11
imagePullPolicy: IfNotPresent
name: drupal
ports:
- containerPort: 80
volumeMounts:
- mountPath: /var/www/html/modules
name: pvc-drupal
subPath: modules
- mountPath: /var/www/html/profiles
name: pvc-drupal
subPath: profiles
- mountPath: /var/www/html/sites
name: pvc-drupal
subPath: sites
- mountPath: /var/www/html/themes
name: pvc-drupal
subPath: themes
volumes:
- name: pvc-drupal
persistentVolumeClaim:
claimName: drupal-pvc
selector:
matchLabels:
app: drupal
Ultimo, ma non ultimo, creiamo i Service necessari per permettere ai due componenti di comunicare: quello per MySQL sarà di tipo ClusterIP, dal momento che dovrà interfacciarsi solo con Drupal, mentre quello per Drupal sarà di tipo LoadBalancer.
apiVersion: v1
kind: Service
metadata:
name: mysql-service
spec:
ports:
- name: mysql
port: 3306
protocol: TCP
selector:
app: mysql
A seconda del tipo di infrastruttura Kubernetes su cui stiamo lavorando, sarà infatti possibile accedere all’istanza tramite browser: nel caso in cui si usi un cluster EKS su AWS, questo andrà a creare un Application Load Balancer che potremo usare per accedere alla prima pagina di Drupal:
apiVersion: v1
kind: Service
metadata:
name: drupal-service
spec:
ports:
- name: http
port: 80
protocol: TCP
selector:
app: drupal
type: LoadBalancer
Ora che la nostra soluzione è stata definita e importata, installiamo Drupal. È sufficiente navigare verso l’indirizzo ottenuto nel passaggio precedente e seguire le istruzioni per l’installazione guidata. Utilizzate le credenziali del database configurate in precedenza nel Deployment di MySQL.
Ad esempio, nel nostro caso, ecco i dati da specificare nella schermata di configurazione del database:
- Nome del database: drupal-database, come la variabile d’ambiente MYSQL_DATABASE nel Deployment di MySQL.
- Password del database: root_password, come la variabile d’ambiente MYSQL_PASSWORD nel Secret di MySQL.
- Host: mysql-service, uguale al nome del Service MySQL
- Porta: 3306, uguale alla porta specificato nel Service MySQL
Questo è tutto!
Ora avete un’istanza di Drupal funzionante, distribuita in meno di 10 minuti.