Moodle – Cluster de frontaux & Base de données

Moodle – Cluster de frontaux & Base de données

26 août 2020 Non Par nospheratus

Principe

Le principe est d’avoir l’ensemble des services (ou la majorité) qui soient redondés et que ceux-ci puissent absorber une charge importante de visiteurs et transactions, liée à des événements exceptionnels. Le schéma de la structure est le suivant :

Afin de partager les documents, les Moodle frontaux avaient besoin d’un stockage commun. Après des études de rapidité, il s’est avéré que le NFS v4 était le protocole qui offrait le plus de rapidité cumulée pour la lecture/écriture.

Un serveur NFS dédié à Moodle a donc été installé. Nous détaillerons ce serveur également dans la partie consacrée aux frontaux.

Cluster de base de données MariaDB : Galera

Le cluster de base de données est composé de 3 nœuds : MoodleDB01, MoodleDB02 et MoodleDB3 qui ont pour IP respectives : 172.20.16.11, 172.20.16.12 et 172.20.16.13.

Installation

  • Première étape :
    Ajouter le repository MariaDD de Debian sur tous les serveurs :

root@MoodleDB01:/# apt install dirmngr software-properties-common
root@MoodleDB01:/# apt-key adv –recv-keys –keyserver hkp://keyserver.ubuntu.com:80 0xF1656F24C74CD1D8
root@MoodleDB01:/# add-apt-repository ‘deb [arch=amd64] http://nyc2.mirrors.digitalocean.com/mariadb/repo/10.4/debian buster main’
root@MoodleDB01:/# apt-get update

  • Seconde étape :
    Installer MariaDB sur tous les serveurs.

root@MoodleDB01:/# apt-get install mariadb-server  -y

Mettre un password pour l’utilisateur root :

mysql –u root
set password = password(« MyP@SsW0rd »);

Et installation de rsync :

apt-get install rsync -y

Configuration

  • Ajouter dans le hosts de chaque serveur les IP des autres.
  • Création du fichier de conf du cluster

vi /etc/mysql/conf.d/galera.cnf

[mysqld]
binlog_format=ROW
default-storage-engine=innodb
innodb_autoinc_lock_mode=2
bind-address=0.0.0.0
# Galera Provider Configuration
wsrep_on=ON
wsrep_provider=/usr/lib/galera/libgalera_smm.so
# Galera Cluster Configuration
wsrep_cluster_name= »MoodleCluster »
wsrep_cluster_address= »gcomm://172.20.16.11,172.20.16.12,172.20.16.13″
# Galera Synchronization Configuration
wsrep_sst_method=rsync
# Galera Node Configuration
wsrep_node_address= »172.20.16.11″
wsrep_node_name= »MoodleDB01″

  • Ouvrir le firewall pour le cluster
    vi /etc/iptables/rules.v4
    Ajouter :

# Allows Galera Cluster MariaDB
-A INPUT -p tcp –dport 3306 -j ACCEPT
-A INPUT -p tcp –dport 4567 -j ACCEPT
-A INPUT -p tcp –dport 4444 -j ACCEPT
-A INPUT -p udp –dport 4567 -j ACCEPT

/etc/init.d/netfilter-persistent restart

  • Démarrer le cluster

Il faut tout d’abord stop mariadb : systemctcl stop mysql sur tous les nœuds
Puis on démarre sur le premier nœud : galera_new_cluster
Pour vérifier : mysql -u root -p -e « SHOW STATUS LIKE ‘wsrep_cluster_size' »

On obtient :


+———————–+——–+
|Variable_name|Value|
+———————–+——–+
|wsrep_cluster_size|1|
+———————–+——–+

Puis systemctl start mysql (sur les nœuds 2 & 3)

  • Paramétrage des nœuds :
    Sur chaque nœud éditer le fichier /etc/mysql/conf.d/mysql.cnf et modifier comme suit :

[mysql]
default-character-set = utf8mb4
[mysqld]
innodb_file_per_table = 1
innodb_buffer_pool_size = 12G
character-set-server = utf8mb4
collation-server = utf8mb4_unicode_ci
skip-character-set-client-handshake

Puis relance des services MySQL : systemctl mysql restart

Exploitation

  • Chaque nœud est indépendant. Ainsi on peut relancer les serveurs sans perdre l’accès à la base. Pour fonctionner le cluster a besoin d’un seul nœud, mais il est préférable de ne relancer les serveurs qu’un par un.
  • En cas d’arrêt complet des 3 nœuds suite à un problème important ayant coupé tous les nœuds, il convient de relancer le cluster sur le nœud 1 (moodledb01) :
    – Vérifier l’arrêt de MariaDB et le stopper en cas de besoin systemctl mysql stop (sur tous les nœuds)
    – Lancer le cluster sur le nœud 1 : galera_new_cluster
    – Lancer MariaDB sur les autres nœuds : systemctl mysql start
    – Vérifier la présence de tous les nœuds mysql -u root -p -e « SHOW STATUS LIKE ‘wsrep_cluster_size' »
  • Requête SQL pour afficher les infos du cluster : show status like ‘wsrep%’;
  • Reqête SQL pour afficher les infos sur les utilisateurs des bases de données : select host, user, password from mysql.user ;
  • Les bases de données sont répliquées sur tous les nœuds. Les datas sont stockées sur le volume LVM /var. Le volume groupe vg1 a été provisionné et on peut aisément agrandir l’espace disque si celui venait à manquer : lvextend –L+50GiB /dev/mapper/vg1-var && resize2fs /dev/mapper/vg1-var  (pour voir l’espace restant sur le volume groupe : pvscan)
  • En cas de crash sur les 3 nœuds et si lors de la relance du cluster sur MoodleDB1, on obtient le message : « WSREP: It may not be safe to bootstrap the cluster from this node. It was not the last one to leave the cluster and may not contain all the updates. To force cluster bootstrap with this node, edit the grastate.dat file manually and set safe_to_bootstrap to 1 . » Il convient alors de stopper tous les serveurs MySQL sur les nœuds. Puis éditer le fichier « /var/lib/mysql/grastate.dat » et changer la valeur de set safe_to_bootstrap de 0 à 1. On fait la même chose sur les 3 nœuds. Puis on reboot les serveurs. Enfin sur Moodledb01 on lance le cluster. On vérifie qu’il tourne correctement. Puis on lance les nœuds un à un.

Cluster de frontaux Moodle

Pour fonctionner Moodle a besoin de partager l’espace de stockage des données (moodledata), pour ce faire nous avons monté un serveur NFS qui centralise donc toutes les données (doc, vidéos etc..) qui sont publiées sur Moodle.
Voici le schéma de fonctionnement :

  • Sur le serveurs NFS :
    On ajoute les autorisations pour les frontaux dans le fichier /etc/exports :

/opt/moodledata/        172.20.16.50(rw,sync,no_subtree_check) 172.20.16.51(rw,sync,no_subtree_check) 172.20.16.52(rw,sync,no_subtree_check)

  • Sur les frontaux :
    Installation du client nfs : apt-get install nfs-common –y
    Puis ajout au fstab: 172.20.16.49:/opt/moodledata   /opt/moodledata nfs4    rw,user,exec 0 0

Procédure d’installation

On installe apache2, php, et HAProxy (qui servira de passerelle MySQL)

  • apt-get install apache2
  • apt-get install apt-transport-https lsb-release ca-certificates
  • wget -O /etc/apt/trusted.gpg.d/php.gpg https://packages.sury.org/php/apt.gpg
  • echo « deb https://packages.sury.org/php/ $(lsb_release -sc) main » > /etc/apt/sources.list.d/php.list
  • apt-get update
  • apt-get install php7.3 php7.3-bcmath php7.3-bz2 php7.3-cli php7.3-common php7.3-curl php7.3-dba php7.3-gd php7.3-intl php7.3-json php7.3-ldap php7.3-mbstring php7.3-mysql php7.3-opcache php7.3-readline php7.3-soap php7.3-xml php7.3-xmlrpc php7.3-zip haproxy
  • apt-get install shibboleth-sp-common  shibboleth-sp-utils shibboleth-sp2-common shibboleth-sp2-utils libapache2-mod-shib libapache2-mod-shib2

Configuration des services

Nous configurons d’abord HAProxy :

sed -i « s/ENABLED=0/ENABLED=1/g » /etc/default/haproxy
sed -i « s/ENABLED=0/ENABLED=1/g » /etc/init.d/haproxy

Puis édition du fichier de conf : vi /etc/haproxy/haproxy.cfg

On ajoute :

listen galera
bind 127.0.0.1:3306
balance leastconn
mode tcp
option tcpka
option mysql-check user haproxy
server moodledb01 172.20.16.11:3306 check weight 1
server moodledb02 172.20.16.12:3306 check weight 1
server moodledb03 172.20.16.13:3306 check weight 1

Le concept est d’ouvrir un port d’écoute sur le port tcp3306 (celui de mysql) et de configurer un cluster de répartition sur les différents nœuds de base de données. Ainsi le frontal via php-mysql (que moodle utilise pour se connecter à la base de données) utilisera l’IP locale (127.0.0.1) comme si la BDD était installée en local, puis le proxy redirigera alternativement sur les nœuds du cluster MariaDB.

Ce choix a été fait de façon à simplifier le passage annuel de la production en serveur d’archive.

Il suffit maintenant de relancer le service HAProxy : /etc/init.d/haproxy restart

Maintenant nous allons configurer Apache. Il y a par défaut un fichier de configuration, et nous allons l’utiliser en modifiant seulement quelques paramètres :

Edition de/etc/apache2/sites-available/000-default.conf

Voici le contenu du fichier :

<VirtualHost *:80>
ServerAdmin webmaster@localhost
DocumentRoot /opt/public_html/
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
<Directory /opt/public_html/>
Options Indexes FollowSymLinks MultiViews
AllowOverride None
  Require all granted
   </Directory>
</VirtualHost>
ExtendedStatus on
<Location /mod_status>
SetHandler server-status
Require host localhost
</Location>

Quelques remarques :

  • La partie apache.conf n’a pas été précisé ici. Il convient de bien tuner les paramètres d’apache en fonction de votre RAM et CPU afin de définir le nombre de users simultanés accepter par chaque frontal.
  • La location « mod_status » sert à activer les outils de statistiques apache (extendedstatus) qui sont ensuite utilisés dans collectd pour les graphs Grafana.

On relance ensuite apache : apache2ctl restart

On récupère les sources de Moodle (je les place en général sur le NFS dans un dossier sourcemoodle\version\date.tar.gz, ex /opt/moodledata/3.9/20200715.tar.gz )

On place les sources pour obtenir /opt/public_html (dataroot de moodle indiqué dans le config.php)

On affecte les bons droits en changeant le propriétaire par www-data (utilisateur apache)
L’intégralité de la configuration Moodle est faite dans le fichier config.php.
Voici les principaux éléments indispensables à modifier ou vérifier pour un fonctionnement correcte :

$CFG->dbtype = ‘mariadb’;
$CFG->dblibrary = ‘native’;
$CFG->dbhost = ‘127.0.0.1’;
$CFG->dbname = ‘moodle’;
$CFG->dbuser = ‘moodleuser’;
$CFG->dbpass = ‘moodleuserpassword’;
$CFG->prefix = ‘mdl_’;
$CFG->dboptions = array (
‘dbpersist’ => 0,
‘dbport’ => ‘3306’,
‘dbsocket’ =>  »,
‘dbcollation’ => ‘utf8mb4_unicode_ci’,
);
$CFG->wwwroot = ‘https://moodle.nosland.com’;
$CFG->dataroot = ‘/opt/moodledata’;
$CFG->directorypermissions = 02770;
$CFG->admin = ‘admin’;
$CFG->sslproxy = true;
$CFG->tempdir = ‘/opt/moodledata/temp’; // doit être partagé
$CFG->cachedir = ‘/opt/moodledata/cache’; // doit être partagé
$CFG->localcachedir = ‘/opt/localcache’; // doit être local

Attention à comment vous configurer vos dossiers. Certains doivent être partagé, et donc utilisé le serveur de stockage NFS, mais d’autre ne doivent jamais l’être.

Si l’on effectue des mise à jour ou des ajouts de plugin sur son Moodle. Il faut procéder avec attention.
Le conseil sera de basculer en mode mono-frontal. D’effectuer les UPdate ou l’ajout de plugin via l’interface web.
Ensuite sur l’ensemble des frontaux que l’on a désactivé, il faut recopier intégralement le contenu du dossier public_html du frontal actif sur les autres.
Une fois fait on peut réactiver le mode cluster de frontaux.

Reverse Proxy

Mon reverse proxy fonctionne avec deux serveurs maintenus via une IP virtuelle de keepalive.
Le reverse proxy est un Nginx.
Le fichier de configuration pour Moodle est le suivant :

upstream moodlecluster {
                ip_hash;
                server moodle00.nosland.com;
                server moodle01.nosland.com;
                server moodle02.nosland.com;
               # server moodleXX.nosland.com; ajouter ici les autres nœuds
}
server {
                listen        80;
                server_name   moodle.nosland.com;
                access_log     /var/log/nginx/moodle_access.log;
                error_log      /var/log/nginx/moodle_error.log;
if ($request_method !~ ^(GET|HEAD|POST)$ ) {
                        return 444;
}
location / {
                        # — Redirection vers https
                         return 301 https://$server_name:443$request_uri;
}
}
server {
                listen               443;
                ssl                  on;
                ssl_certificate      /etc/nginx/certificats/wildcard.Nosland-Bundle.crt;
                ssl_certificate_key  /etc/nginx/certificats/wildcard.Nosland.key;
                server_name     moodle.nosland.com;
                access_log      /var/log/nginx/moodle_access.log;
                error_log       /var/log/nginx/moodle_error.log;
                  if ($request_method !~ ^(GET|HEAD|POST)$ ) {
                        return 444;
}
                location / {
                        #— Redirection
                        #proxy_pass       http://moodle00.nosland.com;
                        proxy_pass      http://moodlecluster ;
}
}

Remarque sur le fichier de conf :

  • Dans la section upstream, on définit les frontaux Moodle du cluster. On utilise l’option ip_hash qui permet d’orienter les utilisateurs sur un frontal et d’y rester. Ceci est plus commode pour les sessions.
  • Dans la section http, on redirige toutes les requêtes sur https
  • Dans la section https, on définit le wildcard car mon proxy est mutualisé avec d’autres sites web
  • Dans location, on a deux proxy_pass de défini :
    L’un commenté qui pointe sur le noeud0 des frontaux. L’autre sur le pool de serveurs.
    Nous gardons le noeud0 en commentaire car cela nous permettra de switcher d’une configuration cluster à une configuration mono frontal indispensable pour les mises à jours de Moodle ou l’ajout de plugins.