diff --git a/metro-ai-suite/image-based-video-search/README.md b/metro-ai-suite/image-based-video-search/README.md index 15703d28eb..e11c75bc4f 100644 --- a/metro-ai-suite/image-based-video-search/README.md +++ b/metro-ai-suite/image-based-video-search/README.md @@ -1,4 +1,4 @@ -# Image-Based Video Search Sample Application +# Image-Based Video Search (IBVS) Sample Application Performs near real-time analysis and image-based search to detect and retrieve objects of interest in large video datasets. @@ -12,7 +12,7 @@ You can use this foundation to build solutions for diverse use cases, including ## How it Works The application workflow has three stages: inputs, processing, and outputs. -![Diagram illustrating the components and interactions within the Image-Based Video Search system, including inputs, processing, and outputs.](docs/user-guide/_images/architecture_simplified.png) +![Diagram illustrating the components and interactions within the Image-Based Video Search system, including inputs, processing, and outputs.](docs/user-guide/_images/architecture.png) ### Inputs @@ -23,6 +23,7 @@ The application includes a demonstration video for testing. The video loops cont ### Processing +- **Nginx reverse proxy server**: All interactions with user happens via Nginx server. It protects IBVS app by handling SSL/TLS encryption, filtering and validating requests and making the app directly inaccessible from external access. - **Video analysis with Deep Learning Streamer Pipeline Server and MediaMTX**: Select **Analyze Stream** to start the DL Streamer Pipeline Server pipeline. The Pipeline Server processes video through **MediaMTX**, which simulates remote video cameras and publishes live streams. The Pipeline Server extracts frames and detects objects in each frame, publishing predictions through **MQTT**. - **Feature extraction with Feature Matching**: DL Streamer Pipeline Server sends metadata and images through MQTT to the Feature Matching microservice. Feature Matching generates feature vectors. If predictions exceed the threshold, the system stores vector embeddings in MilvusDB and saves frames in the Docker file system. - **Storage and retrieval in MilvusDB**: MilvusDB stores feature vectors. You can review them in MilvusUI. diff --git a/metro-ai-suite/image-based-video-search/chart/templates/nginx/configmap.yaml b/metro-ai-suite/image-based-video-search/chart/templates/nginx/configmap.yaml new file mode 100644 index 0000000000..23b559d0a1 --- /dev/null +++ b/metro-ai-suite/image-based-video-search/chart/templates/nginx/configmap.yaml @@ -0,0 +1,276 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: nginx-conf + namespace: {{ .Values.namespace }} +data: + nginx.conf: | + user nginx; + worker_processes auto; + error_log /var/log/nginx/error.log warn; + pid /var/run/nginx.pid; + + events { + worker_connections 1024; + } + + stream { + upstream rtsp_upstream { + server ibvs-mediamtx:8554; # RTSP server inside Docker network + } + + server { + listen 8554; # Nginx listens for RTSP on 8554 + proxy_pass rtsp_upstream; + } + } + + http { + # Upstream blocks + upstream ibvs_app { + server ibvs-app:3000; + } + upstream milvus_ui { + server ibvs-milvusui:3000; + } + upstream feature_matching { + server ibvs-featurematching:8000; + } + upstream dlstreamer { + server ibvs-dlstreamer-pipeline-server:8080; + } + upstream milvus_db { + server ibvs-milvusdb:19530; + } + upstream milvus_db_http { + server ibvs-milvusdb:9091; + } + + # Redirect all HTTP -> HTTPS + server { + listen 80; + return 301 https://$host$request_uri; + } + + # HTTPS server block + server { + listen 443 ssl; + server_name localhost; + client_max_body_size 500M; + + # SSL configuration + ssl_certificate /etc/nginx/ssl/server.crt; + ssl_certificate_key /etc/nginx/ssl/server.key; + + # SSL security settings + ssl_protocols TLSv1.2 TLSv1.3; + ssl_ciphers HIGH:!aNULL:!MD5; + ssl_prefer_server_ciphers on; + + # Security headers + add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; + add_header X-Content-Type-Options nosniff; + add_header X-Frame-Options SAMEORIGIN; + add_header X-XSS-Protection "1; mode=block"; + + # Milvus App (Vue SPA) + location / { + proxy_pass http://ibvs_app/; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } + + # Serve static assets directly + location /assets/ { + proxy_pass http://ibvs_app/assets/; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } + + # Milvus UI + location /ibvs-milvus-ui/ { + proxy_pass http://milvus_ui/; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + } + + # Milvus UI api requests + location /api/ { + proxy_pass http://milvus_ui/api/; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } + + # Milvus UI socket.IO requests + location /socket.io/ { + proxy_pass http://milvus_ui/socket.io/; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } + + # Feature Matching + location /ibvs-feature-matching/ { + proxy_pass http://feature_matching/; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } + + # Feature Matching search requests + location /search/ { + proxy_pass http://feature_matching/search/; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } + + # Get static images for search results + location /static/ { + proxy_pass http://feature_matching/static/; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } + + # Feature Matching clear requests + location /clear/ { + proxy_pass http://feature_matching/clear/; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } + + # Featurematching healthz requests + location /healthz { + proxy_pass http://feature_matching; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } + + # Feature Matching Swagger docs requests + location /docs { + proxy_pass http://feature_matching; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } + + # Feature Matching swagger docs openapi.json requests + location /openapi.json { + proxy_pass http://feature_matching/openapi.json; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } + + # DLStreamer Pipeline Server + location /ibvs-dlstreamer/ { + proxy_pass http://dlstreamer/; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + } + + # # DLStreamer Pipeline Server pipelines requests + location /pipelines/ { + proxy_pass http://dlstreamer/pipelines/; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } + + # Milvus DB API + location /ibvs-milvus-db/ { + proxy_pass http://milvus_db; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + } + + # Milvus DB HTTP + location /ibvs-milvus-db-http/ { + proxy_pass http://milvus_db_http/; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + } + + # Stream video + location /stream/ { + proxy_pass http://ibvs-mediamtx:8888/stream/; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } + + # Health check + location /nginx_healthz { + return 200 "ok\n"; + add_header Content-Type text/plain; + } + } + } +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: generate-certs-script +data: + generate_certs.sh: | + #!/bin/sh + set -e + SSL_DIR="/etc/nginx/ssl" + mkdir -p "$SSL_DIR" + + if ! command -v openssl >/dev/null 2>&1; then + echo "Installing openssl..." + apk add --no-cache openssl + fi + + if [ ! -f "$SSL_DIR/server.crt" ] || [ ! -f "$SSL_DIR/server.key" ]; then + echo "πŸ” Generating self-signed SSL certificate..." + openssl req -x509 -nodes -days 365 \ + -newkey rsa:2048 \ + -keyout "$SSL_DIR/server.key" \ + -out "$SSL_DIR/server.crt" \ + -subj "/C=US/ST=CA/L=San Francisco/O=Intel/OU=Edge AI/CN=localhost" + fi \ No newline at end of file diff --git a/metro-ai-suite/image-based-video-search/chart/templates/nginx/deployment.yaml b/metro-ai-suite/image-based-video-search/chart/templates/nginx/deployment.yaml new file mode 100644 index 0000000000..a556ce538b --- /dev/null +++ b/metro-ai-suite/image-based-video-search/chart/templates/nginx/deployment.yaml @@ -0,0 +1,54 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: '{{ include "image_based_video_search.fullname" . }}-nginx-reverse-proxy' + labels: + {{- include "image_based_video_search.labels" . | nindent 4 }} + katenary.v3/component: nginx-reverse-proxy +spec: + replicas: 1 + selector: + matchLabels: + {{- include "image_based_video_search.selectorLabels" . | nindent 6 }} + katenary.v3/component: nginx-reverse-proxy + template: + metadata: + labels: + {{- include "image_based_video_search.selectorLabels" . | nindent 8 }} + katenary.v3/component: nginx-reverse-proxy + spec: + initContainers: + - name: generate-certs + image: alpine/openssl:3.5.4 + command: + - /bin/sh + - -c + - /scripts/generate_certs.sh + volumeMounts: + - name: generate-certs-script + mountPath: /scripts + - name: nginx-ssl + mountPath: /etc/nginx/ssl + containers: + - name: nginx-reverse-proxy + image: nginx:1.27-alpine + imagePullPolicy: IfNotPresent + ports: + - containerPort: 80 + - containerPort: 443 + volumeMounts: + - name: nginx-conf + mountPath: /etc/nginx/nginx.conf + subPath: nginx.conf + - name: nginx-ssl + mountPath: /etc/nginx/ssl + volumes: + - name: nginx-conf + configMap: + name: nginx-conf + - name: nginx-ssl + emptyDir: {} + - name: generate-certs-script + configMap: + name: generate-certs-script + defaultMode: 0755 \ No newline at end of file diff --git a/metro-ai-suite/image-based-video-search/chart/templates/nginx/service.yaml b/metro-ai-suite/image-based-video-search/chart/templates/nginx/service.yaml new file mode 100644 index 0000000000..695f067da3 --- /dev/null +++ b/metro-ai-suite/image-based-video-search/chart/templates/nginx/service.yaml @@ -0,0 +1,27 @@ +apiVersion: v1 +kind: Service +metadata: + name: '{{ include "image_based_video_search.fullname" . }}-nginx-reverse-proxy' + labels: + {{- include "image_based_video_search.labels" . | nindent 4 }} + katenary.v3/component: nginx-reverse-proxy +spec: + type: NodePort + ports: + - name: nginx-reverse-proxy-80 + port: 80 + protocol: TCP + targetPort: 80 + nodePort: 30080 + - name: nginx-reverse-proxy-443 + port: 443 + protocol: TCP + targetPort: 443 + nodePort: 30443 + - name: nginx-reverse-proxy-8554 + port: 8554 + targetPort: 8554 + nodePort: 30554 # external port for 8554 + selector: + {{- include "image_based_video_search.selectorLabels" . | nindent 4 }} + katenary.v3/component: nginx-reverse-proxy \ No newline at end of file diff --git a/metro-ai-suite/image-based-video-search/chart/values.yaml b/metro-ai-suite/image-based-video-search/chart/values.yaml index ce8adabdb8..ee7dea75ee 100644 --- a/metro-ai-suite/image-based-video-search/chart/values.yaml +++ b/metro-ai-suite/image-based-video-search/chart/values.yaml @@ -402,6 +402,36 @@ featurematching: # key: milvusui.serviceAccount serviceAccount: "" +# nginx reverse proxy configuration +nginx: + repository: + image: nginx + tag: 1.27-alpine + replicas: 1 + nodeSelector: {} + resources: {} + imagePullPolicy: IfNotPresent + serviceAccount: "" + healthcheck: + enabled: true + livenessProbe: + httpGet: + path: /nginx_healthz + port: 80 + initialDelaySeconds: 10 + periodSeconds: 30 + timeoutSeconds: 10 + failureThreshold: 3 + successThreshold: 1 + readinessProbe: + httpGet: + path: /nginx_healthz + port: 80 + initialDelaySeconds: 10 + periodSeconds: 30 + timeoutSeconds: 10 + failureThreshold: 3 + successThreshold: 1 # imagePullSecrets allows you to specify a name of an image pull secret. # You must provide a list of object with the name field set to the name of the diff --git a/metro-ai-suite/image-based-video-search/compose.yml b/metro-ai-suite/image-based-video-search/compose.yml index 0e6ca8b0ea..5b04bb1c43 100644 --- a/metro-ai-suite/image-based-video-search/compose.yml +++ b/metro-ai-suite/image-based-video-search/compose.yml @@ -19,9 +19,6 @@ services: - milvus-data:/var/lib/milvus - ./src/milvus-db/embedEtcd.yaml:/milvus/configs/embedEtcd.yaml - ./src/milvus-db/user.yaml:/milvus/configs/user.yaml - ports: - - "19530:19530" - - "9091:9091" # This port conflicts with etcd when exposed, so it is commented out: # - "2379:2379" healthcheck: @@ -43,8 +40,6 @@ services: - http_proxy= - https_proxy= - no_proxy= - ports: - - "8000:3000" restart: on-failure:5 depends_on: milvus-db: @@ -52,12 +47,13 @@ services: feature-matching: image: ${DOCKER_REGISTRY}intel/feature-matching:v1.0.2-pre-RC1 - ports: - - "9000:8000" container_name: ibvs-featurematching build: context: src/feature-matching dockerfile: Dockerfile + read_only: true + tmpfs: + - /usr/src/app/static environment: MILVUS_ENDPOINT: http://milvus-db:19530 COLLECTION_NAME: my_image_collection @@ -123,21 +119,12 @@ services: - http_proxy= - https_proxy= - no_proxy= - ports: - - "8554:8554" - - "1935:1935" - - "8888:8888" - - "8889:8889" - - "8890:8890/udp" - - "8189:8189/udp" restart: on-failure:5 broker: image: docker.io/library/eclipse-mosquitto:2.0.20 container_name: ibvs-broker volumes: - ./src/broker:/mosquitto/config - ports: - - "1883:1883" restart: unless-stopped healthcheck: test: ["CMD", "mosquitto_sub", "-t", "$$SYS/#", "-C", "1", "-i", "healthcheck", "-W", "3"] @@ -154,8 +141,6 @@ services: privileged: false tty: true entrypoint: ["./run.sh"] - ports: - - '8080:8080' # - '8554:8554' environment: - ENABLE_RTSP=true @@ -219,11 +204,10 @@ services: app: image: ${DOCKER_REGISTRY}intel/image-based-video-search:v1.0.2-pre-RC1 container_name: ibvs-app - ports: - - "3000:3000" build: context: src/app dockerfile: Dockerfile + read_only: true depends_on: streaming-pipeline: condition: service_healthy @@ -238,6 +222,31 @@ services: retries: 3 start_period: 20s restart: on-failure:5 + nginx: + image: nginx:1.27-alpine + container_name: ibvs-reverse-proxy + ports: + - "80:80" + - "443:443" + - "8554:8554" + volumes: + - ./src/nginx/nginx.conf:/etc/nginx/nginx.conf:ro + - ./src/nginx/generate_certs.sh:/usr/local/bin/generate_certs.sh:ro + entrypoint: ["/usr/local/bin/generate_certs.sh"] + depends_on: + - app + environment: + - http_proxy= + - https_proxy= + - no_proxy= + - NO_PROXY= + restart: on-failure:5 + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost/nginx_healthz"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 10s volumes: milvus-data: diff --git a/metro-ai-suite/image-based-video-search/docs/user-guide/Overview.md b/metro-ai-suite/image-based-video-search/docs/user-guide/Overview.md index b72a48ebea..e8358cb8c4 100644 --- a/metro-ai-suite/image-based-video-search/docs/user-guide/Overview.md +++ b/metro-ai-suite/image-based-video-search/docs/user-guide/Overview.md @@ -1,4 +1,4 @@ -# Image-Based Video Search Sample Application +# Image-Based Video Search (IBVS) Sample Application @@ -23,7 +23,7 @@ quickly locate objects of interest across large video datasets. The application workflow has three stages: inputs, processing, and outputs. -![Diagram illustrating the components and interactions within the Image-Based Video Search system, including inputs, processing, and outputs.](_images/architecture_simplified.png) +![Diagram illustrating the components and interactions within the Image-Based Video Search system, including inputs, processing, and outputs.](_images/architecture.png) ### Inputs @@ -35,6 +35,7 @@ continuously and appears in the UI as soon as the application starts. ### Processing +- **Nginx reverse proxy server**: All interactions with user happens via Nginx server. It protects IBVS app by handling SSL/TLS encryption, filtering and validating requests and making the app directly inaccessible from external access. - **Video analysis with Deep Learning Streamer Pipeline Server and MediaMTX**: Select **Analyze Stream** to start the DL Streamer Pipeline Server pipeline. The Pipeline Server processes video through **MediaMTX**, which simulates diff --git a/metro-ai-suite/image-based-video-search/docs/user-guide/_images/architecture.png b/metro-ai-suite/image-based-video-search/docs/user-guide/_images/architecture.png index 6b8a5d6f3e..2e0f38acae 100644 Binary files a/metro-ai-suite/image-based-video-search/docs/user-guide/_images/architecture.png and b/metro-ai-suite/image-based-video-search/docs/user-guide/_images/architecture.png differ diff --git a/metro-ai-suite/image-based-video-search/docs/user-guide/get-started.md b/metro-ai-suite/image-based-video-search/docs/user-guide/get-started.md index 32d6bf64bb..58aa3f5bdd 100644 --- a/metro-ai-suite/image-based-video-search/docs/user-guide/get-started.md +++ b/metro-ai-suite/image-based-video-search/docs/user-guide/get-started.md @@ -130,11 +130,11 @@ a pre-step to prepare models may be needed 6. **Access the Application**: - Open a browser and go to the following endpoints to access the application: - - App UI: `http://localhost:3000` - - Search UI: `http://localhost:9000/docs` - - MilvusDB UI: `http://localhost:8000/` - - Stream UI: `http://localhost:8889/stream`. To access this stream remotely, open this url `rtsp://:8554/stream`. Replace `` with your system IP address - > Note: To access `App UI`, `Search UI` and `MilvusDB UI` urls remotely, replace the `localhost` with your system IP address. + - App UI: `https:///` + - Search UI: `https:///docs` + - MilvusDB UI: `https:///ibvs-milvus-ui` + - Stream UI: You can access https stream at `https:///stream` and RTSP stream at `rtsp://:8554/stream`. + > Note: Replace `` with your host IP address 7. **Run the Application**: diff --git a/metro-ai-suite/image-based-video-search/docs/user-guide/how-to-deploy-helm.md b/metro-ai-suite/image-based-video-search/docs/user-guide/how-to-deploy-helm.md index 55e419335f..6b645acb9f 100644 --- a/metro-ai-suite/image-based-video-search/docs/user-guide/how-to-deploy-helm.md +++ b/metro-ai-suite/image-based-video-search/docs/user-guide/how-to-deploy-helm.md @@ -60,21 +60,9 @@ helm install ibvs . --create-namespace -n ibvs \ --set noProxy="localhost\,127.0.0.1" ``` -To get the port where the application is serving, run the following command: -```bash -kubectl -n ibvs get svc/ibvs-app -``` - -This is an example output of the previous command: - -```text -NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE -ibvs-app NodePort 10.109.118.49 3000:31998/TCP 14m -``` - -Now frontend should be accessible at http://localhost:31998/. -> Note: To access the above url remotely, replace the `localhost` with your system IP address. +Now frontend should be accessible at https://:30443/. +> Note: To access the above url remotely, replace the `` with your system IP address. Finally, the app can be uninstalled using the following command: diff --git a/metro-ai-suite/image-based-video-search/docs/user-guide/index.rst b/metro-ai-suite/image-based-video-search/docs/user-guide/index.rst index 87a85e6699..22adce6818 100644 --- a/metro-ai-suite/image-based-video-search/docs/user-guide/index.rst +++ b/metro-ai-suite/image-based-video-search/docs/user-guide/index.rst @@ -25,7 +25,7 @@ How it Works The application workflow has three stages: inputs, processing, and outputs. -.. figure:: ./_images/architecture_simplified.png +.. figure:: ./_images/architecture.png :alt: Diagram illustrating the components and interactions within the Image-Based Video Search system, including inputs, processing, and outputs. Figure 1: Diagram illustrating the components and interactions within the Image-Based Video Search system, including inputs, processing, and outputs. @@ -42,6 +42,7 @@ continuously and appears in the UI as soon as the application starts. Processing ########## +- **Nginx reverse proxy server**: All interactions with user happens via Nginx server. It protects IBVS app by handling SSL/TLS encryption, filtering and validating requests and making the app directly inaccessible from external access. - **Video analysis with Deep Learning Streamer Pipeline Server and MediaMTX**: Select **Analyze Stream** to start the DL Streamer Pipeline Server pipeline. The Pipeline Server processes video through **MediaMTX**, which simulates diff --git a/metro-ai-suite/image-based-video-search/docs/user-guide/overview-architecture.md b/metro-ai-suite/image-based-video-search/docs/user-guide/overview-architecture.md index 134e180883..9c4b381540 100644 --- a/metro-ai-suite/image-based-video-search/docs/user-guide/overview-architecture.md +++ b/metro-ai-suite/image-based-video-search/docs/user-guide/overview-architecture.md @@ -53,6 +53,11 @@ Architecture of the Image-Based Video Search Application.* ## Key Components and Their Roles +1. **Nginx reverse proxy server** + - **What it is**: An Nginx reverse proxy acts as an intermediary server that forwards client requests to backend servers, helping with load balancing, SSL termination, caching, and centralized access control. + - **How it’s used**: It acts as proxy server. All interactions to IBVS app happens via nginx server. It forwards all the requests from outside world to internal services based on routing configuration. + - **Benefits**: It acts as protective gateway that receives external requests and securely forwards them to internal services, keeping those backend apps hidden and inaccessible from direct external access. + 1. **MediaMTX (Third-Party Microservice)** - **What it is**: A service that simulates remote video cameras. diff --git a/metro-ai-suite/image-based-video-search/src/app/Dockerfile b/metro-ai-suite/image-based-video-search/src/app/Dockerfile index b59f9648c1..8f2015f9c0 100644 --- a/metro-ai-suite/image-based-video-search/src/app/Dockerfile +++ b/metro-ai-suite/image-based-video-search/src/app/Dockerfile @@ -15,7 +15,10 @@ RUN npm install COPY . . # Build the Vue.js application -# RUN npm run build +RUN npm run build + +# Install serve globally *before* switching user +RUN npm install -g serve # Expose the port the app runs on EXPOSE 3000 @@ -28,5 +31,5 @@ RUN useradd -ms /bin/bash ${USER} -o -u $UID && \ RUN mkdir -p /home/${USER}/ && chown -R ${USER}:${USER} /home/${USER} USER ${USER} -# Start the application -CMD ["npm", "run", "dev", "--", "--host", "0.0.0.0", "--port", "3000"] \ No newline at end of file +# Serve built static files +CMD ["serve", "-s", "dist", "-l", "3000"] \ No newline at end of file diff --git a/metro-ai-suite/image-based-video-search/src/app/src/components/MapView.vue b/metro-ai-suite/image-based-video-search/src/app/src/components/MapView.vue index 79bc36d12e..3eea618ae0 100644 --- a/metro-ai-suite/image-based-video-search/src/app/src/components/MapView.vue +++ b/metro-ai-suite/image-based-video-search/src/app/src/components/MapView.vue @@ -36,11 +36,11 @@ export default defineComponent({ L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { attribution: '© OpenStreetMap contributors' - }).addTo(this.map); + }).addTo(this.map as L.Map); L.marker( [33.4484, -112.0740] - ).addTo(this.map) + ).addTo(this.map as L.Map) .bindPopup('11 N Central Ave #4, Phoenix, AZ') .openPopup(); diff --git a/metro-ai-suite/image-based-video-search/src/app/src/vite-env.d.ts b/metro-ai-suite/image-based-video-search/src/app/src/vite-env.d.ts index 11f02fe2a0..969d97fb93 100644 --- a/metro-ai-suite/image-based-video-search/src/app/src/vite-env.d.ts +++ b/metro-ai-suite/image-based-video-search/src/app/src/vite-env.d.ts @@ -1 +1,7 @@ /// + +declare module '*.vue' { + import { DefineComponent } from 'vue'; + const component: DefineComponent<{}, {}, any>; + export default component; +} \ No newline at end of file diff --git a/metro-ai-suite/image-based-video-search/src/nginx/generate_certs.sh b/metro-ai-suite/image-based-video-search/src/nginx/generate_certs.sh new file mode 100755 index 0000000000..5232a7346b --- /dev/null +++ b/metro-ai-suite/image-based-video-search/src/nginx/generate_certs.sh @@ -0,0 +1,24 @@ +#!/bin/sh +set -e + +SSL_DIR="/etc/nginx/ssl" +mkdir -p "$SSL_DIR" + +# Install openssl if missing +if ! command -v openssl >/dev/null 2>&1; then + echo "Installing openssl..." + apk add --no-cache openssl +fi + +# Generate self-signed cert if not present +if [ ! -f "$SSL_DIR/server.crt" ] || [ ! -f "$SSL_DIR/server.key" ]; then + echo "πŸ” Generating self-signed SSL certificate..." + openssl req -x509 -nodes -days 365 \ + -newkey rsa:2048 \ + -keyout "$SSL_DIR/server.key" \ + -out "$SSL_DIR/server.crt" \ + -subj "/C=US/ST=CA/L=San Francisco/O=Intel/OU=Edge AI/CN=localhost" +fi + +# Start nginx +nginx -g "daemon off;" \ No newline at end of file diff --git a/metro-ai-suite/image-based-video-search/src/nginx/nginx.conf b/metro-ai-suite/image-based-video-search/src/nginx/nginx.conf new file mode 100644 index 0000000000..576d555a84 --- /dev/null +++ b/metro-ai-suite/image-based-video-search/src/nginx/nginx.conf @@ -0,0 +1,245 @@ +user nginx; +worker_processes auto; +error_log /var/log/nginx/error.log warn; +pid /var/run/nginx.pid; + +events { + worker_connections 1024; +} + +stream { + upstream rtsp_upstream { + server ibvs-mediamtx:8554; # RTSP server inside Docker network + } + + server { + listen 8554; # Nginx listens for RTSP on 8554 + proxy_pass rtsp_upstream; + } +} + +http { + + # Upstream blocks + upstream ibvs_app { + server ibvs-app:3000; + } + upstream milvus_ui { + server ibvs-milvusui:3000; + } + upstream feature_matching { + server ibvs-featurematching:8000; + } + upstream dlstreamer { + server ibvs-dlstreamer-pipeline-server:8080; + } + upstream milvus_db { + server ibvs-milvusdb:19530; + } + upstream milvus_db_http { + server ibvs-milvusdb:9091; + } + + # Redirect all HTTP -> HTTPS + server { + listen 80; + return 301 https://$host$request_uri; + } + + # HTTPS server block + server { + listen 443 ssl; + server_name localhost; + client_max_body_size 500M; + + # SSL configuration + ssl_certificate /etc/nginx/ssl/server.crt; + ssl_certificate_key /etc/nginx/ssl/server.key; + + # SSL security settings + ssl_protocols TLSv1.2 TLSv1.3; + ssl_ciphers HIGH:!aNULL:!MD5; + ssl_prefer_server_ciphers on; + + # Security headers + add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; + add_header X-Content-Type-Options nosniff; + add_header X-Frame-Options SAMEORIGIN; + add_header X-XSS-Protection "1; mode=block"; + + # Milvus App (Vue SPA) + location / { + proxy_pass http://ibvs_app/; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } + + # Serve static assets directly + location /assets/ { + proxy_pass http://ibvs_app/assets/; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } + + # Milvus UI + location /ibvs-milvus-ui/ { + proxy_pass http://milvus_ui/; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + } + + # Milvus UI api requests + location /api/ { + proxy_pass http://milvus_ui/api/; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } + + # Milvus UI socket.IO requests + location /socket.io/ { + proxy_pass http://milvus_ui/socket.io/; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } + + # Feature Matching + location /ibvs-feature-matching/ { + proxy_pass http://feature_matching/; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } + + # Feature Matching search requests + location /search/ { + proxy_pass http://feature_matching/search/; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } + + # Get static images for search results + location /static/ { + proxy_pass http://feature_matching/static/; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } + + # Feature Matching clear requests + location /clear/ { + proxy_pass http://feature_matching/clear/; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } + + # Featurematching healthz requests + location /healthz { + proxy_pass http://feature_matching; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } + + # Feature Matching Swagger docs requests + location /docs { + proxy_pass http://feature_matching; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } + + # Feature Matching swagger docs openapi.json requests + location /openapi.json { + proxy_pass http://feature_matching/openapi.json; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } + + # DLStreamer Pipeline Server + location /ibvs-dlstreamer/ { + proxy_pass http://dlstreamer/; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + } + + # # DLStreamer Pipeline Server pipelines requests + location /pipelines/ { + proxy_pass http://dlstreamer/pipelines/; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } + + # Milvus DB API + location /ibvs-milvus-db/ { + proxy_pass http://milvus_db; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + } + + # Milvus DB HTTP + location /ibvs-milvus-db-http/ { + proxy_pass http://milvus_db_http/; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + } + + # Stream video + location /stream/ { + proxy_pass http://ibvs-mediamtx:8888/stream/; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } + + # Health check + location /nginx_healthz { + return 200 "ok\n"; + add_header Content-Type text/plain; + } + } +} \ No newline at end of file