Almacenamiento como servicio (minIO)

Hace más de 12 años se produjo el lanzamiento de Amazon Simple Storage Service (Amazon S3, por sus siglas en inglés), un servicio creado para almacenar datos en la nube y que pretendía servir, entre otras cosas, para que las empresas pudieran realizar una copia de seguridad de sus archivos en cualquier momento y desde cualquier ubicación.

Hoy en día, ese servicio se posiciona como el líder del mercado y entre las razones de esa gran popularidad, se encuentran su facilidad de uso, sus bajos precios, su escalabilidad y su seguridad. Sin embargo, a pesar de brindar excelentes ventajas, el servicio S3 de Amazon es desconocido por muchos de sus potenciales usuarios, sobre todo, por aquellos pertenecientes a las empresas multisede o descentralizadas, a los que pudiera beneficiar considerablemente.

Hoy les traigo la forma de tener un STaaS auto hosteado totalmente compatible con el servicio y las aplicaciones para acceder de S3.

Qué beneficios brinda el STaaS auto-hosteado?

Esto es más bien un tema trillado en pleno 2022, pero las principales beneficios serían:

  • Facilidad de uso: No solo se puede acceder al contenido guardado vía web, sino tambien via API.
  • Seguridad: Al ser un servicio auto hosteado, la seguridad corre por nuestra cuenta, asi que el límite en este caso somos nosotros mismos.
  • Disponibilidad: Ocurre lo mismo que en el caso anterior, si tenemos los servidores encendidos y conectados podremos acceder.
  • Escalabilidad: Podremos escalar horizontal y verticalmente cuando y como creamos pertinente.
  • Facilidad de interacción con aplicaciones de terceros: De los beneficios más destacados de STaaS y, más específicamente S3, para los desarrolladores, resalta su facilidad de conectar los datos almacenados en esa plataforma con aplicaciones de terceros, tanto móviles como basadas en la WEB, con excelentes rendimientos.

MinIO

MinIO ofrece almacenamiento de objetos compatible con S3 de alto rendimiento. Nativo de Kubernetes, MinIO es el único paquete de almacenamiento de objetos disponible en todas las nubes públicas, todas las distribuciones de Kubernetes, la nube privada y el perímetro. MinIO está definido por software y es 100 % de código abierto bajo GNU AGPL v3. MinIO en modo distribuido puede ayudarnos a configurar un sistema de almacenamiento de alta disponibilidad con una implementación de almacenamiento de un solo objeto. Con MinIO distribuido, puede utilizar dispositivos de almacenamiento de manera óptima, independientemente de su ubicación en una red.

Protección de Datos
Distributed MinIO brinda protección contra múltiples fallas de nodos/unidades y bit rot mediante el uso de código de borrado. Como los discos mínimos necesarios para MinIO distribuido son 4 (igual que los discos mínimos necesarios para la codificación de borrado), el código de borrado se activa automáticamente al iniciar MinIO distribuido.

Alta disponibilidad
Un servidor MinIO independiente dejaría de funcionar si el servidor que aloja los discos se desconecta. Por el contrario, una configuración de MinIO distribuida con m servidores y n discos mantendrá sus datos seguros siempre que haya m/2 servidores o m(n/2) o más discos en línea.
Por ejemplo, una configuración distribuida de 16 servidores con 200 discos por nodo continuaría sirviendo archivos, hasta 4 servidores pueden estar fuera de línea en la configuración predeterminada, es decir, alrededor de 800 discos MinIO continuaría leyendo y escribiendo objetos.

Garantías de consistencia
MinIO sigue un estricto modelo de coherencia de lectura tras escritura y lista tras escritura para todas las operaciones de E/S, tanto en modo distribuido como independiente. Este modelo de coherencia solo está garantizado si utiliza sistemas de archivos de disco como ***xfs, ext4 o zfs***, etc. para la configuración distribuida.

Instalación

Comenzaremos esta demostración con 4 servidores (ejecutando Ubuntu 20.04), y cada uno de ellos con 4 discos dedicados a estas tareas.

NOTA: Se puede hacer el despliegue de este servicoi en un server stand-alone, pero no cubriría el HA.

1. Preparando los discos en cada nodo

NOTA: Se deben realizar las siguientes acciones en cada nodo

Solo para asegurarse de que los discos estén vacíos (el proceso puede variar en tiempo en dependencia del disco):

dd if=/dev/zero of=/dev/sdb status=progress 
dd if=/dev/zero of=/dev/sdc status=progress
dd if=/dev/zero of=/dev/sdd status=progress
dd if=/dev/zero of=/dev/sde status=progress

Revisemos cuales son los discos que tenemos:

lsblk

[....]
sdb 8:16 0 1G 0 disk
sdc 8:32 0 1G 0 disk
sdd 8:48 0 1G 0 disk
sde 8:64 0 1G 0 disk

Tenemos 4 discos, entonces procedamos a darles formato:

dev='/dev/sdb' && \
printf "o\nn\np\n1\n\n\nw\n" | fdisk "$dev" && \
mkfs.xfs -f -i size=512 "${dev}1" && \
dev='/dev/sdc' && \
printf "o\nn\np\n1\n\n\nw\n" | fdisk "$dev" && \
mkfs.xfs -f -i size=512 "${dev}1" && \
dev='/dev/sdd' && \
printf "o\nn\np\n1\n\n\nw\n" | fdisk "$dev" && \
mkfs.xfs -f -i size=512 "${dev}1" && \
dev='/dev/sde' && \
printf "o\nn\np\n1\n\n\nw\n" | fdisk "$dev" && \
mkfs.xfs -f -i size=512 "${dev}1"

Cuando termine deberemos de ver algo parecido si corremos el comando lsblk:

sdb      8:16   0    1G  0 disk 
└─sdb1   8:17   0 1023M  0 part 
sdc      8:32   0    1G  0 disk 
└─sdc1   8:33   0 1023M  0 part 
sdd      8:48   0    1G  0 disk 
└─sdd1   8:49   0 1023M  0 part 
sde      8:64   0    1G  0 disk 
└─sde1   8:65   0 1023M  0 part

Creamos los puntos de montaje para cada disco con:

mkdir -p /data/disk1 && \
mkdir -p /data/disk2 && \
mkdir -p /data/disk3 && \
mkdir -p /data/disk4

Ahora para montarlos usando el UUID necesitamos primeramente conocerlos:

blkid | egrep "sdb|sdc|sdd|sde" | awk -F '"' '{print $2}'

Lo que nos debe devolver algo como:

2287e737-a29b-488d-8e0e-0fa14d7520e5
0fe8d671-49e1-4f16-a770-d478df73dcb9
2ff07b06-1555-4620-b26b-3f7f8d7ad4c8
cad70d54-50ce-4268-8356-ef938527d96d

Agregar el punto de montaje en `/etc/fstab`:

#echo "UUID=<uuid> /data/<diskX> xfs defaults 0 0" >> /etc/fstab

echo "UUID=2287e737-a29b-488d-8e0e-0fa14d7520e5 /data/disk1 xfs defaults 0 0" >> /etc/fstab && \
echo "UUID=0fe8d671-49e1-4f16-a770-d478df73dcb9 /data/disk2 xfs defaults 0 0" >> /etc/fstab && \
echo "UUID=2ff07b06-1555-4620-b26b-3f7f8d7ad4c8 /data/disk3 xfs defaults 0 0" >> /etc/fstab && \
echo "UUID=cad70d54-50ce-4268-8356-ef938527d96d /data/disk4 xfs defaults 0 0" >> /etc/fstab

Aplicamos y verificamos:

mount -a && \
sleep 3 && \
df -hT | grep disk

2. Obteniendo el minIO:

Correr el siguiente comando en cada nodo descargará el software:

cd /opt && \
wget https://dl.min.io/server/minio/release/linux-amd64/minio && \
chmod +x minio && \
cp minio /usr/local/bin/

3. minIO server distribuído y con ErsarureCode

minIO protege los datos contra fallas de hardware y corrupción silenciosa de datos mediante códigos de borrado y sumas de verificación. Con el nivel más alto de redundancia se puede perder hasta la mitad (N/2) del total de unidades y aún así poder recuperar los datos.
El código de borrado es un algoritmo matemático para reconstruir datos perdidos o corruptos. minIO usa código Reed-Solomon para fragmentar objetos en datos variables y bloques de paridad. Por ejemplo, en una configuración de 12 unidades, un objeto se puede fragmentar en una cantidad variable de datos y bloques de paridad en todas las unidades, desde seis bloques de datos y seis de paridad hasta diez bloques de datos y dos de paridad.

De forma predeterminada, minIO fragmenta los objetos en N/2 datos y N/2 unidades de paridad. Sin embargo, podemos usar clases de almacenamiento para usar una configuración personalizada. La documentación oficial recomienda N/2 datos y bloques de paridad, ya que garantiza la mejor protección contra fallas en la unidad.

En el ejemplo anterior de 12 unidades, con el servidor MinIO ejecutándose en la configuración predeterminada, puede perder cualquiera de las seis unidades y aún así reconstruir los datos de manera confiable a partir de las unidades restantes.

Iniciar un servidor minIO es bastante fácil de lograr. El comando general sería:

export MINIO_ROOT_USER=kcyborg && \
export MINIO_ROOT_PASSWORD=supersecurepassword && \
./minio server \ 
http://<hostname>.{hostname_initial_number...hostname_last_number}:<Port_to_hear>/data/disk{disk_initial_number)...disk_last_number}/ \
--console-address <IP_of_each_server>:<Port_to_answer>
NOTA: Recordar las variables MINIO_ROOT_USER y MINIO_ROOT_PASSWORD pues serán utilizadas luego.

En nuestro caso sería (cambiar el IP de la opción –console-address por el de cada servidor):

export MINIO_ROOT_USER=kcyborg && \
export MINIO_ROOT_PASSWORD=supersecurepassword && \
./minio server http://192.168.43.{101...104}:9000/data/disk{1...4}/ --console-address 192.168.43.101:9001
NOTA: Recuerde que lo anterior se aplica a cada nodo!!!
NOTA: Cuando inicie el servicio en uno de los servidores verá que no comenzará a brindar el servicio como tal hasta que no haya iniciado el servicio en el resto de los servidores.

4. Entrando a través de uno solo de los servidores:

Ahora tenemos una implementación en funcionamiento, pero necesitaremos acceder a una sola IP, no a todas, ¿verdad?

Esto lo haremos usando HAProxy (se pueden usar otras vías, pero esta fue la más sencilla y sin complicaciones que encontré).

apt install haproxy -y && \
haproxy -v

HA-Proxy version 2.0.13-2ubuntu0.3 2021/08/27 - https://haproxy.org/

Podriamos continuar trabajando con IPs solamente, pero vamos a hacernos la vida un poco más fácil editando el archivo /etc/hosts:

cat << EOF >> /etc/hosts

192.168.43.101 minio1
192.168.43.102 minio2
192.168.43.103 minio3
192.168.43.104 minio4
192.168.43.110 minio-haproxy1
EOF

Editamos el archivo de configuracón del haproxy:

cp /etc/haproxy/haproxy.cfg /etc/haproxy/haproxy.cfg.orig && \
cat << EOF >> /etc/haproxy/haproxy.cfg

# Minio API frontend configuration
frontend minio_cluster_frontend_api
bind minio-haproxy1:9000
mode http
default_backend minio_cluster_backend_api

# Minio API backend configuration
backend minio_cluster_backend_api
mode http
option forwardfor
balance roundrobin
http-request set-header X-Forwarded-Port %[dst_port]
http-request add-header X-Forwarded-Proto https if { ssl_fc }
server minio1 minio1:9000 check weight 1
server minio2 minio2:9000 check weight 1
server minio3 minio3:9000 check weight 1
server minio4 minio4:9000 check weight 1


# Minio WEB frontend configuration
frontend minio_cluster_frontend_web
bind minio-haproxy1:9001
mode http
default_backend minio_cluster_backend_web

# Minio WEB backend configuration
backend minio_cluster_backend_web
mode http
option forwardfor
balance roundrobin
http-request set-header X-Forwarded-Port %[dst_port]
http-request add-header X-Forwarded-Proto https if { ssl_fc }
server minio1 minio1:9001 check weight 1
server minio2 minio2:9001 check weight 1
server minio3 minio3:9001 check weight 1
server minio4 minio4:9001 check weight 1
EOF

El servicio de minIO utiliza dos puertos: uno para ser accesado via web y el otro para ser accesado via API, por eso necesitamos decirle al HAProxy que reenvie ambas peticiones

NOTA: En este caso tenemos que tanto el servicio como el HAProxy están en la misma red y no se brinda el servicio hacia afuera, por lo que si se desea utilizar el HAProxy como punto de entrada público a los servidores minIO corriendo en una red privada, en la línea bind necesitará poner la interfaz de red pública del HAProxy.

Dura opciones significa:
balance: Define qué política de selección se utilizará para seleccionar el servidor que atenderá las nuevas conexiones. En nuestro caso seleccionamos `roundrobin`.
mode tcp: Usaremos conexiones tco.
option tcpka: activa la función keepalive para conexiones TCP.
servidor <nombre-servidor> <dirección_IP> check weight 1: es donde se definen los nodos backend.

Reiniciar el servicio:

service haproxy restart

Y ya podremos acceder via web a través del HAProxy:

NOTA: Para acceder el nombre de usuario y la contraseña fueron definidos en las variables: MINIO_ROOT_USER y MINIO_ROOT_PASSWORD.

Vía web podríamos crear buckets, ver el contenido que contienen los mismos, borrarlos, copiarles información… Además podríamos crear usuarios, asignar cuotas… etc.

5. Usando el cliente mc para conectarnos via CLI

Podríamos continuar usando la interfaz web, pero lo que realmente es importante aquí es la integración con aplicaciones. Para ello los buenos de minIO han desarrollado su propio cliente terminal (llamado mc, de MinioClient) para conectarnos a nuestro STaaS via CLI, o tambien puede ser usada la herramienta de AWS.

Para usar el mc solo necesitamos la herramienta:

cd /opt && \
wget https://dl.min.io/client/mc/release/linux-amd64/mc && \
chmod +x mc && \
cp mc /usr/local/bin/

Y ya podremos usarla como un comando más. Pero primero tenemos que decirle a la herramienta a dónde se va a conectar! La terminología general es:

mc alias set \ 
<alias> \ 
<http://address:port> \ 
<access key> \ 
<secret key>

En nuestro caso sería:

mc alias set \
myminio \
http://192.168.43.110:9000 \
kcyborg \
supersecurepassword

Y ya podrímos listar el contenido de nuestro STaaS, preguntando especificamente por un bucket (llamado test y creado via web).

mc ls myminio/test

Podríamos copiar:

mc cp Estopa\ -\ Gafas\ de\ Rosa\ \(Official\ Video\).mp3 myminio/test

A lo que la consolo nos responde con:

...a (Official Video).mp3:  3.68 MiB / 3.68 MiB ┃▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓┃ 301.33 KiB/s 12s

Y podríamos checkear luego vía web:

6. Pensamientos finales

El presente artículo solo sirve para escarbar la superficie, hay mucho más para explotar de este servicio!!!

Autores:

Frank Morales
Franco Díaz

¿De cuánta utilidad te ha parecido este contenido?

¡Haz clic en una estrella para puntuar!

Promedio de puntuación 4.8 / 5. Recuento de votos: 5

Hasta ahora, ¡no hay votos!. Sé el primero en puntuar este contenido.

Sé el primero en comentar

Dejar una contestacion

Tu dirección de correo electrónico no será publicada.


*