mirror of
https://github.com/KohakuBlueleaf/KohakuHub.git
synced 2026-07-23 14:31:41 -05:00
Introduces the prerequisite cache layer tracked in #73. No business code yet consumes the helpers — this is plumbing only, gated by KOHAKU_HUB_CACHE_ENABLED (default: false). Subsequent issues will adopt specific cache patterns on top of this foundation. Why now: every hot read endpoint currently makes 1–3 LakeFS REST calls plus several Postgres queries per request, with the only existing cache being a per-process cachetools.TTLCache in fallback/cache.py — useless across the default 4-worker uvicorn deployment. Design highlights (full design in docs/development/cache.md): - Pure cache, no source-of-truth state. Silent-degradation contract: every cache call is wrapped in try/except and falls back to L3 when Valkey is unreachable. CI runs a dedicated cache-disabled job to regression-guard this. - L1 (per-worker cachetools) restricted to immutable / content-addressed data only — multi-worker uvicorn has no portable cross-worker invalidation channel, and constraining L1 to "key contains its own version" sidesteps that entirely. - L2 (Valkey) holds everything. Helpers ship with TTL jitter (±15% default), two-level singleflight (asyncio.Lock + Valkey SET NX EX), negative cache, generation counters, and per-namespace metrics. - Persistence: RDB on, AOF off, persistent volume. Mode-A (lakefs:commit, lakefs:stat, lakefs:list — commit_id-keyed) survives restart safely. Mode-B (mutable) namespaces are flushed on every Valkey restart by a run_id-based bootstrap coordinator that serializes the flush across workers. Includes: - src/kohakuhub/cache.py — the helper module (319 stmts, 83% coverage via the new test module). - src/kohakuhub/api/admin/routers/cache.py — admin endpoints exposing hit/miss/error counters, Valkey memory state, and bootstrap-flush metadata. - test/kohakuhub/test_cache.py — 34 tests against a real Valkey, covering: round-trips, TTL jitter spread, SCAN-based prefix delete over >SCAN_BATCH_SIZE keys, two-level singleflight (100 concurrent calls fold to 1 fetch), bootstrap flush selectivity (Mode-A survives, Mode-B is wiped, exactly), two-worker bootstrap coordination, silent degradation when Valkey is disabled OR unreachable, generation counters, negative cache, the Mode-B prefix list shape contract. - docker-compose.example.yml — adds the valkey service with RDB + LFU + bind-mounted hub-meta/valkey-data, mirroring the persistence pattern of the other stateful services. - scripts/dev/up_infra.sh / down_infra.sh / reset_local_data.sh — Valkey container plumbing for local dev (host port 26379). - .github/workflows/fullstack-tests.yml — adds valkey to the existing matrix services and adds a separate single-Python job (backend-tests-cache-disabled) running with KOHAKU_HUB_CACHE_ENABLED=false as the silent-degradation contract regression guard. - docs/development/cache.md — the design doc referenced by the cache module's docstrings. Refs: #73 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
196 lines
7.8 KiB
YAML
196 lines
7.8 KiB
YAML
# docker-compose.yml - Example configuration for KohakuHub
|
|
# Copy this to docker-compose.yml and customize for your deployment
|
|
|
|
services:
|
|
hub-ui:
|
|
image: nginx:alpine
|
|
container_name: hub-ui
|
|
restart: always
|
|
ports:
|
|
- "28080:80" # Public web interface
|
|
volumes:
|
|
- ./src/kohaku-hub-ui/dist:/usr/share/nginx/html
|
|
- ./src/kohaku-hub-admin/dist:/usr/share/nginx/html-admin
|
|
- ./docker/nginx/default.conf:/etc/nginx/conf.d/default.conf
|
|
depends_on:
|
|
- hub-api
|
|
|
|
hub-api:
|
|
build: .
|
|
container_name: hub-api
|
|
restart: always
|
|
ports:
|
|
- "48888:48888" # Internal API port (optional, for debugging)
|
|
depends_on:
|
|
- postgres
|
|
- lakefs
|
|
- minio
|
|
- valkey
|
|
environment:
|
|
## ===== CRITICAL: Endpoint Configuration (MUST CHANGE) =====
|
|
## These determine how users access your KohakuHub instance
|
|
- KOHAKU_HUB_BASE_URL=http://127.0.0.1:28080 # Change to your public URL (e.g., https://hub.example.com)
|
|
- KOHAKU_HUB_S3_PUBLIC_ENDPOINT=http://127.0.0.1:29001 # Change to your S3 public URL
|
|
|
|
## ===== CRITICAL: Security Configuration (MUST CHANGE) =====
|
|
- KOHAKU_HUB_SESSION_SECRET=change-this-to-random-string-in-production
|
|
- KOHAKU_HUB_ADMIN_SECRET_TOKEN=change-this-to-random-admin-token-in-production
|
|
- KOHAKU_HUB_DATABASE_KEY=change-this-to-random-encryption-key-in-production # For external tokens (generate with: openssl rand -hex 32)
|
|
|
|
## ===== Performance Configuration =====
|
|
- KOHAKU_HUB_WORKERS=4 # Number of worker processes (1-8, recommend: CPU cores)
|
|
|
|
## ===== Database Configuration =====
|
|
- KOHAKU_HUB_DB_BACKEND=postgres
|
|
- KOHAKU_HUB_DATABASE_URL=postgresql://<user>:<password>@postgres:5432/kohakuhub
|
|
- KOHAKU_HUB_AUTO_MIGRATE=true # Auto-confirm database migrations (required for Docker)
|
|
|
|
## ===== S3 Storage Configuration =====
|
|
- KOHAKU_HUB_S3_ENDPOINT=http://minio:9000
|
|
- KOHAKU_HUB_S3_ACCESS_KEY=minioadmin
|
|
- KOHAKU_HUB_S3_SECRET_KEY=minioadmin
|
|
- KOHAKU_HUB_S3_BUCKET=hub-storage
|
|
- KOHAKU_HUB_S3_REGION=us-east-1 # S3 region (us-east-1 for MinIO, auto for R2, or specific AWS region)
|
|
# - KOHAKU_HUB_S3_SIGNATURE_VERSION=s3v4 # Uncomment for R2/AWS S3 (leave commented for MinIO default)
|
|
|
|
## ===== LakeFS Configuration =====
|
|
- KOHAKU_HUB_LAKEFS_ENDPOINT=http://lakefs:28000
|
|
- KOHAKU_HUB_LAKEFS_REPO_NAMESPACE=hf
|
|
# LakeFS credentials auto-generated on first start
|
|
|
|
## ===== Application Configuration =====
|
|
- KOHAKU_HUB_SITE_NAME=KohakuHub
|
|
- KOHAKU_HUB_LFS_THRESHOLD_BYTES=1000000
|
|
- KOHAKU_HUB_LFS_MULTIPART_THRESHOLD_BYTES=100_000_000 # 100MB - use multipart for files larger than this
|
|
- KOHAKU_HUB_LFS_MULTIPART_CHUNK_SIZE_BYTES=50_000_000 # 50MB - size of each part (min 5MB except last)
|
|
- KOHAKU_HUB_LFS_KEEP_VERSIONS=5
|
|
- KOHAKU_HUB_LFS_AUTO_GC=true
|
|
|
|
## ===== Auth & SMTP Configuration =====
|
|
- KOHAKU_HUB_REQUIRE_EMAIL_VERIFICATION=false
|
|
- KOHAKU_HUB_INVITATION_ONLY=false # Set to true to require invitation for registration
|
|
- KOHAKU_HUB_SESSION_EXPIRE_HOURS=168
|
|
- KOHAKU_HUB_TOKEN_EXPIRE_DAYS=365
|
|
- KOHAKU_HUB_ADMIN_ENABLED=true
|
|
# SMTP (Optional - for email verification)
|
|
- KOHAKU_HUB_SMTP_ENABLED=false
|
|
- KOHAKU_HUB_SMTP_HOST=smtp.gmail.com
|
|
- KOHAKU_HUB_SMTP_PORT=587
|
|
- KOHAKU_HUB_SMTP_USERNAME=
|
|
- KOHAKU_HUB_SMTP_PASSWORD=
|
|
- KOHAKU_HUB_SMTP_FROM=noreply@kohakuhub.local
|
|
- KOHAKU_HUB_SMTP_TLS=true
|
|
|
|
## ===== Storage Quota Configuration (Optional) =====
|
|
- KOHAKU_HUB_DEFAULT_USER_PRIVATE_QUOTA_BYTES=10_000_000
|
|
- KOHAKU_HUB_DEFAULT_USER_PUBLIC_QUOTA_BYTES=100_000_000
|
|
- KOHAKU_HUB_DEFAULT_ORG_PRIVATE_QUOTA_BYTES=10_000_000
|
|
- KOHAKU_HUB_DEFAULT_ORG_PUBLIC_QUOTA_BYTES=100_000_000
|
|
|
|
## ===== Fallback Configuration (Optional) =====
|
|
# - KOHAKU_HUB_FALLBACK_ENABLED=true
|
|
# - KOHAKU_HUB_FALLBACK_REQUIRE_AUTH=false # Set true to require authentication for fallback access
|
|
# - KOHAKU_HUB_FALLBACK_SOURCES=[{"url":"https://huggingface.co","name":"HuggingFace","source_type":"huggingface","priority":1}]
|
|
|
|
## ===== L2 Cache (Valkey) =====
|
|
# See docs/development/cache.md for the design (multi-tier, write-through
|
|
# invalidation, boot-time flush of mutable namespaces).
|
|
- KOHAKU_HUB_CACHE_ENABLED=true
|
|
- KOHAKU_HUB_CACHE_URL=redis://valkey:6379/0
|
|
# - KOHAKU_HUB_CACHE_NAMESPACE=kh # Override if multiple deployments share Valkey
|
|
volumes:
|
|
- ./hub-meta/hub-api:/hub-api-creds
|
|
|
|
minio:
|
|
image: quay.io/minio/minio:latest
|
|
container_name: minio
|
|
command: server /data --console-address ":29000"
|
|
environment:
|
|
- MINIO_ROOT_USER=minioadmin
|
|
- MINIO_ROOT_PASSWORD=minioadmin
|
|
# Required so the SPA can do cross-origin Range reads on presigned
|
|
# /resolve/ targets for the pure-client safetensors/parquet preview
|
|
# (deepghs/KohakuHub#27). Tighten to a specific origin list in prod.
|
|
- MINIO_API_CORS_ALLOW_ORIGIN=*
|
|
ports:
|
|
- "29001:9000" # S3 API
|
|
- "29000:29000" # Web Console
|
|
volumes:
|
|
- ./hub-storage/minio-data:/data
|
|
- ./hub-meta/minio-data:/root/.minio
|
|
|
|
lakefs:
|
|
build:
|
|
context: ./docker/lakefs
|
|
container_name: lakefs
|
|
environment:
|
|
- LAKEFS_DATABASE_TYPE=local
|
|
- LAKEFS_DATABASE_LOCAL_PATH=/var/lakefs/data/metadata.db
|
|
- LAKEFS_BLOCKSTORE_TYPE=s3
|
|
- LAKEFS_BLOCKSTORE_S3_ENDPOINT=http://minio:9000
|
|
- LAKEFS_BLOCKSTORE_S3_BUCKET=hub-storage
|
|
- LAKEFS_BLOCKSTORE_S3_FORCE_PATH_STYLE=true
|
|
- LAKEFS_BLOCKSTORE_S3_CREDENTIALS_ACCESS_KEY_ID=minioadmin
|
|
- LAKEFS_BLOCKSTORE_S3_CREDENTIALS_SECRET_ACCESS_KEY=minioadmin
|
|
- LAKEFS_BLOCKSTORE_S3_REGION=us-east-1 # S3 region (us-east-1 for MinIO, auto for R2, or specific AWS region)
|
|
- LAKEFS_AUTH_ENCRYPT_SECRET_KEY=change-me-in-production
|
|
- LAKEFS_LOGGING_FORMAT=text
|
|
- LAKEFS_LISTEN_ADDRESS=0.0.0.0:28000
|
|
ports:
|
|
- "28000:28000" # LakeFS admin UI (optional)
|
|
user: "${UID}:${GID}"
|
|
depends_on:
|
|
- minio
|
|
volumes:
|
|
- ./hub-meta/lakefs-data:/var/lakefs/data
|
|
- ./hub-meta/lakefs-cache:/lakefs/data/cache
|
|
|
|
postgres:
|
|
image: postgres:15
|
|
container_name: postgres
|
|
restart: always
|
|
environment:
|
|
- POSTGRES_USER=<user>
|
|
- POSTGRES_PASSWORD=<password>
|
|
- POSTGRES_DB=kohakuhub
|
|
ports:
|
|
- "25432:5432" # Optional: for external access
|
|
volumes:
|
|
- ./hub-meta/postgres-data:/var/lib/postgresql/data
|
|
|
|
# L2 cache. Pure cache: losing it never compromises correctness. The
|
|
# volume + RDB persistence is intentional — it preserves the warm Mode-A
|
|
# working set (LakeFS commit_id-keyed entries) across restarts so that
|
|
# Valkey upgrades / patches don't generate a synchronized LakeFS REST
|
|
# spike. Mode-B (mutable) namespaces are flushed on every Valkey restart
|
|
# by the API's bootstrap coordinator, regardless of RDB contents — see
|
|
# MODE_B_PREFIXES in src/kohakuhub/cache.py.
|
|
valkey:
|
|
image: valkey/valkey:8-alpine
|
|
container_name: valkey
|
|
restart: always
|
|
# Internal-only by default. Add a `ports:` entry only if you need
|
|
# to attach valkey-cli from the host for debugging.
|
|
command: >-
|
|
valkey-server
|
|
--maxmemory 512mb
|
|
--maxmemory-policy allkeys-lfu
|
|
--save 300 100
|
|
--appendonly no
|
|
user: "${UID}:${GID}"
|
|
volumes:
|
|
# Same hub-meta convention as the other stateful services so all
|
|
# local persistence is rooted under one tree. Cache contents are
|
|
# recoverable from L3 — the directory is here for warm-restart
|
|
# benefits, not for backup.
|
|
- ./hub-meta/valkey-data:/data
|
|
healthcheck:
|
|
test: ["CMD", "valkey-cli", "ping"]
|
|
interval: 10s
|
|
timeout: 3s
|
|
retries: 5
|
|
|
|
networks:
|
|
default:
|
|
name: hub-net
|