| # Licensed to the Apache Software Foundation (ASF) under one |
| # or more contributor license agreements. See the NOTICE file |
| # distributed with this work for additional information |
| # regarding copyright ownership. The ASF licenses this file |
| # to you under the Apache License, Version 2.0 (the |
| # "License"); you may not use this file except in compliance |
| # with the License. You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, |
| # software distributed under the License is distributed on an |
| # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| # KIND, either express or implied. See the License for the |
| # specific language governing permissions and limitations |
| # under the License. |
| services: |
| # Doris MCP Server |
| doris-mcp-server: |
| build: |
| context: . |
| dockerfile: Dockerfile |
| container_name: doris-mcp-server |
| ports: |
| - "${MCP_HTTP_PORT:-3000}:3000" # Streamable HTTP, liveness, and readiness |
| environment: |
| # Database configuration |
| - DORIS_HOST=doris-fe |
| - DORIS_PORT=9030 |
| - DORIS_USER=root |
| - DORIS_PASSWORD_FILE=/run/secrets/doris_password |
| - DORIS_DATABASE=test_db |
| |
| # Connection pool configuration |
| - DORIS_MIN_CONNECTIONS=5 |
| - DORIS_MAX_CONNECTIONS=20 |
| |
| # Security configuration |
| - SERVER_HOST=0.0.0.0 |
| - SERVER_PORT=3000 |
| - MCP_ALLOWED_HOSTS=${MCP_ALLOWED_HOSTS:-127.0.0.1:*,localhost:*} |
| - ENABLE_TOKEN_AUTH=true |
| - TOKEN_ADMIN_FILE=/run/secrets/mcp_static_token |
| - MAX_RESULT_ROWS=10000 |
| - DEFAULT_RESULT_ROWS=${DEFAULT_RESULT_ROWS:-100} |
| - MAX_RESULT_BYTES=1048576 |
| - QUERY_TIMEOUT=300 |
| |
| # Performance configuration |
| - ENABLE_QUERY_CACHE=true |
| - MAX_CONCURRENT_QUERIES=50 |
| |
| # Logging configuration |
| - LOG_LEVEL=INFO |
| - LOG_FILE_PATH=/app/logs/doris-mcp-server.log |
| |
| # Monitoring configuration |
| - ENABLE_METRICS=true |
| - METRICS_PORT=8081 |
| volumes: |
| - ./logs:/app/logs |
| - ./config:/app/config |
| secrets: |
| - doris_password |
| - mcp_static_token |
| depends_on: |
| doris-fe: |
| condition: service_healthy |
| doris-be: |
| condition: service_healthy |
| networks: |
| - doris-network |
| restart: unless-stopped |
| healthcheck: |
| test: ["CMD", "curl", "--fail", "--silent", "--show-error", "--max-time", "3", "http://127.0.0.1:3000/ready"] |
| interval: 30s |
| timeout: 5s |
| retries: 3 |
| start_period: 40s |
| |
| # Apache Doris Frontend |
| doris-fe: |
| image: apache/doris:fe-3.0.8@sha256:749afa2be75cd58d54a0bdb3edaa805d5974646f67500f094912f8dbc4a96b8f |
| container_name: doris-fe |
| ports: |
| - "8030:8030" # FE HTTP port |
| - "9030:9030" # FE MySQL port |
| environment: |
| - FE_SERVERS=fe1:doris-fe:9010 |
| - FE_ID=1 |
| volumes: |
| - doris-fe-data:/opt/apache-doris/fe/doris-meta |
| - doris-fe-log:/opt/apache-doris/fe/log |
| secrets: |
| - source: doris_password |
| target: /etc/basic_auth/password |
| - source: doris_fe_custom_config |
| target: /opt/apache-doris/fe/conf/fe_custom.conf |
| networks: |
| - doris-network |
| restart: unless-stopped |
| healthcheck: |
| test: ["CMD", "curl", "-f", "http://localhost:8030/api/health"] |
| interval: 30s |
| timeout: 10s |
| retries: 5 |
| start_period: 60s |
| |
| # Apache Doris Backend |
| doris-be: |
| image: apache/doris:be-3.0.8@sha256:a337e2b17a65c86c22a1205467a825d46dc3380c94ba8024e53eea033641f12e |
| container_name: doris-be |
| ports: |
| - "8040:8040" # BE HTTP port |
| - "9060:9060" # BE heartbeat port |
| environment: |
| - FE_SERVERS=doris-fe:9010 |
| - BE_ADDR=doris-be:9050 |
| volumes: |
| - doris-be-data:/opt/apache-doris/be/storage |
| - doris-be-log:/opt/apache-doris/be/log |
| secrets: |
| - source: doris_password |
| target: /etc/basic_auth/password |
| depends_on: |
| - doris-fe |
| networks: |
| - doris-network |
| restart: unless-stopped |
| healthcheck: |
| test: ["CMD", "curl", "-f", "http://localhost:8040/api/health"] |
| interval: 30s |
| timeout: 10s |
| retries: 5 |
| start_period: 60s |
| |
| # Redis cache (optional) |
| redis: |
| image: redis:7.4.10-alpine@sha256:e7723ff73d963f5cc6d9c4643ea3d989527a402a319239054e9472a7fb9219a2 |
| container_name: doris-redis |
| ports: |
| - "6379:6379" |
| command: |
| - /bin/sh |
| - -ec |
| - exec redis-server --appendonly yes --requirepass "$$(cat /run/secrets/redis_password)" |
| volumes: |
| - redis-data:/data |
| secrets: |
| - redis_password |
| networks: |
| - doris-network |
| restart: unless-stopped |
| healthcheck: |
| test: ["CMD-SHELL", "REDISCLI_AUTH=\"$$(cat /run/secrets/redis_password)\" redis-cli --no-auth-warning ping | grep -qx PONG"] |
| interval: 30s |
| timeout: 10s |
| retries: 3 |
| |
| # Prometheus monitoring |
| prometheus: |
| image: prom/prometheus:v3.13.0@sha256:c6b27ea434f8389bfe233fbc7be381cf50587c286e871bc842008f5a1b1908a7 |
| container_name: doris-prometheus |
| ports: |
| - "9090:9090" |
| volumes: |
| - ./monitoring/prometheus.yml:/etc/prometheus/prometheus.yml |
| - prometheus-data:/prometheus |
| command: |
| - '--config.file=/etc/prometheus/prometheus.yml' |
| - '--storage.tsdb.path=/prometheus' |
| - '--web.console.libraries=/etc/prometheus/console_libraries' |
| - '--web.console.templates=/etc/prometheus/consoles' |
| - '--storage.tsdb.retention.time=200h' |
| - '--web.enable-lifecycle' |
| networks: |
| - doris-network |
| restart: unless-stopped |
| |
| # Grafana visualization |
| grafana: |
| image: grafana/grafana:13.1.0@sha256:121a7a9ece6dc10b969f1f96eed64b4f07dfac0d0b8abc070f7cb83bbde86f63 |
| container_name: doris-grafana |
| ports: |
| - "${GRAFANA_HTTP_PORT:-3003}:3000" |
| environment: |
| - GF_SECURITY_ADMIN_PASSWORD__FILE=/run/secrets/grafana_admin_password |
| volumes: |
| - grafana-data:/var/lib/grafana |
| - ./monitoring/grafana/dashboards:/etc/grafana/provisioning/dashboards |
| - ./monitoring/grafana/datasources:/etc/grafana/provisioning/datasources |
| secrets: |
| - grafana_admin_password |
| depends_on: |
| - prometheus |
| networks: |
| - doris-network |
| restart: unless-stopped |
| |
| # Nginx load balancer |
| nginx: |
| image: nginx:1.30.4-alpine@sha256:97d490c12ba55b4946b01546d1c3ed324e8d41ab1c9fcb2a616aa470620e5b46 |
| container_name: doris-nginx |
| ports: |
| - "80:80" |
| - "443:443" |
| volumes: |
| - ./nginx/nginx.conf:/etc/nginx/nginx.conf |
| - ./nginx/ssl:/etc/nginx/ssl |
| - ./nginx/logs:/var/log/nginx |
| depends_on: |
| doris-mcp-server: |
| condition: service_healthy |
| networks: |
| - doris-network |
| restart: unless-stopped |
| |
| volumes: |
| doris-fe-data: |
| driver: local |
| doris-fe-log: |
| driver: local |
| doris-be-data: |
| driver: local |
| doris-be-log: |
| driver: local |
| redis-data: |
| driver: local |
| prometheus-data: |
| driver: local |
| grafana-data: |
| driver: local |
| |
| networks: |
| doris-network: |
| driver: bridge |
| |
| secrets: |
| doris_password: |
| file: ${COMPOSE_DORIS_PASSWORD_FILE:-./.secrets/doris_password} |
| doris_fe_custom_config: |
| file: ${COMPOSE_DORIS_FE_CUSTOM_CONFIG_FILE:-./.secrets/doris_fe_custom.conf} |
| mcp_static_token: |
| file: ${COMPOSE_MCP_STATIC_TOKEN_FILE:-./.secrets/mcp_static_token} |
| redis_password: |
| file: ${COMPOSE_REDIS_PASSWORD_FILE:-./.secrets/redis_password} |
| grafana_admin_password: |
| file: ${COMPOSE_GRAFANA_ADMIN_PASSWORD_FILE:-./.secrets/grafana_admin_password} |