# Copyright 2024 RustFS Team
#
# Licensed 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:
  # RustFS main service
  rustfs:
    security_opt:
      - "no-new-privileges:true"
    image: rustfs/rustfs:latest
    container_name: rustfs-server
    build:
      context: .
      dockerfile: Dockerfile.source
      args:
        TARGETPLATFORM: linux/amd64
    ports:
      - "9000:9000" # S3 API port
      - "9001:9001" # Console port
    environment:
      - RUSTFS_VOLUMES=/data/rustfs{0..3} # Define 4 storage volumes
      - RUSTFS_ADDRESS=0.0.0.0:9000
      - RUSTFS_CONSOLE_ADDRESS=0.0.0.0:9001
      - RUSTFS_CONSOLE_ENABLE=true
      - RUSTFS_CONSOLE_CORS_ALLOWED_ORIGINS=*
      - RUSTFS_ACCESS_KEY=rustfsadmin
      - RUSTFS_SECRET_KEY=rustfsadmin
      - RUSTFS_OBS_LOGGER_LEVEL=info
      - RUSTFS_TLS_PATH=/opt/tls
      - RUSTFS_OBS_ENDPOINT=http://otel-collector:4318
    volumes:
      - ./deploy/data/pro:/data
      - ./deploy/logs:/app/logs
      # TLS configuration directory.
      # Place at least:
      # - /opt/tls/ca.crt
      # - /opt/tls/rustfs_cert.pem
      # - /opt/tls/rustfs_key.pem
      - ./deploy/data/certs/:/opt/tls
      # Permission baseline:
      # - default RustFS runtime user is 10001:10001
      # - ensure host mounts are writable by that user, or run with host-matched user
    networks:
      - rustfs-network
    restart: unless-stopped
    healthcheck:
      # Production strict TLS example (SAN/FQDN aligned, no `-k`):
      # curl -f --cacert /opt/tls/ca.crt --resolve rustfs-a.example.com:9000:127.0.0.1 https://rustfs-a.example.com:9000/health
      # curl -f --cacert /opt/tls/ca.crt --resolve rustfs-a.example.com:9001:127.0.0.1 https://rustfs-a.example.com:9001/rustfs/console/health
      test:
        [
          "CMD",
          "sh", "-c",
          "curl -f http://127.0.0.1:9000/health && curl -f http://127.0.0.1:9001/rustfs/console/health"
        ]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 40s
    depends_on:
      otel-collector:
        condition: service_started
        required: false

  # Development environment
  rustfs-dev:
    image: rustfs/rustfs:devenv
    container_name: rustfs-dev
    build:
      context: .
      dockerfile: Dockerfile.source
      target: dev
      # Pure development environment
    ports:
      - "9010:9000" # S3 API port  
      - "9011:9001" # Console port
    environment:
      - RUSTFS_VOLUMES=/data/rustfs{0..3}
      - RUSTFS_ADDRESS=0.0.0.0:9000
      - RUSTFS_CONSOLE_ADDRESS=0.0.0.0:9001
      - RUSTFS_CONSOLE_ENABLE=true
      - RUSTFS_CONSOLE_CORS_ALLOWED_ORIGINS=*
      - RUSTFS_ACCESS_KEY=devadmin
      - RUSTFS_SECRET_KEY=devadmin
      - RUSTFS_OBS_LOGGER_LEVEL=debug
      - RUSTFS_OBS_LOG_DIRECTORY=/logs
    volumes:
      - .:/app # Mount source code to /app for development
      - cargo_registry:/usr/local/cargo/registry # Mount cargo registry to avoid re-downloading
      - ./deploy/data/dev:/data
    networks:
      - rustfs-network
    restart: unless-stopped
    healthcheck:
      test:
        [
          "CMD",
          "sh", "-c",
          "curl -f http://127.0.0.1:9000/health && curl -f http://127.0.0.1:9001/rustfs/console/health"
        ]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 40s
    profiles:
      - dev

  # --- Observability Stack ---

  tempo-init:
    image: busybox:latest
    command: [ "sh", "-c", "chown -R 10001:10001 /var/tempo" ]
    volumes:
      - tempo_data:/var/tempo
    user: root
    networks:
      - rustfs-network
    restart: "no"
    profiles:
      - observability

  tempo:
    image: grafana/tempo:latest
    user: "10001"
    command: [ "-config.file=/etc/tempo.yaml" ]
    volumes:
      - ./.docker/observability/tempo.yaml:/etc/tempo.yaml:ro
      - tempo_data:/var/tempo
    ports:
      - "3200:3200" # tempo
      - "4317"      # otlp grpc
      - "4318"      # otlp http
    restart: unless-stopped
    networks:
      - rustfs-network
    profiles:
      - observability

  otel-collector:
    image: otel/opentelemetry-collector-contrib:latest
    container_name: otel-collector
    command:
      - --config=/etc/otelcol-contrib/otel-collector.yml
    volumes:
      - ./.docker/observability/otel-collector-config.yaml:/etc/otelcol-contrib/otel-collector.yml:ro
    ports:
      - "1888:1888"   # pprof
      - "8888:8888"   # Prometheus metrics for Collector
      - "8889:8889"   # Prometheus metrics for application indicators
      - "13133:13133" # health check
      - "4317:4317"   # OTLP gRPC
      - "4318:4318"   # OTLP HTTP
      - "55679:55679" # zpages
    networks:
      - rustfs-network
    restart: unless-stopped
    profiles:
      - observability
    depends_on:
      - tempo
      - jaeger
      - prometheus
      - loki

  jaeger:
    image: jaegertracing/jaeger:latest
    container_name: jaeger
    environment:
      - TZ=Asia/Shanghai
      - SPAN_STORAGE_TYPE=badger
      - BADGER_EPHEMERAL=false
      - BADGER_DIRECTORY_VALUE=/badger/data
      - BADGER_DIRECTORY_KEY=/badger/key
      - COLLECTOR_OTLP_ENABLED=true
    volumes:
      - jaeger_data:/badger
    ports:
      - "16686:16686" # Web UI
      - "14269:14269" # Admin/Metrics
    networks:
      - rustfs-network
    restart: unless-stopped
    profiles:
      - observability

  prometheus:
    image: prom/prometheus:latest
    container_name: prometheus
    ports:
      - "9090:9090"
    volumes:
      - ./.docker/observability/prometheus.yml:/etc/prometheus/prometheus.yml:ro
      - prometheus_data:/prometheus
    command:
      - "--config.file=/etc/prometheus/prometheus.yml"
      - "--storage.tsdb.path=/prometheus"
      - "--storage.tsdb.retention.time=30d"
      - "--web.enable-lifecycle"
      - "--web.enable-otlp-receiver"
      - "--web.enable-remote-write-receiver"
    networks:
      - rustfs-network
    restart: unless-stopped
    profiles:
      - observability

  loki:
    image: grafana/loki:latest
    container_name: loki
    environment:
      - TZ=Asia/Shanghai
    volumes:
      - ./.docker/observability/loki.yaml:/etc/loki/local-config.yaml:ro
      - loki_data:/loki
    ports:
      - "3100:3100"
    command: -config.file=/etc/loki/local-config.yaml
    networks:
      - rustfs-network
    restart: unless-stopped
    profiles:
      - observability

  grafana:
    image: grafana/grafana:latest
    container_name: grafana
    ports:
      - "3000:3000"
    environment:
      - GF_SECURITY_ADMIN_USER=admin
      - GF_SECURITY_ADMIN_PASSWORD=admin
      - GF_INSTALL_PLUGINS=grafana-pyroscope-datasource
    volumes:
      - grafana_data:/var/lib/grafana
      - ./.docker/observability/grafana/provisioning:/etc/grafana/provisioning:ro
      - ./.docker/observability/grafana/dashboards:/etc/grafana/dashboards:ro
    networks:
      - rustfs-network
    restart: unless-stopped
    profiles:
      - observability
    depends_on:
      - prometheus
      - tempo
      - loki

  # NGINX reverse proxy (optional)
  nginx:
    security_opt:
      - "no-new-privileges:true"
    image: nginx:alpine
    container_name: nginx-proxy
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./.docker/nginx/nginx.conf:/etc/nginx/nginx.conf:ro
      - ./.docker/nginx/ssl:/etc/nginx/ssl:ro
    tmpfs:
      - /var/run
      - /var/cache/nginx
      - /var/log/nginx
    networks:
      - rustfs-network
    restart: unless-stopped
    read_only: true
    profiles:
      - proxy
    depends_on:
      - rustfs

networks:
  rustfs-network:
    driver: bridge
    ipam:
      config:
        - subnet: 172.20.0.0/16

volumes:
  rustfs_data_0:
    driver: local
  rustfs_data_1:
    driver: local
  rustfs_data_2:
    driver: local
  rustfs_data_3:
    driver: local
  rustfs_dev_data:
    driver: local
  prometheus_data:
    driver: local
  grafana_data:
    driver: local
  tempo_data:
    driver: local
  loki_data:
    driver: local
  jaeger_data:
    driver: local
  logs:
    driver: local
  cargo_registry:
    driver: local
