# In Compose Specification, version key is deprecated.
# Reference: https://github.com/compose-spec/compose-spec/blob/master/spec.md
#version: "3.9"
services:
  # Build streamlit ui server
  ui:
    build:
      context: ./ui-server
      dockerfile: Dockerfile
    # Choose image name
    image: nabot-ui
    # Don't start ui server before chatbot server
    depends_on:
      rasa:
        condition: service_healthy
    # Choose container name
    container_name: ui-server
    restart: always
    # Make the same network for chatbot server and ui server
    networks:
      - frontend-network
    # Mount .env file to the ui server to read chatbot URL
    volumes:
      - ./.env:/flask_server/.env
    # Map TCP port 8501 in the container to port 80 on the Docker host.
    # This is a chatbot rest api port
    ports:
      - 80:8501
    # Healthcheck condition
    healthcheck:
        test: ["CMD", "printf", ".", ">", "/dev/tcp/127.0.0.1/8501"]
        interval: 30s
        timeout: 10s
        retries: 30
  # Build a monitoring server
  monitoring:
    build:
      context: ./monitoring-server
      dockerfile: Dockerfile
    # Choose image name
    image: monitoring-ui
    # Don't start ui server before mysql server
    depends_on:
      rasa:
        condition: service_healthy
    # Choose container name
    container_name: monitoring-server
    restart: always
    # Make the same network for chatbot server and ui server
    networks:
      - events-network
    # Mount .env file to the ui server to read chatbot URL
    volumes:
      - ./.env:/monitoring_ui/.env
    # Map TCP port 8501 in the container to port 80 on the Docker host.
    # This is a chatbot rest api port
    ports:
      - 8501:8501
    # Healthcheck condition
    healthcheck:
        test: ["CMD", "printf", ".", ">", "/dev/tcp/127.0.0.1/8501"]
        interval: 30s
        timeout: 10s
        retries: 30
  # Build chatbot server
  rasa:
    build:
      context: ./rasa-server
      dockerfile: Dockerfile
      args:
        # Pass model weights version as an argument 
        - VERSION=v0.1.0
    # Choose image name
    image: rasa-server
    # Don't start chatbot server before action server
    depends_on:
      app:
        condition: service_healthy
    # Choose container name
    container_name: chatbot-server
    restart: always
    # Expose 5005 port to ui server can see the chatbot server
    expose: 
      - 5005
    # Map TCP port 5005 in the container to port 5005 on the Docker host.
    # This is a chatbot rest api port
    ports:
      - 5005:5005
    # Healthcheck condition
    healthcheck:
        test: ["CMD", "printf", ".", ">", "/dev/tcp/127.0.0.1/5005"]
        interval: 45s
        timeout: 10s
        retries: 30
    # Store chatbot logs out side of the container
    volumes:
      - logs_data:/rasa-server/rasa/logs
      - ./.env:/rasa-server/rasa/.env
    # Make the same network for chatbot server and actions server
    networks:
      - rasa-network
      - frontend-network
      - events-network
  # Build action server
  app:
    build: 
      context: ./action-server
      dockerfile: Dockerfile
    # Choose image name
    image: action-server
    # Don't start action server before database
    depends_on:
      db_datasets:
        condition: service_healthy
    # Choose container name
    container_name: action-server
    restart: always
    # Store chatbot logs out side of the container
    volumes:
      - logs_data:/action-server/logs
      - ./.env:/action-server/.env
    # Make the same network for chatbot server and actions server
    # And also action server and mysql server
    networks:
      - rasa-network
      - datasets-network
    # Expose 5055 port to chatbot server can see the action server
    expose: 
      - 5055
    # Configuration of healthcheck for mysql action server
    healthcheck:
        test: ["CMD", "printf", ".", ">", "/dev/tcp/127.0.0.1/5055"]
        interval: 45s
        timeout: 10s
        retries: 30
  # Build mysql server
  db_datasets:
    # Use mysql image
    image: mysql:8
    container_name: datasets-server
    # Use mysql_native_password instead of caching_sha2_password
    command: '--default-authentication-plugin=mysql_native_password'
    restart: always
    volumes:
      # Load mysql dumps (datasets) to the fresh mysql server during initialization
      - ./datasets-server:/docker-entrypoint-initdb.d
      # Store mysql records in the seperate volume. records won't be removed even with removing containers
      - db-data:/var/lib/mysql
    # Make the same network for mysql server and actions server
    networks:
      - datasets-network
    # Read MYSQL password and database name from .env file
    env_file:
      - ./.env
    environment:
      - MYSQL_DATABASE=${MYSQL_DATASETS_DATABASE}
      - MYSQL_ROOT_PASSWORD=${MYSQL_DATASETS_ROOT_PASSWORD}
    # Expose 3306 port to action server can see the mysql server
    expose: 
      - 3306
    # Add the capability CAP_SYS_NICE to MySQL server can handle mbind error itself silently.
    cap_add:
      - SYS_NICE
    # Configuration of healthcheck for mysql db
    healthcheck:
        test: ["CMD", 'mysqladmin', 'ping', '-h', 'localhost', 
                '-u', 'root', '-p$MYSQL_DATASETS_ROOT_PASSWORD' ]
        interval: 3m30s
        timeout: 45s
        retries: 30
  # Build mysql server
  db_events:
    # Use postgres image
    image: postgres:12
    container_name: events-server
    restart: always
    volumes:
      # Store postgres records in the seperate volume. records won't be removed even with removing containers
      - db-event:/var/lib/postgresql/data/
    # Make the same network for postgres server and actions server
    networks:
      - events-network
    # Read postgres password and database name from .env file
    env_file:
      - ./.env
    environment:
      - POSTGRES_DB=${POSTGRES_EVENTS_DATABASE}
      - POSTGRES_USER=${POSTGRES_USER}
      - POSTGRES_PASSWORD=${POSTGRES_EVENTS_PASSWORD}
    # Expose 5432 port to action server can see the postgres server
    expose: 
      - 5432
    # Add the capability CAP_SYS_NICE to MySQL server can handle mbind error itself silently.
    cap_add:
      - SYS_NICE
    # Configuration of healthcheck for postgres db
    healthcheck:
        test: ["CMD", 'pg_isready', '-d', '$POSTGRES_EVENTS_DATABASE',
                '-h', 'localhost']
        interval: 3m30s
        timeout: 45s
        retries: 30

# List of docker networks
networks:
  # network between chatbot and streamlit server
  frontend-network:
    name: nabot-frontend-network
    driver: bridge
  # network between chatbot and action server
  rasa-network:
    name: nabot-rasa-network
    driver: bridge
  # network between action server and mysql server
  datasets-network:
    name: nabot-datasets-network
    driver: bridge
  # network between ui/rasa server and postgres server
  events-network:
    name: nabot-events-network
    driver: bridge

# Seperate volumes
volumes:
  # MYSQL datasets database volume
  db-data:
    name: data_db
  # postgres events database volume
  db-event:
    name: event_db
  # Storing logs volume
  logs_data:
    name: logs_db
