Перейти до змісту

Версіонування даних в AI-агентах: практичний досвід з lakeFS

English version available

lakeFS архітектура версіонування

Коли я будував Expert Memory Machine (EMM) - платформу для автоматичної класифікації контенту через LangGraph агентів - все здавалось простим. Агент читає Confluence pages, bookmarks з Firefox, локальні markdown файли, класифікує їх через LLM, і складає в правильні теки Obsidian vault. Що може піти не так?

А потім настав той момент, коли агент переніс важливий research document не в ту теку. І ще один. І видалив файл, який я ще не встиг прочитати. Backups? Звісно є. Але як дізнатись, що саме змінилось вчора? Коли з'явилась ця помилка в класифікації? Хто (який агент) зробив цей коміт?

Git? Файли постійно змінюються агентами, git diff стає нечитабельним, а 10+ комітів на день від ботів засмічують історію. Git LFS? Він для великих файлів, а не для версіонування структури даних.

Тоді я знайшов lakeFS. Git, але для S3. І це змінило підхід до всього проекту.

Чому версіонування даних - це не те саме що Git

Git ідеально працює для коду. Ти робиш коміт, пушиш, агент Jenkins чи GitHub Actions підхоплює, деплоїть. Код не змінюється сам по собі між комітами. Ти контролюєш кожен рядок.

Але з даними все інакше. В EMM є 5,000 markdown файлів в Obsidian vault. Кожен день 10-15 нових. Агенти автоматично класифікують їх і переміщують. Confluence pages синхронізуються. PDFs завантажуються з bookmarks.

Git для цього - це як використовувати молоток для загвинчування шурупів. Технічно можна, але є кращі інструменти.

Проблеми Git для даних (мій досвід):

Перша проблема: розмір репозиторію. Git зберігає всю історію локально. З vault 10GB і 18,000 комітів за 5 років - це вже не смішно. git clone займає години.

Друга проблема: бінарні файли. PDFs, images - Git не вміє робити diff. Кожна версія PDF - це повна копія в історії. 10 версій 50MB файлу = 500MB в .git/objects.

Третя проблема (найбільша для мене): Git не інтегрується з S3. EMM працює з локальними файлами, але продакшн має бути в Kubernetes з persistent storage. S3 - очевидний вибір. А Git S3 не знає.

lakeFS - що це і як працює

lakeFS - це version control для object storage. Уявіть Git, але замість локальної файлової системи - S3 bucket. Замість .git/ теки - PostgreSQL database для metadata. Замість git push - прямий запис в S3, але з версіонуванням.

Архітектурно це виглядає так:

User/Agent → lakeFS API → Storage Adapter → S3/MinIO/GCS/Azure
                   ↓
              PostgreSQL (metadata: commits, branches)

lakeFS сам не зберігає дані. Він керує metadata і дає Git-подібний інтерфейс поверх S3.

Що мене захопило:

Zero-copy branching. Створення гілки в lakeFS займає 1 секунду. Навіть якщо в репозиторію 1TB даних. Чому? Тому що lakeFS не копіює файли - він створює metadata запис "branch X points to commit Y". Ось і все. Branch - це pointer в PostgreSQL.

Для EMM це означає: можу створити feature/test-classifier branch, дати агенту експериментувати з новим LLM prompt, подивитись результат, і якщо не подобається - просто видалити branch. Zero cost. Zero затраченого місця на S3.

Immutable storage. lakeFS ніколи не змінює об'єкти в S3. Якщо файл update - записується новий об'єкт з новим hash. Старий залишається. Це означає: - Повна історія завжди доступна - Rollback - це просто зміна pointer - Аудит trail з коробки

S3 compatibility. lakeFS має S3 Gateway. Boto3 працює з ним як з AWS S3, просто змінюєш endpoint. Існуючий код не потребує змін.

Як це працює внутрі

lakeFS використовує 2-layer Merkle Tree - ту саму структуру що Git, але оптимізовану для масштабу.

Commit → MetaRange (root node)
           └─ Range 1: files "00-09/*"
           └─ Range 2: files "10-19/*" 
           └─ Range 3: files "20-29/*"

Range → SSTable (list of files)
  10-19 Tech/article.md → s3://bucket/data/abc123.../obj1
  10-19 Tech/docker.md → s3://bucket/data/def456.../obj2

Коли ти робиш коміт зі зміною 50 файлів з 10,000 - lakeFS не читає всі 10,000. Він оновлює тільки ті Ranges, де є зміни. Решта Ranges просто reuse з попереднього коміту. Deduplication з коробки.

Time complexity: O(changes), а не O(total size). Це критична різниця для data at scale.

Інтеграція в EMM - чому це не тривіальна задача

Коли я почав інтеграцію lakeFS, здавалось що це буде просто. "Замінити local file system на lakeFS backend" - подумав я. Ага, звісно.

Challenge 1: Obsidian Vault

Obsidian - це desktop app. Він працює з локальними файлами. Пише в них, індексує, робить backlinks. Він не знає що таке lakeFS чи S3.

Перший варіант, який спав на думку - FUSE mount. Є lakefs-fuse, який монтує lakeFS repository як локальну файлову систему. Obsidian бачить звичайну теку, а насправді всі операції йдуть через lakeFS API до S3.

Я навіть почав це реалізовувати. І швидко зрозумів чому це погана ідея:

Latency. Кожен read() - це HTTP request до lakeFS, потім до S3. Obsidian індексує vault при старті - це сотні файлів. Кожен запит - 50-100ms. Множимо на 5,000 файлів - це 4-8 хвилин тільки на індексацію. Неприйнятно.

Offline access. FUSE mount потребує мережі. Без інтернету Obsidian не працює. А я часто працюю в потязі, літаку, в метро.

Write conflicts. Obsidian пише в файл, але одночасно агент теж може писати в той самий файл. FUSE не розв'язує конфлікти. Результат: corrupted files або втрачені зміни.

Рішення: Local Clone + Background Sync

Замість FUSE я зробив hybrid підхід:

  1. Obsidian працює з локальною копією vault. Все як завжди. Zero latency. Повний offline access.
  2. Background sync agent (Python service) синхронізує локальну теку з lakeFS:
  3. Кожні 5 хвилин: git diff локальних змін
  4. Якщо є зміни від користувача: commit + push до lakeFS
  5. Якщо є нові коміти на remote: pull + merge в локальну копію
  6. Агенти пишуть напряму в lakeFS. Вони працюють на сервері, їм не потрібен локальний vault.

Це дало: - Obsidian search залишився instant (локальні файли) - Offline доступ без змін - Automatic versioning для всіх змін - Конфлікти розв'язуються через Git merge стратегії

Challenge 2: Multi-Backend Storage

EMM має різні джерела даних: - Input: UNSORTED тека (local) або S3 bucket з новими файлами - Output: Obsidian vault, може бути local, lakeFS, або напряму S3

Спочатку я хардкодив LocalStorageBackend. Потім додавав костилі для lakeFS. Потім зрозумів що треба абстракція.

Результат - storage_backend.py:

class StorageBackend(ABC):
    @abstractmethod
    def write_file(self, path: str, content: bytes): pass

    @abstractmethod  
    def read_file(self, path: str) -> bytes: pass

class LocalStorageBackend(StorageBackend): ...
class LakeFSStorageBackend(StorageBackend): ...
class S3StorageBackend(StorageBackend): ...

def create_storage_backend(backend_type: str = "output") -> StorageBackend:
    backend = os.getenv(f"{backend_type.upper()}_BACKEND", "local")
    # Returns appropriate backend based on env

Тепер можна конфігурувати:

INPUT_BACKEND=local
INPUT_DIR=/tmp/unsorted
OUTPUT_BACKEND=lakefs
LAKEFS_REPO=emm-vault
LAKEFS_BRANCH=main

Або:

INPUT_BACKEND=s3
S3_BUCKET=emm-incoming
OUTPUT_BACKEND=lakefs

Flexibility без зміни коду агента.

Challenge 3: Де зберігаються дані

Це питання спантеличило мене спочатку. lakectl repo create lakefs://emm-vault - і де це лежить?

Відповідь: команда неповна. Правильно:

lakectl repo create lakefs://emm-vault s3://emm-lakefs-storage/

lakeFS має два шари:

DATA layer: S3 bucket (або S3-compatible: MinIO, Cloudflare R2, GCS). Тут лежать всі файли у вигляді content-addressed objects:

s3://emm-lakefs-storage/
  ├─ data/
  │   ├─ abc123.../object1  ← Ваш article.md
  │   └─ def456.../object2  ← Ваш project.md
  └─ _lakefs/
      └─ ranges/, meta-ranges/ (metadata SSTables)

METADATA layer: PostgreSQL database. Тут branches, commits, refs - вся Git-подібна інформація. ~200MB для 18,000 комітів через 5 років.

Для development я використав MinIO в Docker Compose:

services:
  minio:
    image: minio/minio
    volumes:
      - minio-lakefs-data:/data
    ports:
      - "9000:9000"
      - "9001:9001"

Cost: $0. Storage: ваш laptop SSD.

Для production планую Cloudflare R2: - $0.015/GB/month (50% дешевше AWS S3) - Zero egress fees (AWS бере $0.09/GB за download) - S3-compatible API (boto3 works)

Для 10GB vault + 5GB traffic/month: - R2: $0.18/month - AWS S3: $0.69/month

R2 на 74% дешевше. І це без урахування egress, де різниця ще драматичніша.

Практична імплементація

Створення lakefs_backend.py зайняло день. lakeFS має REST API, але офіційного Python SDK ще немає. Довелось писати свій wrapper:

class LakeFSBackend:
    def __init__(self, endpoint: str, access_key: str, secret_key: str, 
                 repo: str, branch: str):
        self.endpoint = endpoint.rstrip("/")
        self.repo = repo
        self.branch = branch
        self.session = requests.Session()
        self.session.auth = (access_key, secret_key)

    def write_file(self, path: str, content: bytes) -> dict:
        url = f"{self.endpoint}/api/v1/repositories/{self.repo}/branches/{self.branch}/objects"
        params = {"path": path}
        response = self.session.post(url, params=params, data=content)
        response.raise_for_status()
        return response.json()

    def commit(self, message: str, metadata: dict = None) -> dict:
        url = f"{self.endpoint}/api/v1/repositories/{self.repo}/branches/{self.branch}/commits"
        payload = {"message": message, "metadata": metadata or {}}
        response = self.session.post(url, json=payload)
        response.raise_for_status()
        return response.json()

Нічого складного, але дві деталі виявились важливими:

Session reuse. requests.Session() підтримує connection pooling. Перший запит: TCP handshake + TLS negotiation = 300ms. Наступні запити через ту саму сесію: 0ms overhead. Для batch операцій (50 файлів) це дає 70% speedup.

Automatic retries. S3 може дати transient error. lakeFS теж. Треба retry logic:

from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry

retry_strategy = Retry(
    total=3,
    backoff_factor=1,  # 1s, 2s, 4s
    status_forcelist=[429, 500, 502, 503, 504]
)
adapter = HTTPAdapter(max_retries=retry_strategy)
self.session.mount("http://", adapter)
self.session.mount("https://", adapter)

Це врятувало мене від десятків падінь агента через тимчасові network glitches.

Testing - локальний setup

Я не хотів чекати production deployment щоб протестувати lakeFS. Docker Compose дав все що треба:

services:
  postgres:
    image: postgres:14
    environment:
      POSTGRES_DB: lakefs
      POSTGRES_USER: lakefs
      POSTGRES_PASSWORD: lakefs_password
    volumes:
      - postgres-lakefs-data:/var/lib/postgresql/data

  minio:
    image: minio/minio
    command: server /data --console-address ":9001"
    volumes:
      - minio-lakefs-data:/data

  lakefs:
    image: treeverse/lakefs:latest
    depends_on:
      - postgres
      - minio
    environment:
      LAKEFS_DATABASE_TYPE: postgres
      LAKEFS_DATABASE_POSTGRES_CONNECTION_STRING: postgres://lakefs:lakefs_password@postgres:5432/lakefs
      LAKEFS_BLOCKSTORE_TYPE: s3
      LAKEFS_BLOCKSTORE_S3_CREDENTIALS_ACCESS_KEY_ID: minioadmin
      LAKEFS_BLOCKSTORE_S3_CREDENTIALS_SECRET_ACCESS_KEY: minioadmin123
      LAKEFS_BLOCKSTORE_S3_ENDPOINT: http://minio:9000
    ports:
      - "8000:8000"

docker-compose up -d - і через 30 секунд маєш повноцінний lakeFS локально. Web UI на http://localhost:8000, MinIO console на http://localhost:9001.

Перший тест був простий - upload, read, commit:

# test_local_setup.py
backend = LakeFSBackend(
    endpoint="http://localhost:8000",
    access_key=os.getenv("LAKEFS_ACCESS_KEY_ID"),
    secret_key=os.getenv("LAKEFS_SECRET_ACCESS_KEY"),
    repo="emm-vault",
    branch="main"
)

# Write file
backend.write_file("test.md", b"Hello from lakeFS!")

# Commit
backend.commit("Add test file")

# Read back
content = backend.read_file("test.md")
assert content == b"Hello from lakeFS!"

Працює. Далі додав tests для branches, diff, merge - все працює як заявлено.

Capacity, Limits, Network - що треба знати

Перше питання яке я поставив собі: а чи потягне lakeFS мій vault? 10GB зараз, ~17GB через 5 років (з versions).

File size limits

Backend визначає максимальний розмір файлу: - AWS S3: 50 TB per object (оновлено December 2025, було 5 TB) - Cloudflare R2: 5 TB per object - MinIO: 48 PB (petabytes!) through multipart upload

Мій largest file: ~100 MB (PDF). Safety margin: 50,000x. Не проблема.

Multipart upload (для файлів > 5GB) автоматично handling через boto3. Файли < 100MB використовують single-part upload - простіше і швидше.

Total storage

lakeFS обмежень не має - це визначає backend.

AWS S3: unlimited Cloudflare R2: unlimited MinIO: обмежений розміром диска

Мій vault projection на 5 років: - Year 0: 10 GB - Year 5: 17 GB (з version history + branches)

Backend capacity: unlimited. PostgreSQL metadata: ~200 MB. Це negligible.

Network bandwidth

Найбільше турбувало мене: чи потягне residential internet daily sync?

Типовий день: - 10 нових/змінених файлів - 500 KB average size - Total: 5 MB upload

На 10 Mbps з'єднанні: ~4 секунди. На 100 Mbps: < 0.5 секунди. Це acceptable.

Initial upload (10 GB vault) - інша історія: - @ 10 Mbps: 2.5 години - @ 100 Mbps: 15 хвилин

Рішення: run overnight або на швидкому з'єднанні (office, coffee shop). Це one-time operation.

Для Obsidian з local clone: bandwidth не потрібен взагалі. Search instant, все працює offline.

Production architecture - Kubernetes deployment

Phase 1 (testing): Docker Compose локально. Phase 3 (production): Kubernetes.

Kubernetes setup має 3 компоненти:

lakeFS Pod:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: lakefs
spec:
  replicas: 1  # Stateless, can scale to 3+
  template:
    spec:
      containers:
      - name: lakefs
        image: treeverse/lakefs:1.73
        resources:
          requests:
            memory: "4Gi"
            cpu: "2"
          limits:
            memory: "8Gi"
            cpu: "4"
        env:
        - name: LAKEFS_DATABASE_TYPE
          value: "postgres"
        - name: LAKEFS_DATABASE_POSTGRES_CONNECTION_STRING
          valueFrom:
            secretKeyRef:
              name: lakefs-secrets
              key: postgres-connection-string
        - name: LAKEFS_BLOCKSTORE_TYPE
          value: "s3"
        - name: LAKEFS_BLOCKSTORE_S3_ENDPOINT
          valueFrom:
            configMapKeyRef:
              name: lakefs-config
              key: s3-endpoint
        livenessProbe:
          httpGet:
            path: /_health
            port: 8000
          initialDelaySeconds: 30
          periodSeconds: 10

Stateless design означає: можна scale horizontally. 1 pod витримує 10k req/s. Якщо треба більше - просто додаєш replicas.

PostgreSQL - managed service:

Спочатку думав про self-hosted PostgreSQL в Kubernetes (StatefulSet). Потім порахував: - Треба backups - Треба реплікація для HA - Треба monitoring - Треба updates, security patches

AWS RDS PostgreSQL t4g.micro: - 1GB RAM, 20GB SSD - Автоматичні backups (35 днів retention) - Multi-AZ replication option - Automated patching - Cost: ~$12/month

Managed service за $12/month vs. 10+ годин роботи на self-hosted setup? Вибір очевидний.

Cloudflare R2 - storage backend:

MinIO добре працює локально. Але в production є нюанс: AGPLv3 license. Якщо деплоїш MinIO доступний через мережу - треба open-source свої зміни в коді. Для enterprise це red flag.

Cloudflare R2: - S3-compatible (boto3 works без змін) - $0.015/GB/month storage - Zero egress fees - Managed service (no ops overhead)

Setup:

# agents/file-system-agent/storage_backend.py
class S3StorageBackend(StorageBackend):
    def __init__(self):
        self.s3_client = boto3.client(
            "s3",
            endpoint_url=os.getenv("S3_ENDPOINT"),  # R2 endpoint
            aws_access_key_id=os.getenv("S3_ACCESS_KEY_ID"),
            aws_secret_access_key=os.getenv("S3_SECRET_ACCESS_KEY"),
            region_name=os.getenv("S3_REGION", "auto")
        )
        self.bucket = os.getenv("S3_BUCKET")

Environment variables:

S3_ENDPOINT=https://[account-id].r2.cloudflarestorage.com
S3_ACCESS_KEY_ID=your_r2_key
S3_SECRET_ACCESS_KEY=your_r2_secret
S3_BUCKET=emm-lakefs-storage
S3_REGION=auto

Boto3 думає що працює з AWS S3. Насправді це R2. API identical.

Technology risk - що може піти не так

Коли інтегруєш нову dependency в production, треба думати: а що якщо вона зникне через 3 роки?

Я проаналізував ризики для трьох компонентів:

PostgreSQL: 🟢 дуже низький ризик

  • Age: 35+ years (since 1986)
  • Backing: PostgreSQL Global Development Group + Enterprise sponsors
  • Adoption: top-3 database worldwide
  • Alternatives: MySQL, MariaDB (easy migration)

Якщо PostgreSQL зникне - ми всі маємо більші проблеми ніж EMM. This won't happen.

MinIO: 🟡 середній ризик

MinIO поміняв ліцензію з Apache 2.0 на AGPLv3 в 2021. Це проблема для network-deployed services - треба open-source весь код.

Alternatives: - AWS S3 (managed, expensive egress) - Cloudflare R2 (managed, zero egress) ← використовую - Google Cloud Storage (managed, expensive)

Migration plan: S3-compatible API означає що можна switch backends без code changes. Потрібен лише новий endpoint і credentials.

Тому для Phase 1 (local development) використовую MinIO. Для Phase 3 (production) - Cloudflare R2. No AGPLv3 complications.

lakeFS: 🟡 вищий ризик (молода компанія)

lakeFS - це startup. Founded 2020, $31M funding (Series B). Це не AWS чи Google.

Pros: - Production adoption: Lockheed Martin, NASA, Microsoft, Adobe - Open-source (Apache 2.0) - Active development (commits кожен день) - Enterprise support available

Cons: - Невелика команда (~50 people) - Залежність від VC funding - Project maturity: 5 років (vs Git 20+ years)

Mitigation strategy:

Data ownership: Дані в S3, metadata в PostgreSQL - обидва standard formats. Якщо lakeFS зникне - можна відновити vault вручну або написати migration script. Ти не locked in proprietary format.

Fallback plan: Якщо lakeFS стане unmaintained - можна: 1. Freeze на останній стабільній версії (self-host) 2. Fork repository (Apache 2.0 license) 3. Migrate до DVC (Data Version Control) - альтернатива з подібним API 4. Fallback до direct S3 + Git для metadata

Monitoring: Створив monitor_tech_health.py - script який кожні 6 місяців чекає GitHub metrics: stars, commits, releases, contributors. Early warning system якщо project стає unmaintained.

Reliability score для lakeFS: 7.35/10. Production-ready, але з monitoring і fallback plan.

Performance benchmarks - реальні цифри

Теоретично lakeFS каже 100k req/s. Практично - скільки?

Я запустив benchmark на локальному Docker Compose setup (laptop MacBook Pro M1, 16GB RAM):

Write performance (batch upload 100 files, 500KB each):

Sequential writes (one by one):
  Time: 24.3 seconds
  Throughput: 4.1 files/second
  Network: ~2 MB/s

Parallel writes (10 threads):
  Time: 3.8 seconds  
  Throughput: 26.3 files/second
  Network: ~13 MB/s

Commit after upload:
  Time: 0.8 seconds
  (Processing 100 changed files)

Висновок: паралелізація критична. 10 threads дали 6x speedup.

Read performance (random access pattern):

Sequential reads (100 files):
  Time: 8.2 seconds
  Throughput: 12.2 files/second

Parallel reads (10 threads):
  Time: 1.4 seconds
  Throughput: 71.4 files/second

Cached reads (repeat access):
  Time: 0.3 seconds
  Throughput: 333 files/second

lakeFS cache працює. Repeat access на порядок швидший.

Branch operations:

Create branch (zero-copy):
  Time: 0.12 seconds
  Storage overhead: ~1 KB metadata

Commit (50 changed files from 5,000):
  Time: 1.8 seconds
  Complexity: O(changes), not O(total)

Merge (3-way, 100 changes, no conflicts):
  Time: 2.4 seconds

Diff (two branches, 200 changes):
  Time: 0.6 seconds

Branch creation практично instant. Commits швидкі навіть для великого repository.

Bottlenecks

Найповільніше - initial upload. 10GB vault: - @ 10 Mbps residential: 2.5 години - @ 100 Mbps: 15 хвилин

Це не lakeFS bottleneck - це network bandwidth. lakeFS на localhost показує 500+ MB/s throughput (обмежений SSD speed).

Lessons learned - що я зробив би інакше

1. Start with capacity planning

Я почав coding перш ніж подумав про limits. Потім довелось перевіряти: - Чи потягне S3 мої файли? (Так, 50TB limit vs мої 100MB max) - Чи вистачить bandwidth? (Так, 5MB/day на 10 Mbps = 4 секунди) - Чи PostgreSQL впорається? (Так, 200MB metadata vs 32TB limit)

Треба було почати з цього. Зекономив би день на unnecessary concerns.

2. Don't use FUSE mount for desktop apps

FUSE здається attractive - "просто mount і все працює". Але latency та offline issues роблять його непрактичним для Obsidian.

Local clone + background sync - правильний підхід. Desktop app працює як завжди, versioning happens у background.

3. Abstract storage backends early

Я почав з LocalStorageBackend hardcoded скрізь. Потім рефакторив до абстракції. Треба було робити storage_backend.py з самого початку.

Interface abstraction дає flexibility без rewrite коду.

4. Use managed services where possible

PostgreSQL, S3/R2 - managed services. lakeFS - self-hosted, але stateless (easy to deploy/scale).

Managed services коштують $10-20/month але економлять дні/тижні ops роботи. Для MVP це trade-off який варто робити.

5. Test network scenarios realistically

Я тестував на localhost (10GB/s throughput). Production використовує internet (10-100 Mbps). Різниця в 100-1000x.

Треба benchmark на realistic network conditions. Я використав tc (traffic control) на Linux для throttling bandwidth:

tc qdisc add dev eth0 root tbf rate 10mbit burst 32kbit latency 400ms

Це симулює 10 Mbps connection. Результат: initial upload стає bottleneck. Daily sync - OK.

Де проект зараз і що далі

Phase 1 (local testing): завершено. Docker Compose setup works, tests pass, documentation written.

Створено: - lakefs_backend.py - REST API client (450 lines) - storage_backend.py - multi-backend abstraction (400 lines) - docker-compose.yml - local development environment - test_local_setup.py - 7 integration tests - demo_multi_backend.py - showcase multi-backend storage

Documentation (2,000+ lines): - ARCHITECTURE_GUIDE.md - lakeFS internals - CAPACITY_LIMITS_GUIDE.md - storage limits & network - STORAGE_LOCATION_GUIDE.md - where data actually lives - OBSIDIAN_LAKEFS_WORKFLOW.md - Obsidian integration design - TECHNOLOGY_RISK_ANALYSIS.md - PostgreSQL/MinIO/lakeFS risks

Phase 2 (development): - Create vault-sync-agent (Python service for Obsidian background sync) - Integrate storage_backend into file-system-agent graph.py - MCP handler for lakeFS operations - Unit tests for all backends

Phase 3 (production): - Kubernetes manifests (lakeFS, RDS, R2 config) - Prometheus metrics + Grafana dashboards - DR testing (disaster recovery) - Migration from MinIO to R2 - Documentation for operations team

Чи варто використовувати lakeFS?

Для EMM - так. Аргументи:

Git-like workflow для даних. Branches для experimentation, commits для history, merges для testing changes. Агенти роблять mistakes - можна rollback.

S3 compatibility. Boto3 works, existing tools work, easy integration.

Zero-copy branches. Можу створити test environment за 1 секунду, прогнати новий classifier, і якщо не працює - видалити branch. Zero cost.

Immutable audit trail. Кожна зміна recorded. Compliance requirements - satisfied.

Cloud-native. Stateless architecture, Kubernetes-ready, horizontal scaling.

Cost-efficient. ~$17/month для production (lakeFS + RDS + R2) vs ~$50+ для self-hosted альтернатив.

Але є нюанси. lakeFS - молодий project. Reliability score 7.35/10. Для mission-critical systems треба HA setup і monitoring. Для EMM (personal project, 1-2 users) - single-pod deployment достатньо.

Висновки з досвіду

Версіонування даних - це не те саме що версіонування коду. Git не підходить. Треба tool який розуміє object storage, працює з S3, і масштабується до terabytes.

lakeFS дає Git-подібний UX поверх S3. Zero-copy operations, immutable storage, S3 compatibility. Architecture продумана: stateless compute, managed database, cloud object storage.

Інтеграція займає час. Local clone для desktop apps (Obsidian). Multi-backend abstraction для flexibility. Managed services для PostgreSQL і S3. Realistic network testing для bandwidth planning.

Документація та risk analysis важливі. Треба розуміти де зберігаються дані (DATA в S3, METADATA в PostgreSQL), які limits (5-50TB per file, unlimited storage), які ризики (молодий project - monitoring + fallback plan).

Для EMM це був правильний вибір. Git-like versioning для vault, zero-copy experiments, S3-compatible storage, ~$17/month production cost. Phase 1 working, Phase 3 architecture ready.

Якщо будуєте систему де AI-агенти працюють з даними - подумайте про versioning з першого дня. Rollback mistakes, audit trail, experiment safely. lakeFS дає це з коробки.


Related: Kubernetes deployment для AI-агентів, Розробка та тестування AI-агентів


Source code: github.com/igorgorovoy/agentic-ai-landing-zone
lakeFS: lakefs.io | docs.lakefs.io


Author: Igor Gorovyy
Role: DevOps Engineer Lead & Senior Solutions Architect
LinkedIn: linkedin.com/in/gorovyyigor

Technical specifications

  • Python: 3.12+
  • lakeFS: 1.73+
  • Storage backends: Local FS, AWS S3, Cloudflare R2, MinIO
  • Metadata: PostgreSQL 14+
  • Deployment: Docker Compose (dev), Kubernetes (prod)
  • Cost: $0 (local), ~$17/month (production)