Il peut parfois être nécessaire d’avoir un proxy devant un ou plusieurs serveurs de bases de données. Même si la configuration ne comporte qu’un seul serveur, ce proxy peut alors être utilisé pour faire du cache de requêtes, du monitoring ou encore du routage.

Dans cette série d’article je vais parler de ProxySQL que j’ai découvert il y a quelques semaines, pourquoi je trouve que c’est un outil puissant pour beaucoup de cas d’usages et pourquoi - si vous cherchez un “routeur de requêtes” - il est intéressant d’y jeter un oeil.

Pour commencer, un lien vers [la documentation] plutôt bien faite de ProxySQL

Si vous utilisez un serveur Debian, l’outil est très facile à installer et tombe en marche à la fin de l’installation. Un grand merci aux développeurs de fournir un repo apt.

Installation sur un système Debian 11

Pour les besoin de cet article, je vais déployer ProxySQL sur un seul serveur. Comme c’est le premier d’une série, il y a fort à parier qu’une mise en cluster sera abordée tôt ou tard.

Hostname IP
psql01 192.168.56.1

En suivant cette documentation, l’installation est rapide :

apt install -y --no-install-recommends lsb-release wget apt-transport-https ca-certificates gnupg
wget -O - 'https://repo.proxysql.com/ProxySQL/proxysql-2.4.x/repo_pub_key' | apt-key add - 
echo deb https://repo.proxysql.com/ProxySQL/proxysql-2.4.x/$(lsb_release -sc)/ ./ | tee /etc/apt/sources.list.d/proxysql.list
apt update
apt install proxysql

Par défaut ProxySQL écoute sur 127.0.0.1:6032 pour son shell d’administration et sur 0.0.0.1:6033 pour les connexions MySQL entrantes. Il est possible de configurer ProxySQL à l’aide de fichiers de configuration situées dans /etc/proxysql ou directement depuis le shell d’administration qui stockera la configuration en base de données.

Je préfère cette dernière possibilité, entre autres car elle permet de configurer l’outil, de charger la configuration dans le runtime et si tout est ok, de sauvegarder la configuration sur disque. Cette fonctionnalité est super intéressante car en cas de mauvaise configuration (sans avoir sauvegardé sur disque) il est tout à fait possible de restaurer une configuration fonctionnelle très rapidement.

Donc pour résumer, il y a 3 étapes pendant la configuration :

  • Ecrire les règles et paramètres dans le shell d’administration.
  • Charger ces règles dans le runtime.
  • Sauvegarder ces règles sur disque pour les rendre permanente.

Première configuration

Comme vu précédemment, ProxySQL écoute sur deux ports différents :

  • 6032 : Le shell d’administration
  • 6033 : A lire de droite à gauche, c’est le port d’écoute pour les requêtes MySQL entrantes.

Comment se connecter à cette chose ?

Pour avoir accès au shell d’administration, il faut install le paquet mysql/mariadb client. Sur Debian 11 :

apt update
apt install mariadb-client --no-install-recommends

Pour tester la connexion :

mysql -u admin -padmin -h localhost -P6032

Vous devriez être dans un shell type MySQL. Ctrl + C pour sortir.

J’ai pour habitude d’ajouter un alias pour faciliter la connexion :

alias proxysqlshell='mysql -u admin -padmin -h 127.0.0.1 -P6032 --prompt ProxySQL\> '

Maintenant il suffit de taper proxysqlshell dans le terminal pour avoir directement accès. Nous verrons sûrement plus tard comment “sécuriser” cet accès.

Et après ?

Une des première choses à faire, selon la doc ProxySQL, c’est de créer un utilisateur “monitoring” sur le noeud ProxySQL. Cet utilisateur servira à monitorer les serveurs de bases de données auxquels le proxy pourra se connecter. Cela lui permettra de garder un état des serveurs “backend”. Cet utilisateur devra donc exister sur tous les noeuds MySQL, avec ses propres privilèges.

Ci-dessous les commandes pour ajouter l’utilisateur à ProxySQL :

root@psql01:~# proxysqlshell
ProxySQL>UPDATE global_variables SET variable_value='psql-monitoring' WHERE variable_name='mysql-monitor_username';
ProxySQL>UPDATE global_variables SET variable_value='psql_monitoring-password' WHERE variable_name='mysql-monitor_password';
ProxySQL>LOAD MYSQL VARIABLES TO RUNTIME;
ProxySQL>SAVE MYSQL VARIABLES TO DISK;

Ici nous avons configuré le compte monitoring psql-monitoring et psql-monitoring-password en mot de passe. On peut noter le LOAD TO RUNTIME et SAVE TO DISK qui sont deux commandes différentes mais toutes aussi importantes l’une que l’autre.

Maintenant il faut se connecter à tous les serveurs MySQL et ajouter cet utilisateur monitoring. Dans le cadre d’un setup master / slave, ne créer cet utilisateur que sur le master, la réplication se chargera de faire le reste 😉

Ci-dessous un exemple :

mysql> create user 'psql-monitoring'@'192.168.56.%' identified by 'psql-monitoring-password';
mysql> grant usage on *.* to 'psql-monitoring'@'192.168.56.%';
mysql> flush privileges;

Ici j’ai utilisé le % wildcard MySQL. L’utilisation de ce wildcard est ok dans le cadre d’un lab. Dans un environnement de production, j’aurais probablement durci la configuration en spécifiant seulement les ip des ProxySQL.

Et mes applications là dedans ?

Pour ce premier article, on la joue KISS.

Nous avons deux serveurs MySQL distincts :

App Db name Ip MySQL user MySQL Password
Nextcloud nextcloud_db 192.168.56.3 nextcloud_sql_admin nextcloud_sql_pass
GLPI glpi_db 192.168.56.4 glpi_sql_admin glpi_sql_pass

La première chose à faire est d’ajouter ces serveurs à notre configuration ProxySQL :

insert into mysql_servers (hostgroup_id,hostname,port,comment) values (20,'192.168.56.3',3306,'Nextcloud db server');
insert into mysql_servers (hostgroup_id,hostname,port,comment) values (30,'192.168.56.4',3306,'Glpi db server');
load mysql servers to runtime;
save mysql servers to disk;

Une nouvelle notion abordée : les hostgroups. Ces derniers sont très importants dans ProxySQL. Il s’agit d’un paramètre central de l’outil et en particulier du “système de routage” de ProxySQL. Dans le cadre d’un déploiement master / slave, un usage très basic mais qui fonctionne très très bien est d’ajouter le serveur dans un hostgroup spécifique, et tous les slaves dans un autre. Ainsi on pourra très facilement, basé sur le nom d’utilisateur, router du trafic à destination des slaves ou du master.

Pour l’instant j’ai simplement ajouté chaque serveur dans un hostgroup dédié.

Maintenant il faut ajouter les utilisateurs qui seront autorisés à se connecter depuis les applications clientes vers les serveurs de bases de données, au travers de ProxySQL. Ces utilisateur doivent donc exister sur les serveurs de base de données.

Il doit être possible de mapper des comptes frontend différents de comptes backend, pour ne pas avoir à toucher l’existant. Je n’ai pas l’usage mais à vérifier si nécessaire.

insert into mysql_users (username,password,active,default_hostgroup) values ('nextcloud_sql_admin','nextcloud_sql_pass',1,20);
insert into mysql_users (username,password,active,default_hostgroup) values ('glpi_sql_admin','glpi_sql_pass',1,30);
load mysql users to runtime;
save mysql users to disk;

Maintenant, toutes les requêtes envoyées à ProxySQL avec les utilisateurs :

  • nextcloud_sql_admin seront routées vers le hostgroup 20 : 192.168.56.3 : nextcloud_db
  • glpi_sql_admin seront routées vers le hostgroup 30 : 192.168.56.4 : glpi_db

Ok mais mes applicatifs parlent sur le port destination tcp/3306 et non pas 6033

La configuration par défaut de ProxySQL est d’écouter sur le port tcp/6033, tandis que MySQL écoute par défaut sur tcp/3306. Il est parfois impossible de changer ce port destination (certains applicatifs sont très rigides..). La meilleure solution est alors de modifier le port d’écoute de ProxSQL par le biais de la variable mysql-interfaces en modifiant 0.0.0.0:6033 en 0.0.0.0:3306

update global_variables set variable_value='0.0.0.0:3306' where variable_name='mysql-interfaces';
save mysql variables to disk;

Vous pouvez maintenant vous connecter à votre ProxySQL directement avec les identifiants crées précédemment, sans avoir à préciser le port de destination :

mysql -u nextcloud_sql_admin -p -h 192.168.56.1

ProxySQL peut maintenant router vos requêtes en fonction du nom d’utilisateur présenté.

Enjoy 😄