From 990a9c2298d6a7579667a024bb0cbac5273fbdbf Mon Sep 17 00:00:00 2001 From: Ali Zarinkolah Date: Sun, 16 Aug 2026 11:54:05 +0330 Subject: [PATCH] chore(docker): add local Postgres/MinIO/Qdrant compose stack --- docker-compose.langfuse.yml | 198 ++++++++++++++++++++++++++++++++++++ docker-compose.yml | 74 ++++++++++++++ 2 files changed, 272 insertions(+) create mode 100644 docker-compose.langfuse.yml create mode 100644 docker-compose.yml diff --git a/docker-compose.langfuse.yml b/docker-compose.langfuse.yml new file mode 100644 index 0000000..ada38c3 --- /dev/null +++ b/docker-compose.langfuse.yml @@ -0,0 +1,198 @@ +# Development/staging Langfuse v4 Docker Compose stack. +# +# Based on the official Langfuse Docker Compose deployment: +# https://langfuse.com/self-hosting/deployment/docker-compose +# +# This file is intentionally separate from the future application compose file. +# Run it alone for Langfuse-only development, or combine it with the app stack: +# +# docker compose \ +# -f docker-compose.yml \ +# -f docker-compose.langfuse.yml \ +# --env-file .env \ +# --env-file .env.langfuse \ +# up -d +# +# If the chatbot app runs in the same Compose project/network, configure it with: +# LANGFUSE_HOST=http://langfuse-web:3000 +# If the chatbot app runs directly on the host machine, configure it with: +# LANGFUSE_HOST=http://localhost:3000 +# +# Do not use this compose stack as-is for high-availability production. +services: + langfuse-worker: + image: docker.io/langfuse/langfuse-worker:4 + restart: always + depends_on: &langfuse-depends-on + langfuse-postgres: + condition: service_healthy + langfuse-minio: + condition: service_healthy + langfuse-redis: + condition: service_healthy + langfuse-clickhouse: + condition: service_healthy + ports: + - 127.0.0.1:${LANGFUSE_WORKER_PORT:-3030}:3030 + environment: &langfuse-worker-env + NEXTAUTH_URL: ${LANGFUSE_NEXTAUTH_URL:-http://localhost:3000} + DATABASE_URL: postgresql://${LANGFUSE_POSTGRES_USER:-postgres}:${LANGFUSE_POSTGRES_PASSWORD:-postgres}@langfuse-postgres:5432/${LANGFUSE_POSTGRES_DB:-postgres} + SALT: ${LANGFUSE_SALT:-mysalt} # CHANGEME + ENCRYPTION_KEY: ${LANGFUSE_ENCRYPTION_KEY:-0000000000000000000000000000000000000000000000000000000000000000} # CHANGEME: generate via `openssl rand -hex 32` + TELEMETRY_ENABLED: ${LANGFUSE_TELEMETRY_ENABLED:-false} + LANGFUSE_ENABLE_EXPERIMENTAL_FEATURES: ${LANGFUSE_ENABLE_EXPERIMENTAL_FEATURES:-false} + CLICKHOUSE_MIGRATION_URL: clickhouse://langfuse-clickhouse:9000 + CLICKHOUSE_URL: http://langfuse-clickhouse:8123 + CLICKHOUSE_USER: ${LANGFUSE_CLICKHOUSE_USER:-clickhouse} + CLICKHOUSE_PASSWORD: ${LANGFUSE_CLICKHOUSE_PASSWORD:-clickhouse} # CHANGEME + CLICKHOUSE_CLUSTER_ENABLED: ${LANGFUSE_CLICKHOUSE_CLUSTER_ENABLED:-false} + LANGFUSE_USE_AZURE_BLOB: ${LANGFUSE_USE_AZURE_BLOB:-false} + LANGFUSE_USE_OCI_NATIVE_OBJECT_STORAGE: ${LANGFUSE_USE_OCI_NATIVE_OBJECT_STORAGE:-false} + LANGFUSE_OCI_AUTH_TYPE: ${LANGFUSE_OCI_AUTH_TYPE:-workload_identity} + LANGFUSE_S3_EVENT_UPLOAD_BUCKET: ${LANGFUSE_S3_EVENT_UPLOAD_BUCKET:-langfuse} + LANGFUSE_S3_EVENT_UPLOAD_REGION: ${LANGFUSE_S3_EVENT_UPLOAD_REGION:-auto} + LANGFUSE_S3_EVENT_UPLOAD_ACCESS_KEY_ID: ${LANGFUSE_S3_EVENT_UPLOAD_ACCESS_KEY_ID:-minio} + LANGFUSE_S3_EVENT_UPLOAD_SECRET_ACCESS_KEY: ${LANGFUSE_S3_EVENT_UPLOAD_SECRET_ACCESS_KEY:-miniosecret} # CHANGEME + LANGFUSE_S3_EVENT_UPLOAD_ENDPOINT: http://langfuse-minio:9000 + LANGFUSE_S3_EVENT_UPLOAD_FORCE_PATH_STYLE: ${LANGFUSE_S3_EVENT_UPLOAD_FORCE_PATH_STYLE:-true} + LANGFUSE_S3_EVENT_UPLOAD_PREFIX: ${LANGFUSE_S3_EVENT_UPLOAD_PREFIX:-events/} + LANGFUSE_S3_MEDIA_UPLOAD_BUCKET: ${LANGFUSE_S3_MEDIA_UPLOAD_BUCKET:-langfuse} + LANGFUSE_S3_MEDIA_UPLOAD_REGION: ${LANGFUSE_S3_MEDIA_UPLOAD_REGION:-auto} + LANGFUSE_S3_MEDIA_UPLOAD_ACCESS_KEY_ID: ${LANGFUSE_S3_MEDIA_UPLOAD_ACCESS_KEY_ID:-minio} + LANGFUSE_S3_MEDIA_UPLOAD_SECRET_ACCESS_KEY: ${LANGFUSE_S3_MEDIA_UPLOAD_SECRET_ACCESS_KEY:-miniosecret} # CHANGEME + LANGFUSE_S3_MEDIA_UPLOAD_ENDPOINT: http://langfuse-minio:9000 + LANGFUSE_S3_MEDIA_UPLOAD_FORCE_PATH_STYLE: ${LANGFUSE_S3_MEDIA_UPLOAD_FORCE_PATH_STYLE:-true} + LANGFUSE_S3_MEDIA_UPLOAD_PREFIX: ${LANGFUSE_S3_MEDIA_UPLOAD_PREFIX:-media/} + LANGFUSE_OBSERVATION_FIELD_OVERFLOW_ENABLED: ${LANGFUSE_OBSERVATION_FIELD_OVERFLOW_ENABLED:-false} + LANGFUSE_OBSERVATION_FIELD_SIZE_LIMIT_BYTES: ${LANGFUSE_OBSERVATION_FIELD_SIZE_LIMIT_BYTES:-2097152} + LANGFUSE_S3_BATCH_EXPORT_ENABLED: ${LANGFUSE_S3_BATCH_EXPORT_ENABLED:-false} + LANGFUSE_S3_BATCH_EXPORT_BUCKET: ${LANGFUSE_S3_BATCH_EXPORT_BUCKET:-langfuse} + LANGFUSE_S3_BATCH_EXPORT_PREFIX: ${LANGFUSE_S3_BATCH_EXPORT_PREFIX:-exports/} + LANGFUSE_S3_BATCH_EXPORT_REGION: ${LANGFUSE_S3_BATCH_EXPORT_REGION:-auto} + LANGFUSE_S3_BATCH_EXPORT_ENDPOINT: http://langfuse-minio:9000 + LANGFUSE_S3_BATCH_EXPORT_EXTERNAL_ENDPOINT: ${LANGFUSE_S3_BATCH_EXPORT_EXTERNAL_ENDPOINT:-http://localhost:9090} + LANGFUSE_S3_BATCH_EXPORT_ACCESS_KEY_ID: ${LANGFUSE_S3_BATCH_EXPORT_ACCESS_KEY_ID:-minio} + LANGFUSE_S3_BATCH_EXPORT_SECRET_ACCESS_KEY: ${LANGFUSE_S3_BATCH_EXPORT_SECRET_ACCESS_KEY:-miniosecret} # CHANGEME + LANGFUSE_S3_BATCH_EXPORT_FORCE_PATH_STYLE: ${LANGFUSE_S3_BATCH_EXPORT_FORCE_PATH_STYLE:-true} + LANGFUSE_INGESTION_QUEUE_DELAY_MS: ${LANGFUSE_INGESTION_QUEUE_DELAY_MS:-} + LANGFUSE_INGESTION_CLICKHOUSE_WRITE_INTERVAL_MS: ${LANGFUSE_INGESTION_CLICKHOUSE_WRITE_INTERVAL_MS:-} + REDIS_HOST: langfuse-redis + REDIS_PORT: ${LANGFUSE_REDIS_PORT:-6379} + REDIS_AUTH: ${LANGFUSE_REDIS_AUTH:-myredissecret} # CHANGEME + LANGFUSE_BULLMQ_SKIP_REDIS_VERSION_CHECK: ${LANGFUSE_BULLMQ_SKIP_REDIS_VERSION_CHECK:-false} + REDIS_TLS_ENABLED: ${LANGFUSE_REDIS_TLS_ENABLED:-false} + REDIS_TLS_CA: ${LANGFUSE_REDIS_TLS_CA:-/certs/ca.crt} + REDIS_TLS_CERT: ${LANGFUSE_REDIS_TLS_CERT:-/certs/redis.crt} + REDIS_TLS_KEY: ${LANGFUSE_REDIS_TLS_KEY:-/certs/redis.key} + EMAIL_FROM_ADDRESS: ${LANGFUSE_EMAIL_FROM_ADDRESS:-} + SMTP_CONNECTION_URL: ${LANGFUSE_SMTP_CONNECTION_URL:-} + + langfuse-web: + image: docker.io/langfuse/langfuse:4 + restart: always + depends_on: *langfuse-depends-on + ports: + - ${LANGFUSE_WEB_PORT:-3000}:3000 + environment: + <<: *langfuse-worker-env + NEXTAUTH_SECRET: ${LANGFUSE_NEXTAUTH_SECRET:-mysecret} # CHANGEME + # This value is used by browser-facing media upload flows and must be + # reachable from the browser, not just from inside the Docker network. + LANGFUSE_S3_MEDIA_UPLOAD_ENDPOINT: ${LANGFUSE_S3_MEDIA_UPLOAD_ENDPOINT_PUBLIC:-http://localhost:9090} + LANGFUSE_INIT_ORG_ID: ${LANGFUSE_INIT_ORG_ID:-} + LANGFUSE_INIT_ORG_NAME: ${LANGFUSE_INIT_ORG_NAME:-} + LANGFUSE_INIT_PROJECT_ID: ${LANGFUSE_INIT_PROJECT_ID:-} + LANGFUSE_INIT_PROJECT_NAME: ${LANGFUSE_INIT_PROJECT_NAME:-} + LANGFUSE_INIT_PROJECT_PUBLIC_KEY: ${LANGFUSE_INIT_PROJECT_PUBLIC_KEY:-} + LANGFUSE_INIT_PROJECT_SECRET_KEY: ${LANGFUSE_INIT_PROJECT_SECRET_KEY:-} + LANGFUSE_INIT_USER_EMAIL: ${LANGFUSE_INIT_USER_EMAIL:-} + LANGFUSE_INIT_USER_NAME: ${LANGFUSE_INIT_USER_NAME:-} + LANGFUSE_INIT_USER_PASSWORD: ${LANGFUSE_INIT_USER_PASSWORD:-} + + langfuse-clickhouse: + image: docker.io/clickhouse/clickhouse-server:25.12 + restart: always + user: "101:101" + environment: + CLICKHOUSE_DB: default + CLICKHOUSE_USER: ${LANGFUSE_CLICKHOUSE_USER:-clickhouse} + CLICKHOUSE_PASSWORD: ${LANGFUSE_CLICKHOUSE_PASSWORD:-clickhouse} # CHANGEME + volumes: + - langfuse_clickhouse_data:/var/lib/clickhouse + - langfuse_clickhouse_logs:/var/log/clickhouse-server + ports: + - 127.0.0.1:${LANGFUSE_CLICKHOUSE_HTTP_PORT:-18123}:8123 + - 127.0.0.1:${LANGFUSE_CLICKHOUSE_NATIVE_PORT:-19000}:9000 + healthcheck: + test: wget --no-verbose --tries=1 --spider http://localhost:8123/ping || exit 1 + interval: 5s + timeout: 5s + retries: 10 + start_period: 1s + + langfuse-minio: + image: cgr.dev/chainguard/minio + restart: always + entrypoint: sh + command: -c 'mkdir -p /data/langfuse && minio server --address ":9000" --console-address ":9001" /data' + environment: + MINIO_ROOT_USER: ${LANGFUSE_MINIO_ROOT_USER:-minio} + MINIO_ROOT_PASSWORD: ${LANGFUSE_MINIO_ROOT_PASSWORD:-miniosecret} # CHANGEME + ports: + - ${LANGFUSE_MINIO_API_PORT:-9090}:9000 + - 127.0.0.1:${LANGFUSE_MINIO_CONSOLE_PORT:-9091}:9001 + volumes: + - langfuse_minio_data:/data + healthcheck: + test: ["CMD", "mc", "ready", "local"] + interval: 1s + timeout: 5s + retries: 5 + start_period: 1s + + langfuse-redis: + image: docker.io/redis:7 + restart: always + command: > + --requirepass ${LANGFUSE_REDIS_AUTH:-myredissecret} + --maxmemory-policy noeviction + ports: + - 127.0.0.1:${LANGFUSE_REDIS_HOST_PORT:-16379}:6379 + volumes: + - langfuse_redis_data:/data + healthcheck: + test: ["CMD", "redis-cli", "ping"] + interval: 3s + timeout: 10s + retries: 10 + + langfuse-postgres: + image: docker.io/postgres:${LANGFUSE_POSTGRES_VERSION:-17} + restart: always + healthcheck: + test: ["CMD-SHELL", "pg_isready -U ${LANGFUSE_POSTGRES_USER:-postgres}"] + interval: 3s + timeout: 3s + retries: 10 + environment: + POSTGRES_USER: ${LANGFUSE_POSTGRES_USER:-postgres} + POSTGRES_PASSWORD: ${LANGFUSE_POSTGRES_PASSWORD:-postgres} # CHANGEME + POSTGRES_DB: ${LANGFUSE_POSTGRES_DB:-postgres} + TZ: UTC + PGTZ: UTC + ports: + - 127.0.0.1:${LANGFUSE_POSTGRES_HOST_PORT:-15432}:5432 + volumes: + - langfuse_postgres_data:/var/lib/postgresql/data + +volumes: + langfuse_postgres_data: + driver: local + langfuse_clickhouse_data: + driver: local + langfuse_clickhouse_logs: + driver: local + langfuse_minio_data: + driver: local + langfuse_redis_data: + driver: local diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..08eaf96 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,74 @@ +# Application-owned local infrastructure: Postgres, MinIO, Qdrant. +# +# Intentionally separate from docker-compose.langfuse.yml (different service +# names, volumes, and ports). Run alone for app development, or combine with +# Langfuse: +# +# docker compose \ +# -f docker-compose.yml \ +# -f docker-compose.langfuse.yml \ +# --env-file .env \ +# --env-file .env.langfuse \ +# up -d +# +# Do not use this compose stack as-is for production. +services: + app-postgres: + image: docker.io/postgres:17 + restart: always + environment: + POSTGRES_USER: ${POSTGRES_USER:-chatbot} + POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-chatbot} + POSTGRES_DB: ${POSTGRES_DB:-chatbot} + ports: + - 127.0.0.1:${POSTGRES_PORT:-5433}:5432 + volumes: + - app_postgres_data:/var/lib/postgresql/data + healthcheck: + test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-chatbot}"] + interval: 3s + timeout: 3s + retries: 10 + + app-minio: + image: cgr.dev/chainguard/minio + restart: always + entrypoint: sh + command: -c 'mkdir -p /data/${MINIO_BUCKET:-chatbot-source-files} && minio server --address ":9000" --console-address ":9001" /data' + environment: + MINIO_ROOT_USER: ${MINIO_ACCESS_KEY:-chatbot} + MINIO_ROOT_PASSWORD: ${MINIO_SECRET_KEY:-chatbot-secret} + ports: + - 127.0.0.1:9100:9000 + - 127.0.0.1:9101:9001 + volumes: + - app_minio_data:/data + healthcheck: + test: ["CMD", "mc", "ready", "local"] + interval: 1s + timeout: 5s + retries: 5 + start_period: 1s + + app-qdrant: + image: docker.io/qdrant/qdrant + restart: always + ports: + - 127.0.0.1:6343:6333 + - 127.0.0.1:6344:6334 + volumes: + - app_qdrant_data:/qdrant/storage + healthcheck: + test: ["CMD-SHELL", "bash -c '/dev/null || exit 1"] + interval: 3s + timeout: 3s + retries: 10 + start_period: 3s + +volumes: + app_postgres_data: + driver: local + app_minio_data: + driver: local + app_qdrant_data: + driver: local