Esta pagina se ve mejor con JavaScript habilitado

MinIO cluster

 ·  🎃 kr0m

MinIO es un servidor de almacenamiento de alto rendimiento compatible com Amazon S3, sus principales características son, arquitectura hyperescalable multi datacenter, alto rendimiento para servir grandes volúmenes de información, actualización fácil no disruptiva, alta disponibilidad/resistencia a fallo de discos y/o nodos, soporte para cifrado y compresión de datos.

Compilamos e instalamos Minio:

emerge -av net-fs/minio

Podemos consultar la versión instalada con:

minio version

Version: 2019-09-11T19-53-16Z
Release-Tag: DEVELOPMENT.2019-09-11T19-53-16Z
Commit-ID: 3e3fbdf8e6e5e889232eb7afc0b27ac054adfda0

Editamos el script de arranque de Minio para asignarle la ACCESS_KEY y la SECRET_KEY:

vi /etc/init.d/minio

#!/sbin/openrc-run
# Copyright 2016-2017 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2

description="Minio Object Storage Server"
pidfile=${pidfile:-"/run/${SVCNAME}.pid"}
export MINIO_ACCESS_KEY=XXXXXXXXXXXXXXXXXXX
export MINIO_SECRET_KEY=YYYYYYYYYYYYYYYYYYY
command="/usr/bin/minio"
command_args="${command_args:-server /var/lib/minio}"
command_background="true"
start_stop_daemon_args="--stdout /var/log/${SVCNAME}.log \
 --stderr /var/log/${SVCNAME}.log"

Arrancamos el servicio y lo añadimos al arranque:

/etc/init.d/minio start
rc-update add minio default

Por defecto Minio arranca en modo mono-server exportanto el directorio /var/lib/minio, podemos comprobar que funciona correctamente accediendo a:
http://IP:9000

Para utilizar múltiples discos(min: 4 discos) tendremos que modificar el script de arranque, en este escenario se podrán perder N/2 discos sin pérdida de datos:

vi /etc/init.d/minio

#!/sbin/openrc-run
# Copyright 2016-2017 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2

description="Minio Object Storage Server"
pidfile=${pidfile:-"/run/${SVCNAME}.pid"}
export MINIO_ACCESS_KEY=XXXXXXXXXXXXXXXXXXX
export MINIO_SECRET_KEY=YYYYYYYYYYYYYYYYYYY
command="/usr/bin/minio"
command_args="${command_args:-server /data1 /data2 /data3 /data4 /data5 /data6 /data7 /data8 /data9 /data10 /data11 /data12}"
command_background="true"
start_stop_daemon_args="--stdout /var/log/${SVCNAME}.log \
 --stderr /var/log/${SVCNAME}.log"

Reiniciamos el servicio para que surta efecto la configuración:

/etc/init.d/minio restart

Si consultamos el proceso podremos ver los parámetros con los que ha arrancado:

ps aux|grep mini

root     10568  0.0  0.2 2130480 91204 ?       Ssl  12:13   0:00 /usr/bin/minio server /data1 /data2 /data3 /data4 /data5 /data6 /data7 /data8 /data9 /data10 /data11 /data12

Para realizar despliegues distribuidos debemos tener en cuenta los siguientes puntos:

  • Mínimo de servidores: 2
  • Máximo de servidores: 32
  • Para que siga funcionando deben quedar N/2 discos vivos pero (N/2)+1 para crear objetos nuevos.
  • Mismo número de discos en cada nodo.
  • Todos los sistemas operativos deben ser el mismo SO y mismo ancho de banda.
  • Los relojes deben estar sincronizados con un error máximo de 3s(net-misc/ntpclient).
  • Las access_keys/secret_keys deben ser compartidas entre servidores.
  • El path de los directorios utilizados como almacenamiento deben ser los mismos en todos los servers.

Asignamos las mismas credenciales en todos los servers y en los argumentos del comando indicaremos la lista de servidores minio:

vi /etc/init.d/minio

#!/sbin/openrc-run
# Copyright 2016-2017 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2

description="Minio Object Storage Server"
pidfile=${pidfile:-"/run/${SVCNAME}.pid"}
export MINIO_ACCESS_KEY=XXXXXXXXXXXXXXXXXXX
export MINIO_SECRET_KEY=YYYYYYYYYYYYYYYYYYY
command="/usr/bin/minio"
command_args="${command_args:-server http://MINIOSERVER1IP/data http://MINIOSERVER2IP/data http://MINIOSERVER3IP/data http://MINIOSERVER4IP/data"
command_background="true"
start_stop_daemon_args="--stdout /var/log/${SVCNAME}.log \
 --stderr /var/log/${SVCNAME}.log"

Arrancamos el servicio y lo añadimos al arranque en todos los nodos:

/etc/init.d/minio start
rc-update add minio default

Finalmente instalamos el cliente en nuestro pc, debemos tener en cuenta que tanto el cliente como los servidores deben compartir versión, en mi caso los servidores son Version: 2019-09-11T19-53-16Z por lo tanto descargamos la versión correspondiente del cliente:

wget https://dl.minio.io/client/mc/release/linux-amd64/archive/mc.RELEASE.2019-09-11T20-17-47Z
chmod +x mc.RELEASE.2019-09-11T20-17-47Z
mv mc.RELEASE.2019-09-11T20-17-47Z /usr/local/bin/mc

Consultamos la versión:

mc version

Version: 2019-09-11T20:17:47Z
Release-tag: RELEASE.2019-09-11T20-17-47Z
Commit-id: 54ee3a280031adabc49a8309b74e5786cf266706

Configuramos las credenciales de nuestro minio:

vi .bashrc

export MINIO_ACCESS_KEY=XXXXXXXXXXXXXXXXXXX
export MINIO_SECRET_KEY=YYYYYYYYYYYYYYYYYYY

Añadimos los servidores:

mc config host add kr0mminio http://MINIOSERVER1IP:9000 XXXXXXXXXXXXXXXXXXX YYYYYYYYYYYYYYYYYYY
mc config host add kr0mminio2 http://MINIOSERVER2IP:9000 XXXXXXXXXXXXXXXXXXX YYYYYYYYYYYYYYYYYYY
mc config host add kr0mminio3 http://MINIOSERVER3IP:9000 XXXXXXXXXXXXXXXXXXX YYYYYYYYYYYYYYYYYYY
mc config host add kr0mminio4 http://MINIOSERVER4IP:9000 XXXXXXXXXXXXXXXXXXX YYYYYYYYYYYYYYYYYYY

Consultamos los servidores:

mc config host list

kr0mminio          
  URL       : http://MINIOSERVER1IP:9000
  AccessKey : XXXXXXXXXXXXXXXXXXX
  SecretKey : YYYYYYYYYYYYYYYYYYY
  API       : s3v4
  Lookup    : auto

kr0mminio2         
  URL       : http://MINIOSERVER2IP:9000
  AccessKey : XXXXXXXXXXXXXXXXXXX
  SecretKey : YYYYYYYYYYYYYYYYYYY
  API       : s3v4
  Lookup    : auto

kr0mminio3         
  URL       : http://MINIOSERVER3IP:9000
  AccessKey : XXXXXXXXXXXXXXXXXXX
  SecretKey : YYYYYYYYYYYYYYYYYYY
  API       : s3v4
  Lookup    : auto

kr0mminio4         
  URL       : http://MINIOSERVER4IP:9000
  AccessKey : XXXXXXXXXXXXXXXXXXX
  SecretKey : YYYYYYYYYYYYYYYYYYY
  API       : s3v4
  Lookup    : auto

Desde la interfaz web he creado un bucket llamado kr0m donde he subido una imagen:

Consultamos el bucket desde CLI:

mc ls kr0mminio/

[2020-02-26 15:27:42 CET]      0B kr0m/

Consultamos el contenido del bucket desde CLI:

mc ls kr0mminio/kr0m/

[2020-02-26 15:27:42 CET]   18KiB zabbixEscalation.jpg

NOTA: Si utilizamos discos mecánicos habilitar la compresión suele ayudar, ya que evitará el tener que leer tanto del disco.

Para habilitar la compresión debemos dumpear la configuración actual, modificarla y volverla a cargarla:

mc admin config get kr0mminio/ > /tmp/myconfig
vi /tmp/myconfig

"compress": {
        "enabled": true,
        "extensions": [".txt",".log",".csv", ".json"],
        "mime-types": ["text/csv","text/plain","application/json"]
}

Cargamos la configuración modificada:

mc admin config set kr0mminio < /tmp/myconfig

Setting new MinIO configuration file has been successful.
Please restart your server with `mc admin service restart kr0mminio`.

Reiniciamos el proceso de minio para que aplique la configuración.

mc admin service restart kr0mminio

Restart command successfully sent to `kr0mminio`.
Restarted `kr0mminio` successfully.

NOTA: Hay que tener en cuenta que Minio no soporta encriptación y compresión simultáneamente ya que esto haría posible ataques de side channel como CRIME y BREACH.

Una funcionalidad interesante de Minio es la sincronización de ficheros en tiempo real:

mkdir work
touch work/AA
mc mirror work kr0mminio/kr0m

Si entramos a cualquier otro servidor Minio deberíamos de ver el mismo contenido:
http://IP:9000

Los permisos de acceso se gestionan mediante las políticas:

  • none (no anonymous access)
  • download (anonymous read-only access)
  • upload (anonymous write-only access)
  • public (anonymous read/write access)

Podemos ver las políticas aplicadas mediante un get:

mc policy get kr0mminio/kr0m

Access permission for `kr0mminio/kr0m` is `none`

Para asignar políticas utilizaremos el comando set:

mc policy set download kr0mminio/kr0m

Access permission for `kr0mminio/kr0m` is set to `download`

Si volvemos a hacer el get podemos ver que la política ha cambiado:

mc policy get kr0mminio/kr0m

Access permission for `kr0mminio/kr0m` is `download`

Si cambiamos un disco podemos hacer que los datos se repliquen al nuevo con el comando heal, para ello primero debemos parar el servicio en el nodo afectado:

/etc/init.d/minio stop

Cambiamos el disco y arrancamos el servicio de nuevo:

/etc/init.d/minio start

Desde el cliente le ordenamos que resincronize el contenido:

mc admin heal -r kr0mminio3

 ◓  kr0m/zabbixEscalation.jpg
    2/2 objects; 18 KiB in 1s
    |--------------------------------------|
    | Green   | 8 | 100.0% ████████████    │
    | Yellow  | 0 |   0.0%                 |
    | Red     | 0 |   0.0%                 |
    | Grey    | 0 |   0.0%                 |
    |--------------------------------------|

Para actualizar las versiones de Minio en los servidores utilizaremos el cliente:

mc admin update kr0mminio

Server `kr0mminio` already running the most recent version 2019-09-11T19-53-16Z of MinIO

Podemos ver el estado del cluster mediante el comando info:

mc admin info server kr0mminio

●  MINIOSERVER1IP:9000
   Uptime: 1 hour 
  Version: 2019-09-11T19-53-16Z
  Storage: Used 215 KiB, Free 2.4 TiB
   Drives: 1/1 OK

   CPU        min        avg      max
   current    0.11%      0.14%    0.18%
   historic   0.05%      0.56%    27.37%

   MEM        usage
   current    70 MiB
   historic   70 MiB

●  MINIOSERVER2IP:9000
   Uptime: 1 hour 
  Version: 2019-09-11T19-53-16Z
  Storage: Used 215 KiB, Free 2.4 TiB
   Drives: 1/1 OK

   CPU        min        avg      max
   current    0.18%      0.23%    0.28%
   historic   0.05%      0.52%    35.29%

   MEM        usage
   current    70 MiB
   historic   70 MiB

●  MINIOSERVER3IP:9000
   Uptime: 1 hour 
  Version: 2019-09-11T19-53-16Z
  Storage: Used 215 KiB, Free 2.4 TiB
   Drives: 1/1 OK

   CPU        min        avg      max
   current    0.33%      0.34%    0.36%
   historic   0.05%      0.51%    21.96%

   MEM        usage
   current    70 MiB
   historic   70 MiB

●  MINIOSERVER4IP:9000
   Uptime: 1 hour 
  Version: 2019-09-11T19-53-16Z
  Storage: Used 215 KiB, Free 2.4 TiB
   Drives: 1/1 OK

   CPU        min        avg      max
   current    0.14%      0.15%    0.15%
   historic   0.05%      0.52%    20.05%

   MEM        usage
   current    70 MiB
   historic   70 MiB

Minio permite la exportación de métricas mediante Prometheus:

vi /etc/prometheus.yml

scrape_configs:
- job_name: minio-job
  scrape_interval: 1m
  scrape_timeout: 10s
  metrics_path: /minio/prometheus/metrics
  scheme: http
  static_configs:
  - targets:
    - kr0mminio:9000
    - kr0mminio2:9000
    - kr0mminio3:9000
    - kr0mminio4:9000

Algunas alertas interesantes serían cuando hay un disco defectuoso o cuando un disco se está quedando sin espacio:

groups:
- name: Minio
  rules:
  - alert: DiskOffline
    expr: minio_offline_disks != 0
    for: 5m
    labels:
      severity: critical
    annotations:
      summary: Disk offline
groups:
- name: Minio
  rules:
  - alert: StorageSpaceExhausted
    expr: minio_disk_storage_free_bytes < 10737418240
    labels:
      severity: info
    annotations:
      summary: Free space threshold reached
groups:
- name: Minio
  rules:
  - alert: MinioNodeDown
    expr: up{job="minio-job"} == 0
    for: 5m
    labels:
      severity: critical

Mediante Prometheus podemos visualizar los datos al vuelo, pero una forma mas cómoda es mediante Grafana, para ello utilizaremos esta dashboard.

Una vez importada la dashboard veremos datos de este estilo:

NOTA: Hay versiones de minio que no exportan la métrica minio_version por lo tanto el desplegable de instancias aparecerá vacío, para solventarlo debemos editar la dashboard y en la sección de Variables -> Instancia cambiar la query a label_values(minio_total_disks,instance)


Cifrar las comunicaciones de los nodos Minio nos protegerá ante el robo de información sensible y nos permitirá detectar alteraciones del contenido.

Generamos un certificado para todos los nodos, si vamos a utilizar las direcciones ip directamente sin dominios tendremos que generar el certificado de una forma especial:

openssl req -x509 -nodes -days 3650 -newkey rsa:2048 -keyout private.key -out public.crt -config <(
cat «-EOF
default_bits = 2048
distinguished_name = dn
x509_extensions = san
req_extensions = san
extensions = san
prompt = no
[ dn ]
countryName = ES
stateOrProvinceName = XXXX
localityName = XXXX
organizationName = Alfaexploit
[ san ]
subjectAltName = @alt_names
[ alt_names ]
IP.1 = MINIOSERVER1IP
IP.2 = MINIOSERVER2IP
IP.3 = MINIOSERVER3IP
IP.4 = MINIOSERVER4IP
EOF
)

Cada servidor servirá el certificado en base a public.crt/private.key y tendrá como CA de confianza public.crt.

scp public.crt kr0mminio:/root/.minio/certs/CAs/
scp public.crt kr0mminio:/root/.minio/certs/
scp private.key kr0mminio:/root/.minio/certs/

scp public.crt kr0mminio2:/root/.minio/certs/CAs/
scp public.crt kr0mminio2:/root/.minio/certs/
scp private.key kr0mminio2:/root/.minio/certs/
scp public.crt kr0mminio3:/root/.minio/certs/CAs/
scp public.crt kr0mminio3:/root/.minio/certs/
scp private.key kr0mminio3:/root/.minio/certs/
scp public.crt kr0mminio4:/root/.minio/certs/CAs/
scp public.crt kr0mminio4:/root/.minio/certs/
scp private.key kr0mminio4:/root/.minio/certs/

Modificamos el script en cada uno de los nodos:

vi /etc/init.d/minio

#!/sbin/openrc-run
# Copyright 2016-2017 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2

description="Minio Object Storage Server"
pidfile=${pidfile:-"/run/${SVCNAME}.pid"}
export MINIO_ACCESS_KEY=XXXXXXXXXXXXXXXXXXX
export MINIO_SECRET_KEY=YYYYYYYYYYYYYYYYYYY
command="/usr/bin/minio"
#command_args="${command_args:-server /var/lib/minio}"
command_args="${command_args:-server https://MINIOSERVER1IP/data https://MINIOSERVER2IP/data https://MINIOSERVER3IP/data https://MINIOSERVER4IP/data}"
command_background="true"
start_stop_daemon_args="--stdout /var/log/${SVCNAME}.log \
 --stderr /var/log/${SVCNAME}.log"

Reiniciamos el servicio:

/etc/init.d/minio restart

También le pasamos los certificados al cliente mc para que pueda conectar sin problemas:

cp public.crt /usr/local/share/ca-certificates/minio.crt

Actualizamos la base de datos de CAs:

update-ca-certificates

Habrá que reañadir los nodos en modo https al cliente:

mc config host remove kr0mminio
mc config host remove kr0mminio2
mc config host remove kr0mminio3
mc config host remove kr0mminio4

mc config host add kr0mminio https://MINIOSERVER1IP:9000 XXXXXXXXXXXXXXXXXXX YYYYYYYYYYYYYYYYYYY
mc config host add kr0mminio2 https://MINIOSERVER2IP:9000 XXXXXXXXXXXXXXXXXXX YYYYYYYYYYYYYYYYYYY
mc config host add kr0mminio3 https://MINIOSERVER3IP:9000 XXXXXXXXXXXXXXXXXXX YYYYYYYYYYYYYYYYYYY
mc config host add kr0mminio4 https://MINIOSERVER4IP:9000 XXXXXXXXXXXXXXXXXXX YYYYYYYYYYYYYYYYYYY

Podemos comprobar los servidores configurados mediante el comando ls:

mc ls kr0mminio

NOTA: Si utilizamos SSL añadiremos el certificado a la configuración de Prometheus, debemos pasarle el contenido del fichero public.crt además de tener en cuenta que si hemos generado los certificados con IP habrá que meter las ips y no los nombres de dominio en la configuración de Prometheus:

vi /etc/prometheus.yml

scrape_configs:
- job_name: minio-job
  scrape_interval: 1m
  scrape_timeout: 10s
  metrics_path: /minio/prometheus/metrics
  scheme: https
  tls_config:
    ca_file: /usr/local/share/ca-certificates/minio.crt
    insecure_skip_verify: false
  static_configs:
  - targets:
    - MINIOSERVER1IP:9000
    - MINIOSERVER2IP:9000
    - MINIOSERVER3IP:9000
    - MINIOSERVER4IP:9000

DEBUG:

La mejor manera de debugear problemas es arrancar manualmente cada uno de los nodos para ver los errores por stdout:

/usr/local/bin/minio server https://MINIOSERVER1IP/data https://MINIOSERVER2IP/data https://MINIOSERVER3IP/data https://MINIOSERVER4IP/data

También podemos consultar los logs de todos los servidores desde el cliente conectando con cualquiera de los servidores:

mc admin console kr0mminio3

Si te ha gustado el artículo puedes invitarme a un RedBull aquí