mirror of
https://github.com/SpecterOps/Nemesis
synced 2026-06-08 12:36:42 +00:00
1028 lines
36 KiB
YAML
1028 lines
36 KiB
YAML
name: nemesis
|
|
|
|
networks:
|
|
nemesis:
|
|
driver: bridge
|
|
|
|
volumes:
|
|
grafana_data:
|
|
jaeger_data:
|
|
loki_data:
|
|
minio_data:
|
|
phoenix_data:
|
|
postgres_data:
|
|
prometheus_data:
|
|
rabbitmq_data:
|
|
empty:
|
|
empty-mounted-containers:
|
|
|
|
services:
|
|
########################################
|
|
# Enrichment Services + Dapr sidecars
|
|
########################################
|
|
|
|
web-api:
|
|
image: ghcr.io/specterops/nemesis/web-api:latest
|
|
healthcheck:
|
|
test: ["CMD", "wget", "--spider", "-q", "http://localhost:8000/healthz"]
|
|
interval: 10s
|
|
timeout: 5s
|
|
retries: 5
|
|
environment:
|
|
- APP_ID=web-api
|
|
- DAPR_GRPC_PORT=50001
|
|
- DAPR_HTTP_PORT=3500
|
|
- DEFAULT_EXPIRATION_DAYS=${DEFAULT_EXPIRATION_DAYS:-100}
|
|
volumes:
|
|
- ${MOUNTED_CONTAINER_PATH:-empty-mounted-containers}:/mounted-containers
|
|
logging: &logging-config
|
|
driver: "json-file"
|
|
options: { max-size: "10m", max-file: "3" }
|
|
depends_on:
|
|
postgres: { condition: service_started }
|
|
placement: { condition: service_started }
|
|
rabbitmq: { condition: service_healthy }
|
|
labels:
|
|
- "traefik.enable=true"
|
|
- "traefik.http.routers.web-api.rule=PathPrefix(`/api`)"
|
|
- "traefik.http.services.web-api.loadbalancer.server.port=8000"
|
|
- "traefik.http.routers.web-api.entrypoints=websecure"
|
|
- "traefik.http.routers.web-api.tls=true"
|
|
- "traefik.http.routers.web-api.middlewares=auth"
|
|
web-api-dapr:
|
|
image: "daprio/daprd:1.16.1"
|
|
command:
|
|
[
|
|
"./daprd",
|
|
"--app-id",
|
|
"web-api",
|
|
"--max-body-size",
|
|
"1Gi",
|
|
"--app-port",
|
|
"8000",
|
|
"--dapr-http-port",
|
|
"3500",
|
|
"--dapr-grpc-port",
|
|
"50001",
|
|
"--placement-host-address",
|
|
"placement:50006",
|
|
"--scheduler-host-address",
|
|
"scheduler:50007",
|
|
"--resources-path",
|
|
"/dapr/components",
|
|
"--config",
|
|
"/dapr/configuration/config.yaml",
|
|
"--enable-metrics",
|
|
"--dapr-graceful-shutdown-seconds",
|
|
"5",
|
|
]
|
|
volumes:
|
|
- ./infra/dapr/components/pubsub.yaml:/dapr/components/pubsub.yaml:ro
|
|
- ./infra/dapr/components/secretstore.yaml:/dapr/components/secretstore.yaml:ro
|
|
- ./infra/dapr/configuration/config_monitoring_${NEMESIS_MONITORING:-disabled}.yaml:/dapr/configuration/config.yaml:ro
|
|
environment:
|
|
- MINIO_ROOT_PASSWORD=${MINIO_ROOT_PASSWORD:?}
|
|
- MINIO_ROOT_USER=${MINIO_ROOT_USER:?}
|
|
- RABBITMQ_CONNECTION_STRING=amqp://${RABBITMQ_USER}:${RABBITMQ_PASSWORD}@rabbitmq:5672
|
|
- POSTGRES_CONNECTION_STRING=postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@postgres:5432/enrichment?sslmode=disable
|
|
- RABBITMQ_PASSWORD=${RABBITMQ_PASSWORD:?}
|
|
- RABBITMQ_USER=${RABBITMQ_USER:?}
|
|
depends_on:
|
|
web-api: { condition: service_started }
|
|
placement: { condition: service_started }
|
|
scheduler: { condition: service_started }
|
|
rabbitmq: { condition: service_healthy }
|
|
network_mode: "service:web-api"
|
|
|
|
noseyparker-scanner:
|
|
image: ghcr.io/specterops/nemesis/noseyparker-scanner:latest
|
|
depends_on:
|
|
minio: { condition: service_healthy }
|
|
rabbitmq: { condition: service_healthy }
|
|
environment:
|
|
- DAPR_GRPC_PORT=50013
|
|
- DAPR_PORT=3513
|
|
- MINIO_ACCESS_KEY=${MINIO_ROOT_USER:?}
|
|
- MINIO_BUCKET=files
|
|
- MINIO_ENDPOINT=http://minio:9000
|
|
- MINIO_SECRET_KEY=${MINIO_ROOT_PASSWORD:?}
|
|
- RUST_LOG=info
|
|
- SNIPPET_LENGTH=512 # context length around any Nosey Parker matches
|
|
- MAX_CONCURRENT_FILES=2 # maximum number of concurrent files to scan
|
|
- MAX_FILE_SIZE_MB=200 # maximum file size to scan
|
|
- DECOMPRESS_ZIPS=true # whether to decompress+scan zips
|
|
- MAX_EXTRACT_SIZE_MB=1000 # maximum number of bytes to extract if decompressing
|
|
volumes:
|
|
- ./projects/noseyparker_scanner/custom_rules/:/opt/noseyparker:ro
|
|
noseyparker-scanner-dapr:
|
|
image: "daprio/daprd:1.16.1"
|
|
command:
|
|
[
|
|
"./daprd",
|
|
"--max-body-size",
|
|
"1Gi",
|
|
"--app-id",
|
|
"noseyparker-scanner",
|
|
"--app-port",
|
|
"50042",
|
|
"--app-protocol",
|
|
"grpc",
|
|
"--dapr-http-port",
|
|
"3513",
|
|
"--dapr-grpc-port",
|
|
"50013",
|
|
"--placement-host-address",
|
|
"placement:50006",
|
|
"--resources-path",
|
|
"/dapr/components",
|
|
"--config",
|
|
"/dapr/configuration/config.yaml",
|
|
"--app-max-concurrency",
|
|
"1",
|
|
"--enable-metrics",
|
|
"--dapr-graceful-shutdown-seconds",
|
|
"5",
|
|
]
|
|
environment:
|
|
- RABBITMQ_CONNECTION_STRING=amqp://${RABBITMQ_USER}:${RABBITMQ_PASSWORD}@rabbitmq:5672
|
|
volumes:
|
|
- ./infra/dapr/components/pubsub.yaml:/dapr/components/pubsub.yaml:ro
|
|
- ./infra/dapr/components/secretstore.yaml:/dapr/components/secretstore.yaml:ro
|
|
- ./infra/dapr/configuration/config_monitoring_${NEMESIS_MONITORING:-disabled}.yaml:/dapr/configuration/config.yaml:ro
|
|
depends_on: [noseyparker-scanner, placement]
|
|
network_mode: "service:noseyparker-scanner"
|
|
|
|
dotnet-service:
|
|
image: ghcr.io/specterops/nemesis/dotnet-service:latest
|
|
healthcheck:
|
|
test: ["CMD", "curl", "-f", "http://localhost:5000/health"]
|
|
interval: 30s
|
|
timeout: 10s
|
|
retries: 3
|
|
start_period: 30s
|
|
depends_on:
|
|
minio: { condition: service_healthy }
|
|
rabbitmq: { condition: service_healthy }
|
|
environment:
|
|
- DAPR_GRPC_PORT=50014
|
|
- DAPR_PORT=3514
|
|
- MINIO_ACCESS_KEY=${MINIO_ROOT_USER:?}
|
|
- MINIO_BUCKET=files
|
|
- MINIO_ENDPOINT=http://minio:9000
|
|
- MINIO_SECRET_KEY=${MINIO_ROOT_PASSWORD:?}
|
|
- ASPNETCORE_URLS=http://0.0.0.0:5000
|
|
expose:
|
|
- "5000"
|
|
dotnet-service-dapr:
|
|
image: "daprio/daprd:1.16.1"
|
|
command:
|
|
[
|
|
"./daprd",
|
|
"--max-body-size",
|
|
"1Gi",
|
|
"--app-id",
|
|
"dotnet-service",
|
|
"--app-port",
|
|
"5000",
|
|
"--app-protocol",
|
|
"http",
|
|
"--dapr-http-port",
|
|
"3514",
|
|
"--dapr-grpc-port",
|
|
"50014",
|
|
"--placement-host-address",
|
|
"placement:50006",
|
|
"--resources-path",
|
|
"/dapr/components",
|
|
"--config",
|
|
"/dapr/configuration/config.yaml",
|
|
"--app-max-concurrency",
|
|
"1",
|
|
"--enable-metrics",
|
|
"--dapr-graceful-shutdown-seconds",
|
|
"5",
|
|
]
|
|
environment:
|
|
- RABBITMQ_CONNECTION_STRING=amqp://${RABBITMQ_USER}:${RABBITMQ_PASSWORD}@rabbitmq:5672
|
|
volumes:
|
|
- ./infra/dapr/components/pubsub.yaml:/dapr/components/pubsub.yaml:ro
|
|
- ./infra/dapr/components/secretstore.yaml:/dapr/components/secretstore.yaml:ro
|
|
- ./infra/dapr/configuration/config_monitoring_${NEMESIS_MONITORING:-disabled}.yaml:/dapr/configuration/config.yaml:ro
|
|
depends_on: [dotnet-service, placement]
|
|
network_mode: "service:dotnet-service"
|
|
|
|
file-enrichment:
|
|
image: ghcr.io/specterops/nemesis/file-enrichment:latest
|
|
healthcheck:
|
|
test: ["CMD", "wget", "--spider", "-q", "http://localhost:8001/healthz"]
|
|
interval: 10s
|
|
timeout: 5s
|
|
retries: 5
|
|
volumes: []
|
|
# Uncomment the following line to use custom YARA rules
|
|
# - ./libs/file_enrichment_modules/yara_rules/prod/:/yara_rules/:ro
|
|
environment:
|
|
- APP_ID=file-enrichment
|
|
- DAPR_GRPC_PORT=50003
|
|
- DAPR_HTTP_PORT=3503
|
|
- LOG_LEVEL=${LOG_LEVEL:-INFO}
|
|
- MAX_PARALLEL_ENRICHMENT_MODULES=${MAX_PARALLEL_ENRICHMENT_MODULES:-5}
|
|
- MAX_PARALLEL_WORKFLOWS=${MAX_PARALLEL_WORKFLOWS:-5}
|
|
- MAX_WORKFLOW_EXECUTION_TIME=${MAX_WORKFLOW_EXECUTION_TIME:-300}
|
|
- NEMESIS_MONITORING=${NEMESIS_MONITORING:-disabled}
|
|
- NEMESIS_URL=${NEMESIS_URL:?}
|
|
- OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=http://otel-collector:4317
|
|
- OTEL_EXPORTER_OTLP_TRACES_ENDPOINT_INSECURE=true
|
|
- RIGGING_GENERATOR_CREDENTIALS=${RIGGING_GENERATOR_CREDENTIALS:-}
|
|
- RIGGING_GENERATOR_SUMMARY=${RIGGING_GENERATOR_SUMMARY:-}
|
|
- RIGGING_GENERATOR_TRIAGE=${RIGGING_GENERATOR_TRIAGE:-}
|
|
- UVICORN_WORKERS=${UVICORN_WORKERS:-2}
|
|
- WORKFLOW_RUNTIME_LOG_LEVEL=${WORKFLOW_RUNTIME_LOG_LEVEL:-WARNING}
|
|
- WORKFLOW_CLIENT_LOG_LEVEL=${WORKFLOW_CLIENT_LOG_LEVEL:-WARNING}
|
|
logging: *logging-config
|
|
depends_on:
|
|
postgres: { condition: service_started }
|
|
placement: { condition: service_started }
|
|
rabbitmq: { condition: service_healthy }
|
|
file-enrichment-dapr:
|
|
image: "daprio/daprd:1.16.1"
|
|
command:
|
|
[
|
|
"./daprd",
|
|
"--max-body-size",
|
|
"1Gi",
|
|
"--app-id",
|
|
"file-enrichment",
|
|
"--app-port",
|
|
"8001",
|
|
"--dapr-http-port",
|
|
"3503",
|
|
"--dapr-grpc-port",
|
|
"50003",
|
|
"--placement-host-address",
|
|
"placement:50006",
|
|
"--scheduler-host-address",
|
|
"scheduler:50007",
|
|
"--resources-path",
|
|
"/dapr/components",
|
|
"--config",
|
|
"/dapr/configuration/config.yaml",
|
|
"--enable-metrics",
|
|
"--dapr-graceful-shutdown-seconds",
|
|
"5",
|
|
]
|
|
volumes:
|
|
- ./infra/dapr/components/pubsub.yaml:/dapr/components/pubsub.yaml:ro
|
|
- ./infra/dapr/components/secretstore.yaml:/dapr/components/secretstore.yaml:ro
|
|
- ./infra/dapr/components/workflowstate.yaml:/dapr/components/workflowstate.yaml:ro
|
|
- ./infra/dapr/configuration/config_monitoring_${NEMESIS_MONITORING:-disabled}.yaml:/dapr/configuration/config.yaml:ro
|
|
environment:
|
|
- POSTGRES_CONNECTION_STRING=postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@postgres:5432/enrichment?sslmode=disable
|
|
- RABBITMQ_CONNECTION_STRING=amqp://${RABBITMQ_USER}:${RABBITMQ_PASSWORD}@rabbitmq:5672
|
|
- MINIO_ROOT_USER=${MINIO_ROOT_USER:?}
|
|
- MINIO_ROOT_PASSWORD=${MINIO_ROOT_PASSWORD:?}
|
|
depends_on:
|
|
file-enrichment: { condition: service_started }
|
|
placement: { condition: service_started }
|
|
scheduler: { condition: service_started }
|
|
rabbitmq: { condition: service_healthy }
|
|
network_mode: "service:file-enrichment"
|
|
|
|
frontend:
|
|
image: ghcr.io/specterops/nemesis/frontend:latest
|
|
depends_on: [postgres, hasura]
|
|
environment:
|
|
- HASURA_ADMIN_SECRET=${HASURA_ADMIN_SECRET:-pass456}
|
|
command: >
|
|
sh -c "
|
|
SECRET=\"$$HASURA_ADMIN_SECRET\" &&
|
|
sed -i \"s/\\$$HASURA_ADMIN_SECRET/$$SECRET/g\" /usr/share/nginx/html/index.html &&
|
|
nginx -g 'daemon off;'
|
|
"
|
|
healthcheck:
|
|
test: ["CMD", "wget", "--spider", "-q", "http://localhost:3000"]
|
|
interval: 10s
|
|
timeout: 10s
|
|
retries: 3
|
|
labels:
|
|
- "traefik.enable=true"
|
|
- "traefik.http.routers.frontend.rule=PathPrefix(`/`)"
|
|
- "traefik.http.services.frontend.loadbalancer.server.port=3000"
|
|
- "traefik.http.routers.frontend.entrypoints=websecure"
|
|
- "traefik.http.routers.frontend.tls=true"
|
|
- "traefik.http.routers.frontend.middlewares=auth"
|
|
|
|
jupyter:
|
|
profiles: ["jupyter"]
|
|
image: ghcr.io/specterops/nemesis/jupyter:latest
|
|
depends_on: [postgres, hasura]
|
|
environment:
|
|
- HASURA_ADMIN_SECRET=${HASURA_ADMIN_SECRET:-pass456}
|
|
- HASURA_GRAPHQL_URL=http://hasura:8080/v1/graphql
|
|
- JUPYTER_PASSWORD=${JUPYTER_PASSWORD:-}
|
|
volumes:
|
|
- "./projects/jupyter/notebooks:/home/jovyan/work"
|
|
healthcheck:
|
|
test: ["CMD", "curl", "-f", "http://localhost:8888/jupyter/api"]
|
|
interval: 30s
|
|
timeout: 10s
|
|
retries: 3
|
|
labels:
|
|
- "traefik.enable=true"
|
|
- "traefik.http.routers.jupyter.rule=PathPrefix(`/jupyter`)"
|
|
- "traefik.http.services.jupyter.loadbalancer.server.port=8888"
|
|
- "traefik.http.routers.jupyter.entrypoints=websecure"
|
|
- "traefik.http.routers.jupyter.tls=true"
|
|
- "traefik.http.routers.jupyter.middlewares=auth"
|
|
|
|
alerting:
|
|
image: ghcr.io/specterops/nemesis/alerting:latest
|
|
environment:
|
|
- DAPR_HTTP_PORT=3508
|
|
- DAPR_GRPC_PORT=50008
|
|
- APPRISE_URLS=${APPRISE_URLS:-}
|
|
- NEMESIS_URL=${NEMESIS_URL:?}
|
|
logging: *logging-config
|
|
depends_on:
|
|
postgres: { condition: service_healthy }
|
|
placement: { condition: service_started }
|
|
rabbitmq: { condition: service_healthy }
|
|
hasura: { condition: service_healthy }
|
|
healthcheck: &healthcheck-python-svc
|
|
test: ["CMD", "wget", "--spider", "-q", "http://localhost:8000/healthz"]
|
|
interval: 10s
|
|
timeout: 5s
|
|
retries: 5
|
|
start_period: 20s
|
|
alerting-dapr:
|
|
image: "daprio/daprd:1.16.1"
|
|
command:
|
|
[
|
|
"./daprd",
|
|
"--max-body-size",
|
|
"1Gi",
|
|
"--app-id",
|
|
"alerting",
|
|
"--app-port",
|
|
"8000",
|
|
"--dapr-http-port",
|
|
"3508",
|
|
"--dapr-grpc-port",
|
|
"50008",
|
|
"--placement-host-address",
|
|
"placement:50006",
|
|
"--scheduler-host-address",
|
|
"scheduler:50007",
|
|
"--resources-path",
|
|
"/dapr/components",
|
|
"--config",
|
|
"/dapr/configuration/config.yaml",
|
|
"--enable-metrics",
|
|
"--dapr-graceful-shutdown-seconds",
|
|
"5",
|
|
]
|
|
volumes:
|
|
- ./infra/dapr/components/pubsub.yaml:/dapr/components/pubsub.yaml:ro
|
|
- ./infra/dapr/components/secretstore.yaml:/dapr/components/secretstore.yaml:ro
|
|
- ./infra/dapr/configuration/config_monitoring_${NEMESIS_MONITORING:-disabled}.yaml:/dapr/configuration/config.yaml:ro
|
|
environment:
|
|
- RABBITMQ_CONNECTION_STRING=amqp://${RABBITMQ_USER}:${RABBITMQ_PASSWORD}@rabbitmq:5672
|
|
- HASURA_ADMIN_SECRET=${HASURA_ADMIN_SECRET:-pass456}
|
|
depends_on:
|
|
alerting: { condition: service_started }
|
|
placement: { condition: service_started }
|
|
scheduler: { condition: service_started }
|
|
rabbitmq: { condition: service_healthy }
|
|
network_mode: "service:alerting"
|
|
|
|
agents:
|
|
image: ghcr.io/specterops/nemesis/agents:latest
|
|
environment:
|
|
- DAPR_HTTP_PORT=3509
|
|
- DAPR_GRPC_PORT=50009
|
|
- NEMESIS_URL=${NEMESIS_URL:?}
|
|
- WORKFLOW_RUNTIME_LOG_LEVEL=${WORKFLOW_RUNTIME_LOG_LEVEL:-WARNING}
|
|
- WORKFLOW_CLIENT_LOG_LEVEL=${WORKFLOW_CLIENT_LOG_LEVEL:-WARNING}
|
|
- LITELLM_ADMIN_KEY=sk-${LITELLM_ADMIN_PASSWORD:-admin123}
|
|
- MAX_BUDGET=${LLM_MAX_BUDGET:-100}
|
|
- BUDGET_DURATION=${LLM_BUDGET_DURATION:-30d}
|
|
- DOTNET_ANALYSIS_RUN_REQUEST_LIMIT=${DOTNET_ANALYSIS_RUN_REQUEST_LIMIT:-25} # max LLM calls to use per .NET program analysis run
|
|
- DOTNET_ANALYSIS_RUN_TOKENS_LIMIT=${DOTNET_ANALYSIS_RUN_TOKENS_LIMIT:-1000000} # max tokens to use per .NET program analysis run
|
|
# if we hit this number of the same triage values for the same file, all future findings get that value
|
|
- TRIAGE_CONSENSUS_THRESHOLD=${TRIAGE_CONSENSUS_THRESHOLD:-3}
|
|
# Phoenix LLM tracing configuration
|
|
- PHOENIX_ENABLED=${PHOENIX_ENABLED:-false}
|
|
- PHOENIX_ENDPOINT=${PHOENIX_ENDPOINT:-http://phoenix:6006/v1/traces}
|
|
- PHOENIX_SQL_DATABASE_URL=postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@postgres:5432/phoenix
|
|
- NEMESIS_MONITORING=${NEMESIS_MONITORING:-disabled}
|
|
- OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=http://otel-collector:4317
|
|
- OTEL_EXPORTER_OTLP_TRACES_ENDPOINT_INSECURE=true
|
|
logging: *logging-config
|
|
depends_on:
|
|
postgres: { condition: service_healthy }
|
|
placement: { condition: service_started }
|
|
rabbitmq: { condition: service_healthy }
|
|
hasura: { condition: service_healthy }
|
|
healthcheck: *healthcheck-python-svc
|
|
agents-dapr:
|
|
image: "daprio/daprd:1.16.1"
|
|
command:
|
|
[
|
|
"./daprd",
|
|
"--max-body-size",
|
|
"1Gi",
|
|
"--app-id",
|
|
"agents",
|
|
"--app-port",
|
|
"8000",
|
|
"--dapr-http-port",
|
|
"3509",
|
|
"--dapr-grpc-port",
|
|
"50009",
|
|
"--placement-host-address",
|
|
"placement:50006",
|
|
"--scheduler-host-address",
|
|
"scheduler:50007",
|
|
"--resources-path",
|
|
"/dapr/components",
|
|
"--config",
|
|
"/dapr/configuration/config.yaml",
|
|
"--enable-metrics",
|
|
"--dapr-graceful-shutdown-seconds",
|
|
"5",
|
|
]
|
|
volumes:
|
|
- ./infra/dapr/components/secretstore.yaml:/dapr/components/secretstore.yaml:ro
|
|
- ./infra/dapr/components/workflowstate.yaml:/dapr/components/workflowstate.yaml:ro
|
|
- ./infra/dapr/configuration/config_monitoring_${NEMESIS_MONITORING:-disabled}.yaml:/dapr/configuration/config.yaml:ro
|
|
environment:
|
|
- POSTGRES_CONNECTION_STRING=postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@postgres:5432/enrichment?sslmode=disable
|
|
- POSTGRES_CONNECTION_URL=postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@postgres:5432/enrichment
|
|
- HASURA_ADMIN_SECRET=${HASURA_ADMIN_SECRET:-pass456}
|
|
- RABBITMQ_CONNECTION_STRING=amqp://${RABBITMQ_USER}:${RABBITMQ_PASSWORD}@rabbitmq:5672
|
|
- MINIO_ROOT_USER=${MINIO_ROOT_USER:?}
|
|
- MINIO_ROOT_PASSWORD=${MINIO_ROOT_PASSWORD:?}
|
|
depends_on:
|
|
agents: { condition: service_started }
|
|
placement: { condition: service_started }
|
|
scheduler: { condition: service_started }
|
|
rabbitmq: { condition: service_healthy }
|
|
network_mode: "service:agents"
|
|
|
|
housekeeping:
|
|
image: ghcr.io/specterops/nemesis/housekeeping:latest
|
|
environment:
|
|
- APP_ID=housekeeping
|
|
- CLEANUP_SCHEDULE=*/3 * * * * # Every 3 minutes
|
|
- DAPR_GRPC_PORT=50011
|
|
- DAPR_HTTP_PORT=3510
|
|
logging: *logging-config
|
|
depends_on:
|
|
postgres: { condition: service_healthy }
|
|
placement: { condition: service_started }
|
|
rabbitmq: { condition: service_healthy }
|
|
healthcheck: *healthcheck-python-svc
|
|
housekeeping-dapr:
|
|
image: "daprio/daprd:1.16.1"
|
|
command:
|
|
[
|
|
"./daprd",
|
|
"--max-body-size",
|
|
"1Gi",
|
|
"--app-id",
|
|
"housekeeping",
|
|
"--app-port",
|
|
"8000",
|
|
"--dapr-http-port",
|
|
"3510",
|
|
"--dapr-grpc-port",
|
|
"50011",
|
|
"--placement-host-address",
|
|
"placement:50006",
|
|
"--scheduler-host-address",
|
|
"scheduler:50007",
|
|
"--resources-path",
|
|
"/dapr/components",
|
|
"--config",
|
|
"/dapr/configuration/config.yaml",
|
|
"--enable-metrics",
|
|
"--dapr-graceful-shutdown-seconds",
|
|
"5",
|
|
]
|
|
volumes:
|
|
- ./infra/dapr/components/secretstore.yaml:/dapr/components/secretstore.yaml:ro
|
|
- ./infra/dapr/configuration/config_monitoring_${NEMESIS_MONITORING:-disabled}.yaml:/dapr/configuration/config.yaml:ro
|
|
environment:
|
|
- MINIO_ROOT_PASSWORD=${MINIO_ROOT_PASSWORD:?}
|
|
- MINIO_ROOT_USER=${MINIO_ROOT_USER:?}
|
|
- POSTGRES_CONNECTION_STRING=postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@postgres:5432/enrichment?sslmode=disable
|
|
depends_on:
|
|
housekeeping: { condition: service_started }
|
|
placement: { condition: service_started }
|
|
scheduler: { condition: service_started }
|
|
rabbitmq: { condition: service_healthy }
|
|
network_mode: "service:housekeeping"
|
|
|
|
document-conversion:
|
|
image: ghcr.io/specterops/nemesis/document-conversion:latest
|
|
volumes:
|
|
- ./infra/tika/tika-config.xml:/tika-config.xml:ro
|
|
environment:
|
|
- APP_ID=document-conversion
|
|
- DAPR_GRPC_PORT=50002
|
|
- DAPR_HTTP_PORT=3501
|
|
- TIKA_CONFIG=/tika-config.xml
|
|
# If you want to have additional language packs supported (see https://github.com/tesseract-ocr/tessdata for a full list):
|
|
# $ export TIKA_OCR_LANGUAGES="eng chi_sim chi_tra jpn rus deu spa"
|
|
# To change the default:
|
|
# - TIKA_OCR_LANGUAGES=${TIKA_OCR_LANGUAGES:-eng chi_sim chi_tra jpn rus deu spa}
|
|
# Note: each package installed will increase the image size!
|
|
- TIKA_OCR_LANGUAGES=${TIKA_OCR_LANGUAGES:-eng}
|
|
- MAX_PARALLEL_WORKFLOWS=${MAX_PARALLEL_WORKFLOWS:-5}
|
|
- MAX_WORKFLOW_EXECUTION_TIME=${MAX_WORKFLOW_EXECUTION_TIME:-300}
|
|
healthcheck:
|
|
test: ["CMD", "wget", "--spider", "-q", "http://localhost:8000/healthz"]
|
|
interval: 10s
|
|
timeout: 5s
|
|
retries: 5
|
|
logging: *logging-config
|
|
depends_on:
|
|
postgres: { condition: service_started }
|
|
placement: { condition: service_started }
|
|
rabbitmq: { condition: service_healthy }
|
|
document-conversion-dapr:
|
|
image: "daprio/daprd:1.16.1"
|
|
command:
|
|
[
|
|
"./daprd",
|
|
"--max-body-size",
|
|
"1Gi",
|
|
"--app-id",
|
|
"document-conversion",
|
|
"--app-port",
|
|
"8000",
|
|
"--dapr-http-port",
|
|
"3501",
|
|
"--dapr-grpc-port",
|
|
"50002",
|
|
"--placement-host-address",
|
|
"placement:50006",
|
|
"--scheduler-host-address",
|
|
"scheduler:50007",
|
|
"--resources-path",
|
|
"/dapr/components",
|
|
"--config",
|
|
"/dapr/configuration/config.yaml",
|
|
"--enable-metrics",
|
|
"--dapr-graceful-shutdown-seconds",
|
|
"5",
|
|
]
|
|
volumes:
|
|
- ./infra/dapr/components/pubsub.yaml:/dapr/components/pubsub.yaml:ro
|
|
- ./infra/dapr/components/secretstore.yaml:/dapr/components/secretstore.yaml:ro
|
|
- ./infra/dapr/components/workflowstate.yaml:/dapr/components/workflowstate.yaml:ro
|
|
- ./infra/dapr/configuration/config_monitoring_${NEMESIS_MONITORING:-disabled}.yaml:/dapr/configuration/config.yaml:ro
|
|
environment:
|
|
- MINIO_ROOT_PASSWORD=${MINIO_ROOT_PASSWORD:?}
|
|
- MINIO_ROOT_USER=${MINIO_ROOT_USER:?}
|
|
- POSTGRES_CONNECTION_STRING=postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@postgres:5432/enrichment?sslmode=disable
|
|
- RABBITMQ_CONNECTION_STRING=amqp://${RABBITMQ_USER}:${RABBITMQ_PASSWORD}@rabbitmq:5672
|
|
depends_on:
|
|
document-conversion: { condition: service_started }
|
|
placement: { condition: service_started }
|
|
scheduler: { condition: service_started }
|
|
rabbitmq: { condition: service_healthy }
|
|
network_mode: "service:document-conversion"
|
|
|
|
gotenberg:
|
|
image: gotenberg/gotenberg:8.21.1
|
|
command:
|
|
[
|
|
"gotenberg",
|
|
"--api-timeout=180s",
|
|
"--libreoffice-restart-after=5",
|
|
"--libreoffice-auto-start=true",
|
|
"--prometheus-collect-interval=10s",
|
|
]
|
|
environment: { DISABLE_GOOGLE_CHROME: "1" }
|
|
healthcheck:
|
|
test: ["CMD", "curl", "-sSf", "http://localhost:3000/health"]
|
|
interval: 30s
|
|
timeout: 10s
|
|
retries: 3
|
|
gotenberg-dapr:
|
|
image: "daprio/daprd:1.16.1"
|
|
command:
|
|
[
|
|
"./daprd",
|
|
"--max-body-size",
|
|
"1Gi",
|
|
"--app-id",
|
|
"gotenberg",
|
|
"--app-port",
|
|
"3000",
|
|
"--dapr-http-port",
|
|
"3505",
|
|
"--dapr-grpc-port",
|
|
"50005",
|
|
"--placement-host-address",
|
|
"placement:50006",
|
|
"--scheduler-host-address",
|
|
"scheduler:50007",
|
|
"--resources-path",
|
|
"/dapr/components",
|
|
"--config",
|
|
"/dapr/configuration/config.yaml",
|
|
"--enable-metrics",
|
|
"--dapr-graceful-shutdown-seconds",
|
|
"5",
|
|
]
|
|
volumes:
|
|
- ./infra/dapr/configuration/config_monitoring_${NEMESIS_MONITORING:-disabled}.yaml:/dapr/configuration/config.yaml:ro
|
|
- empty:/dapr/components:ro
|
|
|
|
depends_on:
|
|
gotenberg: { condition: service_started }
|
|
placement: { condition: service_started }
|
|
scheduler: { condition: service_started }
|
|
rabbitmq: { condition: service_healthy }
|
|
network_mode: "service:gotenberg"
|
|
|
|
############################
|
|
# Infrastructure Services
|
|
############################
|
|
minio:
|
|
image: minio/minio:latest
|
|
environment:
|
|
MINIO_PROMETHEUS_AUTH_TYPE: public
|
|
MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD:?}
|
|
MINIO_ROOT_USER: ${MINIO_ROOT_USER:?}
|
|
volumes:
|
|
- minio_data:/data
|
|
command: server /data --console-address ":9001" --address ":9000"
|
|
healthcheck:
|
|
test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"]
|
|
interval: 30s
|
|
timeout: 20s
|
|
retries: 3
|
|
|
|
minio-init:
|
|
image: minio/mc:latest
|
|
depends_on: [minio]
|
|
environment:
|
|
- MINIO_ROOT_PASSWORD=${MINIO_ROOT_PASSWORD}
|
|
- MINIO_ROOT_USER=${MINIO_ROOT_USER}
|
|
entrypoint:
|
|
[
|
|
"/bin/sh",
|
|
"-c",
|
|
"sleep 1; until mc alias set minio http://minio:9000 $${MINIO_ROOT_USER} $${MINIO_ROOT_PASSWORD}; do echo 'Minio is not online. Waiting for it to start...'; sleep 2; done && mc mb minio/loki-data --ignore-existing",
|
|
]
|
|
restart: "no"
|
|
|
|
rabbitmq:
|
|
image: rabbitmq:4.1.2-management
|
|
hostname: rabbitmq-node # have to do this for persistence reasons
|
|
environment:
|
|
- RABBITMQ_DEFAULT_PASS=${RABBITMQ_PASSWORD:?}
|
|
- RABBITMQ_DEFAULT_USER=${RABBITMQ_USER:?}
|
|
- RABBITMQ_SERVER_ADDITIONAL_ERL_ARGS=-rabbitmq_management path_prefix "/rabbitmq"
|
|
- RABBITMQ_NODENAME=rabbit@rabbitmq-node # have to do this for persistence reasons
|
|
volumes:
|
|
- rabbitmq_data:/var/lib/rabbitmq
|
|
- ./infra/rabbitmq/enabled_plugins:/etc/rabbitmq/enabled_plugins:ro
|
|
healthcheck:
|
|
test: ["CMD", "rabbitmq-diagnostics", "check_port_connectivity"]
|
|
interval: 10s
|
|
timeout: 10s
|
|
retries: 5
|
|
labels:
|
|
- "traefik.enable=true"
|
|
- "traefik.http.routers.rabbitmq-ui.entrypoints=websecure"
|
|
- "traefik.http.routers.rabbitmq-ui.tls=true"
|
|
- "traefik.http.services.rabbitmq-ui.loadbalancer.server.port=15672"
|
|
- "traefik.http.routers.rabbitmq-ui.rule=PathPrefix(`/rabbitmq`)"
|
|
|
|
postgres:
|
|
image: postgres:17.6-alpine
|
|
command: [
|
|
"postgres",
|
|
"-c", "max_connections=200",
|
|
"-c", "shared_buffers=256MB"
|
|
]
|
|
environment:
|
|
POSTGRES_DB: ${POSTGRES_DB:-enrichment}
|
|
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?}
|
|
POSTGRES_USER: ${POSTGRES_USER:?}
|
|
volumes:
|
|
- ./infra/postgres:/docker-entrypoint-initdb.d:ro
|
|
- postgres_data:/var/lib/postgresql/data
|
|
healthcheck:
|
|
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d enrichment"]
|
|
interval: 10s
|
|
timeout: 5s
|
|
retries: 5
|
|
|
|
postgres-exporter:
|
|
profiles: ["monitoring"]
|
|
image: prometheuscommunity/postgres-exporter:latest
|
|
environment:
|
|
DATA_SOURCE_NAME: "postgresql://${POSTGRES_USER:?}:${POSTGRES_PASSWORD:?}@postgres:5432/enrichment?sslmode=disable"
|
|
volumes:
|
|
- ./infra/postgres-exporter/postgres_exporter.yml:/postgres_exporter.yml:ro
|
|
depends_on:
|
|
postgres: { condition: service_healthy }
|
|
|
|
hasura:
|
|
image: hasura/graphql-engine:v2.48.6.cli-migrations-v2
|
|
depends_on:
|
|
postgres: { condition: service_healthy }
|
|
environment:
|
|
HASURA_GRAPHQL_ADMIN_SECRET: "${HASURA_ADMIN_SECRET:-pass456}"
|
|
HASURA_GRAPHQL_BASE_PATH: "/hasura"
|
|
HASURA_GRAPHQL_DATABASE_URL: postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@postgres:5432/enrichment
|
|
HASURA_GRAPHQL_ENABLE_CONSOLE: "true"
|
|
HASURA_GRAPHQL_ENABLE_METADATA_SYNC: "true"
|
|
HASURA_GRAPHQL_ENABLE_TELEMETRY: "false"
|
|
HASURA_GRAPHQL_ENABLED_LOG_TYPES: startup, http-log, webhook-log, websocket-log, query-log
|
|
HASURA_GRAPHQL_LOG_LEVEL: "warn"
|
|
HASURA_GRAPHQL_METADATA_DATABASE_URL: postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@postgres:5432/enrichment
|
|
HASURA_GRAPHQL_METADATA_DIR: /hasura-metadata
|
|
HASURA_GRAPHQL_UNAUTHORIZED_ROLE: anonymous
|
|
volumes:
|
|
- ./infra/hasura/metadata:/hasura-metadata:ro
|
|
labels:
|
|
- "traefik.enable=true"
|
|
- "traefik.http.routers.hasura.rule=PathPrefix(`/hasura`)"
|
|
- "traefik.http.services.hasura.loadbalancer.server.port=8080"
|
|
- "traefik.http.routers.hasura.middlewares=graphql-stripprefix"
|
|
- "traefik.http.middlewares.graphql-stripprefix.stripprefix.prefixes=/hasura"
|
|
- "traefik.http.routers.hasura.entrypoints=websecure"
|
|
- "traefik.http.routers.hasura.tls=true"
|
|
|
|
traefik:
|
|
image: traefik:v3.4.4
|
|
command:
|
|
- "--api.insecure=true"
|
|
# - "--log.level=DEBUG"
|
|
- "--log.level=WARN"
|
|
- "--providers.docker=true"
|
|
- "--providers.docker.exposedbydefault=false"
|
|
- "--providers.file=true"
|
|
- "--providers.file.directory=/config"
|
|
- "--providers.file.watch=true"
|
|
- "--entrypoints.web.address=:80"
|
|
- "--entrypoints.web.http.redirections.entryPoint.to=websecure"
|
|
- "--entrypoints.web.http.redirections.entryPoint.scheme=https"
|
|
- "--entrypoints.websecure.address=:443"
|
|
- "--metrics.prometheus=true"
|
|
- "--metrics.prometheus.addrouterslabels=true"
|
|
labels:
|
|
- "traefik.enable=true"
|
|
- "traefik.http.middlewares.auth.basicauth.users=${BASIC_AUTH_USERS:-n:$$apr1$$RbnOjtKr$$S706SPJ3KzCKIref.gRFT.}"
|
|
- "traefik.http.routers.dashboard.tls=true"
|
|
environment:
|
|
- NEMESIS_PORT=${NEMESIS_PORT:-7443}
|
|
ports: ["${NEMESIS_PORT:-7443}:443"]
|
|
volumes:
|
|
- /var/run/docker.sock:/var/run/docker.sock:ro
|
|
- ./auth:/auth:ro
|
|
- ./infra/traefik/certs:/certs:ro
|
|
- ./infra/traefik/config:/config:ro
|
|
|
|
placement:
|
|
image: "daprio/dapr:1.16.1"
|
|
command: ["./placement", "-port", "50006"]
|
|
|
|
scheduler:
|
|
image: "daprio/dapr:1.16.1"
|
|
command:
|
|
[
|
|
"./scheduler",
|
|
"--port",
|
|
"50007",
|
|
"--etcd-data-dir=/var/lock/dapr/scheduler",
|
|
]
|
|
|
|
############################
|
|
# Monitoring Services (optional profile)
|
|
############################
|
|
|
|
otel-collector:
|
|
profiles: ["monitoring"]
|
|
image: otel/opentelemetry-collector:latest
|
|
command: ["--config=/etc/otel-collector-config.yaml"]
|
|
volumes:
|
|
- ./infra/otel-collector/otel-collector-config.yaml:/etc/otel-collector-config.yaml:ro
|
|
depends_on: [jaeger]
|
|
|
|
jaeger:
|
|
profiles: ["monitoring"]
|
|
image: jaegertracing/jaeger:latest # v2.x image
|
|
user: "0:0"
|
|
environment:
|
|
- QUERY_BASE_PATH=/jaeger
|
|
volumes:
|
|
- ./infra/jaeger/jaeger-config.yaml:/etc/jaeger/config.yaml
|
|
- jaeger_data:/badger # Persist trace data
|
|
command: ["--config", "/etc/jaeger/config.yaml"]
|
|
labels:
|
|
- "traefik.enable=true"
|
|
- "traefik.http.routers.jaeger.rule=PathPrefix(`/jaeger`)"
|
|
- "traefik.http.services.jaeger.loadbalancer.server.port=16686"
|
|
- "traefik.http.routers.jaeger.entrypoints=websecure"
|
|
- "traefik.http.routers.jaeger.tls=true"
|
|
- "traefik.http.routers.jaeger.middlewares=auth"
|
|
healthcheck:
|
|
test: ["CMD-SHELL", "wget --no-verbose --tries=1 --spider http://localhost:13133/status || exit 1"]
|
|
interval: 30s
|
|
timeout: 10s
|
|
retries: 3
|
|
start_period: 30s
|
|
|
|
phoenix:
|
|
profiles: ["monitoring"]
|
|
image: arizephoenix/phoenix:11.24.1
|
|
environment:
|
|
- PHOENIX_WORKING_DIR=/data
|
|
- PHOENIX_HOST_ROOT_PATH=/phoenix
|
|
- PHOENIX_SQL_DATABASE_URL=postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@postgres:5432/phoenix
|
|
- PHOENIX_DEFAULT_RETENTION_POLICY_DAYS=100
|
|
volumes:
|
|
- phoenix_data:/data
|
|
# ports:
|
|
# - "6006:6006" # Phoenix UI port, for debugging
|
|
labels:
|
|
- "traefik.enable=true"
|
|
- "traefik.http.services.phoenix.loadbalancer.server.port=6006"
|
|
- "traefik.http.routers.phoenix.rule=PathPrefix(`/phoenix`)"
|
|
- "traefik.http.routers.phoenix.entrypoints=websecure"
|
|
- "traefik.http.routers.phoenix.tls=true"
|
|
- "traefik.http.routers.phoenix.middlewares=auth,phoenix-stripprefix"
|
|
- "traefik.http.middlewares.phoenix-stripprefix.stripprefix.prefixes=/phoenix"
|
|
depends_on:
|
|
postgres: { condition: service_healthy }
|
|
healthcheck:
|
|
test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://localhost:6006/healthz').read()"]
|
|
interval: 30s
|
|
timeout: 10s
|
|
retries: 3
|
|
start_period: 30s
|
|
|
|
loki:
|
|
profiles: ["monitoring"]
|
|
image: grafana/loki:3.3.2
|
|
command:
|
|
["-config.file=/etc/loki/local-config.yaml", "-config.expand-env=true"]
|
|
environment:
|
|
- MINIO_ROOT_PASSWORD=${MINIO_ROOT_PASSWORD}
|
|
- MINIO_ROOT_USER=${MINIO_ROOT_USER}
|
|
volumes:
|
|
- ./infra/loki:/etc/loki:ro
|
|
- loki_data:/loki
|
|
depends_on: [minio-init]
|
|
healthcheck:
|
|
test:
|
|
[
|
|
"CMD-SHELL",
|
|
"wget --no-verbose --tries=1 --spider http://localhost:3100/ready || exit 1",
|
|
]
|
|
interval: 10s
|
|
|
|
promtail:
|
|
profiles: ["monitoring"]
|
|
image: grafana/promtail:3.3.2
|
|
user: "0:0"
|
|
volumes:
|
|
- ./infra/promtail:/etc/promtail:ro
|
|
- /var/run/docker.sock:/var/run/docker.sock:ro
|
|
- /var/lib/docker/containers:/var/lib/docker/containers:ro
|
|
command:
|
|
["-config.file=/etc/promtail/config.yaml", "-config.expand-env=true"]
|
|
depends_on: [loki]
|
|
|
|
grafana:
|
|
profiles: ["monitoring"]
|
|
image: grafana/grafana:11.4.0
|
|
environment:
|
|
- GF_AUTH_ANONYMOUS_ENABLED=true
|
|
- GF_AUTH_ANONYMOUS_ORG_ROLE=Editor
|
|
# - GF_SECURITY_ADMIN_PASSWORD=${GRAFANA_ADMIN_PASSWORD:-Qwerty12345}
|
|
# - GF_SECURITY_ADMIN_USER=${GRAFANA_ADMIN_USER:-nemesis}
|
|
- GF_SERVER_DOMAIN=${EXTERNAL_HOST:-https://localhost}
|
|
- GF_SERVER_ROOT_URL=${EXTERNAL_HOST:-https://localhost}/grafana
|
|
- GF_SERVER_SERVE_FROM_SUB_PATH=true
|
|
volumes:
|
|
- ./infra/grafana/provisioning:/etc/grafana/provisioning:ro
|
|
- grafana_data:/var/lib/grafana
|
|
depends_on:
|
|
postgres: { condition: service_healthy }
|
|
labels:
|
|
- "traefik.enable=true"
|
|
- "traefik.http.routers.grafana.rule=PathPrefix(`/grafana`)"
|
|
- "traefik.http.services.grafana.loadbalancer.server.port=3000"
|
|
- "traefik.http.routers.grafana.entrypoints=websecure"
|
|
- "traefik.http.routers.grafana.tls=true"
|
|
- "traefik.http.routers.grafana.middlewares=auth"
|
|
healthcheck:
|
|
test: ["CMD", "curl", "-sSf", "http://localhost:3000/"]
|
|
interval: 10s
|
|
|
|
prometheus:
|
|
profiles: ["monitoring"]
|
|
image: prom/prometheus:v3.1.0
|
|
volumes:
|
|
- ./infra/prometheus:/etc/prometheus:ro
|
|
- prometheus_data:/prometheus
|
|
command:
|
|
[
|
|
"--config.file=/etc/prometheus/prometheus.yml",
|
|
"--storage.tsdb.path=/prometheus",
|
|
"--web.external-url=/prometheus/",
|
|
]
|
|
healthcheck:
|
|
test:
|
|
[
|
|
"CMD",
|
|
"wget",
|
|
"--spider",
|
|
"-q",
|
|
"http://localhost:9090/prometheus/-/healthy",
|
|
]
|
|
interval: 10s
|
|
labels:
|
|
- "traefik.enable=true"
|
|
- "traefik.http.routers.prometheus.rule=PathPrefix(`/prometheus`)"
|
|
- "traefik.http.services.prometheus.loadbalancer.server.port=9090"
|
|
- "traefik.http.routers.prometheus.entrypoints=websecure"
|
|
- "traefik.http.routers.prometheus.tls=true"
|
|
- "traefik.http.routers.prometheus.middlewares=auth"
|
|
|
|
node-exporter:
|
|
profiles: ["monitoring"]
|
|
image: prom/node-exporter:latest
|
|
restart: unless-stopped
|
|
volumes:
|
|
- /proc:/host/proc:ro
|
|
- /sys:/host/sys:ro
|
|
- /:/rootfs:ro
|
|
command:
|
|
[
|
|
"--path.procfs=/host/proc",
|
|
"--path.rootfs=/rootfs",
|
|
"--path.sysfs=/host/sys",
|
|
"--collector.filesystem.mount-points-exclude=^/(sys|proc|dev|host|etc)($$|/)",
|
|
]
|
|
|
|
cadvisor:
|
|
profiles: ["monitoring"]
|
|
image: gcr.io/cadvisor/cadvisor:latest
|
|
restart: unless-stopped
|
|
privileged: true
|
|
volumes:
|
|
- /:/rootfs:ro
|
|
- /dev/disk/:/dev/disk:ro
|
|
- /sys:/sys:ro
|
|
- /var/lib/docker/:/var/lib/docker:ro
|
|
- /var/run:/var/run:ro
|
|
devices: ["/dev/kmsg:/dev/kmsg"]
|
|
|
|
|
|
############################
|
|
# LLM Services (optional profile)
|
|
############################
|
|
|
|
litellm:
|
|
profiles: ["llm"]
|
|
image: ghcr.io/berriai/litellm:v1.74.0-stable
|
|
environment:
|
|
- DATABASE_URL=postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@postgres:5432/litellm
|
|
- STORE_MODEL_IN_DB=True
|
|
- AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID:-}
|
|
- AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY:-}
|
|
- AWS_REGION_NAME=${AWS_REGION_NAME:-us-east-1}
|
|
- LITELLM_MASTER_KEY=sk-${LITELLM_ADMIN_PASSWORD:-admin123}
|
|
- LITELLM_SALT_KEY=sk-${LITELLM_ADMIN_PASSWORD:-admin123}
|
|
- SERVER_ROOT_PATH=/llm
|
|
- PROXY_BASE_URL=${NEMESIS_URL:?}
|
|
- UI_BASE_PATH=/llm/ui
|
|
volumes:
|
|
- ./infra/litellm/config.yml:/app/config.yml:ro
|
|
command: ["--config", "/app/config.yml"]
|
|
depends_on:
|
|
postgres: { condition: service_healthy }
|
|
healthcheck:
|
|
test: ["CMD", "wget", "--quiet", "--tries=1", "-O", "/dev/null", "--header=Authorization: Bearer sk-${LITELLM_ADMIN_PASSWORD:-admin123}", "http://localhost:4000/health"]
|
|
interval: 30s
|
|
timeout: 10s
|
|
retries: 3
|
|
start_period: 30s
|
|
disable: true
|
|
logging: *logging-config
|
|
labels:
|
|
- "traefik.enable=true"
|
|
- "traefik.http.routers.litellm.rule=PathPrefix(`/llm`)"
|
|
- "traefik.http.services.litellm.loadbalancer.server.port=4000"
|
|
- "traefik.http.routers.litellm.entrypoints=websecure"
|
|
- "traefik.http.routers.litellm.tls=true"
|