À quoi ça sert

MinIO fait la même chose qu'Amazon S3 — stocker des fichiers (« objets ») dans des « buckets » accessibles par HTTP — mais chez toi. Même API, mêmes commandes, mêmes SDK. Tu peux développer en local contre MinIO puis pointer la même appli sur S3 en prod sans rien changer.

  • Backend de stockage pour MLflow — datasets, artefacts, poids de modèles versionnés.
  • Stockage de datasets — images, vidéos, audios trop gros pour Git ou une base SQL.
  • Backups — dumps de base, snapshots, archives.
  • Partage entre services — une API dépose un fichier, un worker le récupère plus tard.
  • CDN privé — servir des assets web (images, vidéos).
Stockage objet vs fichier vs bloc

Le stockage fichier (NFS, disque local) organise les données en arborescence avec des permissions Unix. Le stockage bloc (SSD, EBS) expose des volumes bruts qu'on formate. Le stockage objet — la spécialité de MinIO et S3 — voit chaque fichier comme un « objet » identifié par une clé, accédé en HTTP, sans hiérarchie réelle de dossiers. C'est le modèle qui scale le mieux pour des milliards de fichiers et qui est devenu le standard du cloud.

Le concept S3 en 3 termes

  • Bucket — un « dossier racine » qui contient des objets. Tu en crées un par usage (datasets, mlflow, backups). Son nom est unique sur le serveur.
  • Objet — un fichier dans un bucket, identifié par une clé (qui peut contenir des / simulant des dossiers, mais ce n'est qu'un préfixe textuel).
  • Access Key + Secret Key — l'identifiant et le mot de passe utilisés par les SDK pour s'authentifier (équivalent login/password pour HTTP basic, mais utilisé dans tous les SDK S3).
« Compatible S3 » — pourquoi c'est puissant

Amazon a publié l'API de S3 sans la breveter, et tout l'écosystème cloud s'est aligné dessus. Du coup MinIO, Backblaze B2, Cloudflare R2, Wasabi, OVH Object Storage parlent la même langue. Tu écris ton code avec le SDK boto3 (Amazon) ou minio, et tu changes juste l'URL pour basculer d'un fournisseur à l'autre.

Un exemple d'usage

Démarrer MinIO en local avec Docker et y déposer un fichier en 3 minutes :

bash
# 1. Lancer le serveur MinIO
docker run -d --name minio \
  -p 9000:9000 -p 9001:9001 \
  -e MINIO_ROOT_USER=admin \
  -e MINIO_ROOT_PASSWORD=adminadmin \
  -v minio-data:/data \
  quay.io/minio/minio server /data --console-address ":9001"

Tu accèdes ensuite à la console web sur http://localhost:9001 (login admin / adminadmin), tu crées un bucket à la souris, et tu y déposes un fichier. L'API S3 elle-même tourne sur le port 9000.

Depuis Python, on uploade un fichier en quelques lignes :

python
from minio import Minio

client = Minio(
    "localhost:9000",
    access_key="admin",
    secret_key="adminadmin",
    secure=False,           # pas de TLS en local
)

# Créer un bucket s'il n'existe pas
if not client.bucket_exists("datasets"):
    client.make_bucket("datasets")

# Uploader un fichier
client.fput_object("datasets", "images/chat.jpg", "./chat.jpg")

How-to : installer et utiliser MinIO

  1. Lancer MinIO avec Docker Compose

    En pratique on utilise Docker Compose pour faire tourner MinIO durablement, avec un volume persistant.

    yaml (docker-compose.yml)
    services:
      minio:
        image: quay.io/minio/minio:latest
        command: server /data --console-address ":9001"
        ports:
          - "9000:9000"     # API S3
          - "9001:9001"     # Console web
        environment:
          MINIO_ROOT_USER: admin
          MINIO_ROOT_PASSWORD: adminadmin
        volumes:
          - minio-data:/data
        restart: unless-stopped
    
    volumes:
      minio-data:
    bash
    docker compose up -d
    Choisir un mot de passe sérieux dès le départ

    MinIO refuse de démarrer si le mot de passe fait moins de 8 caractères. En prod, mets-les dans un .env (jamais dans le YAML committé). Le compte MINIO_ROOT_USER est root, équivalent à un administrateur S3.

  2. Créer un bucket via la console web

    Ouvre http://localhost:9001, connecte-toi, puis Buckets → Create Bucket. Donne un nom (en minuscules, sans espaces : mlflow-artifacts, datasets). C'est le moyen le plus simple pour démarrer.

  3. Créer des access keys dédiées

    Plutôt que de partager le compte root, on crée des paires access key / secret key par application : Access Keys → Create Access Key. Tu obtiens deux chaînes à passer à ton SDK. On peut limiter leurs permissions par policy (lecture seule, accès à un bucket précis…).

  4. Installer un client Python

    Deux options : la lib officielle minio (légère, axée MinIO mais marche aussi sur S3), ou boto3 (AWS, plus répandue, marche aussi sur MinIO). On reste dans la logique UV.

    bash
    uv add minio       # client officiel MinIO
    # ou
    uv add boto3       # SDK AWS, fonctionne aussi sur MinIO
  5. Uploader, lister, télécharger des objets

    python (lib minio)
    from minio import Minio
    
    client = Minio(
        "localhost:9000",
        access_key="admin",
        secret_key="adminadmin",
        secure=False,
    )
    
    # Uploader un fichier local
    client.fput_object("datasets", "img/01.jpg", "./01.jpg")
    
    # Lister les objets d'un bucket
    for obj in client.list_objects("datasets", recursive=True):
        print(obj.object_name, obj.size)
    
    # Télécharger
    client.fget_object("datasets", "img/01.jpg", "./local.jpg")
    
    # Supprimer
    client.remove_object("datasets", "img/01.jpg")

    Avec boto3, la même chose mais syntaxe AWS :

    python (boto3)
    import boto3
    
    s3 = boto3.client(
        "s3",
        endpoint_url="http://localhost:9000",
        aws_access_key_id="admin",
        aws_secret_access_key="adminadmin",
    )
    
    s3.upload_file("./01.jpg", "datasets", "img/01.jpg")
    s3.download_file("datasets", "img/01.jpg", "./local.jpg")
  6. Générer une URL temporaire (presigned URL)

    Un cas très courant : tu veux qu'un utilisateur puisse télécharger un fichier privé pendant 1 heure, sans lui donner les credentials. MinIO sait générer une URL signée qui expire :

    python
    from datetime import timedelta
    
    url = client.presigned_get_object(
        "datasets",
        "img/01.jpg",
        expires=timedelta(hours=1),
    )
    print(url)   # http://localhost:9000/datasets/img/01.jpg?X-Amz-...

    On utilise la même méthode presigned_put_object() pour autoriser un upload — l'utilisateur peut alors envoyer son fichier directement à MinIO sans transiter par ton API.

  7. Le client en ligne de commande (mc)

    MinIO fournit un CLI mc très pratique pour les opérations d'admin (un peu comme aws s3 pour AWS). On le lance dans un conteneur :

    bash
    # Enregistrer le serveur sous l'alias "local"
    docker run --rm --network host \
      quay.io/minio/mc alias set local http://localhost:9000 admin adminadmin
    
    # Lister les buckets
    docker run --rm --network host quay.io/minio/mc ls local
    
    # Copier un dossier entier
    docker run --rm -v $(pwd):/data --network host \
      quay.io/minio/mc cp --recursive /data/photos local/datasets/

Aide-mémoire

python (client minio)
client.make_bucket("bucket")
client.bucket_exists("bucket")
client.list_buckets()
client.fput_object("b", "key", "./file")
client.fget_object("b", "key", "./out")
client.list_objects("b", recursive=True)
client.remove_object("b", "key")
client.presigned_get_object("b", "key", expires=timedelta(hours=1))
bash (mc — admin)
mc alias set local http://localhost:9000 admin pass
mc ls local                          # liste buckets
mc ls local/bucket --recursive
mc cp ./file local/bucket/key
mc cp --recursive ./folder local/bucket/
mc mirror ./local local/bucket       # sync (rsync-like)
mc rm local/bucket/key
mc admin info local                  # état du serveur
env vars (config app)
MINIO_ENDPOINT=http://minio:9000
MINIO_ACCESS_KEY=...
MINIO_SECRET_KEY=...
MINIO_BUCKET=mlflow-artifacts

MinIO et le reste de l'écosystème

  • MLflow — le combo le plus classique en MLOps. MLflow stocke ses artefacts (modèles, métriques, plots) dans MinIO en pointant MLFLOW_S3_ENDPOINT_URL vers ton instance.
  • Docker — MinIO se déploie toujours en conteneur, c'est la façon de l'installer en pratique. Image officielle quay.io/minio/minio.
  • FastAPI — pattern classique : ton API reçoit un upload, l'envoie à MinIO via boto3, stocke seulement la clé en base. Pour les gros fichiers, on donne plutôt une presigned URL au client pour qu'il uploade directement.
  • Kubernetes — MinIO publie un opérateur K8s pour gérer des clusters multi-nœuds en mode distribué (haute dispo, erasure coding).
  • Prefect — utilise MinIO comme storage block pour ses résultats de flows et ses artefacts (logs, plots générés par une tâche).
En prod : single node ou cluster ?

Un seul conteneur MinIO suffit pour dev, perso, ou petite équipe. En production sérieuse, on déploie un cluster multi-nœuds avec erasure coding : MinIO découpe chaque objet en morceaux avec redondance, ce qui permet de perdre plusieurs disques sans perdre les données. C'est ce qui rend MinIO viable en alternative à S3 pour des gros volumes.

Pour aller plus loin