Introducción: ¿Por qué autoalojar un Almacenamiento S3?
El almacenamiento de objetos se ha convertido en una pieza fundamental en el mundo del desarrollo y el autoalojamiento (self-hosting). La capacidad de gestionar grandes volúmenes de datos no estructurados, desde copias de seguridad y archivos multimedia hasta artefactos de compilación, de manera escalable y accesible a través de una API estándar como S3 es indispensable.
Tener el control estratégico sobre los datos propios, alejado de las dependencias y los costes de los proveedores cloud, es un objetivo clave para muchos.
Como comentábamos en el anterior artículo, la comunidad ha estado buscando activamente alternativas a soluciones populares como MinIO.
Garage vs SeaweedFS
En este contexto, emergen dos alternativas principales que destacan por su madurez y enfoque: Garage y SeaweedFS.
Basándonos en las experiencias compartidas por la comunidad, podemos describirlas de la siguiente manera:
Garage: ligero, resiliente y simple
Una solución ligera, simple y diseñada explícitamente para la resiliencia en redes no ideales. Su objetivo es ser 'Internet enabled', es decir, funcionar de manera fiable entre ubicaciones geográficas conectadas a través de Internet, sin requerir redes de centro de datos de baja latencia.
SeaweedFS: más funcionalidades y más complejidad
Una opción más rica en funcionalidades, que incluye características avanzadas como el borrado de código (Erasure Coding). Esta flexibilidad, sin embargo, puede comportar una mayor complejidad en su configuración inicial, ya que su arquitectura se compone de múltiples servicios coordinados (master, volume servers, filer).
Este manual se centrará en la implementación práctica de Garage. Su simplicidad operativa, su bajo consumo de recursos y su diseño robusto enfocado a la consistencia de los datos lo convierten en el candidato ideal para un primer clúster autoalojado, especialmente para un usuario técnico que valora la estabilidad y la facilidad de mantenimiento.
Antes de sumergirnos en los archivos de configuración y las líneas de comandos, es fundamental entender los conceptos que sustentan cualquier sistema de almacenamiento distribuido. Comprenderlos no solo facilitará la implementación, sino que también te dará las herramientas para diagnosticar problemas y escalar tu infraestructura en el futuro.
1. Conceptos Clave del Almacenamiento Distribuido
Antes de construir, un buen arquitecto debe entender los fundamentos. En el almacenamiento distribuido, estos fundamentos son los que garantizan que tus datos estén seguros, disponibles y accesibles, incluso cuando las cosas van mal. Comprender el "porqué" detrás de cada parámetro de configuración es crucial para tomar decisiones informadas durante la instalación y para resolver problemas de manera eficiente cuando aparezcan.
1.1. Qué es un clúster y por qué es importante
El principal motivo para no depender de un único servidor es evitar lo que se conoce como un punto único de fallo (Single Point of Failure). Si todos tus datos residen en una sola máquina, cualquier problema como un fallo de disco, un corte de corriente, un error de software puede dejar todo tu sistema inoperativo y tus datos inaccesibles.
Un clúster, formado por múltiples servidores (llamados nodos), mitiga este riesgo distribuyendo la carga y los datos. Si un nodo falla, los otros pueden continuar operando, garantizando una alta disponibilidad (High Availability).
Beneficios principales de un clúster
Además de la resiliencia, un clúster ofrece escalabilidad. En lugar de intentar hacer un solo servidor cada vez más potente (escalado vertical), puedes añadir más nodos al clúster para aumentar la capacidad y el rendimiento (escalado horizontal).
Esta filosofía queda perfectamente ilustrada en discusiones sobre sistemas como Ceph, donde los usuarios experimentados señalan que "Ceph scales out not up" (Ceph escala hacia fuera, no hacia arriba). Es decir, su diseño favorece la adición de más máquinas (escalado horizontal) por encima del aumento de la potencia de una única máquina (escalado vertical).
1.2. Replicación de datos: el corazón de la resiliencia
En términos sencillos, consiste en crear y mantener múltiples copias idénticas de tus datos en diferentes nodos del clúster (e idealmente, en diferentes zonas físicas, como centros de datos o incluso edificios). Si un nodo que contiene una copia de tus datos falla, el sistema puede continuar sirviendo las lecturas desde las otras copias disponibles.
En Garage, este comportamiento se controla principalmente con el parámetro replication_factor. Su valor tiene un impacto directo en la durabilidad y la disponibilidad del clúster.
replication_factor | Tolerancia a Fallos y Comportamiento |
1 | Sin redundancia. Los datos se almacenan en un solo nodo. Cualquier fallo del nodo provoca la pérdida de disponibilidad. Solo apto para entornos de prueba. |
2 | Tolera el fallo de un nodo para lecturas. Los datos se replican en dos nodos. Si un nodo cae, los datos se pueden seguir leyendo, pero las nuevas escrituras fallarán hasta que el nodo se recupere, ya que no se puede garantizar la segunda copia. |
3 | Tolerancia a fallos robusta. Los datos se replican en tres nodos. El clúster puede tolerar el fallo de un nodo (o incluso dos, en ciertas condiciones) mientras las operaciones de lectura y escritura continúan funcionando con normalidad. Este es el valor recomendado para entornos de producción. |
Este principio no es exclusivo de Garage. Sistemas como Ceph operan bajo una premisa similar por defecto. Como comentaba un usuario en un foro, en un clúster de 3 nodos, "ceph usually writes every bit of data 3 times" (Ceph normalmente escribe cada bit de datos 3 veces), asegurando así una alta durabilidad.
1.3. Por qué el hardware y la red son cruciales para el rendimiento
En un sistema distribuido, el rendimiento global está inevitablemente ligado a su componente más lento. Ya sea un disco duro, un procesador o la conexión de red, un solo cuello de botella puede degradar la experiencia de todo el clúster.
Un caso de estudio práctico ilustra perfectamente este punto. Un usuario de Ceph en Reddit experimentó un rendimiento de escritura decepcionante de unos ~700 MB/s en su clúster de 3 nodos con unidades NVMe. Después de una investigación exhaustiva, descubrió que dos de sus discos NVMe, debido a adaptadores PCIe defectuosos, estaban operando a velocidades de SATA, muy inferiores a su capacidad. Después de solucionar el problema de hardware, el rendimiento de escritura se disparó a ~2700 MB/s.
Su conclusión es una lección fundamental en sistemas distribuidos: el rendimiento del clúster entero se ve limitado por el nodo o componente más lento (the slowest node bottleneck). Antes de asumir un problema de software, es imperativo verificar y comparar el rendimiento de cada componente de hardware de manera aislada.
Buenas prácticas recomendadas
Esta sensibilidad al rendimiento del hardware se refleja directamente en las recomendaciones de Garage:
- El directorio de metadatos (metadata_dir) debería almacenarse en un "fast SSD drive" (un disco SSD rápido). Los metadatos implican operaciones pequeñas y frecuentes que dependen de la baja latencia de los SSD para un rendimiento óptimo.
- El directorio de datos (data_dir), donde se guardan los bloques de datos reales, puede residir en un HDD más lento y de mayor capacidad, ya que las operaciones de datos suelen ser lecturas/escrituras secuenciales más grandes.
Finalmente, la red es el tejido que une el clúster. Una red lenta o congestionada se convertirá rápidamente en el principal cuello de botella, ya que todas las operaciones de replicación y coordinación dependen de ella. Para sistemas de alto rendimiento como Ceph, la comunidad recomienda conexiones de "al menos 10gbps" para asegurar que el ancho de banda no limite la velocidad de los discos.
Con estos conceptos clave interiorizados, estamos preparados para aplicarlos en una configuración práctica y funcional con Garage.
2. Implementación Práctica: Clúster Garage de 2 Nodos
Ahora que hemos cubierto la teoría, es hora de ponerse manos a la obra. En esta sección, configuraremos un clúster de Garage básico pero completamente funcional, formado por dos nodos. Para simplificar al máximo el despliegue y la gestión, utilizaremos Docker Compose, una herramienta que nos permite definir y ejecutar aplicaciones multicontenedor con un solo archivo de configuración.
2.1. Requisitos previos
Antes de empezar, asegúrate de que tu entorno cumple los siguientes requisitos:
- Dos servidores (pueden ser máquinas físicas, máquinas virtuales o incluso VPS) con un sistema operativo Linux.
- Docker y Docker Compose instalados en cada uno de los dos servidores.
- Conocimientos básicos de la línea de comandos de Linux.
- Conectividad de red entre los dos servidores. Asegúrate de que los puertos necesarios (por defecto, 3900-3903) no están bloqueados por un cortafuegos.
2.2. Paso 1: El Archivo de Configuración (garage.toml)
El archivo garage.toml es el cerebro de cada nodo de Garage. Define su identidad, cómo debe comportarse y cómo se conecta con el resto de nodos del clúster. Crearemos la estructura de carpetas y el archivo garage.toml en cada uno de los dos servidores.
mkdir -p garage/{data,config} garage/data/{garage-data,garage-meta}
touch garage/config/garage.toml
Aquí tienes un ejemplo de configuración para un clúster de dos nodos. Tendrás que crear este archivo en cada nodo, sustituyendo los marcadores de posición <IP_DEL_NODE_1> y <IP_DEL_NODE_2> por las direcciones IP reales de tus servidores.
Generaremos una clave para rpc_secret ejecutando:
openssl rand -hex 32
Archivo garage.toml para el NODE 1:
metadata_dir = "/var/lib/garage/meta" data_dir = "/var/lib/garage/data" replication_factor = 2 db_engine = "sqlite" # Secrets i adreces de xarxa rpc_secret = "<UNA_CLAU_SECRETA_IDÈNTICA_PER_ALS_DOS_NODES>" rpc_bind_addr = "[::]:3901" rpc_public_addr = "<IP_DEL_NODE_1>:3901"
# Endpoints de l'API S3 i administració [s3_api] api_bind_addr = "[::]:3900" s3_region = "cat-central-1" [admin] api_bind_addr = "[::]:3903"
Archivo garage.toml para el NODE 2:
metadata_dir = "/var/lib/garage/meta" data_dir = "/var/lib/garage/data" replication_factor = 2 db_engine = "sqlite" # Secrets i adreces de xarxa rpc_secret = "<UNA_CLAU_SECRETA_IDÈNTICA_PER_ALS_DOS_NODES>" rpc_bind_addr = "[::]:3901" rpc_public_addr = "<IP_DEL_NODE_1>:3901" bootstrap_peers = ["<IP_DEL_NODE_2>:3901"] # Endpoints de l'API S3 i administració [s3_api] api_bind_addr = "[::]:3900" s3_region = "cat-central-1" [admin] api_bind_addr = "[::]:3903"
A continuación, analizamos los parámetros clave de esta configuración:
Parámetreo | Función |
metadata_dir | Donde se almacenan los metadatos (índice de objetos, buckets, etc.). Como se ha mencionado, se recomienda ubicarlo en un SSD para un rendimiento óptimo. |
data_dir | Donde se almacenan los bloques de datos reales de los objetos. Este directorio puede estar en un HDD de gran capacidad. |
replication_factor | Lo hemos establecido en 2 para este clúster de dos nodos. Esto significa que cada objeto tendrá dos copias, una en cada nodo, tolerando el fallo de un nodo para las lecturas. |
rpc_secret | Una clave secreta compartida para la comunicación entre nodos. Es crucial que sea idéntica en todos los nodos del clúster. |
rpc_public_addr | La dirección pública (IP y puerto) que los otros nodos utilizarán para contactar con este nodo. Debe ser la dirección IP única de cada servidor. |
bootstrap_peers | La lista de direcciones de otros nodos que se utilizará para iniciar la conexión y descubrir la topología del clúster. Cada nodo debe listar al otro. |
2.3. Paso 2: El Archivo Docker Compose (docker-compose.yml)
Docker Compose leerá este archivo para lanzar y gestionar el contenedor de Garage, asegurándose de que la configuración y los volúmenes de datos sean persistentes. Crea un archivo llamado docker-compose.yml con el siguiente contenido en cada uno de los dos servidores.
services:
garage:
image: dxflrs/garage:v2.1.0
container_name: garage
restart: always
network_mode: host
volumes:
- ./config/garage.toml:/etc/garage.toml:ro
- ./data/garage-meta:/var/lib/garage/meta
- ./data/garage-data:/var/lib/garage/data
cap_add:
- IPC_LOCK
Nota: Utilizamos network_mode: host por simplicidad en este ejemplo, ya que expone directamente los puertos del contenedor a la red del anfitrión, evitando la necesidad de mapear cada puerto individualmente. Esto es eficiente pero reduce el aislamiento de la red. Este mismo archivo docker-compose.yml se puede utilizar sin cambios en ambos nodos. La diferenciación se hace a través de su respectivo garage.toml.
Usamos una versión específica de la imagen (v2.1.0) para garantizar la reproducibilidad de este manual. En un entorno de producción, es una buena práctica fijar las versiones para evitar actualizaciones inesperadas, actualizándolas de manera controlada después de revisar los cambios.
2.4. Paso 3: Lanzamiento e Inicialización del Clúster
Amb els fitxers de configuració a punt, el llançament és molt senzill.
- En cada uno de los dos nodos, ejecuta el siguiente comando desde el directorio donde has creado los archivos:
docker compose up -d
Una vez los contenedores estén en marcha en ambos nodos, el clúster se habrá formado, pero todavía no sabe cómo distribuir los datos. Debemos definir la topología (el layout).
- Primero, obtén los IDs únicos de cada nodo ejecutando en cada uno:
docker exec -it garage /garage node id
- La salida será similar a esta:
d06175cc04a095ca607a2837f40d0bac6744c0252bf586e7c1c9d9488c04133a@192.168.18.2:3901
To instruct a node to connect to this node, run the following command on that node:
garage [-c <config file path>] node connect d06175cc04a095ca607a2837f40d0bac6744c0252bf586e7c1c9d9488c04133a@192.168.18.2:3901
This node identifier can also be added as a bootstrap node in other node's garage.toml files:
bootstrap_peers = [
"d06175cc04a095ca607a2837f40d0bac6744c0252bf586e7c1c9d9488c04133a@192.168.18.2:3901",
...
]
Security notice: Garage's intra-cluster communications are secured primarily by the shared
secret value rpc_secret. However, an attacker that knows rpc_secret (for example if it
leaks) cannot connect if they do not know any of the identifiers of the nodes in the
cluster. It is thus a good security measure to try to keep them secret if possible.
Copiaremos las líneas de bootstrap_peers eliminando lo que no necesitamos. Del ejemplo anterior quedará así:
bootstrap_peers = [ "d06175cc04a095ca607a2837f40d0bac6744c0252bf586e7c1c9d9488c04133a@192.168.18.2:3901",
]
El resultado del node1 lo copiaremos en el archivo garage.toml del node2 y al revés.
En cada nodo, reiniciamos el contenedor
docker compose restart
Verificamos que la comunicación se ha establecido correctamente:
docker compose exec garage /garage status
El resultado será similar al siguiente:
2026-02-26T04:25:46.221886Z INFO garage_net::netapp: Connected to 192.168.18.2:3901, negotiating handshake...
2026-02-26T04:25:46.264198Z INFO garage_net::netapp: Connection established to d06175cc04a095ca
==== HEALTHY NODES ====
ID Hostname Address Tags Zone Capacity DataAvail Version
32c3ac0eec51a2b7 node1 192.168.10.4:3901 NO ROLE ASSIGNED v2.1.0
d06175cc04a095ca node2 192.168.20.2:3901 NO ROLE ASSIGNED v2.1.0
- Ahora, asigna cada nodo a una "zona" y define su capacidad de almacenamiento. Las zonas son una construcción lógica para mejorar la resiliencia; en un entorno de producción, cada zona debería corresponder a una ubicación física diferente (ej: un centro de datos diferente).
#Node 1
docker exec garage /garage layout assign <ID_NODE1>
#Node 2
docker exec garage /garage layout assign <ID_NODE2>
- Finalmente, aplica la nueva configuración de la topología al clúster ejecutando en 1 de los dos nodos:
docker exec garage /garage layout apply --version 1
La salida será similar a esta:
2026-02-26T04:37:43.042306Z INFO garage_net::netapp: Connected to 192.168.10.4:3901, negotiating handshake... 2026-02-26T04:37:43.087192Z INFO garage_net::netapp: Connection established to 32c3ac0eec51a2b7 ==== COMPUTATION OF A NEW PARTITION ASSIGNATION ====Partitions are replicated 2 times on at least 2 distinct zones.Optimal partition size: 39.1 MBUsable capacity / total cluster capacity: 20.0 GB / 20.0 GB (100.0 %)Effective capacity (replication factor 2): 10.0 GBzona-node1 Tags Partitions Capacity Usable capacity 32c3ac0eec51a2b7 [] 256 (256 new) 10.0 GB 10.0 GB (100.0%) TOTAL 256 (256 unique) 10.0 GB 10.0 GB (100.0%)zona-node2 Tags Partitions Capacity Usable capacity d06175cc04a095ca [] 256 (256 new) 10.0 GB 10.0 GB (100.0%) TOTAL 256 (256 unique) 10.0 GB 10.0 GB (100.0%)
¡Enhorabuena! Tu clúster de dos nodos ya está operativo y preparado para almacenar datos de manera resiliente. El siguiente paso es aprender a interactuar con él.
3. Utilizar tu Clúster de Almacenamiento
Un clúster de almacenamiento distribuido solo es útil si podemos interactuar con él de manera sencilla y estandarizada. Afortunadamente, Garage expone una API compatible con Amazon S3, lo que significa que podemos utilizar un amplio ecosistema de herramientas y librerías ya existentes. Esta sección te mostrará cómo gestionar tus contenedores de almacenamiento (buckets) y cómo acceder a tus datos.
3.1. Gestión de Buckets y Claves de API
La gestión fundamental del clúster, como la creación de buckets y la gestión de las credenciales de acceso, se realiza a través de la línea de comandos de Garage. Estas operaciones deben ejecutarse desde uno de los nodos del clúster.
Para probar que todo funciona, crearemos un bucket que se replicará automáticamente entre las dos VM gracias al replication_factor = 2 que hemos puesto en el archivo de configuración.
Crear una clave S3: Guarda el "secret key" que te mostrará porque lo necesitaremos para poder acceder.
docker exec -it garage /garage key create test-key
Crear el bucket:
docker exec -it garage garage bucket create el-meu-bucket
Dar permisos a la clave sobre el bucket:
docker exec -it garage /garage bucket allow bucket-test --read --write --key test-key
3.2. Interacción con un Cliente S3 (AWS CLI)
Con el bucket y las claves creadas, ahora puedes interactuar con tu clúster utilizando cualquier herramienta compatible con S3. Utilizaremos AWS CLI, el cliente oficial de línea de comandos de Amazon Web Services, como ejemplo por su popularidad y robustez.
Obtener las credenciales
Primero, necesitas el Access Key y el Secret Key que Garage ha generado cuando has creado la clave. Puedes obtener el Access Key listando las claves. El Secret Key es el que has anotado en los pasos anteriores.
docker exec garage /garage key list
# I per veure els detalls d'una clau específica: docker exec garage /garage key info test-key
Configurar el perfil
Escribe lo siguiente (puedes poner valores inventados para la región, ya que Garage no la valida estrictamente, pero debe existir):
aws configure --profile garage # Access Key ID: [La teva clau] # Secret Access Key: [La teva clau secreta] # Default region name: garage # Default output format: json
Prueba de Subida de Archivos
Como Garage no es AWS oficial, hay que añadir el campo endpoint-url al archivo vi ~/.aws/config
endpoint_url = http://<IP_NODE1>:3900
Crear un archivo de prueba y subirlo
echo "Hola Garage, soc una dada replicada" > prova.txt aws --profile garage s3 cp prova.txt s3://bucket-test
Listar el contenido
aws --profile garage --endpoint-url http://IP_VM1:3900 s3 ls s3://el-meu-bucket/
Puedes listar el contenido del nodo 2 especificando el endpoint directamente
aws --profile garage --endpoint-url http://<IP_NODE2>:3900 s3 ls s3://bucket-test/
Comprobación interna (Garage Stats)
Ejecuta este comando en cualquier nodo. Te mostrará si hay datos "pendientes" de replicar o si todo está en sincronía:
docker exec garage /garage stats
Deberías ver que el número de objetos y el tamaño ocupado coinciden con lo que acabas de subir.
La potencia de una API estándar como S3 radica en el amplio ecosistema de herramientas que la soportan. Además de AWS CLI, podéis utilizar alternativas populares como rclone para sincronizaciones complejas, s3cmd para scripts, minio-client (mc) o clientes gráficos como Cyberduck.
Con estos pasos, no solo tienes un clúster de almacenamiento resiliente en funcionamiento, sino que también has validado que puedes interactuar con él utilizando herramientas estándar del ecosistema S3.
4. Conclusión y Próximos Pasos
¡Felicidades! Has completado con éxito el despliegue de tu propio clúster de almacenamiento de objetos S3. Durante este proceso, has aprendido los conceptos fundamentales que hacen que los sistemas distribuidos sean resilientes, como la replicación y la importancia crítica del hardware. Además, has implementado un clúster de dos nodos con Garage y Docker Compose, una solución ligera, eficiente y diseñada para la simplicidad operativa, y has aprendido a gestionarlo y a utilizarlo con herramientas estándar.
Ahora tienes una base sólida sobre la que construir. Este clúster es solo el punto de partida. Aquí tienes algunas ideas para continuar explorando y mejorando tu infraestructura:
- Monitorización: Un sistema en producción necesita ser observado. Investiga cómo configurar la monitorización con herramientas como Prometheus. Garage expone un endpoint de métricas (/metrics) a través de su puerto de administración (definido en la sección [admin] de tu garage.toml), que te permitirá visualizar el rendimiento, el uso del espacio y la salud del clúster.
- Escalabilidad: Añade un tercer nodo al clúster para aumentar aún más la resiliencia. Con tres nodos, podrás configurar un replication_factor = 3, lo que permitirá que el clúster tolere la pérdida completa de un nodo sin interrumpir las operaciones de lectura ni de escritura.
- Seguridad: Configura un reverse proxy (como Caddy o Nginx) delante de tus nodos. Esto no solo cifra el tráfico (TLS/SSL), sino que también proporciona un único punto de entrada al clúster, simplifica la gestión de certificados y permite implementar controles de acceso más avanzados o limitación de velocidad (rate limiting) a nivel de la capa de aplicación.
- Exploración de Alternativas: Una vez te sientas cómodo gestionando tu clúster de Garage, considera explorar alternativas si tus necesidades evolucionan. Si requieres funcionalidades más avanzadas como Erasure Coding (una técnica de ahorro de espacio respecto a la replicación simple) o una compatibilidad más profunda con el ecosistema HDFS, podrías desplegar un clúster de pruebas con SeaweedFS para comparar sus características y el rendimiento.
El autoalojamiento es un viaje de aprendizaje continuo. Con las bases que has establecido, estás en una posición excelente para construir soluciones de almacenamiento robustas, seguras y totalmente bajo tu control.