Ir al contenido
  1. Posts/

MinIO: almacenamiento compatible con S3 en tu homelab

Hay un problema que aparece tarde o temprano cuando llevas un tiempo con el homelab: necesitas almacenamiento de objetos compatible con S3. No porque seas Amazon, sino porque muchas herramientas modernas hablan S3 de forma nativa. Velero para backups de Kubernetes. Loki para logs. Restic, Rclone, Backblaze. Incluso algunas aplicaciones como Immich o Seafile pueden usar S3 como backend.

Si dependes de AWS S3 real, tienes un coste mensual variable y tus datos en manos de Amazon. MinIO resuelve eso: un servidor de objetos que habla la misma API que S3, que corres en tu propio hardware.

Lo tengo en producción haciendo de backend para los backups de mi cluster Kubernetes desde hace tiempo. Te cuento qué es, cómo instalarlo y para qué sirve realmente.

Qué es MinIO
#

MinIO es un servidor de almacenamiento de objetos. Guarda archivos (objetos) en buckets, igual que S3. La diferencia es que lo corres tú en tu propio servidor.

La compatibilidad con la API de S3 es total: si una herramienta soporta S3, puede usar MinIO sin cambios. Solo tienes que cambiar el endpoint y las credenciales. Eso es el verdadero valor de MinIO: no tienes que aprender una API nueva ni adaptar nada.

Está escrito en Go, es extremadamente rápido, y puede funcionar tanto en modo servidor único como en clúster distribuido con varios nodos y erasure coding. Para homelab, el modo servidor único es más que suficiente.

Para qué lo uso en mi homelab
#

Antes de entrar en la instalación, te cuento los casos de uso concretos donde lo tengo integrado, porque creo que es más útil que una lista abstracta de características.

Backups de Kubernetes con Velero: Velero necesita un backend de objetos para guardar los snapshots del cluster. Puede usar AWS S3, Google Cloud Storage o cualquier backend compatible. MinIO es la opción obvia para homelab. Cada backup del cluster (deployments, configmaps, PVCs) va a un bucket en MinIO.

Backups de bases de datos: Tengo scripts que hacen dump de PostgreSQL y MySQL periódicamente y suben el resultado a MinIO. Rclone puede montar MinIO como si fuera un sistema de archivos o usarlo directamente para sincronizar.

Almacenamiento secundario para aplicaciones: Algunas aplicaciones como Loki (agregación de logs) pueden usar S3 como backend. En vez de crecer sin límite en disco local, Loki va escribiendo sus chunks a MinIO.

Artefactos de builds: Si tienes pipelines de CI/CD que generan artefactos, MinIO es un buen lugar para guardarlos de forma accesible y versionada.

No lo uso como almacenamiento principal de archivos para el día a día. Para eso prefiero un NAS con Samba o NFS. MinIO brilla para datos estructurados que las aplicaciones necesitan leer y escribir programáticamente.

Instalación con Docker
#

La forma más rápida de probar MinIO es con Docker. Para producción uso Docker Compose con un volumen persistente.

Crea la carpeta del proyecto:

1
2
mkdir ~/minio
cd ~/minio

Crea el archivo docker-compose.yml:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
version: "3.8"

services:
  minio:
    image: minio/minio:latest
    container_name: minio
    restart: unless-stopped
    command: server /data --console-address ":9001"
    environment:
      MINIO_ROOT_USER: admin
      MINIO_ROOT_PASSWORD: cambia-esta-clave-larga-y-segura
    volumes:
      - /ruta/a/tus/datos:/data
    ports:
      - "9000:9000"   # API (S3 compatible)
      - "9001:9001"   # Consola web
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"]
      interval: 30s
      timeout: 20s
      retries: 3

El puerto 9000 es la API S3. El 9001 es la consola web de administración.

Levanta el contenedor:

1
docker compose up -d

Accede a la consola en http://tu-servidor:9001 con las credenciales que pusiste en el compose. Verás un panel desde donde puedes crear buckets, gestionar usuarios y monitorizar el estado.

Instalación como binario (sin Docker)
#

Si prefieres no usar Docker, MinIO tiene binarios estáticos que funcionan sin dependencias.

1
2
3
4
5
6
7
# Descargar el binario (arquitectura amd64)
curl -LO https://dl.min.io/server/minio/release/linux-amd64/minio
chmod +x minio
sudo mv minio /usr/local/bin/

# Verificar
minio --version

Crea el directorio de datos y un usuario de sistema:

1
2
3
sudo useradd -r -s /sbin/nologin minio-user
sudo mkdir -p /mnt/datos-minio
sudo chown minio-user:minio-user /mnt/datos-minio

Crea la configuración en /etc/default/minio:

1
2
3
4
MINIO_VOLUMES="/mnt/datos-minio"
MINIO_OPTS="--console-address :9001"
MINIO_ROOT_USER=admin
MINIO_ROOT_PASSWORD=cambia-esta-clave-larga-y-segura

Crea el servicio systemd en /etc/systemd/system/minio.service:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
[Unit]
Description=MinIO
Documentation=https://docs.min.io
Wants=network-online.target
After=network-online.target
AssertFileIsExecutable=/usr/local/bin/minio

[Service]
WorkingDirectory=/usr/local/

User=minio-user
Group=minio-user
ProtectProc=invisible

EnvironmentFile=/etc/default/minio
ExecStartPre=/bin/bash -c "if [ -z \"${MINIO_VOLUMES}\" ]; then echo \"Variable MINIO_VOLUMES not set in /etc/default/minio\"; exit 1; fi"
ExecStart=/usr/local/bin/minio server $MINIO_OPTS $MINIO_VOLUMES

Restart=always
LimitNOFILE=65536
TasksMax=infinity
TimeoutStopSec=infinity
SendSIGKILL=no

[Install]
WantedBy=multi-user.target

Activa e inicia el servicio:

1
2
3
sudo systemctl daemon-reload
sudo systemctl enable minio
sudo systemctl start minio

Crear buckets y usuarios
#

Desde la consola web puedes hacer casi todo, pero el cliente de línea de comandos mc (MinIO Client) es más versátil para automatizar.

Instala mc:

1
2
3
curl -LO https://dl.min.io/client/mc/release/linux-amd64/mc
chmod +x mc
sudo mv mc /usr/local/bin/

Configura el alias para tu servidor:

1
mc alias set mi-minio http://tu-servidor:9000 admin cambia-esta-clave-larga-y-segura

Desde ahora puedes usar mi-minio como alias en los comandos de mc.

Crea tu primer bucket:

1
mc mb mi-minio/backups

Verifica que funciona:

1
mc ls mi-minio

Sube un archivo de prueba:

1
2
3
4
5
echo "prueba" > test.txt
mc cp test.txt mi-minio/backups/test.txt

# Verifica que subió
mc ls mi-minio/backups

Usuarios y políticas de acceso
#

El usuario root que configuraste al instalar tiene acceso total. Para producción es mala idea usar esas credenciales en las aplicaciones. Mejor crear usuarios con permisos específicos.

Desde la consola web, ve a Identity > Users > Add User. Crea un usuario con el nombre que quieras. Luego asígnale políticas.

MinIO viene con políticas predefinidas:

  • readonly: solo lectura
  • writeonly: solo escritura
  • readwrite: lectura y escritura
  • diagnostics: para monitorización

También puedes crear políticas personalizadas en JSON. Por ejemplo, una política que solo permite acceder a un bucket específico:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": ["s3:GetObject", "s3:PutObject", "s3:DeleteObject", "s3:ListBucket"],
      "Resource": [
        "arn:aws:s3:::backups",
        "arn:aws:s3:::backups/*"
      ]
    }
  ]
}

Con esto el usuario solo puede ver y modificar el bucket backups, y no tiene acceso al resto.

Integrar MinIO con Velero (backups Kubernetes)
#

Este es el caso de uso que más me interesaba. Velero es la herramienta estándar para hacer backups de clusters Kubernetes. Necesita un backend de objetos para guardar los snapshots.

Primero, crea un bucket en MinIO específico para Velero:

1
mc mb mi-minio/velero

Crea un usuario de servicio con acceso solo a ese bucket. En la consola web: Identity > Service Accounts > Add Service Account. Guarda las credenciales generadas.

Crea el archivo de credenciales para Velero:

1
2
3
4
5
cat > /tmp/minio-credentials << EOF
[default]
aws_access_key_id = ACCESS_KEY_DEL_SERVICE_ACCOUNT
aws_secret_access_key = SECRET_KEY_DEL_SERVICE_ACCOUNT
EOF

Instala Velero apuntando a MinIO:

1
2
3
4
5
6
7
velero install \
  --provider aws \
  --plugins velero/velero-plugin-for-aws:v1.9.0 \
  --bucket velero \
  --secret-file /tmp/minio-credentials \
  --backup-location-config region=minio,s3ForcePathStyle=true,s3Url=http://tu-servidor:9000 \
  --use-volume-snapshots=false

El s3ForcePathStyle=true es importante para MinIO: fuerza el formato de URL servidor/bucket en vez del formato de subdominios que usa AWS real.

Verifica que Velero puede conectarse:

1
velero backup-location get

Si el estado dice “Available”, todo va bien. Lanza un backup de prueba:

1
2
velero backup create test-backup --include-namespaces default
velero backup describe test-backup

En unos segundos verás el backup creado y en MinIO aparecerá el objeto correspondiente en el bucket velero.

Integrar MinIO con Rclone
#

Rclone es la navaja suiza del almacenamiento. Puede sincronizar entre casi cualquier sistema de archivos o servicio cloud. Con MinIO como backend, puedes usar Rclone para:

  • Sincronizar carpetas locales a MinIO
  • Mover datos entre MinIO y otros servicios (Backblaze, S3 real, etc.)
  • Montar MinIO como sistema de archivos local

Configura MinIO en Rclone:

1
rclone config

Elige “New remote”, nombre “minio-homelab”, tipo “s3”, proveedor “Minio”. Introduce el endpoint, access key y secret key. Deja el resto por defecto.

O directamente edita ~/.config/rclone/rclone.conf:

1
2
3
4
5
6
7
[minio-homelab]
type = s3
provider = Minio
env_auth = false
access_key_id = TU_ACCESS_KEY
secret_access_key = TU_SECRET_KEY
endpoint = http://tu-servidor:9000

Prueba la conexión:

1
rclone ls minio-homelab:backups

Sincronizar una carpeta local a MinIO:

1
rclone sync /home/luis/documentos minio-homelab:backups/documentos

Montar MinIO como directorio local:

1
rclone mount minio-homelab:backups /mnt/minio-backups --daemon

Este último comando es útil si quieres que las aplicaciones que no soportan S3 nativamente puedan usar MinIO como si fuera un disco normal.

Políticas de lifecycle (retención automática)
#

Una cosa muy práctica de MinIO es que puedes definir reglas de ciclo de vida para los objetos. Por ejemplo, eliminar automáticamente backups que tengan más de 30 días.

Desde la consola web: Buckets > tu-bucket > Lifecycle. Añade una regla:

  • Status: Enabled
  • Prefix: dejar vacío (aplica a todo el bucket)
  • Expiry: número de días hasta que los objetos se eliminan

Con mc también puedes hacerlo:

1
2
mc ilm add mi-minio/backups \
  --expiry-days 30

Con esto los backups más viejos de 30 días desaparecen automáticamente. No tienes que acordarte de limpiar manualmente ni escribir scripts. Es una de esas pequeñas cosas que marcan la diferencia en un sistema que quieres que funcione solo.

Monitorización
#

MinIO expone métricas en formato Prometheus. Si ya tienes Prometheus configurado en tu homelab (si no, puedes ver el post sobre Grafana y Prometheus), añade MinIO como target.

La URL de métricas es: http://tu-servidor:9000/minio/v2/metrics/cluster

Para acceder a las métricas necesitas un token de bearer. Genéralo desde la consola web: Monitoring > Metrics > Generate Prometheus Config. Te da el bloque de configuración listo para pegar en tu prometheus.yml.

MinIO también tiene un dashboard de Grafana oficial en el ID 13502. Lo importas en Grafana y tienes visibilidad de operaciones por segundo, latencias, uso de disco y estado del cluster.

Rendimiento
#

Para homelab con un solo disco o RAID, MinIO va muy bien. Los números dependen completamente del disco subyacente. En mi servidor con disco SATA SSD:

  • Escritura secuencial: cerca de 400 MB/s (prácticamente el límite del disco)
  • Lectura secuencial: similar
  • Operaciones pequeñas: la latencia es baja, funciona bien para miles de archivos pequeños

Si necesitas más rendimiento, MinIO soporta modo distribuido con varios nodos y erasure coding. Pero para backups de homelab el modo single-node es más que suficiente.

Backups del propio MinIO
#

El dato crítico: si MinIO guarda tus backups, ¿qué pasa si falla el servidor donde corre MinIO?

Hay dos enfoques.

Enfoque 1: Replicación a otro destino

MinIO tiene replicación de buckets integrada. Puedes configurar que un bucket se replique automáticamente a otro servidor MinIO, a S3 de Amazon, o a Backblaze B2.

1
2
3
4
# Configurar replicación desde bucket local a Backblaze B2
mc replicate add mi-minio/backups \
  --remote-bucket b2:mi-bucket-remoto \
  --replicate "delete,delete-marker,existing-objects"

Enfoque 2: Backup del directorio de datos

Más simple: el directorio de datos de MinIO (/mnt/datos-minio) son simplemente archivos en el sistema de archivos del servidor. Puedes hacer backup de ese directorio con Restic, rsync o cualquier herramienta.

1
restic -r sftp:otro-servidor:/backups-minio backup /mnt/datos-minio

Yo uso los dos: Rclone sincroniza los buckets más importantes a Backblaze B2 una vez al día, y Restic hace snapshot del directorio completo semanalmente.

¿Cuándo tiene sentido MinIO?
#

Vale la pena si:

  • Tienes aplicaciones que hablan S3 (Velero, Loki, Restic con backend S3, etc.)
  • Quieres centralizar almacenamiento de backups con una API estándar
  • Manejas volúmenes de datos medianos o grandes y quieres control total

No tiene tanto sentido si:

  • Solo necesitas guardar archivos para acceso manual: mejor un NAS con Samba
  • Tu carga es poca y no te importa depender de AWS: S3 real es más simple
  • Empiezas y quieres lo mínimo: hay cosas más urgentes en el homelab

Lo que me convenció fue que varias herramientas que ya quería usar (Velero, Loki) necesitaban un backend S3. Montar MinIO una sola vez y que todas las herramientas lo usen es más limpio que gestionar diferentes sistemas de almacenamiento para cada una.

Recursos
#