Развёртывание полного AI-стека с Docker Compose: оркестрация в один клик от LLM до векторной базы данных

DevOps

Настройка среды разработки AI всё ещё занимает три дня?

В 2026 году настройка среды разработки AI остаётся кошмаром для разработчиков. Нужно установить Ollama для LLM-сервинга, настроить Qdrant для векторного хранилища, настроить сервисы эмбеддингов, создать API-шлюз для аутентификации и разобраться с драйверами GPU, версиями CUDA и загрузкой моделей... Три дня прошло, а вы не написали ни строчки кода.

Развёртывание полного AI-стека с Docker Compose оркестрирует всё в одном файле. docker compose up -d запускает весь AI-стек за минуты. Эта статья — полное практическое руководство, охватывающее 7 основных паттернов, 5 распространённых ловушек, 10 шагов устранения ошибок и стратегии продакшн-усиления.

Ключевые выводы

  • Развёртывание полного AI-стека с Docker Compose = LLM + Векторная БД + Эмбеддинги + API-шлюз + Мониторинг, один файл для управления всем
  • Ollama + OpenWebUI — самое зрелое решение для локального LLM-сервинга
  • Qdrant/Milvus — основные векторные базы данных с максимально простым Docker-развёртыванием
  • Проброс GPU критически важен для AI-развёртывания — настраивается через deploy.resources.reservations.devices
  • Продакшн требует аутентификации, ограничения запросов, мониторинга и усиления резервного копирования

Содержание

  • Обзор архитектуры полного AI-стека
  • Паттерн 1: LLM-сервинг с Ollama + OpenWebUI
  • Паттерн 2: Векторные базы данных Qdrant/Milvus
  • Паттерн 3: Сервисы эмбеддингов и управление моделями
  • Паттерн 4: API-шлюз и аутентификация
  • Паттерн 5: Проброс GPU и лимиты ресурсов
  • Паттерн 6: Мониторинг и наблюдаемость
  • Паттерн 7: Продакшн-усиление и безопасность
  • 5 распространённых ловушек и решения
  • 10 способов устранения распространённых ошибок
  • Продвинутые советы по оптимизации
  • Сравнение: Docker Compose vs K8s vs Docker Swarm
  • Рекомендуемые онлайн-инструменты
  • Итоги

Обзор архитектуры полного AI-стека

Развёртывание полного AI-стека с Docker Compose строится на 7-уровневой архитектуре, от GPU внизу до API-шлюза наверху:

┌─────────────────────────────────────────────────────┐
│                   API Gateway                        │
│              (Traefik / Nginx)                       │
│         Auth · Rate Limit · Routing · TLS            │
├──────────┬──────────┬──────────┬────────────────────┤
│ OpenWebUI│  RAG App │  Agent   │  Admin Panel       │
│  (Chat)  │ (Search) │  (Proxy) │  (Management)      │
├──────────┴──────────┴──────────┴────────────────────┤
│              Embedding Service                       │
│       (TEI / Infinity / FastEmbed)                  │
├──────────────────┬──────────────────────────────────┤
│   Ollama LLM     │    vLLM / TGI                    │
│  (Model Serving) │  (High-Perf Inference)           │
├──────────────────┴──────────────────────────────────┤
│           Vector Database                            │
│     (Qdrant / Milvus / Weaviate)                    │
├─────────────────────────────────────────────────────┤
│              Infrastructure                          │
│   Redis · PostgreSQL · MinIO · Prometheus            │
├─────────────────────────────────────────────────────┤
│              GPU / CPU Runtime                       │
│     NVIDIA CUDA · ROCm · CPU Fallback               │
└─────────────────────────────────────────────────────┘

Структура каталогов проекта для развёртывания полного AI-стека с Docker Compose:

ai-stack/
├── docker-compose.yml
├── docker-compose.gpu.yml
├── docker-compose.prod.yml
├── .env
├── ollama/
│   └── Modelfile
├── qdrant/
│   └── config.yaml
├── traefik/
│   ├── traefik.yml
│   └── acme.json
├── monitoring/
│   ├── prometheus.yml
│   └── grafana/
│       └── dashboards/
└── scripts/
    ├── init-models.sh
    └── backup-vectors.sh

Паттерн 1: LLM-сервинг с Ollama + OpenWebUI

Ollama — самое зрелое решение для локального LLM-сервинга в 2026 году, поддерживающее Llama 4, Qwen 3, DeepSeek V3 и другие основные модели. OpenWebUI предоставляет веб-интерфейс в стиле ChatGPT.

Базовая конфигурация

services:
  ollama:
    image: ollama/ollama:latest
    container_name: ollama
    ports:
      - "11434:11434"
    volumes:
      - ollama_data:/root/.ollama
    environment:
      OLLAMA_KEEP_ALIVE: "24h"
      OLLAMA_NUM_PARALLEL: "4"
      OLLAMA_MAX_LOADED_MODELS: "3"
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:11434/api/tags"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 60s
    restart: unless-stopped

  open-webui:
    image: ghcr.io/open-webui/open-webui:main
    container_name: open-webui
    ports:
      - "3000:8080"
    volumes:
      - open_webui_data:/app/backend/data
    environment:
      OLLAMA_BASE_URL: "http://ollama:11434"
      WEBUI_SECRET_KEY: "${WEBUI_SECRET_KEY}"
      ENABLE_SIGNUP: "false"
      DEFAULT_USER_ROLE: "user"
    depends_on:
      ollama:
        condition: service_healthy
    restart: unless-stopped

volumes:
  ollama_data:
  open_webui_data:

Автоматическая загрузка моделей

После запуска Ollama необходимо загрузить модели вручную. Автоматизируйте это с помощью скрипта инициализации:

#!/bin/bash
# scripts/init-models.sh

MODELS=(
  "qwen3:8b"
  "llama4:8b"
  "deepseek-v3:8b"
  "nomic-embed-text"
)

for model in "${MODELS[@]}"; do
  echo "Pulling model: $model"
  until curl -s http://localhost:11434/api/pull -d "{\"name\":\"$model\"}" | grep -q "success"; do
    echo "  Retrying $model..."
    sleep 5
  done
  echo "  ✓ $model ready"
done

echo "All models pulled successfully!"

Добавьте сервис инициализации в Docker Compose:

  model-init:
    image: curlimages/curl:latest
    container_name: model-init
    depends_on:
      ollama:
        condition: service_healthy
    volumes:
      - ./scripts/init-models.sh:/init-models.sh:ro
    entrypoint: ["/bin/sh", "/init-models.sh"]
    restart: "no"

Пользовательский Modelfile

# ollama/Modelfile
FROM qwen3:8b

PARAMETER temperature 0.7
PARAMETER top_p 0.9
PARAMETER num_ctx 8192
PARAMETER stop "<|im_end|>"

SYSTEM """
You are a professional AI assistant. When answering questions:
1. Give a concise conclusion first
2. Then provide detailed explanation
3. If uncertain, say so explicitly
"""

Создайте пользовательскую модель:

docker exec ollama ollama create my-assistant -f /root/.ollama/Modelfile

Паттерн 2: Векторные базы данных Qdrant/Milvus

Векторные базы данных — ядро архитектуры RAG. Развёртывание полного AI-стека с Docker Compose обычно использует Qdrant (лёгкий) или Milvus (масштабный).

Конфигурация Qdrant (рекомендуется для малых и средних проектов)

  qdrant:
    image: qdrant/qdrant:latest
    container_name: qdrant
    ports:
      - "6333:6333"
      - "6334:6334"
    volumes:
      - qdrant_data:/qdrant/storage
      - ./qdrant/config.yaml:/qdrant/config/production.yaml:ro
    environment:
      QDRANT__SERVICE__GRPC_PORT: "6334"
      QDRANT__LOG_LEVEL: "INFO"
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:6333/healthz"]
      interval: 10s
      timeout: 5s
      retries: 3
    restart: unless-stopped

Конфигурационный файл Qdrant:

# qdrant/config.yaml
storage:
  performance:
    max_search_threads: 4
  wal:
    wal_capacity_mb: 32
    wal_segments_ahead: 0
  optimizers:
    indexing_threshold: 20000
    memmap_threshold: 50000
service:
  max_request_size_mb: 64
  enable_cors: true
telemetry_disabled: true

Конфигурация Milvus (рекомендуется для масштабных проектов)

  etcd:
    image: quay.io/coreos/etcd:v3.5.16
    container_name: milvus-etcd
    environment:
      ETCD_AUTO_COMPACTION_MODE: "revision"
      ETCD_AUTO_COMPACTION_RETENTION: "1000"
      ETCD_QUOTA_BACKEND_BYTES: "4294967296"
    volumes:
      - etcd_data:/etcd
    command: etcd -advertise-client-urls=http://127.0.0.1:2379 -listen-client-urls http://0.0.0.0:2379
    restart: unless-stopped

  minio:
    image: minio/minio:latest
    container_name: milvus-minio
    environment:
      MINIO_ACCESS_KEY: "${MINIO_ACCESS_KEY}"
      MINIO_SECRET_KEY: "${MINIO_SECRET_KEY}"
    ports:
      - "9001:9001"
      - "9000:9000"
    volumes:
      - minio_data:/minio_data
    command: minio server /minio_data --console-address ":9001"
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"]
      interval: 30s
      timeout: 20s
      retries: 3
    restart: unless-stopped

  milvus:
    image: milvusdb/milvus:v2.5-latest
    container_name: milvus
    ports:
      - "19530:19530"
      - "9091:9091"
    volumes:
      - milvus_data:/var/lib/milvus
    environment:
      ETCD_ENDPOINTS: "etcd:2379"
      MINIO_ADDRESS: "minio:9000"
    depends_on:
      - etcd
      - minio
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:9091/healthz"]
      interval: 30s
      timeout: 20s
      retries: 3
      start_period: 90s
    restart: unless-stopped

Сравнение векторных баз данных

Характеристика Qdrant Milvus Weaviate ChromaDB
Сложность развёртывания Очень низкая (1 контейнер) Высокая (3+ контейнера) Низкая (1 контейнер) Очень низкая (1 контейнер)
Производительность (миллионы) Отличная Отличная Хорошая Удовлетворительная
Производительность (миллиарды) Хорошая Отличная Удовлетворительная Н/Д
Фильтрованный поиск ✅ Мощный ✅ Мощный ✅ Хороший ⚠️ Базовый
Персистентность ⚠️ По умолчанию в памяти
Мульти-реплика
Поддержка gRPC
Совместимость с Docker Compose ✅ Лучшая ⚠️ Тяжёлый ✅ Хорошая ✅ Только разработка
Готовность к продакшну ❌ Только разработка

Рекомендация: Для развёртывания полного AI-стека с Docker Compose Qdrant — первый выбор: простое развёртывание, отличная производительность. Рассмотрите Milvus, когда количество векторов превышает 100 миллионов. ChromaDB подходит только для прототипирования.


Паттерн 3: Сервисы эмбеддингов и управление моделями

Сервисы эмбеддингов преобразуют текст в векторы — критический этап в конвейере RAG. Оркестрация контейнеров Docker Compose AI предлагает три основных решения.

Hugging Face TEI (рекомендуется)

  tei:
    image: ghcr.io/huggingface/text-embeddings-inference:latest
    container_name: tei
    ports:
      - "8080:80"
    volumes:
      - tei_cache:/data
    environment:
      MODEL_ID: "BAAI/bge-m3"
      REVISION: "main"
      MAX_BATCH_TOKENS: "16384"
      MAX_CLIENT_BATCH_SIZE: "32"
      HF_TOKEN: "${HF_TOKEN}"
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:80/health"]
      interval: 10s
      timeout: 5s
      retries: 3
      start_period: 120s
    restart: unless-stopped

Сервис эмбеддингов Infinity

  infinity:
    image: michaelf34/infinity:latest
    container_name: infinity
    ports:
      - "7997:7997"
    volumes:
      - infinity_cache:/app/.cache
    environment:
      MODEL_ID: "BAAI/bge-m3"
      ENGINE: "optimum"
      BATCH_SIZE: "32"
    command: >
      --model-id BAAI/bge-m3
      --engine optimum
      --port 7997
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:7997/health"]
      interval: 10s
      timeout: 5s
      retries: 3
    restart: unless-stopped

Пример использования сервиса эмбеддингов

import httpx
import numpy as np

async def get_embeddings(texts: list[str]) -> list[list[float]]:
    async with httpx.AsyncClient(timeout=30.0) as client:
        response = await client.post(
            "http://tei:80/embed",
            json={"inputs": texts}
        )
        response.raise_for_status()
        return response.json()

async def search_similar(query: str, top_k: int = 5) -> list[dict]:
    query_embedding = await get_embeddings([query])
    async with httpx.AsyncClient(timeout=30.0) as client:
        response = await client.post(
            "http://qdrant:6333/collections/documents/points/search",
            json={
                "vector": query_embedding[0],
                "limit": top_k,
                "with_payload": True
            }
        )
        response.raise_for_status()
        return response.json()["result"]

Сравнение сервисов эмбеддингов

Характеристика TEI Infinity FastEmbed
GPU-ускорение ✅ Нативное ✅ Нативное ❌ Только CPU
Пакетный вывод ✅ Эффективный ✅ Эффективный ⚠️ Удовлетворительный
Мульти-модель
Размер Docker-образа ~2ГБ ~4ГБ ~500МБ
Готовность к продакшну ⚠️ Только разработка
API, совместимая с OpenAI

Паттерн 4: API-шлюз и аутентификация

Продакшн-развёртывание полного AI-стека с Docker Compose требует API-шлюза для унифицированной аутентификации, ограничения запросов и маршрутизации.

Конфигурация Traefik

  traefik:
    image: traefik:v3.2
    container_name: traefik
    ports:
      - "80:80"
      - "443:443"
      - "8080:8080"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - ./traefik/traefik.yml:/etc/traefik/traefik.yml:ro
      - traefik_certs:/etc/traefik/certs
      - ./traefik/dynamic:/etc/traefik/dynamic:ro
    command:
      - "--api.dashboard=true"
      - "--providers.docker=true"
      - "--providers.docker.exposedbydefault=false"
      - "--providers.file.directory=/etc/traefik/dynamic"
      - "--entrypoints.web.address=:80"
      - "--entrypoints.websecure.address=:443"
      - "--entrypoints.web.http.redirections.entrypoint.to=websecure"
    labels:
      traefik.enable: "true"
      traefik.http.routers.traefik.rule: "Host(`traefik.ai-stack.local`)"
      traefik.http.routers.traefik.entrypoints: "websecure"
      traefik.http.routers.traefik.tls: "true"
      traefik.http.services.traefik.loadbalancer.server.port: "8080"
    restart: unless-stopped

OpenWebUI с Traefik

  open-webui:
    image: ghcr.io/open-webui/open-webui:main
    container_name: open-webui
    volumes:
      - open_webui_data:/app/backend/data
    environment:
      OLLAMA_BASE_URL: "http://ollama:11434"
    labels:
      traefik.enable: "true"
      traefik.http.routers.webui.rule: "Host(`chat.ai-stack.local`)"
      traefik.http.routers.webui.entrypoints: "websecure"
      traefik.http.routers.webui.tls: "true"
      traefik.http.services.webui.loadbalancer.server.port: "8080"
    depends_on:
      ollama:
        condition: service_healthy
    restart: unless-stopped

Middleware аутентификации

# traefik/dynamic/auth.yml
http:
  middlewares:
    auth-middleware:
      forwardAuth:
        address: "http://auth-service:8000/verify"
        trustForwardHeader: true
        authResponseHeaders:
          - "X-User-Id"
          - "X-User-Role"

    rate-limit:
      rateLimit:
        average: 30
        burst: 60
        period: 1m

  routers:
    api-router:
      rule: "Host(`api.ai-stack.local`)"
      entrypoints:
        - "websecure"
      tls: true
      middlewares:
        - "auth-middleware"
        - "rate-limit"
      service: "ollama-api"

Паттерн 5: Проброс GPU и лимиты ресурсов

GPU — ядро AI-развёртывания. Развёртывание полного AI-стека с Docker Compose включает проброс GPU через deploy.resources.reservations.devices.

Проброс NVIDIA GPU

  ollama:
    image: ollama/ollama:latest
    container_name: ollama
    volumes:
      - ollama_data:/root/.ollama
    deploy:
      resources:
        reservations:
          devices:
            - driver: nvidia
              count: 1
              capabilities: [gpu]
        limits:
          memory: 16G
          cpus: "8.0"
    environment:
      NVIDIA_VISIBLE_DEVICES: "all"
      NVIDIA_DRIVER_CAPABILITIES: "compute,utility"
      OLLAMA_KEEP_ALIVE: "24h"
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:11434/api/tags"]
      interval: 30s
      timeout: 10s
      retries: 3
    restart: unless-stopped

Распределение нескольких GPU

  ollama:
    image: ollama/ollama:latest
    deploy:
      resources:
        reservations:
          devices:
            - driver: nvidia
              device_ids: ["0"]
              capabilities: [gpu]
    environment:
      CUDA_VISIBLE_DEVICES: "0"

  tei:
    image: ghcr.io/huggingface/text-embeddings-inference:latest
    deploy:
      resources:
        reservations:
          devices:
            - driver: nvidia
              device_ids: ["1"]
              capabilities: [gpu]
    environment:
      CUDA_VISIBLE_DEVICES: "1"

Конфигурация CPU-резерва

  ollama-cpu:
    image: ollama/ollama:latest
    profiles: ["cpu-only"]
    container_name: ollama
    volumes:
      - ollama_data:/root/.ollama
    environment:
      OLLAMA_NUM_PARALLEL: "2"
      OLLAMA_MAX_LOADED_MODELS: "1"
    deploy:
      resources:
        limits:
          memory: 8G
          cpus: "4.0"

  ollama-gpu:
    image: ollama/ollama:latest
    profiles: ["gpu"]
    container_name: ollama
    volumes:
      - ollama_data:/root/.ollama
    deploy:
      resources:
        reservations:
          devices:
            - driver: nvidia
              count: all
              capabilities: [gpu]
        limits:
          memory: 16G

Команды запуска:

# Режим GPU
docker compose --profile gpu up -d

# Режим CPU
docker compose --profile cpu-only up -d

Скрипт мониторинга ресурсов GPU

import subprocess
import json
import time

def monitor_gpu_usage(interval: int = 60):
    while True:
        result = subprocess.run(
            ["nvidia-smi", "--query-gpu=index,name,memory.used,memory.total,utilization.gpu",
             "--format=csv,noheader,nounits"],
            capture_output=True, text=True
        )
        for line in result.stdout.strip().split("\n"):
            idx, name, mem_used, mem_total, util = line.split(", ")
            print(f"GPU {idx} ({name}): {mem_used}/{mem_total}MB, Util: {util}%")
        time.sleep(interval)

if __name__ == "__main__":
    monitor_gpu_usage()

Паттерн 6: Мониторинг и наблюдаемость

Мониторинг развёртывания полного AI-стека с Docker Compose должен охватывать утилизацию GPU, задержку вывода, производительность векторной базы данных и другие AI-специфические метрики.

Prometheus + Grafana

  prometheus:
    image: prom/prometheus:v3.2.0
    container_name: prometheus
    volumes:
      - ./monitoring/prometheus.yml:/etc/prometheus/prometheus.yml:ro
      - prometheus_data:/prometheus
    command:
      - "--config.file=/etc/prometheus/prometheus.yml"
      - "--storage.tsdb.retention.time=30d"
      - "--storage.tsdb.retention.size=10GB"
    ports:
      - "9090:9090"
    restart: unless-stopped

  grafana:
    image: grafana/grafana:11.5.0
    container_name: grafana
    volumes:
      - grafana_data:/var/lib/grafana
      - ./monitoring/grafana/dashboards:/etc/grafana/provisioning/dashboards:ro
      - ./monitoring/grafana/datasources:/etc/grafana/provisioning/datasources:ro
    environment:
      GF_SECURITY_ADMIN_USER: "${GRAFANA_USER}"
      GF_SECURITY_ADMIN_PASSWORD: "${GRAFANA_PASSWORD}"
      GF_USERS_ALLOW_SIGN_UP: "false"
    ports:
      - "3001:3000"
    depends_on:
      - prometheus
    restart: unless-stopped

  dcgm-exporter:
    image: nvidia/dcgm-exporter:latest
    container_name: dcgm-exporter
    deploy:
      resources:
        reservations:
          devices:
            - driver: nvidia
              count: all
              capabilities: [gpu]
    ports:
      - "9400:9400"
    restart: unless-stopped

Конфигурация Prometheus

# monitoring/prometheus.yml
global:
  scrape_interval: 15s
  evaluation_interval: 15s

scrape_configs:
  - job_name: "ollama"
    static_configs:
      - targets: ["ollama:11434"]
    metrics_path: "/metrics"
    scrape_interval: 30s

  - job_name: "qdrant"
    static_configs:
      - targets: ["qdrant:6333"]
    metrics_path: "/metrics"
    scrape_interval: 30s

  - job_name: "dcgm"
    static_configs:
      - targets: ["dcgm-exporter:9400"]
    scrape_interval: 10s

  - job_name: "node-exporter"
    static_configs:
      - targets: ["node-exporter:9100"]

  - job_name: "traefik"
    static_configs:
      - targets: ["traefik:8080"]

Ключевые правила оповещений

# monitoring/alerts.yml
groups:
  - name: ai-stack
    rules:
      - alert: OllamaHighLatency
        expr: histogram_quantile(0.95, rate(ollama_request_duration_seconds_bucket[5m])) > 30
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: "Задержка вывода Ollama слишком высока"

      - alert: GPUMemoryHigh
        expr: DCGM_FI_DEV_FB_USED / DCGM_FI_DEV_FB_TOTAL > 0.9
        for: 5m
        labels:
          severity: critical
        annotations:
          summary: "Использование памяти GPU превышает 90%"

      - alert: QdrantHighLatency
        expr: histogram_quantile(0.95, rate(qdrant_request_duration_seconds_bucket[5m])) > 5
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: "Задержка запросов Qdrant слишком высока"

      - alert: OllamaContainerDown
        expr: up{job="ollama"} == 0
        for: 2m
        labels:
          severity: critical
        annotations:
          summary: "Сервис Ollama недоступен"

Паттерн 7: Продакшн-усиление и безопасность

Безопасность — базовое требование для продакшн-развёртывания полного AI-стека с Docker Compose.

Управление секретами

services:
  ollama:
    image: ollama/ollama:latest
    secrets:
      - hf_token
    environment:
      HF_TOKEN_FILE: /run/secrets/hf_token

  qdrant:
    image: qdrant/qdrant:latest
    secrets:
      - qdrant_api_key
    environment:
      QDRANT__SERVICE__API_KEY_FILE: /run/secrets/qdrant_api_key

secrets:
  hf_token:
    file: ./secrets/hf_token.txt
  qdrant_api_key:
    file: ./secrets/qdrant_api_key.txt
  db_password:
    file: ./secrets/db_password.txt

Сетевая изоляция

networks:
  frontend:
    driver: bridge
  backend:
    driver: bridge
    internal: true
  monitoring:
    driver: bridge
    internal: true

services:
  traefik:
    networks:
      - frontend
      - backend

  open-webui:
    networks:
      - frontend
      - backend

  ollama:
    networks:
      - backend

  qdrant:
    networks:
      - backend

  tei:
    networks:
      - backend

  prometheus:
    networks:
      - monitoring
      - backend

  grafana:
    networks:
      - frontend
      - monitoring

Стратегия резервного копирования

#!/bin/bash
# scripts/backup-vectors.sh

BACKUP_DIR="/backups/$(date +%Y%m%d_%H%M%S)"
mkdir -p "$BACKUP_DIR"

echo "Backing up Qdrant..."
curl -s -X POST "http://localhost:6333/snapshots" | jq .

echo "Backing up Ollama models list..."
curl -s "http://localhost:11434/api/tags" | jq . > "$BACKUP_DIR/ollama_models.json"

echo "Backing up environment config..."
cp .env "$BACKUP_DIR/.env.backup"
cp docker-compose.yml "$BACKUP_DIR/docker-compose.yml.backup"

echo "Backup completed: $BACKUP_DIR"

Полная продакшн-конфигурация

# docker-compose.prod.yml
services:
  ollama:
    deploy:
      resources:
        reservations:
          devices:
            - driver: nvidia
              count: 1
              capabilities: [gpu]
        limits:
          memory: 16G
          cpus: "8.0"
      restart_policy:
        condition: on-failure
        delay: 10s
        max_attempts: 5
        window: 120s
    logging:
      driver: json-file
      options:
        max-size: "100m"
        max-file: "5"
    read_only: true
    tmpfs:
      - /tmp

  qdrant:
    deploy:
      resources:
        limits:
          memory: 4G
          cpus: "2.0"
      restart_policy:
        condition: on-failure
        delay: 5s
        max_attempts: 3
    logging:
      driver: json-file
      options:
        max-size: "50m"
        max-file: "3"

5 распространённых ловушек и решения

Ловушка 1: Таймаут загрузки моделей Ollama

Симптом: После docker compose up Ollama зависает при загрузке моделей. Большие модели (напр., Llama 4 70B) могут загружаться более часа.

Решение: Используйте сервис model-init для асинхронной загрузки. Сам сервис Ollama не должен ждать модели.

  model-init:
    image: curlimages/curl:latest
    depends_on:
      ollama:
        condition: service_healthy
    volumes:
      - ./scripts/init-models.sh:/init-models.sh:ro
    entrypoint: ["/bin/sh", "/init-models.sh"]
    restart: "no"
    deploy:
      resources:
        limits:
          memory: 256M

Ловушка 2: OOM контейнера Qdrant

Симптом: По мере роста векторных данных контейнер Qdrant получает OOM Killed.

Решение: Установите лимиты памяти и включите отображение памяти.

  qdrant:
    image: qdrant/qdrant:latest
    deploy:
      resources:
        limits:
          memory: 8G
    environment:
      QDRANT__STORAGE__PERFORMANCE__MAX_SEARCH_THREADS: "4"
      QDRANT__STORAGE__WAL__WAL_CAPACITY_MB: "64"

Ловушка 3: Несовпадение версии драйвера GPU

Симптом: docker compose up выдаёт ошибку CUDA driver version is insufficient.

Решение: Убедитесь, что драйвер NVIDIA на хосте ≥ 535, установите nvidia-container-toolkit.

# Проверить версию драйвера
nvidia-smi | head -3

# Установить nvidia-container-toolkit (Ubuntu)
curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey | \
  sudo gpg --dearmor -o /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg
curl -s -L https://nvidia.github.io/libnvidia-container/stable/deb/nvidia-container-toolkit.list | \
  sed 's#deb https://#deb [signed-by=/usr/share/keyrings/nvidia-container-toolkit-keyring.gpg] https://#g' | \
  sudo tee /etc/apt/sources.list.d/nvidia-container-toolkit.list
sudo apt-get update
sudo apt-get install -y nvidia-container-toolkit
sudo nvidia-ctk runtime configure --runtime=docker
sudo systemctl restart docker

Ловушка 4: Сервис эмбеддингов и LLM конкурируют за GPU

Симптом: Недостаточно памяти GPU при одновременной работе TEI и Ollama; загрузка модели не удаётся.

Решение: Используйте device_ids для точного распределения GPU или запускайте сервис эмбеддингов на CPU.

  ollama:
    deploy:
      resources:
        reservations:
          devices:
            - driver: nvidia
              device_ids: ["0"]
              capabilities: [gpu]

  tei:
    # Запуск сервиса эмбеддингов в режиме CPU
    environment:
      MODEL_ID: "BAAI/bge-m3"
      # Без назначения GPU, используется CPU

Ловушка 5: Ошибка разрешения DNS между контейнерами

Симптом: OpenWebUI сообщает ollama: Name or service not known.

Решение: Убедитесь, что все сервисы в одной сети, используйте container_name или имя сервиса как имя хоста.

networks:
  ai-network:
    driver: bridge

services:
  ollama:
    container_name: ollama
    networks:
      - ai-network

  open-webui:
    container_name: open-webui
    networks:
      - ai-network
    environment:
      OLLAMA_BASE_URL: "http://ollama:11434"

10 способов устранения распространённых ошибок

1. could not select device driver — NVIDIA runtime не установлен

# Установить nvidia-container-toolkit и перезапустить Docker
sudo nvidia-ctk runtime configure --runtime=docker
sudo systemctl restart docker
docker info | grep -i runtime
# Должен отображаться nvidia runtime

2. OOM Killed — Недостаточно памяти GPU

# Проверить память GPU
nvidia-smi
# Использовать меньшие или квантованные модели
docker exec ollama ollama run qwen3:4b

3. Connection refused к Ollama — Сервис не готов

# Проверить статус здоровья Ollama
docker compose ps
docker compose logs ollama
# Дождаться прохождения healthcheck перед подключением

4. permission denied на Docker-сокете

sudo usermod -aG docker $USER
newgrp docker

5. Qdrant collection not found — Коллекция не создана

curl -X PUT "http://localhost:6333/collections/documents" \
  -H "Content-Type: application/json" \
  -d '{"vectors": {"size": 1024, "distance": "Cosine"}}'

6. model not found — Модель Ollama не загружена

docker exec ollama ollama pull qwen3:8b

7. CUDA out of memory — Переполнение памяти GPU при выводе

# Уменьшить параллельные запросы
# Настроить в docker-compose.yml
environment:
  OLLAMA_NUM_PARALLEL: "1"
  OLLAMA_MAX_LOADED_MODELS: "1"

8. TLS handshake error — Проблема с сертификатом Traefik

# Проверить права доступа к файлу сертификата
chmod 600 traefik/acme.json
# Проверить логи Traefik
docker compose logs traefik

9. too many open files — Лимит файловых дескрипторов

# Временно увеличить лимит
ulimit -n 65536
# Постоянная настройка (/etc/security/limits.conf)
# * soft nofile 65536
# * hard nofile 65536

10. vector dimension mismatch — Несовпадение размерностей эмбеддингов

# Убедиться, что размерность коллекции Qdrant соответствует выходу модели эмбеддингов
# bge-m3: 1024 размерности
# nomic-embed-text: 768 размерностей
curl -X PUT "http://localhost:6333/collections/documents" \
  -d '{"vectors": {"size": 1024, "distance": "Cosine"}}'

Продвинутые советы по оптимизации

Многоэтапный прогрев моделей

  model-warmer:
    image: curlimages/curl:latest
    container_name: model-warmer
    depends_on:
      ollama:
        condition: service_healthy
    entrypoint: >
      /bin/sh -c "
        echo 'Warming up models...' &&
        curl -s http://ollama:11434/api/generate -d '{\"model\":\"qwen3:8b\",\"prompt\":\"hi\",\"stream\":false}' > /dev/null &&
        curl -s http://ollama:11434/api/generate -d '{\"model\":\"nomic-embed-text\",\"prompt\":\"test\",\"stream\":false}' > /dev/null &&
        echo 'Models warmed up!'
      "
    restart: "no"

Умная выгрузка моделей

  ollama:
    environment:
      OLLAMA_KEEP_ALIVE: "5m"
      OLLAMA_NUM_PARALLEL: "4"
      OLLAMA_MAX_LOADED_MODELS: "2"

OLLAMA_KEEP_ALIVE: "5m" автоматически выгружает модели, простаивающие 5 минут, освобождая память GPU.

Цепочки зависимостей проверок здоровья

  tei:
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:80/health"]
      interval: 10s
      timeout: 5s
      retries: 5
      start_period: 120s

  qdrant:
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:6333/healthz"]
      interval: 10s
      timeout: 5s
      retries: 3

  rag-app:
    depends_on:
      ollama:
        condition: service_healthy
      tei:
        condition: service_healthy
      qdrant:
        condition: service_healthy

Docker Compose Watch для разработки

# docker-compose.yml
services:
  rag-app:
    build: .
    develop:
      watch:
        - action: rebuild
          path: ./app
          target: /app
        - action: sync
          path: ./app/static
          target: /app/static

Сравнение: Docker Compose vs K8s vs Docker Swarm

Измерение Docker Compose Kubernetes Docker Swarm
Сложность развёртывания AI-стека ⭐ Очень низкая ⭐⭐⭐⭐⭐ Очень высокая ⭐⭐ Низкая
Планирование GPU ✅ Нативное ✅ Device Plugin ⚠️ Требует настройки
Автомасштабирование ✅ HPA ⚠️ Ручное
Обнаружение сервисов ✅ DNS ✅ CoreDNS ✅ DNS
Плавающие обновления ⚠️ Требуют скриптов ✅ Нативные ✅ Нативные
Управление конфигурацией ✅ .env ✅ ConfigMap ⚠️ Config
Управление секретами ✅ Docker Secret ✅ K8s Secret ⚠️ Базовое
Экосистема мониторинга ✅ Prometheus ✅ Полная ⚠️ Ограниченная
Многоузловая оркестрация ❌ Один узел ✅ Основная возможность ✅ Нативная
Кривая обучения Низкая Высокая Низкая
Активность сообщества ✅ Активное ✅ Очень активное ❌ Снижается
Подходящий масштаб AI-проекта 1-5 GPU 10+ GPU 2-5 GPU

Рекомендация: Развёртывание полного AI-стека с Docker Compose идеально для сценариев с одной машиной и 1-5 GPU — лучший выбор для AI-разработки и малого продакшна. Для 5+ GPU или многоузловых потребностей рассмотрите Kubernetes + KServe/vLLM. Docker Swarm не рекомендуется для AI-развёртывания.


Рекомендуемые онлайн-инструменты


Итоги

Развёртывание полного AI-стека с Docker Compose превращает настройку среды разработки AI из «три дня на настройку» в «одна команда для запуска». Ollama + OpenWebUI обслуживает LLM-сервинг, Qdrant — векторное хранилище, TEI — эмбеддинги, Traefik — шлюз, Prometheus + Grafana — мониторинг, а проброс GPU ускоряет вывод. 7 паттернов покрывают всю цепочку от разработки до продакшна, 5 распространённых ловушек и 10 шагов устранения ошибок помогут избежать обходных путей. Для AI-проектов с 1-5 GPU Docker Compose — самое практичное решение оркестрации AI-контейнеров в 2026 году.

Связанные публикации

Внешние ссылки

Попробуйте эти локальные браузерные инструменты — регистрация не требуется →

#Docker#Docker Compose#AI部署#LLM#向量数据库#Ollama#2026#DevOps