Introducció: Per què autohospedar un Emmagatzematge S3?
L'emmagatzematge d'objectes s'ha convertit en una peça fonamental en el món del desenvolupament i l'autohospedatge (self-hosting). La capacitat de gestionar grans volums de dades no estructurades, des de còpies de seguretat i arxius multimèdia fins a artefactes de compilació, de manera escalable i accessible a través d'una API estàndard com S3 és indispensable.
Tenir el control estratègic sobre les dades pròpies, allunyat de les dependències i els costos dels proveïdors cloud, és un objectiu clau per a molts.
Com comentàvem a l'anterior article, la comunitat ha estat buscant activament alternatives a solucions populars com MinIO.
Garage vs SeaweedFS
En aquest context, emergeixen dues alternatives principals que destaquen per la seva maduresa i enfocament: Garage i SeaweedFS.
Basant-nos en les experiències compartides per la comunitat, podem descriure-les de la següent manera:
Garage: lleuger, resilient i simple
Una solució lleugera, simple i dissenyada explícitament per a la resiliència en xarxes no ideals. El seu objectiu és ser 'Internet enabled', és a dir, funcionar de manera fiable entre ubicacions geogràfiques connectades a través d'Internet, sense requerir xarxes de centre de dades de baixa latència.
SeaweedFS: més funcionalitats i més complexitat
Una opció més rica en funcionalitats, que inclou característiques avançades com l'esborrat de codi (Erasure Coding). Aquesta flexibilitat, però, pot comportar una major complexitat en la seva configuració inicial, ja que la seva arquitectura es compon de múltiples serveis coordinats (master, volume servers, filer).
Aquest manual se centrarà en la implementació pràctica de Garage. La seva simplicitat operativa, el seu baix consum de recursos i el seu disseny robust enfocat a la consistència de les dades el converteixen en el candidat ideal per a un primer clúster autohospedat, especialment per a un usuari tècnic que valora l'estabilitat i la facilitat de manteniment.
Abans de submergir-nos en els fitxers de configuració i les línies de comandes, és fonamental entendre els conceptes que sustenten qualsevol sistema d'emmagatzematge distribuït. Comprendre'ls no només facilitarà la implementació, sinó que també et donarà les eines per diagnosticar problemes i escalar la teva infraestructura en el futur.
1. Conceptes Clau de l'Emmagatzematge Distribuït
Abans de construir, un bon arquitecte ha d'entendre els fonaments. En l'emmagatzematge distribuït, aquests fonaments són els que garanteixen que les teves dades estiguin segures, disponibles i accessibles, fins i tot quan les coses van malament. Comprendre el "perquè" darrere de cada paràmetre de configuració és crucial per prendre decisions informades durant la instal·lació i per resoldre problemes de manera eficient quan apareguin.
1.1. Què és un clúster i per què és important
El principal motiu per no dependre d'un únic servidor és evitar el que es coneix com un punt únic de fallada (Single Point of Failure). Si totes les teves dades resideixen en una sola màquina, qualsevol problema com una fallada de disc, un tall de corrent, un error de programari pot deixar tot el teu sistema inoperatiu i les teves dades inaccessibles.
Un clúster, format per múltiples servidors (anomenats nodes), mitiga aquest risc distribuint la càrrega i les dades. Si un node falla, els altres poden continuar operant, garantint una alta disponibilitat (High Availability).
Beneficis principals d’un clúster
A més de la resiliència, un clúster ofereix escalabilitat. En lloc d'intentar fer un sol servidor cada cop més potent (escalat vertical), pots afegir més nodes al clúster per augmentar la capacitat i el rendiment (escalat horitzontal).
Aquesta filosofia queda perfectament il·lustrada en discussions sobre sistemes com Ceph, on els usuaris experimentats assenyalen que "Ceph scales out not up" (Ceph escala cap enfora, no cap amunt). És a dir, el seu disseny afavoreix l'addició de més màquines (escalat horitzontal) per sobre de l'augment de la potència d'una única màquina (escalat vertical).
1.2. Replicació de dades: el cor de la resiliència
En termes senzills, consisteix a crear i mantenir múltiples còpies idèntiques de les teves dades en diferents nodes del clúster (i idealment, en diferents zones físiques, com centres de dades o fins i tot edificis). Si un node que conté una còpia de les teves dades falla, el sistema pot continuar servint les lectures des de les altres còpies disponibles.
A Garage, aquest comportament es controla principalment amb el paràmetre replication_factor. El seu valor té un impacte directe en la durabilitat i la disponibilitat del clúster.
replication_factor | Tolerància a Fallades i Comportament |
1 | Sense redundància. Les dades s'emmagatzemen en un sol node. Qualsevol fallada del node provoca la pèrdua de disponibilitat. Només apte per a entorns de prova. |
2 | Tolera la fallada d'un node per a lectures. Les dades es repliquen en dos nodes. Si un node cau, les dades es poden continuar llegint, però les noves escriptures fallaran fins que el node es recuperi, ja que no es pot garantir la segona còpia. |
3 | Tolerància a fallades robusta. Les dades es repliquen en tres nodes. El clúster pot tolerar la fallada d'un node (o fins i tot dos, en certes condicions) mentre les operacions de lectura i escriptura continuen funcionant amb normalitat. Aquest és el valor recomanat per a entorns de producció. |
Aquest principi no és exclusiu de Garage. Sistemes com Ceph operen sota una premissa similar per defecte. Com comentava un usuari en un fòrum, en un clúster de 3 nodes, "ceph usually writes every bit of data 3 times" (Ceph normalment escriu cada bit de dades 3 vegades), assegurant així una alta durabilitat.
1.3. Per què el maquinari i la xarxa són crucials per al rendiment
En un sistema distribuït, el rendiment global està inevitablement lligat al seu component més lent. Ja sigui un disc dur, un processador o la connexió de xarxa, un sol coll d'ampolla pot degradar l'experiència de tot el clúster.
Un cas d'estudi pràctic il·lustra perfectament aquest punt. Un usuari de Ceph a Reddit va experimentar un rendiment d'escriptura decebedor d'uns ~700 MB/s en el seu clúster de 3 nodes amb unitats NVMe. Després d'una investigació exhaustiva, va descobrir que dos dels seus discs NVMe, a causa d'adaptadors PCIe defectuosos, estaven operant a velocitats de SATA, molt inferiors a la seva capacitat. Després de solucionar el problema de maquinari, el rendiment d'escriptura es va disparar a ~2700 MB/s.
La seva conclusió és una lliçó fonamental en sistemes distribuïts: el rendiment del clúster sencer es veu limitat pel node o component més lent (the slowest node bottleneck). Abans d'assumir un problema de programari, és imperatiu verificar i comparar el rendiment de cada component de maquinari de manera aïllada.
Bones pràctiques recomanades
Aquesta sensibilitat al rendiment del maquinari es reflecteix directament en les recomanacions de Garage:
- El directori de metadades (metadata_dir) s'hauria d'emmagatzemar en un "fast SSD drive" (un disc SSD ràpid). Les metadades impliquen operacions petites i freqüents que depenen de la baixa latència dels SSD per a un rendiment òptim.
- El directori de dades (data_dir), on es guarden els blocs de dades reals, pot residir en un HDD més lent i de major capacitat, ja que les operacions de dades solen ser lectures/escriptures seqüencials més grans.
Finalment, la xarxa és el teixit que uneix el clúster. Una xarxa lenta o congestionada es convertirà ràpidament en el principal coll d'ampolla, ja que totes les operacions de replicació i coordinació depenen d'ella. Per a sistemes d'alt rendiment com Ceph, la comunitat recomana connexions d'"almenys 10gbps" per assegurar que l'ample de banda no limiti la velocitat dels discs.
Amb aquests conceptes clau interioritzats, estem preparats per aplicar-los en una configuració pràctica i funcional amb Garage.
2. Implementació Pràctica: Clúster Garage de 2 Nodes
Ara que hem cobert la teoria, és hora de posar-se mans a l'obra. En aquesta secció, configurarem un clúster de Garage bàsic però completament funcional, format per dos nodes. Per simplificar al màxim el desplegament i la gestió, utilitzarem Docker Compose, una eina que ens permet definir i executar aplicacions multi-contenidor amb un sol fitxer de configuració.
2.1. Requisits previs
Abans de començar, assegura't que el teu entorn compleix els següents requisits:
- Dos servidors (poden ser màquines físiques, màquines virtuals o fins i tot VPS) amb un sistema operatiu Linux.
- Docker i Docker Compose instal·lats a cada un dels dos servidors.
- Coneixements bàsics de la línia de comandes de Linux.
- Connectivitat de xarxa entre els dos servidors. Assegura't que els ports necessaris (per defecte, 3900-3903) no estan bloquejats per un tallafoc.
2.2. Pas 1: El Fitxer de Configuració (garage.toml)
El fitxer garage.toml és el cervell de cada node de Garage. Defineix la seva identitat, com s'ha de comportar i com es connecta amb la resta de nodes del clúster. Crearem l'estructura de carpetes i el fitxer garage.toml a cada un dels dos servidors.
mkdir -p garage/{data,config} garage/data/{garage-data,garage-meta}
touch garage/config/garage.toml
Aquí tens un exemple de configuració per a un clúster de dos nodes. Hauràs de crear aquest fitxer a cada node, substituint els marcadors de posició <IP_DEL_NODE_1> i <IP_DEL_NODE_2> amb les adreces IP reals dels teus servidors.
Generarem una clau per rpc_secret executant:
openssl rand -hex 32
Fitxer garage.toml per al 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"
Fitxer garage.toml per al 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_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ó, analitzem els paràmetres clau d'aquesta configuració:
Paràmetre | Funció |
metadata_dir | On s'emmagatzemen les metadades (índex d'objectes, buckets, etc.). Com s'ha mencionat, es recomana ubicar-lo en un SSD per a un rendiment òptim. |
data_dir | On s'emmagatzemen els blocs de dades reals dels objectes. Aquest directori pot estar en un HDD de gran capacitat. |
replication_factor | L'hem establert a 2 per a aquest clúster de dos nodes. Això significa que cada objecte tindrà dues còpies, una a cada node, tolerant la fallada d'un node per a les lectures. |
rpc_secret | Una clau secreta compartida per a la comunicació entre nodes. És crucial que sigui idèntica a tots els nodes del clúster. |
rpc_public_addr | L'adreça pública (IP i port) que els altres nodes utilitzaran per contactar amb aquest node. Ha de ser l'adreça IP única de cada servidor. |
bootstrap_peers | La llista d'adreces d'altres nodes que s'utilitzarà per iniciar la connexió i descobrir la topologia del clúster. Cada node ha de llistar l'altre. |
2.3. Pas 2: El Fitxer Docker Compose (docker-compose.yml)
Docker Compose llegirà aquest fitxer per llançar i gestionar el contenidor de Garage, assegurant-se que la configuració i els volums de dades siguin persistents. Crea un fitxer anomenat docker-compose.yml amb el següent contingut a cada un dels dos servidors.
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: Utilitzem network_mode: host per simplicitat en aquest exemple, ja que exposa directament els ports del contenidor a la xarxa de l'amfitrió, evitant la necessitat de mapejar cada port individualment. Això és eficient però redueix l'aïllament de la xarxa. Aquest mateix fitxer docker-compose.yml es pot utilitzar sense canvis en ambdós nodes. La diferenciació es fa a través del seu respectiu garage.toml.
Fem servir una versió específica de la imatge (v2.1.0) per garantir la reproductibilitat d'aquest manual. En un entorn de producció, és una bona pràctica fixar les versions per evitar actualitzacions inesperades, actualitzant-les de manera controlada després de revisar els canvis.
2.4. Pas 3: Llançament i Inicialització del Clúster
Amb els fitxers de configuració a punt, el llançament és molt senzill.
- A cada un dels dos nodes, executa la següent comanda des del directori on has creat els fitxers:
docker compose up -d
Un cop els contenidors estiguin en marxa a ambdós nodes, el clúster s'haurà format, però encara no sap com distribuir les dades. Hem de definir la topologia (el layout).
- Primer, obtén els IDs únics de cada node executant a cadascun:
docker exec -it garage /garage node id
- La sortida serà similar a aquesta:
d06175cc04a095ca607a2837f40d0bac6744c0252bf586e7c1c9d9488c04133a@192.168.20.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.20.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.20.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.
Copiarem les línies de bootstrap_peers eliminant el que no necessitem. De l'exemple anterior quedarà així:
bootstrap_peers = [ "d06175cc04a095ca607a2837f40d0bac6744c0252bf586e7c1c9d9488c04133a@192.168.20.2:3901",
]
El resultat del node1 el copiarem en el fitxer garage.toml del node2 i a l'inrevés.
En cada node, reiniciem el contenidor
docker compose restart
Verifiquem que la comunicació s'ha establert correctament:
docker compose exec -it garage /garage status
El resultat serà similar al següent:
2026-02-26T04:25:46.221886Z INFO garage_net::netapp: Connected to 192.168.20.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
- Ara, assigna cada node a una "zona" i defineix la seva capacitat d'emmagatzematge. Les zones són una construcció lògica per millorar la resiliència; en un entorn de producció, cada zona hauria de correspondre a una ubicació física diferent (ex: un centre de dades diferent).
#Node 1
docker exec garage /garage layout assign <ID_NODE1>
#Node 2
docker exec garage /garage layout assign <ID_NODE2>
- Finalment, aplica la nova configuració de la topologia al clúster executant en 1 dels dos nodes:
docker exec garage /garage layout apply --version 1
La sortida serà similar a aquesta:
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%)
Enhorabona! El teu clúster de dos nodes ja està operatiu i preparat per emmagatzemar dades de manera resilient. El següent pas és aprendre a interactuar-hi.
3. Utilitzar el teu Clúster d'Emmagatzematge
Un clúster d'emmagatzematge distribuït només és útil si podem interactuar-hi de manera senzilla i estandarditzada. Afortunadament, Garage exposa una API compatible amb Amazon S3, la qual cosa significa que podem utilitzar un ecosistema ampli d'eines i llibreries ja existents. Aquesta secció et mostrarà com gestionar els teus contenidors d'emmagatzematge (buckets) i com accedir a les teves dades.
3.1. Gestió de Buckets i Claus d'API
La gestió fonamental del clúster, com la creació de buckets i la gestió de les credencials d'accés, es realitza a través de la línia de comandes de Garage. Aquestes operacions s'han d'executar des d'un dels nodes del clúster.
Per provar que tot funciona, crearem un bucket que es replicarà automàticament entre les dues VM gràcies al replication_factor = 2 que hem posat al fitxer de configuració.
Crear una clau S3: Guarda el "secret key" que et mostrarà perquè el necessitarem per poder accedir-hi.
docker exec -it garage /garage key create test-key
Crear el bucket:
docker exec -it garage garage bucket create el-meu-bucket
Donar permisos a la clau sobre el bucket:
docker exec -it garage /garage bucket allow bucket-test --read --write --key test-key
3.2. Interacció amb un Client S3 (AWS CLI)
Amb el bucket i les claus creades, ara pots interactuar amb el teu clúster utilitzant qualsevol eina compatible amb S3. Farem servir AWS CLI, el client oficial de línia de comandes d'Amazon Web Services, com a exemple per la seva popularitat i robustesa.
Obtenir les credencials
Primer, necessites l'Access Key i el Secret Key que Garage ha generat quan has creat la clau. Pots obtenir l'Access Key llistant les claus. El Secret Key és el que has anotat en els passos anteriors.
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
Escriu el següent (pots posar valors inventats per a la regió, ja que Garage no la valida estrictament, però ha d'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
Prova de Pujada de Fitxers
Com que Garage no és AWS oficial, cal afegir el camp endpoint-url al fitxer vi ~/.aws/config
endpoint_url = http://<IP_NODE1>:3900
Crear un fitxer de prova i pujar-lo
echo "Hola Garage, soc una dada replicada" > prova.txt aws --profile garage s3 cp prova.txt s3://bucket-test
Llistar el contingut
aws --profile garage --endpoint-url http://IP_VM1:3900 s3 ls s3://el-meu-bucket/
Pots llistar el contingut del node 2 especificant l'endpoint directament
aws --profile garage --endpoint-url http://<IP_NODE2>:3900 s3 ls s3://bucket-test/
Comprovació interna (Garage Stats)
Executa aquesta comanda a qualsevol node. Et mostrarà si hi ha dades "pendents" de replicar o si tot està en sincronia:
docker exec garage /garage stats
Hauries de veure que el nombre d'objectes i la mida ocupada coincideixen amb el que acabes de pujar.
La potència d'una API estàndard com S3 rau en l'ampli ecosistema d'eines que la suporten. A més d'AWS CLI, podeu utilitzar alternatives populars com rclone per a sincronitzacions complexes, s3cmd per a scripts, minio-client (mc) o clients gràfics com Cyberduck.
Amb aquests passos, no només tens un clúster d'emmagatzematge resilient en funcionament, sinó que també has validat que pots interactuar-hi utilitzant eines estàndard de l'ecosistema S3.
4. Conclusió i Pròxims Passos
Felicitats! Has completat amb èxit el desplegament del teu propi clúster d'emmagatzematge d'objectes S3. Durant aquest procés, has après els conceptes fonamentals que fan que els sistemes distribuïts siguin resilients, com la replicació i la importància crítica del maquinari. A més, has implementat un clúster de dos nodes amb Garage i Docker Compose, una solució lleugera, eficient i dissenyada per a la simplicitat operativa, i has après a gestionar-lo i a utilitzar-lo amb eines estàndard.
Ara tens una base sòlida sobre la qual construir. Aquest clúster és només el punt de partida. Aquí tens algunes idees per continuar explorant i millorant la teva infraestructura:
- Monitorització: Un sistema en producció necessita ser observat. Investiga com configurar la monitorització amb eines com Prometheus. Garage exposa un endpoint de mètriques (/metrics) a través del seu port d'administració (definit a la secció [admin] del teu garage.toml), que et permetrà visualitzar el rendiment, l'ús de l'espai i la salut del clúster.
- Escalabilitat: Afegeix un tercer node al clúster per augmentar encara més la resiliència. Amb tres nodes, podràs configurar un replication_factor = 3, la qual cosa permetrà que el clúster toleri la pèrdua completa d'un node sense interrompre les operacions de lectura ni d'escriptura.
- Seguretat: Configura un reverse proxy (com ara Caddy o Nginx) davant dels teus nodes. Això no només xifra el trànsit (TLS/SSL), sinó que també proporciona un únic punt d'entrada al clúster, simplifica la gestió de certificats i permet implementar controls d'accés més avançats o limitació de velocitat (rate limiting) a nivell de la capa d'aplicació.
- Exploració d'Alternatives: Un cop et sentis còmode gestionant el teu clúster de Garage, considera explorar alternatives si les teves necessitats evolucionen. Si requereixes funcionalitats més avançades com Erasure Coding (una tècnica d'estalvi d'espai respecte a la replicació simple) o una compatibilitat més profunda amb l'ecosistema HDFS, podries desplegar un clúster de proves amb SeaweedFS per comparar-ne les característiques i el rendiment.
L'autohospedatge és un viatge d'aprenentatge continu. Amb les bases que has establert, estàs en una posició excel·lent per construir solucions d'emmagatzematge robustes, segures i totalment sota el teu control.