Traefik リバースプロキシを使用した Onyx Docker Compose セットアップ

この投稿では、ワークプレイス検索とチャットのためのオープンソース AI プラットフォームである Onyx を、リバースプロキシとして Traefik を使用して Docker Compose でセットアップする方法を紹介します。Traefik は /api (および /openapi.json) を API サーバーに、その他すべてを Web フロントエンドにルーティングします。

ディレクトリのセットアップ

まずデータディレクトリを作成します。Vespa はデータディレクトリが UID 1000 に所有されている必要があります:

init.sh
#!/bin/sh
mkdir -p vespa_data
chown -R 1000:1000 vespa_data
Setup-Onyx.sh
mkdir -p onyx && cd onyx
./init.sh

設定

docker-compose.yml の隣に .env ファイルを作成します:

.env
# ドメイン設定
DOMAIN=onyx.mydomain.com
WEB_DOMAIN=https://onyx.mydomain.com

# データベース認証情報
POSTGRES_USER=postgres
POSTGRES_PASSWORD=INSERT_YOUR_PASSWORD_HERE
POSTGRES_DB=onyx

# 認証設定 (disabled / basic / oidc)
AUTH_TYPE=disabled
USER_AUTH_SECRET=INSERT_RANDOM_SECRET_HERE

# Traefik 設定
TRAEFIK_ENTRYPOINT=websecure
TRAEFIK_CERTRESOLVER=cloudflare

openssl rand -hex 32 でランダムな USER_AUTH_SECRET を生成します。

docker-compose.yml

docker-compose.yml
services:
  db:
    image: postgres:15-alpine
    restart: unless-stopped
    environment:
      POSTGRES_USER: ${POSTGRES_USER}
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
      POSTGRES_DB: ${POSTGRES_DB}
    volumes:
      - ./postgres_data:/var/lib/postgresql/data

  index:
    image: vespaengine/vespa:8
    restart: unless-stopped
    environment:
      VESPA_CLI_TELEMETRY: "false"
    volumes:
      - ./vespa_data:/opt/vespa/var

  api_server:
    image: onyxdotapp/onyx-backend:latest
    restart: unless-stopped
    command: >
      /bin/sh -c "alembic upgrade head &&
      echo 'Starting Onyx Api Server' &&
      uvicorn onyx.main:app --host 0.0.0.0 --port 8080"
    environment:
      - POSTGRES_USER=${POSTGRES_USER}
      - POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
      - POSTGRES_HOST=db
      - POSTGRES_PORT=5432
      - POSTGRES_DB=${POSTGRES_DB}
      - VESPA_HOST=index
      - VESPA_PORT=8081
      - ONYX_DISABLE_VESPA=false
      - ENABLE_OPENSEARCH_INDEXING_FOR_ONYX=false
      - REDIS_HOST=cache
      - FILE_STORE_BACKEND=postgres
      - MODEL_SERVER_HOST=inference_model_server
      - INDEXING_MODEL_SERVER_HOST=indexing_model_server
      - WEB_DOMAIN=${WEB_DOMAIN}
      - AUTH_TYPE=${AUTH_TYPE}
      - USER_AUTH_SECRET=${USER_AUTH_SECRET}
    depends_on:
      - db
      - index
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.onyx-api.rule=Host(`${DOMAIN}`) && (PathPrefix(`/api`) || PathPrefix(`/openapi.json`))"
      - "traefik.http.routers.onyx-api.entrypoints=${TRAEFIK_ENTRYPOINT}"
      - "traefik.http.routers.onyx-api.tls.certresolver=${TRAEFIK_CERTRESOLVER}"
      - "traefik.http.routers.onyx-api.middlewares=onyx-strip-api"
      - "traefik.http.middlewares.onyx-strip-api.stripprefix.prefixes=/api"
      - "traefik.http.services.onyx-api.loadbalancer.server.port=8080"

  background:
    image: onyxdotapp/onyx-backend:latest
    restart: unless-stopped
    command: /bin/bash /app/scripts/supervisord_entrypoint.sh
    environment:
      - POSTGRES_USER=${POSTGRES_USER}
      - POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
      - POSTGRES_HOST=db
      - POSTGRES_PORT=5432
      - POSTGRES_DB=${POSTGRES_DB}
      - VESPA_HOST=index
      - VESPA_PORT=8081
      - ONYX_DISABLE_VESPA=false
      - ENABLE_OPENSEARCH_INDEXING_FOR_ONYX=false
      - REDIS_HOST=cache
      - FILE_STORE_BACKEND=postgres
      - MODEL_SERVER_HOST=inference_model_server
      - INDEXING_MODEL_SERVER_HOST=indexing_model_server
      - WEB_DOMAIN=${WEB_DOMAIN}
      - USER_AUTH_SECRET=${USER_AUTH_SECRET}
      - SANDBOX_BACKEND=docker
      - SANDBOX_PROXY_HOST=sandbox-proxy
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    depends_on:
      - db
      - index

  cache:
    image: redis:7-alpine
    restart: unless-stopped

  inference_model_server:
    image: onyxdotapp/onyx-model-server:latest
    restart: unless-stopped
    volumes:
      - ./model_cache_huggingface:/app/.cache/huggingface/

  indexing_model_server:
    image: onyxdotapp/onyx-model-server:latest
    restart: unless-stopped
    environment:
      - INDEXING_ONLY=True
    volumes:
      - ./indexing_huggingface_model_cache:/app/.cache/huggingface/

  web_server:
    image: onyxdotapp/onyx-web-server:latest
    restart: unless-stopped
    environment:
      - INTERNAL_URL=http://api_server:8080
    depends_on:
      - api_server
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.onyx-web.rule=Host(`${DOMAIN}`)"
      - "traefik.http.routers.onyx-web.entrypoints=${TRAEFIK_ENTRYPOINT}"
      - "traefik.http.routers.onyx-web.tls.certresolver=${TRAEFIK_CERTRESOLVER}"
      - "traefik.http.services.onyx-web.loadbalancer.server.port=3000"

設定に関する注意

明示的なネットワークなし。 すべてのサービスは compose のデフォルトネットワーク上で実行されます。Traefik がそのネットワークに参加していれば、api_server と web_server に到達でき、追加の networks: セクションや traefik.docker.network ラベルは必要ありません。Traefik が別の compose プロジェクトで実行されている場合は、両方のファイルを一緒に起動するか (docker compose -f docker-compose.yml -f docker-compose.traefik.yml up -d)、-p onyx で同じプロジェクトを指定してください。

background の SANDBOX_BACKEND=docker。 Onyx の Craft/サンドボックス機能は、使用するかどうかに関係なく、定期的な cleanup_idle_sandboxes Celery タスクを実行します。SANDBOX_BACKEND のデフォルトは kubernetes で、プレーンな Docker ホストでは RuntimeError: Failed to load Kubernetes configuration でクラッシュします。docker バックエンドは、空でない SANDBOX_PROXY_HOST とコンテナにマウントされた Docker ソケットを必要とします — 上記の3行はそのためです。Craft を使用しない場合、マネージャーは初期化し、実行中のサンドボックスがゼロであることを確認して、静かに終了します。

パスルーティング。 Traefik は API サーバーに転送する前に /api を削除するため (onyx-strip-api ミドルウェア)、https://onyx.mydomain.com/api/... は /... として api_server に到達します。その他のすべてのパスは web_server に送られます。

起動

Start-Onyx.sh
docker compose up -d

最初の起動には数分かかります。api_server がデータベースマイグレーションを実行し、モデルサーバーが HuggingFace モデルをダウンロードするためです。docker compose logs -f api_server で進行状況を確認できます。

https://onyx.mydomain.com を開きます — 初回実行時に管理者アカウントの作成を求められ、その後チャット UI に移動します。

docker-compose プロジェクト用の systemd サービスを10秒で作成する を使用して自動起動を設定できます。TL;DR:

Setup-Autostart.sh
curl -fsSL https://techoverflow.net/scripts/create-docker-compose-service.sh | sudo bash /dev/stdin

同じカテゴリの類似記事をチェック: AI Docker