Nodos

Vamos con la configuración de los nodos que contendrán Apache2 + PHP + MySQL Galera Clusters + GlusterFS + memcached

GlusterFs

El primer problema que nos encontramos cuando queremos utilizar un sistema de nodos es que cada servidor tiene sus discos duros y por lo tanto tenemos que buscar alguna manera de sincronizar los ficheros, para esto vamos a usar GlusterFS

Tenemos varios métodos de sincronización de ficheros pero nosotros vamos a utilizar el tipo replica

Lo primero que vamos a realizar es añadir al fichero hosts las direcciones de la red interna de los diferentes nodos para facilitarnos la vida en la comunicación con gusterfs

vim /etc/hosts
XXX.XXX.XXX.XXX   node-1
XXX.XXX.XXX.XXX   node-2
XXX.XXX.XXX.XXX   node-3

Para tener la ultima versión de GlusterFS vamos a agregar el respositorio PPA

add-apt-repository ppa:gluster/glusterfs-10
apt-get update

Instalamos el paquete software-properties-common

apt install software-properties-common

Instalamos glusterfs-server en todos los nodos

apt install glusterfs-server

Arrancamos GlusterFs

systemctl start glusterd.service

Y lo habilitamos para que arranque al arrancar el sistema

systemctl enable glusterd.service

Vamos a conectar los nodos entre si, no es necesario conectar el nodo-1 a si mismo por lo que lo obviamos

gluster peer probe node-2
gluster peer probe node-3

Para comprobar que los nodos están conectados disponemos de los siguientes comandos

gluster peer status
Number of Peers: 2

Hostname: node-2
Uuid: 544725c4-a02b-449b-8464-744b97bf08b6
State: Peer in Cluster (Connected)

Hostname: node-3
Uuid: 3c1b7579-deb7-4900-a1f8-83ee71140ee0
State: Peer in Cluster (Connected)
gluster pool list
UUID                                    Hostname        State
544725c4-a02b-449b-8464-744b97bf08b6    node-2          Connected
3c1b7579-deb7-4900-a1f8-83ee71140ee0    node-3          Connected
d340a141-848d-4ee5-96d7-71605c30a023    localhost       Connected

NOTA: Para servers en producción es recomendable usar glusterfs en otra partición que no sea la de sistema.

mkdir -p /gfsvolume/gv0

Creamos un volumen con los 3 nodos en modo replica

gluster volume create clusterVaClusterViene replica 3 node-1:/gfsvolume/gv0/ node-2:/gfsvolume/gv0 node-3:/gfsvolume/gv0

Si en el futuro quisiéramos agregar un nuevo nodo para dar más maquinas a nuestro clusters, lo realizaríamos de la siguiente manera

gluster volume add-brick clusterVaClusterViene replica 4 node-4:/gfsvolume/gv0/

Una vez listo el el volumen lo arrancamos

gluster volume start clusterVaClusterViene

Podemos comprobar el estado del volumen

gluster volume status
Status of volume: clusterVaClusterViene
Gluster process                             TCP Port  RDMA Port  Online  Pid
------------------------------------------------------------------------------
Brick node-1:/gfsvolume/gv0                 49152     0          Y       30787
Brick node-2:/gfsvolume/gv0                 49152     0          Y       30424
Brick node-3:/gfsvolume/gv0                 49152     0          Y       25287
Self-heal Daemon on localhost               N/A       N/A        Y       30808
Self-heal Daemon on node-2                  N/A       N/A        Y       30445
Self-heal Daemon on node-3                  N/A       N/A        Y       25308

Task Status of Volume clusterVaClusterViene
------------------------------------------------------------------------------
There are no active volume tasks

Ahora para poder utilizar nuestro volumen vamos a montarlo en la carpeta /var/www/html/ para ello en cada nodo editamos el fstab

vim /etc/fstab

Y agregamos la siguiente linea

node-1:/clusterVaClusterViene /var/www/html/ glusterfs defaults,_netdev 0 0

guardamos y montamos el nuevo punto

mount -a

Ahora cada fichero que se cree modifique o elimine de uno de los nodos se replicara en los otros nodos de manera automática.

Existe un bug en glusterfs en ubuntu si se usan los volúmenes en los propios servidores.

Durante el proceso de arranque, GlusterFS tardará un poco en iniciarse. systemd-mount, que maneja los puntos de montaje desde /etc/fstab, se ejecutará antes de que el servicio glusterfs-server termine de iniciarse.

El montaje fallará, por lo que terminará sin su volumen montado después de reiniciar.

La solución es crear el siguiente directorio

mkdir -p /etc/systemd/system/www.mount.d/

y dentro el siguiente fichero

vim /etc/systemd/system/www.mount.d/override.conf
[Unit]
After=glusterfs-server.service
Wants=glusterfs-server.service

recargamos systemd

systemctl daemon-reload

Y en el siguiente arranque ya tendremos el punto de montaje cargado automaticamente.

Apache + PHP

Ahora que ya nos funciona el sistema de archivos compartidos vamos instalar apache2 + php

apt install apache2

instalamos php y los complementos para mysql

apt install php libapache2-mod-php php-mysql

Agregamos apache al arranque del sistema

systemctl enable apache2

Eliminar el banner de la versión del servidor

Apache por defecto nos muestra en las peticiones su versión y el sistema operativo en el que esta corriendo.

Vamos a ocultar las versiones y el sistema operativo de nuestro servidor para dar la menor información posible a los atacantes, para ello editamos el siguiente fichero

vim /etc/apache2/conf-available/security.conf

Dejando los siguiente valores de esta manera

ServerTokens Prod

ServerSignature Off

Deshabilitar el listado de directorios en el navegador

Una configuración que trae por defecto apache es listar los ficheros de los directorios por lo que se puede producir una fuga de información si no nos acordamos de poner un fichero index.php o index.html para evitar el listado, para no tener que revisar todas las carpetas.

Editamos el fichero

vim /etc/apache2/apache2.conf

y buscamos donde se encuentre la opcion Indexes y le ponemos un guion delante quedando de la siguiente manera o podemos eliminar directamente la opcion

<Directory /var/www/>
        Options -Indexes FollowSymLinks
        AllowOverride None
        Require all granted
</Directory>

Reiniciamos apache para aplicar los cambios.

systemctl restart apache2

Mariadb Galera Cluster

Tenemos muchas maneras de montar un sistema de base de datos en modo clúster con mysql, Percona, galera, en nuestro caso lo vamos a realizar con MariaDB.

Nos descargamos el siguiente paquete para configurar los repositorios según nuestro sistema

wget https://downloads.mariadb.com/MariaDB/mariadb_repo_setup

Damos permisos de ejecución

chmod +x mariadb_repo_setup

Ejecutamos el script para que nos agregue los repositorios

Como los repositorios de mariadb no han sido actualizados todavía a "22.04 (Jammy Jellyfish)" No lanzaremos los repositorios oficiales, por lo que las versiones que se nos instalaran son las siguiente:

Cuando se lance el repositorio seria recomendable activarlos.

./mariadb_repo_setup

Si no tenemos el siguiente paquete nos dará error a la hora de agregar los repositorios

apt install apt-transport-https

Actualizamos

apt update

Instalamos MariaDB y galera

apt install mariadb-server mariadb-backup galera-4

Ahora vamos a pasar a configurar los nodos, las configuraciones entre ellos son casi idénticas.

De forma predeterminada, MariaDB está configurado para comprobar el directorio /etc/mysql/mariadb.conf.d donde busca configuraciones adicionales desde los archivos que terminan en .cnf. Por lo que vamos a crear el siguiente fichero.

vim /etc/mysql/mariadb.conf.d/61-clustervaclusterviene.cnf

Agregamos la siguiente configuración:

  • bind-address: En la ip que escuchara galera.

  • wsrep_cluster_name: El nombre de nuestro cluster

  • wsrep_cluster_address: Los nodos del cluster

  • wsrep_node_address: La ip del nodo

  • wsrep_node_name: EL nombre del nodo

[mariadb]
binlog_format=ROW
default-storage-engine=innodb
innodb_autoinc_lock_mode=2
bind-address=xxx.xxx.xxx.xxx

# Galera Provider Configuration
wsrep_on=ON
wsrep_provider=/usr/lib/galera/libgalera_smm.so

# Galera Cluster Configuration
wsrep_cluster_name="clusterVaClusterViene_cluster"
wsrep_cluster_address="gcomm://xxx.xxx.xxx.xxx,yyy.yyy.yyy.yyy,zzz.zzz.zzz.zzz"

# Galera Synchronization Configuration
wsrep_sst_method=rsync

# Galera Node Configuration
wsrep_node_address="xxx.xxx.xxx.xxx"
wsrep_node_name="node-1"

Replicamos esta configuración en el resto de los nodos cambiado los diferentes datos.

Activamos mysql para que arranque al comienzo

systemctl enable mariadb

Para configurar el primer nodo, deberá usar una secuencia de comandos de inicio especial. Por la manera en que configuró el clúster, cada nodo que se conecte intentará establecer conexión con al menos otro nodo especificado en su archivo 61-clustervaclusterviene.cnf para obtener su estado inicial. Un systemctl start mysql normal fallaría porque no hay en ejecución nodos con los que el primer nodo se pueda conectar.

Ejecutamos en el primer nodo

galera_new_cluster

Una vez terminado podemos comprobar el tamaño del cluster

mysql -u root -p -e "SHOW STATUS LIKE 'wsrep_cluster_size'"
+--------------------+-------+
| Variable_name      | Value |
+--------------------+-------+
| wsrep_cluster_size | 1     |
+--------------------+-------+

En el resto de los nodos arrancamos mysql de manera normal

systemctl start mariadb

Repetimos el comando de antes para ver el aumento del cluster

mysql -u root -p -e "SHOW STATUS LIKE 'wsrep_cluster_size'"
+--------------------+-------+
| Variable_name      | Value |
+--------------------+-------+
| wsrep_cluster_size | 2     |
+--------------------+-------+

Y así sucesivamente entre todos los nodos que tengamos.

Vamos a probar la replicación

mysql -u root -p -e 'CREATE DATABASE clusterVaClusterViene;
CREATE TABLE clusterVaClusterViene.equipment ( id INT NOT NULL AUTO_INCREMENT, type VARCHAR(50), quant INT, color VARCHAR(25), PRIMARY KEY(id));
INSERT INTO clusterVaClusterViene.equipment (type, quant, color) VALUES ("slide", 2, "blue");'

Con este comando crearemos la base de datos clusterVaClusterViene y la table equipment, donde agregaremos un row con los valores, slide, 2, blue.

Ahora vamos a otro nodo para ver que los datos son accesibles y ejecutamos

mysql -u root -p -e 'SELECT * FROM clusterVaClusterViene.equipment;'
+----+-------+-------+-------+
| id | type  | quant | color |
+----+-------+-------+-------+
|  1 | slide |     2 | blue  |
+----+-------+-------+-------+

Insertamos otro dato y repetimos el proceso en el resto de nodos.

mysql -u root -p -e 'INSERT INTO clusterVaClusterViene.equipment (type, quant, color) VALUES ("swing", 10, "yellow");'

Para que la gente no se pueda conectar por la ip publica a los puertos 80 y 443 lo bloqueamos mediante iptables en la interfaz publica

iptables -A INPUT -i {interface} -p tcp --destination-port 80 -j DROP
iptables -A INPUT -i {interface} -p tcp --destination-port 443 -j DROP

Como las iptables si se reinicia el equipo se pierden y no queremos estar agregándolas manualmente vamos a instalar el paquete iptables-persistent

apt install iptables-persistent

Las configuraciones se guardan en estos dos ficheros

/etc/iptables/rules.v4

/etc/iptables/rules.v6

Si hacemos algún cambio a las iptables nos tenemos que acordar de guardarlas

iptables-save > /etc/iptables/rules.v4

iptables-save > /etc/iptables/rules.v6

Memcached

Ahora que ya solo nos falta poder tener las sesiones compartidas entre los diferentes nodos para ello vamos a usar memcached

sudo apt install php-memcached memcached

Si vamos a la configuración vemos que la ip de escucha es localhost pero para poderlo tener en modo cluster tenemos que decirle que escuche en nuestra red interna.

vim /etc/memcached.conf
# Specify which IP address to listen on. The default is to listen on all IP addresses
# This parameter is one of the only security measures that memcached has, so make sure
# it's listening on a firewalled interface.
-l 127.0.0.1

cambiándola de la siguiente manera en cada nodo

-l 192.168.10.X

Una vez que tenemos configurado reiniciamos los nodos e iremos a configurar php

systemctl restart memcached

Abrimos la configuración de php y buscamos la sección de sesiones

vim /etc/php/8.1/apache2/php.ini

Y la dejamos de la siguiente manera

session.save_handler = memcache
session.save_path = 'tcp://192.168.10.3:11211,tcp://192.168.10.4:11211,tcp://192.168.10.5:11211'

Ahora vamos a configurar el modulo de memcached

vim /etc/php/8.1/mods-available/memcached.ini
memcache.allow_failover=1
memcache.session_redundancy=4

La directiva memcache.session_redundancy debe ser igual a la cantidad de servidores Memcached + 1 para que la información de la sesión se replique en todos los servidores. Esto se debe a un error en PHP.

Estas directivas permiten la conmutación por error y la redundancia de la sesión, por lo que PHP escribe la información de la sesión en todos los servidores especificados en session.save_path; similar a una configuración RAID-1.

systemctl restart apache2

Última actualización