Files
microdao-daarion/docs/INFRA_ASSETS_MINIO.md
2026-02-16 05:47:10 -08:00

9.2 KiB
Raw Blame History

INFRA_ASSETS_MINIO — Налаштування MinIO для Assets

Огляд

DAARION використовує MinIO (S3-compatible object storage) для зберігання assets:

  • Логотипи MicroDAO
  • Банери MicroDAO
  • Аватарки агентів
  • Інші статичні файли

Переваги:

  • Assets не залежать від локального сервера
  • Можливість реплікації на зовнішній S3/R2
  • Масштабованість
  • Простота backup/restore

1. Архітектура

┌─────────────┐
│   Frontend  │ → https://assets.daarion.space/daarion-assets/...
└─────────────┘
       │
       ↓
┌─────────────┐
│   Caddy     │ → Reverse proxy
│  / NGINX    │
└─────────────┘
       │
       ↓
┌─────────────┐
│    MinIO    │ → S3 API (port 9000)
│  (Docker)   │ → Console (port 9001)
└─────────────┘
       │
       ↓
┌─────────────┐
│   Volume    │ → minio_data (persistent)
└─────────────┘

2. Docker Compose конфігурація

Файл: docker-compose.db.yml

services:
  minio:
    image: minio/minio:latest
    container_name: daarion-minio
    restart: unless-stopped
    command: server /data --console-address ":9001"
    environment:
      MINIO_ROOT_USER: ${MINIO_ROOT_USER}
      MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD}
    ports:
      - "9000:9000"  # S3 API
      - "9001:9001"  # Web console
    volumes:
      - minio_data:/data

ENV змінні (.env):

MINIO_ROOT_USER=assets-admin
MINIO_ROOT_PASSWORD=very-strong-password
ASSETS_BUCKET=daarion-assets
ASSETS_PUBLIC_BASE_URL=https://assets.daarion.space/daarion-assets
MINIO_ENDPOINT=http://minio:9000

3. Початкове налаштування

Крок 1: Запустити MinIO

docker compose -f docker-compose.db.yml up -d minio

Крок 2: Відкрити консоль

Відкрити в браузері: http://localhost:9001 (або https://minio.daarion.space)

Логін:

  • Username: assets-admin (з .env)
  • Password: very-strong-password (з .env)

Крок 3: Створити bucket

  1. Натиснути "Create Bucket"
  2. Назва: daarion-assets
  3. Region: залишити за замовчуванням
  4. Натиснути "Create Bucket"

Крок 4: Встановити public read policy

  1. Відкрити bucket daarion-assets
  2. Перейти в "Access Policy"
  3. Вибрати "Public" або "Custom"
  4. Для Custom policy:
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {"AWS": ["*"]},
      "Action": ["s3:GetObject"],
      "Resource": ["arn:aws:s3:::daarion-assets/*"]
    }
  ]
}

4. DNS налаштування

A/AAAA записи

assets.daarion.space    → IP NODE1 (для публічного доступу)
minio.daarion.space     → IP NODE1 (опційно, для консолі)

5. Reverse Proxy (Caddy)

Файл: Caddyfile

# Assets public access
assets.daarion.space {
    encode gzip

    reverse_proxy minio:9000 {
        header_up Host {upstream_hostport}
        header_up X-Real-IP {remote_host}
        header_up X-Forwarded-For {remote_host}
        header_up X-Forwarded-Proto {scheme}
    }
}

# MinIO console (опційно)
minio.daarion.space {
    encode gzip

    reverse_proxy minio:9001 {
        header_up Host {upstream_hostport}
        header_up X-Real-IP {remote_host}
        header_up X-Forwarded-For {remote_host}
        header_up X-Forwarded-Proto {scheme}
    }
}

Docker Compose:

  caddy:
    image: caddy:2
    container_name: daarion-caddy
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile:ro
      - caddy_data:/data
      - caddy_config:/config
    depends_on:
      - minio

6. Reverse Proxy (NGINX)

Файл: nginx.conf (фрагмент)

http {
    upstream minio_api {
        server minio:9000;
    }

    server {
        listen 80;
        server_name assets.daarion.space;

        client_max_body_size 100M;

        location / {
            proxy_pass http://minio_api;
            proxy_set_header Host $http_host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
        }
    }
}

7. Формат URL в БД

Після завантаження файлу через API, в БД зберігається повний HTTPS URL:

https://assets.daarion.space/daarion-assets/microdao/logo/2025/12/02/abc123def456.png

Структура:

  • https://assets.daarion.space - public domain
  • /daarion-assets - bucket name
  • /microdao/logo - prefix (тип asset)
  • /2025/12/02 - дата завантаження
  • /abc123def456.png - унікальний ID + розширення

8. Backend інтеграція

Upload endpoint (приклад)

from fastapi import UploadFile, File
from lib.assets_client import upload_asset

@router.post("/microdao/{slug}/logo")
async def upload_logo(slug: str, file: UploadFile = File(...)):
    url = upload_asset(
        file.file,
        file.content_type,
        prefix="microdao/logo",
        filename=file.filename
    )
    # Зберегти url в БД
    await repo.update_logo(slug=slug, logo_url=url)
    return {"logo_url": url}

Клієнт MinIO

Файл: services/city-service/lib/assets_client.py

Функції:

  • upload_asset() - завантажити файл, повернути URL
  • delete_asset() - видалити файл
  • ensure_bucket() - переконатися що bucket існує

9. Frontend інтеграція

Файл: apps/web/src/lib/utils/assetUrl.ts

export function normalizeAssetUrl(url?: string | null): string | null {
  if (!url) return null;
  
  // Full HTTPS URLs (from MinIO) - return as-is
  if (url.startsWith('https://') || url.startsWith('http://')) {
    return url;
  }
  
  // Legacy local paths - handle fallback
  // ...
}

10. Backup MinIO

Створити backup bucket

# Використовуючи MinIO Client (mc)
mc alias set local http://localhost:9000 assets-admin <password>
mc mirror local/daarion-assets ./backups/minio/

Автоматичний backup (cron)

# Додати в crontab
0 2 * * * docker exec daarion-minio mc mirror minio/daarion-assets /backups/minio/$(date +\%F)

11. Міграція з локальних файлів

Крок 1: Завантажити існуючі файли в MinIO

# Використовуючи mc
mc cp ./services/city-service/static/uploads/microdao/logo/* local/daarion-assets/microdao/logo/
mc cp ./services/city-service/static/uploads/microdao/banner/* local/daarion-assets/microdao/banner/

Крок 2: Оновити URL в БД

UPDATE microdao
SET logo_url = REPLACE(logo_url, '/api/static/uploads/', 'https://assets.daarion.space/daarion-assets/')
WHERE logo_url LIKE '/api/static/uploads/%';

12. Troubleshooting

Проблема: "Access Denied"

Перевірити:

  1. Bucket має public read policy
  2. URL правильний (включає bucket name)
  3. DNS налаштований правильно

Проблема: "Connection refused"

# Перевірити статус
docker ps | grep minio

# Перезапустити
docker compose -f docker-compose.db.yml restart minio

Проблема: "Bucket does not exist"

# Створити через mc
mc mb local/daarion-assets

# Або через консоль MinIO

13. Моніторинг

Перевірка використання диска

docker exec daarion-minio du -sh /data

Перевірка кількості об'єктів

Через MinIO Console → Bucket → Statistics


14. Реплікація на зовнішній S3 (опційно)

Для додаткової надійності можна налаштувати реплікацію на AWS S3 або Cloudflare R2:

# Налаштувати remote
mc alias set s3 https://s3.amazonaws.com ACCESS_KEY SECRET_KEY

# Налаштувати реплікацію
mc replicate add local/daarion-assets --remote-bucket s3/daarion-assets-backup

15. Чекліст налаштування

  • MinIO запущений (docker ps | grep minio)
  • Bucket daarion-assets створений
  • Public read policy встановлена
  • DNS assets.daarion.space налаштований
  • Caddy/NGINX проксує запити до MinIO
  • Backend використовує assets_client.py
  • Frontend відображає assets з HTTPS URLs
  • Тестовий upload працює