Technologie

Comme il devenait peu rationnel de continuer à utiliser un S3 externe pour les tests, j'ai mis en place mon propre stockage basé sur SeaweedFS

AAnonymous
13 min de lecture

Introduction

Quand on répète en local des tests d'upload, de presigned URL, de bucket public, de cache CDN et de miniatures, continuer à raccorder un S3 externe uniquement pour les tests se révèle plus artificiel qu'on ne l'imagine. Ce n'était pas seulement une question de coût : à chaque expérimentation, devoir encore passer par un compte et des ressources externes finissait par me gêner.

J'ai donc changé d'approche. Le stockage utilisé de façon répétée dans les tests, je l'ai tout simplement rapatrié on-premise, tout en conservant autant que possible l'interface vue par l'application comme S3 그대로. Cela me paraissait bien plus sain d'utiliser, en local et en dev, un stockage compatible S3 on-premise, puis de pouvoir remplacer directement la même interface par AWS S3 ou Cloudflare R2 en production.

Au final, j'ai construit un stockage compatible S3 sur un noeud unique avec la combinaison SeaweedFS + Nginx CDN + TLS + TTL. Ce travail est aussi un exemple où l'IA a automatisé de bout en bout l'ébauche de recherche, la première version de la configuration d'infrastructure, la rédaction des manifestes et la formalisation de la procédure de déploiement. Dans cet article, toutes les informations sensibles comme les vraies clés, les secrets, les chemins internes ou les IP internes sont masquées.

Pourquoi l'avoir mis en place moi-même ?

AWS S3 lui-même n'était pas le problème. Mais, pour des usages de test, cela devenait progressivement maladroit.

  • Il fallait valider de manière répétée les flux d'upload dans les environnements local et de développement.
  • Il fallait séparer buckets publics et privés, puis vérifier ensemble le CDN, les presigned URL et la couche de miniatures.
  • De nombreux flux créaient et supprimaient des fichiers temporaires à intervalle court.
  • À force, expérimenter systématiquement sur un stockage externe rendait des tests pourtant simples inutilement lourds.

Ce que je cherchais n'était pas une énorme plateforme de stockage, mais une compatibilité S3 suffisante pour les tests et une exploitation on-premise simple. Plus précisément, j'avais besoin d'une structure où le contrat de stockage vu par le développeur reste figé sur une interface compatible S3, tandis que l'implémentation backend puisse être remplacée selon l'environnement.

Pourquoi SeaweedFS ?

Au départ, j'ai d'abord examiné les options les plus familières, mais à la fin de 2025 il devenait difficile de conserver MinIO comme choix par défaut. L'évolution de sa licence et la direction prise par la communauté me semblaient le rendre moins adapté à une solution légère à conserver dans la durée.

À l'inverse, Ceph RGW était une option beaucoup plus complète, mais bien trop lourde pour cet objectif. J'avais besoin d'un stockage de test à noeud unique et d'un support simple pour des médias, pas d'exploiter un cluster de stockage à grande échelle.

Le choix final a donc été SeaweedFS.

  • Sa licence Apache 2.0 impose peu de contraintes commerciales.
  • Il fournit un S3 Gateway, ce qui évite de modifier profondément les flux existants basés sur SDK.
  • Sur les usages principaux comme l'upload, le téléchargement, la séparation par bucket et les presigned URL, l'interface S3 reste pratiquement inchangée.
  • Via Helm, il se déploie facilement sur Kubernetes.
  • Son profil convient bien aux petits fichiers média, comme les images, l'audio ou de courtes vidéos.

Plutôt que de chercher un remplacement intégral à S3, j'ai surtout retenu l'option la plus concise pour obtenir, dans le périmètre dont j'avais besoin, un stockage qui fonctionne presque selon le même contrat que S3.

Voici comment je l'ai réellement structuré

Je n'ai pas voulu d'une architecture compliquée. J'ai construit une couche compatible S3 autour de SeaweedFS, avec une couche de cache Nginx en frontal. J'y ai ajouté TLS, une couche de miniatures pour les buckets publics et une politique TTL pour les fichiers temporaires.

À grands traits, l'exploitation se découpait ainsi.

  • S3 endpoint : stockage principal auquel l'application se connecte directement
  • CDN endpoint : diffusion en cache des ressources publiques
  • thumbnail endpoint : couche de transformation d'images réservée aux buckets publics
  • séparation des buckets : static, public sont publics ; images, videos, bgm, files sont privés
  • TTL : le préfixe _tmp/ expire automatiquement au bout de deux semaines

Avec cette structure, j'ai pu valider d'un seul coup les principaux flux nécessaires aux tests : upload, accès public, presigned URL privés, cache CDN, génération de miniatures et nettoyage des fichiers temporaires, le tout sur le même stockage.

Du côté de Spring Boot, je n'ai pas non plus profondément modifié la façon d'intégrer S3. Dans les profils locaux et de test, j'ai simplement remplacé l'endpoint par une adresse compatible S3 on-premise, puis ajusté l'accès en path-style et les règles de buckets publics/privés. Autrement dit, même après avoir introduit un nouveau stockage, le code applicatif a pu conserver sa structure générale.

C'est ce point que j'ai particulièrement apprécié. En local et en dev, on branche un stockage on-premise comme SeaweedFS ; en production, on peut basculer vers AWS S3 ou R2 tout en gardant pratiquement la même interface côté application. Changer de produit de stockage ne conduit donc pas immédiatement à remettre en cause toute l'abstraction de persistance.

Autrement dit, la valeur essentielle de cette mise en place ne tenait pas simplement au fait d'avoir levé un serveur de stockage, mais au fait d'avoir fixé sur une compatibilité S3 l'interface observée par le code, même si l'implémentation du stockage varie selon l'environnement. Une telle interface est utile pour les tests et bien plus souple lorsque vient le moment de changer le stockage de production.

Jusqu'où l'IA est-elle allée cette fois ?

Ce qui était intéressant dans ce travail, ce n'était pas seulement SeaweedFS lui-même, mais jusqu'où l'IA pouvait réellement porter le processus.

Concrètement, les tâches suivantes ont été automatisées de bout en bout par l'IA, l'intervention humaine se limitant à la saisie des informations sensibles et à la relecture finale.

  • recherche des candidats de stockage compatible S3 et rédaction d'un premier comparatif
  • comparaison de MinIO, SeaweedFS, Ceph, RustFS, puis resserrement des options
  • première version des valeurs Helm, des manifestes Nginx de cache et de la configuration TLS
  • formalisation de la structure des buckets, de la politique TTL, des procédures de test et de la checklist d'exploitation
  • rédaction du guide de déploiement et de la documentation de dépannage

Cette expérience m'a confirmé un point : lorsque les exigences et le périmètre de sécurité sont cadrés en amont, l'IA peut automatiser assez profondément le travail d'infrastructure lui-même. L'effet d'efficacité était particulièrement tangible dans un flux répétitif comme celui-ci : rédaction du brouillon -> génération des fichiers de configuration -> documentation de la procédure de déploiement -> mise en application réelle.

Conclusion

Cette mise en place n'est pas le récit grandiose d'une nouvelle plateforme de stockage. C'est plutôt la trace du moment où j'ai rapatrié un peu plus dans mon propre périmètre le S3 utilisé à répétition pour les tests.

Mais même à cette échelle, le gain est réel. J'ai pu vérifier plus souvent, sans dépendance externe, des flux très concrets : ressources publiques et privées, CDN, presigned URL, miniatures, TTL. Plus important encore, j'ai obtenu une architecture où local et dev peuvent rester on-premise, tandis que la production peut choisir entre S3 et R2 sous une même interface compatible S3.

Et un autre point est devenu encore plus net. L'IA ne se limite pas à écrire du code : elle peut aussi automatiser à un niveau déjà élevé des brouillons d'infrastructure, des configurations et de la documentation de déploiement. Le travail humain n'a pas disparu, mais il est désormais beaucoup plus clair de voir jusqu'où on peut déléguer.


Annexe

Ci-dessous figure le texte intégral de documents/workspace/infrastructure/S3_COMPATIBLE_STORAGE_RESEARCH.md.

Recherche sur des solutions de stockage objet compatibles S3

Date de rédaction : 2025-12-30 Objectif : sélectionner une solution d'infrastructure interne en alternative à AWS S3

Contexte

Situation de MinIO (décembre 2025)

MinIO n'est plus recommandé. Principales raisons :

  1. Problème de licence : passage de Apache 2.0 à AGPL-3.0

    • obligation de publier le code source en cas de fourniture comme service réseau
    • pour un usage commercial, la licence démarre à 96 000 $/an
  2. Passage en mode maintenance (décembre 2025)

    • arrêt des nouvelles fonctionnalités, des améliorations et de l'acceptation des PR
    • seuls les correctifs de sécurité sont appliqués après évaluation au cas par cas
    • arrêt de la distribution des binaires communautaires (code source uniquement)
  3. Suppression de l'interface d'administration

    • la console d'administration a été retirée de l'édition communautaire
    • l'ensemble des fonctionnalités n'est disponible que dans la version payante

Référence : InfoQ - MinIO in Maintenance Mode


Exigences

ÉlémentExigence
Compatibilité S3Obligatoire - l'AWS SDK doit pouvoir être utilisé tel quel
LicencePréférence pour une licence sans restriction d'usage commercial (Apache 2.0, MIT, etc.)
Données stockéesImages, BGM, courtes vidéos de type shorts
Extension CDNPossibilité de mettre en place un CDN de cache avec un reverse proxy Nginx
Environnement de déploiementKubernetes + chart Helm
CoûtRéduire les coûts AWS grâce à une infrastructure interne

Comparaison des solutions

1. SeaweedFS ⭐ (recommandé)

ÉlémentContenu
LicenceApache 2.0 (usage commercial libre)
LangageGo
ArchitectureStructure Master + Volume + Filer
CaractéristiquesSeek disque en O(1), basé sur l'architecture Facebook Haystack
Compatibilité S3Fournit un S3 Gateway (prise en charge complète des opérations S3 de base)
HelmChart Helm officiel + opérateur Kubernetes
MaturitéValidé en production (cas de déploiement à plus de 1,5 PB)
EntrepriseGratuit jusqu'à 25 To, puis 1 $/To/mois

Avantages

  • Peut gérer des dizaines de milliards de fichiers (très adapté au stockage média)
  • Accès rapide aux petits fichiers grâce au seek O(1)
  • Prise en charge de l'erasure coding pour une meilleure efficacité de stockage
  • Tiering cloud (déplacement automatique des données froides)
  • Prise en charge des montages FUSE, de WebDAV et de l'intégration Hadoop

Inconvénients

  • Certaines fonctions S3 avancées ne sont pas prises en charge (politiques de cycle de vie, etc.)
  • Sauvegarde des métadonnées indispensable (si les métadonnées du Filer sont perdues, les fichiers deviennent orphelins)

Installation Helm

Bash
helm repo add seaweedfs https://seaweedfs.github.io/seaweedfs/helm
helm upgrade --install seaweedfs seaweedfs/seaweedfs -n storage --create-namespace

Référence : SeaweedFS GitHub


2. RustFS

ÉlémentContenu
LicenceApache 2.0
LangageRust
Performance2,3 fois plus rapide que MinIO sur des objets de 4 Ko
Compatibilité S3Prise en charge complète de l'API S3
HelmChart Helm officiel
Maturité⚠️ Bêta (version 0.0.77 en décembre 2025)

Avantages

  • Prend en charge la migration depuis MinIO et la coexistence avec lui
  • Excellentes performances sur les petits objets
  • Licence Apache 2.0

Inconvénients

  • Toujours en phase bêta (prudence en production)
  • Documentation et communauté encore limitées

Installation Helm

Bash
helm repo add rustfs https://charts.rustfs.com
helm install rustfs rustfs/rustfs -n rustfs --create-namespace \
  --set ingress.className="nginx"

Référence : RustFS GitHub


3. Ceph RGW (via Rook)

ÉlémentContenu
LicenceLGPL 2.1
LangageC++ (chemin de données), Go (opérateur Rook)
ArchitectureStockage unifié basé sur RADOS (bloc + fichier + objet)
Compatibilité S3Niveau le plus élevé (576 tests s3-tests réussis)
HelmOpérateur Rook disponible
MaturitéNiveau entreprise (éprouvé depuis des années)

Avantages

  • Numéro 1 en compatibilité S3 (prise en charge du plus grand nombre d'API S3)
  • Unifie stockage bloc, fichier et objet
  • Multi-tenancy et isolation par namespace
  • Paramétrage avancé de l'erasure coding
  • Extensible à l'échelle de l'exaoctet

Inconvénients

  • Installation et exploitation complexes
  • Exigences élevées en ressources (minimum 3 noeuds, réseau rapide requis)
  • Courbe d'apprentissage importante

Installation Helm (Rook)

Bash
helm repo add rook-release https://charts.rook.io/release
helm install rook-ceph rook-release/rook-ceph -n rook-ceph --create-namespace
# CephCluster CRD 적용 필요

Référence : Rook Documentation


4. Garage

ÉlémentContenu
Licence⚠️ AGPL-3.0 (même problème que MinIO)
LangageRust
CaractéristiquesLéger, spécialisé dans les déploiements distribués géographiquement
Compatibilité S3Prise en charge des opérations S3 essentielles (fonctions avancées limitées)
HelmChart communautaire
MaturitéAdapté au self-hosting de petite taille

Avantages

  • Léger et économe en ressources
  • Réplication multi-zone/site prise en charge nativement
  • Sûreté mémoire grâce à Rust

Inconvénients

  • Licence AGPL-3.0 (contraintes pour l'usage commercial)
  • Pas d'erasure coding (réplication x3 seulement)
  • Fonctions S3 avancées limitées

Référence : Garage


Comparaison de la compatibilité S3

SolutionTests s3-tests réussisÉvaluation
Ceph RGW576Excellent
Zenko CloudServer382Très bon
MinIO321Correct
SeaweedFS56Basique

SeaweedFS prend parfaitement en charge les opérations S3 essentielles (PUT, GET, DELETE, LIST, etc.), mais les fonctions avancées (Object Lock, Lifecycle, etc.) restent limitées.


Recommandation finale

🥇 SeaweedFS (fortement recommandé)

Pourquoi cette recommandation :

  1. Licence Apache 2.0 - usage commercial entièrement libre
  2. Optimisé pour le stockage média - excellent pour les images, l'audio et la vidéo
  3. Éprouvé en production - grands déploiements validés sur plusieurs années
  4. Compatible Kubernetes - chart Helm officiel et Operator
  5. Tarification raisonnable - gratuit jusqu'à 25 To, puis 1 $/To/mois

🥈 Alternative de second choix

SituationRecommandation
Besoin d'une compatibilité S3 parfaiteCeph RGW (en acceptant la complexité)
Préférence pour les technologies récentes et expérimentalesRustFS (en acceptant la bêta)
Petit périmètre et AGPL acceptableGarage

Guide de configuration d'un CDN Nginx

Exemple de configuration CDN avec la combinaison SeaweedFS + Nginx :

Configuration du cache Nginx

Nginx
# /etc/nginx/nginx.conf

http {
    # 캐시 저장소 설정
    proxy_cache_path /var/cache/nginx/s3
        levels=1:2
        keys_zone=s3_cache:100m
        max_size=50g
        inactive=7d
        use_temp_path=off;

    upstream seaweedfs_s3 {
        server seaweedfs-s3.storage.svc.cluster.local:8333;
        keepalive 64;
    }

    server {
        listen 80;
        server_name cdn.example.com;

        # 이미지 캐싱 (7일)
        location ~* \.(jpg|jpeg|png|gif|webp|ico|svg)$ {
            proxy_pass http://seaweedfs_s3;
            proxy_cache s3_cache;
            proxy_cache_valid 200 7d;
            proxy_cache_valid 404 1m;
            proxy_cache_use_stale error timeout updating;
            proxy_cache_lock on;

            add_header X-Cache-Status $upstream_cache_status;
            add_header Cache-Control "public, max-age=604800";

            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
        }

        # 오디오/비디오 캐싱 (30일)
        location ~* \.(mp3|wav|ogg|mp4|webm|m4a)$ {
            proxy_pass http://seaweedfs_s3;
            proxy_cache s3_cache;
            proxy_cache_valid 200 30d;
            proxy_cache_valid 404 1m;
            proxy_cache_use_stale error timeout updating;
            proxy_cache_lock on;

            add_header X-Cache-Status $upstream_cache_status;
            add_header Cache-Control "public, max-age=2592000";

            # Range 요청 지원 (비디오 스트리밍)
            proxy_set_header Range $http_range;
            proxy_set_header If-Range $http_if_range;

            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
        }

        # 기타 파일
        location / {
            proxy_pass http://seaweedfs_s3;
            proxy_cache s3_cache;
            proxy_cache_valid 200 1d;

            add_header X-Cache-Status $upstream_cache_status;

            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
        }
    }
}

En-têtes d'état du cache

  • HIT : servi depuis le cache
  • MISS : récupéré depuis l'origine
  • STALE : cache expiré servi en cas d'erreur de l'origine
  • UPDATING : rafraîchissement en arrière-plan en cours

Référence : NGINX Caching Guide


Architecture de déploiement Kubernetes

┌─────────────────────────────────────────────────────────────────┐
│                        Kubernetes Cluster                        │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│  ┌──────────────────────────────────────────────────────────┐   │
│  │                    Ingress (Nginx)                        │   │
│  │                   cdn.example.com                         │   │
│  └──────────────────────┬───────────────────────────────────┘   │
│                         │                                        │
│  ┌──────────────────────▼───────────────────────────────────┐   │
│  │              Nginx Cache Layer (CDN)                      │   │
│  │          /var/cache/nginx (PVC: 50Gi+)                   │   │
│  └──────────────────────┬───────────────────────────────────┘   │
│                         │                                        │
│  ┌──────────────────────▼───────────────────────────────────┐   │
│  │                   SeaweedFS                               │   │
│  │  ┌─────────┐  ┌─────────┐  ┌─────────┐  ┌─────────┐      │   │
│  │  │ Master  │  │ Volume  │  │ Volume  │  │ Volume  │      │   │
│  │  │  (x3)   │  │   #1    │  │   #2    │  │   #3    │      │   │
│  │  └────┬────┘  └────┬────┘  └────┬────┘  └────┬────┘      │   │
│  │       │            │            │            │            │   │
│  │  ┌────▼────────────▼────────────▼────────────▼────┐      │   │
│  │  │              Filer (S3 Gateway)                 │      │   │
│  │  │           seaweedfs-s3:8333                     │      │   │
│  │  └─────────────────────────────────────────────────┘      │   │
│  └──────────────────────────────────────────────────────────┘   │
│                                                                  │
│  ┌──────────────────────────────────────────────────────────┐   │
│  │                  Persistent Volumes                       │   │
│  │     Volume #1      Volume #2      Volume #3               │   │
│  │     (100Gi+)       (100Gi+)       (100Gi+)                │   │
│  └──────────────────────────────────────────────────────────┘   │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

Prochaines étapes

  1. Mettre en place l'environnement de test avec le chart Helm SeaweedFS
  2. Tester l'intégration au SDK S3 (vérifier la compatibilité avec le code existant)
  3. Mettre en place la couche de cache Nginx
  4. Réaliser des benchmarks de performance (image, audio, vidéo)
  5. Établir un plan de déploiement en production

Références