diff --git a/sf-docker/special/high-availability/README.md b/sf-docker/special/high-availability/README.md new file mode 100644 index 00000000..aa6e3e1e --- /dev/null +++ b/sf-docker/special/high-availability/README.md @@ -0,0 +1,4 @@ +# SmartFace Large Scale Deployment + +This sample is intended to be deployed on a single host for demonstration purposes. When running on multiple hosts (either physical or virtual), changes listed bellow are required. + diff --git a/sf-docker/special/high-availability/minio/docker-compose.yml b/sf-docker/special/high-availability/minio/docker-compose.yml new file mode 100644 index 00000000..820dc776 --- /dev/null +++ b/sf-docker/special/high-availability/minio/docker-compose.yml @@ -0,0 +1,80 @@ +version: '3.7' + +# Settings and configurations that are common for all containers +x-minio-common: &minio-common + image: quay.io/minio/minio:RELEASE.2023-04-13T03-08-07Z + command: server --console-address ":9001" http://minio{1...4}/data{1...2} + expose: + - "9000" + - "9001" + # environment: + # MINIO_ROOT_USER: minioadmin + # MINIO_ROOT_PASSWORD: minioadmin + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"] + interval: 30s + timeout: 20s + retries: 3 + +# starts 4 docker containers running minio server instances. +# using nginx reverse proxy, load balancing, you can access +# it through port 9000. +services: + minio1: + <<: *minio-common + hostname: minio1 + volumes: + - data1-1:/data1 + - data1-2:/data2 + + minio2: + <<: *minio-common + hostname: minio2 + volumes: + - data2-1:/data1 + - data2-2:/data2 + + minio3: + <<: *minio-common + hostname: minio3 + volumes: + - data3-1:/data1 + - data3-2:/data2 + + minio4: + <<: *minio-common + hostname: minio4 + volumes: + - data4-1:/data1 + - data4-2:/data2 + + minio-proxy: + image: nginx:1.19.2-alpine + hostname: nginx + volumes: + - ./nginx.conf:/etc/nginx/nginx.conf:ro + ports: + - "9000:9000" + - "9001:9001" + depends_on: + - minio1 + - minio2 + - minio3 + - minio4 + +## By default this config uses default local driver, +## For custom volumes replace with volume driver configuration. +volumes: + data1-1: + data1-2: + data2-1: + data2-2: + data3-1: + data3-2: + data4-1: + data4-2: + +networks: + default: + external: + name: HighAvailabilityClusterNetwork diff --git a/sf-docker/special/high-availability/minio/nginx.conf b/sf-docker/special/high-availability/minio/nginx.conf new file mode 100644 index 00000000..e8dc198b --- /dev/null +++ b/sf-docker/special/high-availability/minio/nginx.conf @@ -0,0 +1,106 @@ +user nginx; +worker_processes auto; + +error_log /var/log/nginx/error.log warn; +pid /var/run/nginx.pid; + +events { + worker_connections 4096; +} + +http { + include /etc/nginx/mime.types; + default_type application/octet-stream; + + log_format main '$remote_addr - $remote_user [$time_local] "$request" ' + '$status $body_bytes_sent "$http_referer" ' + '"$http_user_agent" "$http_x_forwarded_for"'; + + access_log /var/log/nginx/access.log main; + sendfile on; + keepalive_timeout 65; + + # include /etc/nginx/conf.d/*.conf; + + upstream minio { + server minio1:9000; + server minio2:9000; + server minio3:9000; + server minio4:9000; + } + + upstream console { + ip_hash; + server minio1:9001; + server minio2:9001; + server minio3:9001; + server minio4:9001; + } + + server { + listen 9000; + listen [::]:9000; + server_name localhost; + + # To allow special characters in headers + ignore_invalid_headers off; + # Allow any size file to be uploaded. + # Set to a value such as 1000m; to restrict file size to a specific value + client_max_body_size 0; + # To disable buffering + proxy_buffering off; + proxy_request_buffering off; + + location / { + proxy_set_header Host $http_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_connect_timeout 300; + # Default is HTTP/1, keepalive is only enabled in HTTP/1.1 + proxy_http_version 1.1; + proxy_set_header Connection ""; + chunked_transfer_encoding off; + + proxy_pass http://minio; + } + } + + server { + listen 9001; + listen [::]:9001; + server_name localhost; + + # To allow special characters in headers + ignore_invalid_headers off; + # Allow any size file to be uploaded. + # Set to a value such as 1000m; to restrict file size to a specific value + client_max_body_size 0; + # To disable buffering + proxy_buffering off; + proxy_request_buffering off; + + location / { + proxy_set_header Host $http_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_set_header X-NginX-Proxy true; + + # This is necessary to pass the correct IP to be hashed + real_ip_header X-Real-IP; + + proxy_connect_timeout 300; + + # To support websocket + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + + chunked_transfer_encoding off; + + proxy_pass http://console; + } + } +} \ No newline at end of file diff --git a/sf-docker/special/high-availability/pgsql/docker-compose.yml b/sf-docker/special/high-availability/pgsql/docker-compose.yml new file mode 100644 index 00000000..664ac3d0 --- /dev/null +++ b/sf-docker/special/high-availability/pgsql/docker-compose.yml @@ -0,0 +1,30 @@ +version: '3' +services: + pgsql: + image: "postgres:14.3" + container_name: pgsql + ports: + - "5432:5432" + environment: + - POSTGRES_PASSWORD=Test1234 + restart: unless-stopped + volumes: + - pgsqldata:/var/lib/postgresql/data + #- /var/lib/smartface/pgsql:/var/lib/postgresql/data + + pgadmin: + image: "dpage/pgadmin4:6.10" + container_name: pgadmin + environment: + PGADMIN_DEFAULT_EMAIL: admin@admin.com + PGADMIN_DEFAULT_PASSWORD: Test1234 + ports: + - "7070:80" + +volumes: + pgsqldata: + +networks: + default: + external: + name: HighAvailabilityClusterNetwork \ No newline at end of file diff --git a/sf-docker/special/high-availability/server1/.env b/sf-docker/special/high-availability/server1/.env new file mode 100644 index 00000000..f6a38d0f --- /dev/null +++ b/sf-docker/special/high-availability/server1/.env @@ -0,0 +1,47 @@ +# RMQ config +RabbitMQ__Hostname=rmq1 +RabbitMQ__Username=guest +RabbitMQ__Password=guest +RabbitMQ__VirtualHost=/ +RabbitMQ__Port=5672 +RabbitMQ__UseSsl=false + +# Database config +#Database__DbEngine=MsSql +#ConnectionStrings__CoreDbContext=Server=mssql;Database=SmartFace;User ID=sa;Password=Test1234;TrustServerCertificate=true; +Database__DbEngine=PgSql +ConnectionStrings__CoreDbContext=Server=pgsql;Database=smartface;Username=postgres;Password=Test1234;Trust Server Certificate=true; + +# S3 config +S3Bucket__Endpoint=http://minio-proxy:9000 +S3Bucket__BucketName=inno-smartface +S3Bucket__AccessKey=minioadmin +S3Bucket__SecretKey=minioadmin + +# Set true when a Jaeger tracing is required +AppSettings__USE_JAEGER_APP_SETTINGS=false + +# Jaeger tracing endpoint. 'jaeger' is the name of included docker container. +# If targeting outside SmartFace docker, change to remote URL +JAEGER_AGENT_HOST=jaeger + +# API config - we use port 80 in docker and forward it as needed +Hosting__Host=http://0.0.0.0 +Hosting__Port=80 + +# we override the default generation of preview ports for camera in favor of static configuration +CameraDefaults__PreviewPort=30000 + +# Using NoSql database +NoSqlDataStorageDisabled=false + +# Using template for Gstreamer pipeline +GstPipelineTemplate=uridecodebin uri={0} source::latency=0 ! queue max-size-buffers=1 leaky=downstream ! nvvideoconvert ! video/x-raw, format=(string)BGRx ! videoconvert ! video/x-raw, format=(string)BGR ! appsink + +# Registry, must end with a forward slash `/` +REGISTRY=registry.gitlab.com/innovatrics/smartface/ + +# Version +SF_VERSION=v5_4.18.1 +AC_VERSION=v5_1.8.0 +SFS_VERSION=v5_1.15.0 diff --git a/sf-docker/special/high-availability/server1/.env.sfac b/sf-docker/special/high-availability/server1/.env.sfac new file mode 100644 index 00000000..f311821b --- /dev/null +++ b/sf-docker/special/high-availability/server1/.env.sfac @@ -0,0 +1,47 @@ +FilterConfiguration__FaceOrderConfiguration__Enabled=false +FilterConfiguration__FaceOrderConfiguration__Order=1 + +FilterConfiguration__OpeningDebounceConfiguration__OpeningDebounceEnabled=true +FilterConfiguration__OpeningDebounceConfiguration__OpeningDebounceMs=4000 + +FilterConfiguration__BlockingDebounceConfiguration__BlockingDebounceEnabled=true +FilterConfiguration__BlockingDebounceConfiguration__BlockingDebounceMs=4000 + +FilterConfiguration__ExclusiveCameraConfiguration__Enabled=true +FilterConfiguration__ExclusiveCameraConfiguration__ExclusivityMs=5000 + +FilterConfiguration__NotIdentifiedPersonConfiguration__Enabled=true +FilterConfiguration__NotIdentifiedPersonConfiguration__RoamingLimitTimeMs=3000 + +FilterConfiguration__BlacklistsConfiguration__Enabled=true +FilterConfiguration__BlacklistsConfiguration__Blacklists__0=firt_black_list_id +FilterConfiguration__BlacklistsConfiguration__Blacklists__1=second_black_list_id +FilterConfiguration__BlacklistsConfiguration__Blacklists__2=third_black_list_id + +FilterConfiguration__FaceMaskConfiguration__Enabled=false +FilterConfiguration__FaceMaskConfiguration__DenyingDebounceMs=4000 + +FilterConfiguration__IntentionalAccessConfiguration__Enabled=false +FilterConfiguration__IntentionalAccessConfiguration__AlwaysOpenForFaceAreaPercentLargerThan=7 +FilterConfiguration__IntentionalAccessConfiguration__RequiredFaceApproachingRatePercent=0.4 + +FilterConfiguration__StreamGroupsConfiguration__Enabled=true +FilterConfiguration__StreamGroupsConfiguration__GroupOpeningDebounceMs=3000 + +FilterConfiguration__SpoofCheckConfiguration__Enabled=false +FilterConfiguration__SpoofCheckConfiguration__DenyingDebounceMs=4000 + +# Set true when a Jaeger tracing is required +AppSettings__0__Key=USE_JAEGER_APP_SETTINGS +AppSettings__0__Value=false + +AppSettings__1__Key=JAEGER_SAMPLER_TYPE +AppSettings__1__Value=const + +AppSettings__2__Key=JAEGER_SAMPLER_PARAM +AppSettings__2__Value=1 + +# Jaeger tracing endpoint. 'jaeger' is the name of included docker container. +# If targeting outside SmartFace docker, change to remote URL +AppSettings__3__Key=JAEGER_AGENT_HOST +AppSettings__3__Value=jaeger \ No newline at end of file diff --git a/sf-docker/special/high-availability/server1/.env.sfstation b/sf-docker/special/high-availability/server1/.env.sfstation new file mode 100644 index 00000000..cf0d5ab5 --- /dev/null +++ b/sf-docker/special/high-availability/server1/.env.sfstation @@ -0,0 +1,96 @@ +# IP address, where SmartFace Station server will bind to +HOST=0.0.0.0 + +# Port number, where SmartFace Station server will bind to +PORT=8000 + +# Full addresses to SmartFace Server APIs +# CORE API example: http://[sf-server-host]:[port]/api/v1 +CORE_API_ROOT=http://SFApi:80/api/v1 + +# ODATA API example: http://[sf-server-host]:[port] +ODATA_API_ROOT=http://SFODataApi:80 + +# ZERO_MQ_HOST example: [sf-server-host] +ZERO_MQ_HOST=SFBase + +# Full address to SmartFace Server GraphQL APIs +GRAPHQL_ROOT=http://SFGraphQLApi:80/graphql + +# example: CAM_PREVIEW_HOST_[camera.serviceName]=[sf-camera-host] +CAM_PREVIEW_HOST_SFCAM1=SFCam1 +CAM_PREVIEW_HOST_SFCAM2=SFCam2 +CAM_PREVIEW_HOST_SFCAM3=SFCam3 +CAM_PREVIEW_HOST_SFCAM4=SFCam4 +CAM_PREVIEW_HOST_SFCAM5=SFCam5 + +# Address to Access Controller gRPC endpoint +# Example: [sf-server-host]:[port] +ACCESS_CONTROLLER_ADDRESS=SFAccessController:80 + +# Comma separated Watchlist IDs used as a global blacklists +BLACKLIST_WATCHLIST_IDS=abcdabcd-abcd-1234-abcd-abcdabcdacd + +# Whether to run with Keycloak authentication server or not +ENABLE_AUTHENTICATION=false + +# Full URL address to Keycloak's users management (if empty no url will be shown in webapp configuration) +KEYCLOAK_ADMIN_URL=http://keycloak-host:8080/auth/admin + +# In case of unauthorize access user will be redirected to provided URL (eg. keycloack login) +# If URL is not provided No access page will be shown +UNAUTHORIZE_ACCESS_REDIRECTION_URL=http://keycloak.login + +# Score to percentage conversion parameters +SCORE_CONVERSION_LOWER_LIMIT=20 +SCORE_CONVERSION_LOWER_LIMIT_PERCENTAGE=30 +SCORE_CONVERSION_UPPER_LIMIT=40 +SCORE_CONVERSION_UPPER_LIMIT_PERCENTAGE=90 + +# DOT camera parameters (HTTPS is required) +DOT_FACE_CAMERA_ENABLED=false +DOT_FACE_CAMERA_FACE_CENTER_LIMIT=0.2 +DOT_FACE_CAMERA_FACE_CONFIDENCE=0.06 + +# Wether to run with HTTPS authentication server or not +HTTPS_ENABLED=false +HTTPS_HOST_NAME= +HTTPS_KEY_FILE=server.key +HTTPS_CERT_FILE=server.cert + +# Setup for S3 / MinIO API +S3_ENDPOINT=http://127.0.0.1:9000 +S3_ACCESS_KEY=minioadmin +S3_SECRET_KEY=minioadmin +S3_REGION=eu-west-1 +S3_BUCKET=inno-smartface +# If we are using s3/minio over https this determine if certificate needs to be valid or not +# for http version of s3/minio needs to be set to false +S3_SKIP_SSL=false +# Presigned URL expiration in seconds +S3_URL_EXPIRATION=300 # 5 minutes +# Create bucket if it doesn't exist already +S3_PRECREATE_BUCKET=true + +# Add optional labels to watclist member (key is used in API requests, label is visual representation of key and used only in station frontend) +# WATCHLIST_MEMBER_KEY_0=date +# WATCHLIST_MEMBER_LABEL_0=Date of birth +# WATCHLIST_MEMBER_KEY_1=tax_number +# WATCHLIST_MEMBER_LABEL_1=Tax number +# WATCHLIST_MEMBER_KEY_2=phone +# WATCHLIST_MEMBER_LABEL_2=Phone number + +# Optional roles are used for locking specified part of frontend for given roles +# Claim name is "Group mapper name" specified in Keycloak or "cognito:groups" in Cognito +# ROLES_CLAIM_NAME=sf_roles +# ROLE_KEY_ADMIN=/admin +# ROLE_KEY_SECURITY_SUPERVISOR=/security_supervisor +# ROLE_KEY_SECURITY_OPERATOR=/security_operator +# ROLE_KEY_ACCESS_SUPERVISOR=/access_supervisor +# ROLE_KEY_ACCESS_OPERATOR=/access_operator +# ROLE_KEY_INVESTIGATION_SUPERVISOR=/investigation_supervisor +# ROLE_KEY_INVESTIGATION_OPERATOR=/investigation_operator +# ROLE_KEY_SECURITY_ADMIN=/security_admin +# ROLE_KEY_ACCESS_ADMIN=/access_admin +# ROLE_KEY_INVESTIGATION_ADMIN=/investigation_admin +# FORCED_ROLE_NAME_0=/admin diff --git a/sf-docker/special/high-availability/server1/docker-compose.yml b/sf-docker/special/high-availability/server1/docker-compose.yml new file mode 100644 index 00000000..278f1837 --- /dev/null +++ b/sf-docker/special/high-availability/server1/docker-compose.yml @@ -0,0 +1,373 @@ +version: "3.4" +services: + sf-base: + image: ${REGISTRY}sf-base:${SF_VERSION} + container_name: SFBase + command: --serviceName SFBase + ports: + - 2406:2406 + restart: unless-stopped + environment: + - RabbitMQ__Hostname + - RabbitMQ__Username + - RabbitMQ__Password + - RabbitMQ__Port + - ConnectionStrings__CoreDbContext + - Database__DbEngine + - AppSettings__Log_RollingFile_Enabled=false + - AppSettings__USE_JAEGER_APP_SETTINGS + - JAEGER_AGENT_HOST + - S3Bucket__Endpoint + - S3Bucket__BucketName + - S3Bucket__AccessKey + - S3Bucket__SecretKey + - NoSqlDataStorageDisabled + volumes: + - "./iengine.lic:/etc/innovatrics/iengine.lic" + + sf-group: + image: ${REGISTRY}sf-grouping:${SF_VERSION} + command: --serviceName SFGroup + restart: unless-stopped + environment: + - RabbitMQ__Hostname + - RabbitMQ__Username + - RabbitMQ__Password + - RabbitMQ__Port + - ConnectionStrings__CoreDbContext + - Database__DbEngine + - AppSettings__Log_RollingFile_Enabled=false + - AppSettings__USE_JAEGER_APP_SETTINGS + - JAEGER_AGENT_HOST + - S3Bucket__Endpoint + - S3Bucket__BucketName + - S3Bucket__AccessKey + - S3Bucket__SecretKey + - NoSqlDataStorageDisabled + volumes: + - "./iengine.lic:/etc/innovatrics/iengine.lic" + + sf-cam-1: + image: ${REGISTRY}sf-cam:${SF_VERSION} + command: --serviceName SFCam1 + ports: + - 30001:${CameraDefaults__PreviewPort} + restart: unless-stopped + environment: + - RabbitMQ__Hostname + - RabbitMQ__Username + - RabbitMQ__Password + - RabbitMQ__Port + - ConnectionStrings__CoreDbContext + - Database__DbEngine + - AppSettings__Log_RollingFile_Enabled=false + - AppSettings__USE_JAEGER_APP_SETTINGS + - JAEGER_AGENT_HOST + - S3Bucket__Endpoint + - S3Bucket__BucketName + - S3Bucket__AccessKey + - S3Bucket__SecretKey + # - GstPipelineTemplate + # - Gpu__GpuNeuralRuntime=Tensor + volumes: + - "./iengine.lic:/etc/innovatrics/iengine.lic" + # - "/var/tmp/innovatrics/tensor-rt:/var/tmp/innovatrics/tensor-rt" + #runtime: nvidia + + api: + image: ${REGISTRY}sf-api:${SF_VERSION} + container_name: SFApi + ports: + # we forward the configured ports to default SF ports + - 8098:${Hosting__Port} + restart: unless-stopped + environment: + - RabbitMQ__Hostname + - RabbitMQ__Username + - RabbitMQ__Password + - RabbitMQ__Port + - ConnectionStrings__CoreDbContext + - Database__DbEngine + - Hosting__Host + - Hosting__Port + - AppSettings__Log_RollingFile_Enabled=false + - AppSettings__USE_JAEGER_APP_SETTINGS + - JAEGER_AGENT_HOST + - S3Bucket__Endpoint + - S3Bucket__BucketName + - S3Bucket__AccessKey + - S3Bucket__SecretKey + - NoSqlDataStorageDisabled + - CameraDefaults__PreviewPort + volumes: + - "./iengine.lic:/etc/innovatrics/iengine.lic" + + sf-graphql-api: + image: ${REGISTRY}sf-graphql-api:${SF_VERSION} + container_name: SFGraphQLApi + ports: + # we forward the configured ports to default SF ports + - 8097:${Hosting__Port} + restart: unless-stopped + environment: + - RabbitMQ__Hostname + - RabbitMQ__Username + - RabbitMQ__Password + - RabbitMQ__Port + - ConnectionStrings__CoreDbContext + - Database__DbEngine + - Hosting__Host + - Hosting__Port + - AppSettings__Log_RollingFile_Enabled=false + - AppSettings__USE_JAEGER_APP_SETTINGS + - JAEGER_AGENT_HOST + - AppSettings__Log_RabbitMq_Enabled + + odata-api: + image: ${REGISTRY}sf-odata-api:${SF_VERSION} + container_name: SFODataApi + ports: + # we forward the configured ports to default SF ports + - 8099:${Hosting__Port} + restart: unless-stopped + environment: + - RabbitMQ__Hostname + - RabbitMQ__Username + - RabbitMQ__Password + - RabbitMQ__Port + - ConnectionStrings__CoreDbContext + - Database__DbEngine + - Hosting__Host + - Hosting__Port + - AppSettings__Log_RollingFile_Enabled=false + - AppSettings__USE_JAEGER_APP_SETTINGS + - JAEGER_AGENT_HOST + - S3Bucket__Endpoint + - S3Bucket__BucketName + - S3Bucket__AccessKey + - S3Bucket__SecretKey + - NoSqlDataStorageDisabled + volumes: + - "./iengine.lic:/etc/innovatrics/iengine.lic" + + detector: + image: ${REGISTRY}sf-detector:${SF_VERSION} + restart: unless-stopped + environment: + - RabbitMQ__Hostname + - RabbitMQ__Username + - RabbitMQ__Password + - RabbitMQ__Port + - AppSettings__Log_RollingFile_Enabled=false + - AppSettings__USE_JAEGER_APP_SETTINGS + - JAEGER_AGENT_HOST + # - Gpu__GpuEnabled=true + # - Gpu__GpuNeuralRuntime=Tensor + volumes: + - "./iengine.lic:/etc/innovatrics/iengine.lic" + # - "/var/tmp/innovatrics/tensor-rt:/var/tmp/innovatrics/tensor-rt" + #runtime: nvidia + + pedestrian-detector: + image: ${REGISTRY}sf-pedestrian-detector:${SF_VERSION} + restart: unless-stopped + environment: + - RabbitMQ__Hostname + - RabbitMQ__Username + - RabbitMQ__Password + - RabbitMQ__Port + - AppSettings__Log_RollingFile_Enabled=false + - AppSettings__USE_JAEGER_APP_SETTINGS + - JAEGER_AGENT_HOST + # - Gpu__GpuEnabled=true + # - Gpu__GpuNeuralRuntime=Tensor + volumes: + - "./iengine.lic:/etc/innovatrics/iengine.lic" + # - "/var/tmp/innovatrics/tensor-rt:/var/tmp/innovatrics/tensor-rt" + #runtime: nvidia + + extractor: + image: ${REGISTRY}sf-extractor:${SF_VERSION} + restart: unless-stopped + environment: + - RabbitMQ__Hostname + - RabbitMQ__Username + - RabbitMQ__Password + - RabbitMQ__Port + - AppSettings__Log_RollingFile_Enabled=false + - AppSettings__USE_JAEGER_APP_SETTINGS + - JAEGER_AGENT_HOST + # - Gpu__GpuEnabled=true + # - Gpu__GpuNeuralRuntime=Tensor + volumes: + - "./iengine.lic:/etc/innovatrics/iengine.lic" + # - "/var/tmp/innovatrics/tensor-rt:/var/tmp/innovatrics/tensor-rt" + #runtime: nvidia + + matcher: + image: ${REGISTRY}sf-matcher:${SF_VERSION} + restart: unless-stopped + environment: + - RabbitMQ__Hostname + - RabbitMQ__Username + - RabbitMQ__Password + - RabbitMQ__Port + - ConnectionStrings__CoreDbContext + - Database__DbEngine + - AppSettings__Log_RollingFile_Enabled=false + - AppSettings__USE_JAEGER_APP_SETTINGS + - JAEGER_AGENT_HOST + volumes: + - "./iengine.lic:/etc/innovatrics/iengine.lic" + cpuset: "0" + + face-matcher: + image: ${REGISTRY}sf-face-matcher:${SF_VERSION} + restart: unless-stopped + environment: + - RabbitMQ__Hostname + - RabbitMQ__Username + - RabbitMQ__Password + - RabbitMQ__Port + - ConnectionStrings__CoreDbContext + - Database__DbEngine + - AppSettings__Log_RollingFile_Enabled=false + - AppSettings__USE_JAEGER_APP_SETTINGS + - JAEGER_AGENT_HOST + volumes: + - "./iengine.lic:/etc/innovatrics/iengine.lic" + + liveness: + image: ${REGISTRY}sf-liveness:${SF_VERSION} + restart: unless-stopped + environment: + - RabbitMQ__Hostname + - RabbitMQ__Username + - RabbitMQ__Password + - RabbitMQ__Port + - AppSettings__Log_RollingFile_Enabled=false + - AppSettings__USE_JAEGER_APP_SETTINGS + - JAEGER_AGENT_HOST + # - Gpu__GpuEnabled=true + # - Gpu__GpuNeuralRuntime=Tensor + volumes: + - "./iengine.lic:/etc/innovatrics/iengine.lic" + # - "/var/tmp/innovatrics/tensor-rt:/var/tmp/innovatrics/tensor-rt" + #runtime: nvidia + + video-aggregator: + image: ${REGISTRY}sf-video-aggregator:${SF_VERSION} + restart: unless-stopped + environment: + - RabbitMQ__Hostname + - RabbitMQ__Username + - RabbitMQ__Password + - RabbitMQ__Port + - ConnectionStrings__CoreDbContext + - Database__DbEngine + - AppSettings__Log_RollingFile_Enabled=false + - AppSettings__USE_JAEGER_APP_SETTINGS + - JAEGER_AGENT_HOST + - S3Bucket__Endpoint + - S3Bucket__BucketName + - S3Bucket__AccessKey + - S3Bucket__SecretKey + - NoSqlDataStorageDisabled + volumes: + - "./iengine.lic:/etc/innovatrics/iengine.lic" + + video-collector: + image: ${REGISTRY}sf-video-collector:${SF_VERSION} + restart: unless-stopped + environment: + - RabbitMQ__Hostname + - RabbitMQ__Username + - RabbitMQ__Password + - RabbitMQ__Port + - ConnectionStrings__CoreDbContext + - Database__DbEngine + - AppSettings__Log_RollingFile_Enabled=false + - AppSettings__USE_JAEGER_APP_SETTINGS + - JAEGER_AGENT_HOST + - S3Bucket__Endpoint + - S3Bucket__BucketName + - S3Bucket__AccessKey + - S3Bucket__SecretKey + - NoSqlDataStorageDisabled + volumes: + - "./iengine.lic:/etc/innovatrics/iengine.lic" + + video-reader: + image: ${REGISTRY}sf-video-reader:${SF_VERSION} + restart: unless-stopped + environment: + - RabbitMQ__Hostname + - RabbitMQ__Username + - RabbitMQ__Password + - RabbitMQ__Port + - AppSettings__Log_RollingFile_Enabled=false + - AppSettings__USE_JAEGER_APP_SETTINGS + - S3Bucket__Endpoint + - S3Bucket__BucketName + - S3Bucket__AccessKey + - S3Bucket__SecretKey + - JAEGER_AGENT_HOST + volumes: + - "./iengine.lic:/etc/innovatrics/iengine.lic" + + body-parts-detector: + image: ${REGISTRY}sf-body-parts-detector:${SF_VERSION} + restart: unless-stopped + environment: + - RabbitMQ__Hostname + - RabbitMQ__Username + - RabbitMQ__Password + - RabbitMQ__Port + - AppSettings__Log_RollingFile_Enabled=false + - AppSettings__USE_JAEGER_APP_SETTINGS + - JAEGER_AGENT_HOST + volumes: + - "./iengine.lic:/etc/innovatrics/iengine.lic" + + edge-stream-processor: + image: ${REGISTRY}sf-edge-stream-processor:${SF_VERSION} + restart: unless-stopped + environment: + - RabbitMQ__Hostname + - RabbitMQ__Username + - RabbitMQ__Password + - RabbitMQ__Port + - ConnectionStrings__CoreDbContext + - Database__DbEngine + - AppSettings__Log_RollingFile_Enabled=false + - AppSettings__Log_RabbitMq_Enabled + - NoSqlDataStorageDisabled + volumes: + - "./iengine.lic:/etc/innovatrics/iengine.lic" + + access-controller: + image: ${REGISTRY}sf-access-controller:${AC_VERSION} + container_name: SFAccessController + ports: + # we forward the configured ports to default SF ports + - 5050:${Hosting__Port} + restart: unless-stopped + environment: + - RabbitMq__HostName=${RabbitMQ__Hostname} + - RabbitMq__UserName=${RabbitMQ__Username} + - RabbitMq__Password=${RabbitMQ__Password} + - RabbitMq__Port=${RabbitMQ__Port} + - Kestrel__EndPoints__Http__Url=${Hosting__Host}:${Hosting__Port} + env_file: .env.sfac + + sf-station: + image: ${REGISTRY}sf-station:${SFS_VERSION} + restart: unless-stopped + ports: + - 8000:8000 + env_file: .env.sfstation + +networks: + default: + external: + name: HighAvailabilityClusterNetwork \ No newline at end of file diff --git a/sf-docker/special/high-availability/server1/run.sh b/sf-docker/special/high-availability/server1/run.sh new file mode 100644 index 00000000..68ac59da --- /dev/null +++ b/sf-docker/special/high-availability/server1/run.sh @@ -0,0 +1,90 @@ +#!/bin/bash + +set -x +set -e + +if [ ! -f iengine.lic ]; then + echo "License file not found. Please make sure that the license file is present in the current directory." >&2 + exit 1 +fi + +COMPOSE_COMMAND="docker compose" + +set +e + +$COMPOSE_COMMAND version + +if [ $? -ne 0 ]; then + COMPOSE_COMMAND="docker-compose" + $COMPOSE_COMMAND version + if [ $? -ne 0 ]; then + echo "No compose command found. Please install docker compose" >&2 + exit 1 + fi +fi + +set -e +# HighAvailabilityClusterNetwork is used so that sf-dependencies and sf containers can communicate +# this can fail if the network already exists, but we don't mind that +docker network create HighAvailabilityClusterNetwork || true + +# start dependencies of SF - MsSql, RMQ and minio +$COMPOSE_COMMAND -f sf_dependencies/docker-compose.yml up -d + +# sleep to wait for the dependencies to start up +sleep 10 + +# load version and registry from .env +VERSION=$(grep -E ^SF_VERSION .env | cut -d '=' -f2 | cut -d$'\r' -f1) +REGISTRY=$(grep -E ^REGISTRY .env | cut -d '=' -f2 | cut -d$'\r' -f1) + +# we use the DB engine that will be used by SF to create and migrate the DB +# to switch DB engine, change the .env file +DB_ENGINE=$(grep -E ^Database__DbEngine .env | cut -d '=' -f2 | cut -d$'\r' -f1) + +# load RabbitMQ properties from .env +RMQ_HOST=$(grep -E ^RabbitMQ__Hostname .env | cut -d '=' -f2 | cut -d$'\r' -f1) +RMQ_USER=$(grep -E ^RabbitMQ__Username .env | cut -d '=' -f2 | cut -d$'\r' -f1) +RMQ_PASS=$(grep -E ^RabbitMQ__Password .env | cut -d '=' -f2 | cut -d$'\r' -f1) +RMQ_VHOST=$(grep -E ^RabbitMQ__VirtualHost .env | cut -d '=' -f2 | cut -d$'\r' -f1) +RMQ_PORT=$(grep -E ^RabbitMQ__Port .env | cut -d '=' -f2 | cut -d$'\r' -f1) +RMQ_SSL=$(grep -E ^RabbitMQ__UseSsl .env | cut -d '=' -f2 | cut -d$'\r' -f1) + +S3_ENDPOINT=$(grep -E ^S3Bucket__Endpoint .env | cut -d '=' -f2 | cut -d$'\r' -f1) +S3_ACCESS=$(grep -E ^S3Bucket__AccessKey .env | cut -d '=' -f2 | cut -d$'\r' -f1) +S3_SECRET=$(grep -E ^S3Bucket__SecretKey .env | cut -d '=' -f2 | cut -d$'\r' -f1) +S3_BUCKET=$(grep -E ^S3Bucket__BucketName .env | cut -d '=' -f2 | cut -d$'\r' -f1) +# set correct hostname to sfstation env file +sed -i "s/S3_ENDPOINT=.*/S3_ENDPOINT=http:\/\/$(hostname):9000/g" .env.sfstation + +echo $VERSION +echo $REGISTRY + +# create mqtt user for rmq mqtt plugin +docker exec -it rmq1 /opt/rabbitmq/sbin/rabbitmqctl add_user mqtt mqtt || true +docker exec -it rmq1 /opt/rabbitmq/sbin/rabbitmqctl set_user_tags mqtt administrator || true +docker exec -it rmq1 /opt/rabbitmq/sbin/rabbitmqctl set_permissions -p "/" mqtt ".*" ".*" ".*" || true + +docker exec -it rmq1 /opt/rabbitmq/sbin/rabbitmqctl stop_app +docker exec -it rmq1 /opt/rabbitmq/sbin/rabbitmqctl reset +docker exec -it rmq1 /opt/rabbitmq/sbin/rabbitmqctl start_app + +if [[ "$DB_ENGINE" == "MsSql" ]]; then + # create SmartFace database in MsSql + docker exec mssql /opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P Test1234 -Q "CREATE DATABASE SmartFace" || true + # run database migration to current version + docker run --rm --name admin_migration --network HighAvailabilityClusterNetwork ${REGISTRY}sf-admin:${VERSION} run-migration -p 5 -c "Server=mssql;Database=SmartFace;User ID=sa;Password=Test1234;" -dbe $DB_ENGINE --rmq-host ${RMQ_HOST} --rmq-user ${RMQ_USER} --rmq-pass ${RMQ_PASS} --rmq-virtual-host ${RMQ_VHOST} --rmq-port ${RMQ_PORT} --rmq-use-ssl ${RMQ_SSL} +elif [[ "$DB_ENGINE" == "PgSql" ]]; then + # create SmartFace database in PgSql + docker exec pgsql psql -U postgres -c "CREATE DATABASE smartface" || true + # run database migration to current version + docker run --rm --name admin_migration --network HighAvailabilityClusterNetwork ${REGISTRY}sf-admin:${VERSION} run-migration -p 5 -c "Server=pgsql;Database=smartface;Username=postgres;Password=Test1234;Trust Server Certificate=true;" -dbe $DB_ENGINE --rmq-host ${RMQ_HOST} --rmq-user ${RMQ_USER} --rmq-pass ${RMQ_PASS} --rmq-virtual-host ${RMQ_VHOST} --rmq-port ${RMQ_PORT} --rmq-use-ssl ${RMQ_SSL} +else + echo "Unknown DB engine: ${DB_ENGINE}!" >&2 + exit 1 +fi + +docker run --rm --name s3-bucket-create --network HighAvailabilityClusterNetwork ${REGISTRY}sf-admin:${VERSION} ensure-s3-bucket-exists --endpoint "$S3_ENDPOINT" --access-key "$S3_ACCESS" --secret-key "$S3_SECRET" --bucket-name "$S3_BUCKET" + +# finally start SF images +$COMPOSE_COMMAND up -d --force-recreate \ No newline at end of file diff --git a/sf-docker/special/high-availability/server1/sf_dependencies/.erlang.cookie b/sf-docker/special/high-availability/server1/sf_dependencies/.erlang.cookie new file mode 100644 index 00000000..bd41cba7 --- /dev/null +++ b/sf-docker/special/high-availability/server1/sf_dependencies/.erlang.cookie @@ -0,0 +1 @@ +12345 \ No newline at end of file diff --git a/sf-docker/special/high-availability/server1/sf_dependencies/docker-compose.yml b/sf-docker/special/high-availability/server1/sf_dependencies/docker-compose.yml new file mode 100644 index 00000000..d5a0b846 --- /dev/null +++ b/sf-docker/special/high-availability/server1/sf_dependencies/docker-compose.yml @@ -0,0 +1,30 @@ +version: '3' +services: + rmq1: + image: "rabbitmq:3.10.2-management" + container_name: rmq1 + expose: + - "15672" + - "5672" + - "1883" + - "4369" + - "25672" + ports: + - "15677:15672" + environment: + RABBITMQ_NODENAME: rabbit@rmq1 + RABBITMQ_CONFIG_FILE: /etc/rabbitmq/external/rabbitmq.conf + RABBITMQ_ENABLED_PLUGINS_FILE: /etc/rabbitmq/external/enabled_plugins + volumes: + - ./.erlang.cookie:/var/lib/rabbitmq/.erlang.cookie + - ./etc_rmq/:/etc/rabbitmq/external + - rmqdata1:/var/lib/rabbitmq + restart: unless-stopped + +volumes: + rmqdata1: + +networks: + default: + external: + name: HighAvailabilityClusterNetwork \ No newline at end of file diff --git a/sf-docker/special/high-availability/server1/sf_dependencies/etc_rmq/enabled_plugins b/sf-docker/special/high-availability/server1/sf_dependencies/etc_rmq/enabled_plugins new file mode 100644 index 00000000..288b0ae2 --- /dev/null +++ b/sf-docker/special/high-availability/server1/sf_dependencies/etc_rmq/enabled_plugins @@ -0,0 +1 @@ +[rabbitmq_management,rabbitmq_mqtt,rabbitmq_prometheus,rabbitmq_federation]. \ No newline at end of file diff --git a/sf-docker/special/high-availability/server1/sf_dependencies/etc_rmq/rabbitmq.conf b/sf-docker/special/high-availability/server1/sf_dependencies/etc_rmq/rabbitmq.conf new file mode 100644 index 00000000..020a9cc5 --- /dev/null +++ b/sf-docker/special/high-availability/server1/sf_dependencies/etc_rmq/rabbitmq.conf @@ -0,0 +1,8 @@ +## Consumer timeout +## If a message delivered to a consumer has not been acknowledge before this timer +## triggers the channel will be force closed by the broker. This ensure that +## faultly consumers that never ack will not hold on to messages indefinitely. +## 6 hours = 21600000 ms +consumer_timeout = 21600000 + +mqtt.allow_anonymous = false \ No newline at end of file diff --git a/sf-docker/special/high-availability/server2/.env b/sf-docker/special/high-availability/server2/.env new file mode 100644 index 00000000..56bbeb69 --- /dev/null +++ b/sf-docker/special/high-availability/server2/.env @@ -0,0 +1,47 @@ +# RMQ config +RabbitMQ__Hostname=rmq2 +RabbitMQ__Username=guest +RabbitMQ__Password=guest +RabbitMQ__VirtualHost=/ +RabbitMQ__Port=5672 +RabbitMQ__UseSsl=false + +# Database config +#Database__DbEngine=MsSql +#ConnectionStrings__CoreDbContext=Server=mssql;Database=SmartFace;User ID=sa;Password=Test1234;TrustServerCertificate=true; +Database__DbEngine=PgSql +ConnectionStrings__CoreDbContext=Server=pgsql;Database=smartface;Username=postgres;Password=Test1234;Trust Server Certificate=true; + +# S3 config +S3Bucket__Endpoint=http://minio-proxy:9000 +S3Bucket__BucketName=inno-smartface +S3Bucket__AccessKey=minioadmin +S3Bucket__SecretKey=minioadmin + +# Set true when a Jaeger tracing is required +AppSettings__USE_JAEGER_APP_SETTINGS=false + +# Jaeger tracing endpoint. 'jaeger' is the name of included docker container. +# If targeting outside SmartFace docker, change to remote URL +JAEGER_AGENT_HOST=jaeger + +# API config - we use port 80 in docker and forward it as needed +Hosting__Host=http://0.0.0.0 +Hosting__Port=80 + +# we override the default generation of preview ports for camera in favor of static configuration +CameraDefaults__PreviewPort=30000 + +# Using NoSql database +NoSqlDataStorageDisabled=false + +# Using template for Gstreamer pipeline +GstPipelineTemplate=uridecodebin uri={0} source::latency=0 ! queue max-size-buffers=1 leaky=downstream ! nvvideoconvert ! video/x-raw, format=(string)BGRx ! videoconvert ! video/x-raw, format=(string)BGR ! appsink + +# Registry, must end with a forward slash `/` +REGISTRY=registry.gitlab.com/innovatrics/smartface/ + +# Version +SF_VERSION=v5_4.18.1 +AC_VERSION=v5_1.8.0 +SFS_VERSION=v5_1.15.0 diff --git a/sf-docker/special/high-availability/server2/.env.sfac b/sf-docker/special/high-availability/server2/.env.sfac new file mode 100644 index 00000000..f311821b --- /dev/null +++ b/sf-docker/special/high-availability/server2/.env.sfac @@ -0,0 +1,47 @@ +FilterConfiguration__FaceOrderConfiguration__Enabled=false +FilterConfiguration__FaceOrderConfiguration__Order=1 + +FilterConfiguration__OpeningDebounceConfiguration__OpeningDebounceEnabled=true +FilterConfiguration__OpeningDebounceConfiguration__OpeningDebounceMs=4000 + +FilterConfiguration__BlockingDebounceConfiguration__BlockingDebounceEnabled=true +FilterConfiguration__BlockingDebounceConfiguration__BlockingDebounceMs=4000 + +FilterConfiguration__ExclusiveCameraConfiguration__Enabled=true +FilterConfiguration__ExclusiveCameraConfiguration__ExclusivityMs=5000 + +FilterConfiguration__NotIdentifiedPersonConfiguration__Enabled=true +FilterConfiguration__NotIdentifiedPersonConfiguration__RoamingLimitTimeMs=3000 + +FilterConfiguration__BlacklistsConfiguration__Enabled=true +FilterConfiguration__BlacklistsConfiguration__Blacklists__0=firt_black_list_id +FilterConfiguration__BlacklistsConfiguration__Blacklists__1=second_black_list_id +FilterConfiguration__BlacklistsConfiguration__Blacklists__2=third_black_list_id + +FilterConfiguration__FaceMaskConfiguration__Enabled=false +FilterConfiguration__FaceMaskConfiguration__DenyingDebounceMs=4000 + +FilterConfiguration__IntentionalAccessConfiguration__Enabled=false +FilterConfiguration__IntentionalAccessConfiguration__AlwaysOpenForFaceAreaPercentLargerThan=7 +FilterConfiguration__IntentionalAccessConfiguration__RequiredFaceApproachingRatePercent=0.4 + +FilterConfiguration__StreamGroupsConfiguration__Enabled=true +FilterConfiguration__StreamGroupsConfiguration__GroupOpeningDebounceMs=3000 + +FilterConfiguration__SpoofCheckConfiguration__Enabled=false +FilterConfiguration__SpoofCheckConfiguration__DenyingDebounceMs=4000 + +# Set true when a Jaeger tracing is required +AppSettings__0__Key=USE_JAEGER_APP_SETTINGS +AppSettings__0__Value=false + +AppSettings__1__Key=JAEGER_SAMPLER_TYPE +AppSettings__1__Value=const + +AppSettings__2__Key=JAEGER_SAMPLER_PARAM +AppSettings__2__Value=1 + +# Jaeger tracing endpoint. 'jaeger' is the name of included docker container. +# If targeting outside SmartFace docker, change to remote URL +AppSettings__3__Key=JAEGER_AGENT_HOST +AppSettings__3__Value=jaeger \ No newline at end of file diff --git a/sf-docker/special/high-availability/server2/.env.sfstation b/sf-docker/special/high-availability/server2/.env.sfstation new file mode 100644 index 00000000..cf0d5ab5 --- /dev/null +++ b/sf-docker/special/high-availability/server2/.env.sfstation @@ -0,0 +1,96 @@ +# IP address, where SmartFace Station server will bind to +HOST=0.0.0.0 + +# Port number, where SmartFace Station server will bind to +PORT=8000 + +# Full addresses to SmartFace Server APIs +# CORE API example: http://[sf-server-host]:[port]/api/v1 +CORE_API_ROOT=http://SFApi:80/api/v1 + +# ODATA API example: http://[sf-server-host]:[port] +ODATA_API_ROOT=http://SFODataApi:80 + +# ZERO_MQ_HOST example: [sf-server-host] +ZERO_MQ_HOST=SFBase + +# Full address to SmartFace Server GraphQL APIs +GRAPHQL_ROOT=http://SFGraphQLApi:80/graphql + +# example: CAM_PREVIEW_HOST_[camera.serviceName]=[sf-camera-host] +CAM_PREVIEW_HOST_SFCAM1=SFCam1 +CAM_PREVIEW_HOST_SFCAM2=SFCam2 +CAM_PREVIEW_HOST_SFCAM3=SFCam3 +CAM_PREVIEW_HOST_SFCAM4=SFCam4 +CAM_PREVIEW_HOST_SFCAM5=SFCam5 + +# Address to Access Controller gRPC endpoint +# Example: [sf-server-host]:[port] +ACCESS_CONTROLLER_ADDRESS=SFAccessController:80 + +# Comma separated Watchlist IDs used as a global blacklists +BLACKLIST_WATCHLIST_IDS=abcdabcd-abcd-1234-abcd-abcdabcdacd + +# Whether to run with Keycloak authentication server or not +ENABLE_AUTHENTICATION=false + +# Full URL address to Keycloak's users management (if empty no url will be shown in webapp configuration) +KEYCLOAK_ADMIN_URL=http://keycloak-host:8080/auth/admin + +# In case of unauthorize access user will be redirected to provided URL (eg. keycloack login) +# If URL is not provided No access page will be shown +UNAUTHORIZE_ACCESS_REDIRECTION_URL=http://keycloak.login + +# Score to percentage conversion parameters +SCORE_CONVERSION_LOWER_LIMIT=20 +SCORE_CONVERSION_LOWER_LIMIT_PERCENTAGE=30 +SCORE_CONVERSION_UPPER_LIMIT=40 +SCORE_CONVERSION_UPPER_LIMIT_PERCENTAGE=90 + +# DOT camera parameters (HTTPS is required) +DOT_FACE_CAMERA_ENABLED=false +DOT_FACE_CAMERA_FACE_CENTER_LIMIT=0.2 +DOT_FACE_CAMERA_FACE_CONFIDENCE=0.06 + +# Wether to run with HTTPS authentication server or not +HTTPS_ENABLED=false +HTTPS_HOST_NAME= +HTTPS_KEY_FILE=server.key +HTTPS_CERT_FILE=server.cert + +# Setup for S3 / MinIO API +S3_ENDPOINT=http://127.0.0.1:9000 +S3_ACCESS_KEY=minioadmin +S3_SECRET_KEY=minioadmin +S3_REGION=eu-west-1 +S3_BUCKET=inno-smartface +# If we are using s3/minio over https this determine if certificate needs to be valid or not +# for http version of s3/minio needs to be set to false +S3_SKIP_SSL=false +# Presigned URL expiration in seconds +S3_URL_EXPIRATION=300 # 5 minutes +# Create bucket if it doesn't exist already +S3_PRECREATE_BUCKET=true + +# Add optional labels to watclist member (key is used in API requests, label is visual representation of key and used only in station frontend) +# WATCHLIST_MEMBER_KEY_0=date +# WATCHLIST_MEMBER_LABEL_0=Date of birth +# WATCHLIST_MEMBER_KEY_1=tax_number +# WATCHLIST_MEMBER_LABEL_1=Tax number +# WATCHLIST_MEMBER_KEY_2=phone +# WATCHLIST_MEMBER_LABEL_2=Phone number + +# Optional roles are used for locking specified part of frontend for given roles +# Claim name is "Group mapper name" specified in Keycloak or "cognito:groups" in Cognito +# ROLES_CLAIM_NAME=sf_roles +# ROLE_KEY_ADMIN=/admin +# ROLE_KEY_SECURITY_SUPERVISOR=/security_supervisor +# ROLE_KEY_SECURITY_OPERATOR=/security_operator +# ROLE_KEY_ACCESS_SUPERVISOR=/access_supervisor +# ROLE_KEY_ACCESS_OPERATOR=/access_operator +# ROLE_KEY_INVESTIGATION_SUPERVISOR=/investigation_supervisor +# ROLE_KEY_INVESTIGATION_OPERATOR=/investigation_operator +# ROLE_KEY_SECURITY_ADMIN=/security_admin +# ROLE_KEY_ACCESS_ADMIN=/access_admin +# ROLE_KEY_INVESTIGATION_ADMIN=/investigation_admin +# FORCED_ROLE_NAME_0=/admin diff --git a/sf-docker/special/high-availability/server2/docker-compose.yml b/sf-docker/special/high-availability/server2/docker-compose.yml new file mode 100644 index 00000000..7b2b91eb --- /dev/null +++ b/sf-docker/special/high-availability/server2/docker-compose.yml @@ -0,0 +1,228 @@ +version: "3.4" +services: + sf-cam-2: + image: ${REGISTRY}sf-cam:${SF_VERSION} + command: --serviceName SFCam2 + ports: + - 30002:${CameraDefaults__PreviewPort} + restart: unless-stopped + environment: + - RabbitMQ__Hostname + - RabbitMQ__Username + - RabbitMQ__Password + - RabbitMQ__Port + - ConnectionStrings__CoreDbContext + - Database__DbEngine + - AppSettings__Log_RollingFile_Enabled=false + - AppSettings__USE_JAEGER_APP_SETTINGS + - JAEGER_AGENT_HOST + - S3Bucket__Endpoint + - S3Bucket__BucketName + - S3Bucket__AccessKey + - S3Bucket__SecretKey + # - GstPipelineTemplate + # - Gpu__GpuNeuralRuntime=Tensor + volumes: + - "./iengine.lic:/etc/innovatrics/iengine.lic" + # - "/var/tmp/innovatrics/tensor-rt:/var/tmp/innovatrics/tensor-rt" + #runtime: nvidia + + detector: + image: ${REGISTRY}sf-detector:${SF_VERSION} + restart: unless-stopped + environment: + - RabbitMQ__Hostname + - RabbitMQ__Username + - RabbitMQ__Password + - RabbitMQ__Port + - AppSettings__Log_RollingFile_Enabled=false + - AppSettings__USE_JAEGER_APP_SETTINGS + - JAEGER_AGENT_HOST + # - Gpu__GpuEnabled=true + # - Gpu__GpuNeuralRuntime=Tensor + volumes: + - "./iengine.lic:/etc/innovatrics/iengine.lic" + # - "/var/tmp/innovatrics/tensor-rt:/var/tmp/innovatrics/tensor-rt" + #runtime: nvidia + + pedestrian-detector: + image: ${REGISTRY}sf-pedestrian-detector:${SF_VERSION} + restart: unless-stopped + environment: + - RabbitMQ__Hostname + - RabbitMQ__Username + - RabbitMQ__Password + - RabbitMQ__Port + - AppSettings__Log_RollingFile_Enabled=false + - AppSettings__USE_JAEGER_APP_SETTINGS + - JAEGER_AGENT_HOST + # - Gpu__GpuEnabled=true + # - Gpu__GpuNeuralRuntime=Tensor + volumes: + - "./iengine.lic:/etc/innovatrics/iengine.lic" + # - "/var/tmp/innovatrics/tensor-rt:/var/tmp/innovatrics/tensor-rt" + #runtime: nvidia + + extractor: + image: ${REGISTRY}sf-extractor:${SF_VERSION} + restart: unless-stopped + environment: + - RabbitMQ__Hostname + - RabbitMQ__Username + - RabbitMQ__Password + - RabbitMQ__Port + - AppSettings__Log_RollingFile_Enabled=false + - AppSettings__USE_JAEGER_APP_SETTINGS + - JAEGER_AGENT_HOST + # - Gpu__GpuEnabled=true + # - Gpu__GpuNeuralRuntime=Tensor + volumes: + - "./iengine.lic:/etc/innovatrics/iengine.lic" + # - "/var/tmp/innovatrics/tensor-rt:/var/tmp/innovatrics/tensor-rt" + #runtime: nvidia + + matcher: + image: ${REGISTRY}sf-matcher:${SF_VERSION} + restart: unless-stopped + environment: + - RabbitMQ__Hostname + - RabbitMQ__Username + - RabbitMQ__Password + - RabbitMQ__Port + - ConnectionStrings__CoreDbContext + - Database__DbEngine + - AppSettings__Log_RollingFile_Enabled=false + - AppSettings__USE_JAEGER_APP_SETTINGS + - JAEGER_AGENT_HOST + volumes: + - "./iengine.lic:/etc/innovatrics/iengine.lic" + cpuset: "0" + + face-matcher: + image: ${REGISTRY}sf-face-matcher:${SF_VERSION} + restart: unless-stopped + environment: + - RabbitMQ__Hostname + - RabbitMQ__Username + - RabbitMQ__Password + - RabbitMQ__Port + - ConnectionStrings__CoreDbContext + - Database__DbEngine + - AppSettings__Log_RollingFile_Enabled=false + - AppSettings__USE_JAEGER_APP_SETTINGS + - JAEGER_AGENT_HOST + volumes: + - "./iengine.lic:/etc/innovatrics/iengine.lic" + + liveness: + image: ${REGISTRY}sf-liveness:${SF_VERSION} + restart: unless-stopped + environment: + - RabbitMQ__Hostname + - RabbitMQ__Username + - RabbitMQ__Password + - RabbitMQ__Port + - AppSettings__Log_RollingFile_Enabled=false + - AppSettings__USE_JAEGER_APP_SETTINGS + - JAEGER_AGENT_HOST + # - Gpu__GpuEnabled=true + # - Gpu__GpuNeuralRuntime=Tensor + volumes: + - "./iengine.lic:/etc/innovatrics/iengine.lic" + # - "/var/tmp/innovatrics/tensor-rt:/var/tmp/innovatrics/tensor-rt" + #runtime: nvidia + + video-aggregator: + image: ${REGISTRY}sf-video-aggregator:${SF_VERSION} + restart: unless-stopped + environment: + - RabbitMQ__Hostname + - RabbitMQ__Username + - RabbitMQ__Password + - RabbitMQ__Port + - ConnectionStrings__CoreDbContext + - Database__DbEngine + - AppSettings__Log_RollingFile_Enabled=false + - AppSettings__USE_JAEGER_APP_SETTINGS + - JAEGER_AGENT_HOST + - S3Bucket__Endpoint + - S3Bucket__BucketName + - S3Bucket__AccessKey + - S3Bucket__SecretKey + - NoSqlDataStorageDisabled + volumes: + - "./iengine.lic:/etc/innovatrics/iengine.lic" + + video-collector: + image: ${REGISTRY}sf-video-collector:${SF_VERSION} + restart: unless-stopped + environment: + - RabbitMQ__Hostname + - RabbitMQ__Username + - RabbitMQ__Password + - RabbitMQ__Port + - ConnectionStrings__CoreDbContext + - Database__DbEngine + - AppSettings__Log_RollingFile_Enabled=false + - AppSettings__USE_JAEGER_APP_SETTINGS + - JAEGER_AGENT_HOST + - S3Bucket__Endpoint + - S3Bucket__BucketName + - S3Bucket__AccessKey + - S3Bucket__SecretKey + - NoSqlDataStorageDisabled + volumes: + - "./iengine.lic:/etc/innovatrics/iengine.lic" + + video-reader: + image: ${REGISTRY}sf-video-reader:${SF_VERSION} + restart: unless-stopped + environment: + - RabbitMQ__Hostname + - RabbitMQ__Username + - RabbitMQ__Password + - RabbitMQ__Port + - AppSettings__Log_RollingFile_Enabled=false + - AppSettings__USE_JAEGER_APP_SETTINGS + - S3Bucket__Endpoint + - S3Bucket__BucketName + - S3Bucket__AccessKey + - S3Bucket__SecretKey + - JAEGER_AGENT_HOST + volumes: + - "./iengine.lic:/etc/innovatrics/iengine.lic" + + body-parts-detector: + image: ${REGISTRY}sf-body-parts-detector:${SF_VERSION} + restart: unless-stopped + environment: + - RabbitMQ__Hostname + - RabbitMQ__Username + - RabbitMQ__Password + - RabbitMQ__Port + - AppSettings__Log_RollingFile_Enabled=false + - AppSettings__USE_JAEGER_APP_SETTINGS + - JAEGER_AGENT_HOST + volumes: + - "./iengine.lic:/etc/innovatrics/iengine.lic" + + edge-stream-processor: + image: ${REGISTRY}sf-edge-stream-processor:${SF_VERSION} + restart: unless-stopped + environment: + - RabbitMQ__Hostname + - RabbitMQ__Username + - RabbitMQ__Password + - RabbitMQ__Port + - ConnectionStrings__CoreDbContext + - Database__DbEngine + - AppSettings__Log_RollingFile_Enabled=false + - AppSettings__Log_RabbitMq_Enabled + - NoSqlDataStorageDisabled + volumes: + - "./iengine.lic:/etc/innovatrics/iengine.lic" + +networks: + default: + external: + name: HighAvailabilityClusterNetwork diff --git a/sf-docker/special/high-availability/server2/run.sh b/sf-docker/special/high-availability/server2/run.sh new file mode 100644 index 00000000..a2034189 --- /dev/null +++ b/sf-docker/special/high-availability/server2/run.sh @@ -0,0 +1,91 @@ +#!/bin/bash + +set -x +set -e + +if [ ! -f iengine.lic ]; then + echo "License file not found. Please make sure that the license file is present in the current directory." >&2 + exit 1 +fi + +COMPOSE_COMMAND="docker compose" + +set +e + +$COMPOSE_COMMAND version + +if [ $? -ne 0 ]; then + COMPOSE_COMMAND="docker-compose" + $COMPOSE_COMMAND version + if [ $? -ne 0 ]; then + echo "No compose command found. Please install docker compose" >&2 + exit 1 + fi +fi + +set -e +# HighAvailabilityClusterNetwork is used so that sf-dependencies and sf containers can communicate +# this can fail if the network already exists, but we don't mind that +docker network create HighAvailabilityClusterNetwork || true + +# start dependencies of SF - MsSql, RMQ and minio +$COMPOSE_COMMAND -f sf_dependencies/docker-compose.yml up -d + +# sleep to wait for the dependencies to start up +sleep 10 + +# load version and registry from .env +VERSION=$(grep -E ^SF_VERSION .env | cut -d '=' -f2 | cut -d$'\r' -f1) +REGISTRY=$(grep -E ^REGISTRY .env | cut -d '=' -f2 | cut -d$'\r' -f1) + +# we use the DB engine that will be used by SF to create and migrate the DB +# to switch DB engine, change the .env file +DB_ENGINE=$(grep -E ^Database__DbEngine .env | cut -d '=' -f2 | cut -d$'\r' -f1) + +# load RabbitMQ properties from .env +RMQ_HOST=$(grep -E ^RabbitMQ__Hostname .env | cut -d '=' -f2 | cut -d$'\r' -f1) +RMQ_USER=$(grep -E ^RabbitMQ__Username .env | cut -d '=' -f2 | cut -d$'\r' -f1) +RMQ_PASS=$(grep -E ^RabbitMQ__Password .env | cut -d '=' -f2 | cut -d$'\r' -f1) +RMQ_VHOST=$(grep -E ^RabbitMQ__VirtualHost .env | cut -d '=' -f2 | cut -d$'\r' -f1) +RMQ_PORT=$(grep -E ^RabbitMQ__Port .env | cut -d '=' -f2 | cut -d$'\r' -f1) +RMQ_SSL=$(grep -E ^RabbitMQ__UseSsl .env | cut -d '=' -f2 | cut -d$'\r' -f1) + +S3_ENDPOINT=$(grep -E ^S3Bucket__Endpoint .env | cut -d '=' -f2 | cut -d$'\r' -f1) +S3_ACCESS=$(grep -E ^S3Bucket__AccessKey .env | cut -d '=' -f2 | cut -d$'\r' -f1) +S3_SECRET=$(grep -E ^S3Bucket__SecretKey .env | cut -d '=' -f2 | cut -d$'\r' -f1) +S3_BUCKET=$(grep -E ^S3Bucket__BucketName .env | cut -d '=' -f2 | cut -d$'\r' -f1) +# set correct hostname to sfstation env file +sed -i "s/S3_ENDPOINT=.*/S3_ENDPOINT=http:\/\/$(hostname):9000/g" .env.sfstation + +echo $VERSION +echo $REGISTRY + +# create mqtt user for rmq mqtt plugin +docker exec -it rmq2 /opt/rabbitmq/sbin/rabbitmqctl add_user mqtt mqtt || true +docker exec -it rmq2 /opt/rabbitmq/sbin/rabbitmqctl set_user_tags mqtt administrator || true +docker exec -it rmq2 /opt/rabbitmq/sbin/rabbitmqctl set_permissions -p "/" mqtt ".*" ".*" ".*" || true + +docker exec -it rmq2 /opt/rabbitmq/sbin/rabbitmqctl stop_app +docker exec -it rmq2 /opt/rabbitmq/sbin/rabbitmqctl reset +docker exec -it rmq2 /opt/rabbitmq/sbin/rabbitmqctl join_cluster rabbit@rmq1 +docker exec -it rmq2 /opt/rabbitmq/sbin/rabbitmqctl start_app + +if [[ "$DB_ENGINE" == "MsSql" ]]; then + # create SmartFace database in MsSql + docker exec mssql /opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P Test1234 -Q "CREATE DATABASE SmartFace" || true + # run database migration to current version + docker run --rm --name admin_migration --network HighAvailabilityClusterNetwork ${REGISTRY}sf-admin:${VERSION} run-migration -p 5 -c "Server=mssql;Database=SmartFace;User ID=sa;Password=Test1234;" -dbe $DB_ENGINE --rmq-host ${RMQ_HOST} --rmq-user ${RMQ_USER} --rmq-pass ${RMQ_PASS} --rmq-virtual-host ${RMQ_VHOST} --rmq-port ${RMQ_PORT} --rmq-use-ssl ${RMQ_SSL} +elif [[ "$DB_ENGINE" == "PgSql" ]]; then + # create SmartFace database in PgSql + docker exec pgsql psql -U postgres -c "CREATE DATABASE smartface" || true + # run database migration to current version + docker run --rm --name admin_migration --network HighAvailabilityClusterNetwork ${REGISTRY}sf-admin:${VERSION} run-migration -p 5 -c "Server=pgsql;Database=smartface;Username=postgres;Password=Test1234;Trust Server Certificate=true;" -dbe $DB_ENGINE --rmq-host ${RMQ_HOST} --rmq-user ${RMQ_USER} --rmq-pass ${RMQ_PASS} --rmq-virtual-host ${RMQ_VHOST} --rmq-port ${RMQ_PORT} --rmq-use-ssl ${RMQ_SSL} +else + echo "Unknown DB engine: ${DB_ENGINE}!" >&2 + exit 1 +fi + +docker run --rm --name s3-bucket-create --network HighAvailabilityClusterNetwork ${REGISTRY}sf-admin:${VERSION} ensure-s3-bucket-exists --endpoint "$S3_ENDPOINT" --access-key "$S3_ACCESS" --secret-key "$S3_SECRET" --bucket-name "$S3_BUCKET" + +# finally start SF images +$COMPOSE_COMMAND up -d --force-recreate \ No newline at end of file diff --git a/sf-docker/special/high-availability/server2/sf_dependencies/.erlang.cookie b/sf-docker/special/high-availability/server2/sf_dependencies/.erlang.cookie new file mode 100644 index 00000000..bd41cba7 --- /dev/null +++ b/sf-docker/special/high-availability/server2/sf_dependencies/.erlang.cookie @@ -0,0 +1 @@ +12345 \ No newline at end of file diff --git a/sf-docker/special/high-availability/server2/sf_dependencies/docker-compose.yml b/sf-docker/special/high-availability/server2/sf_dependencies/docker-compose.yml new file mode 100644 index 00000000..6b3ade4f --- /dev/null +++ b/sf-docker/special/high-availability/server2/sf_dependencies/docker-compose.yml @@ -0,0 +1,30 @@ +version: '3' +services: + rmq2: + image: "rabbitmq:3.10.2-management" + container_name: rmq2 + expose: + - "15672" + - "5672" + - "1883" + - "4369" + - "25672" + ports: + - "15678:15672" + environment: + RABBITMQ_NODENAME: rabbit@rmq2 + RABBITMQ_CONFIG_FILE: /etc/rabbitmq/external/rabbitmq.conf + RABBITMQ_ENABLED_PLUGINS_FILE: /etc/rabbitmq/external/enabled_plugins + volumes: + - ./.erlang.cookie:/var/lib/rabbitmq/.erlang.cookie + - ./etc_rmq/:/etc/rabbitmq/external + - rmqdata2:/var/lib/rabbitmq + restart: unless-stopped + +volumes: + rmqdata2: + +networks: + default: + external: + name: HighAvailabilityClusterNetwork \ No newline at end of file diff --git a/sf-docker/special/high-availability/server2/sf_dependencies/etc_rmq/enabled_plugins b/sf-docker/special/high-availability/server2/sf_dependencies/etc_rmq/enabled_plugins new file mode 100644 index 00000000..288b0ae2 --- /dev/null +++ b/sf-docker/special/high-availability/server2/sf_dependencies/etc_rmq/enabled_plugins @@ -0,0 +1 @@ +[rabbitmq_management,rabbitmq_mqtt,rabbitmq_prometheus,rabbitmq_federation]. \ No newline at end of file diff --git a/sf-docker/special/high-availability/server2/sf_dependencies/etc_rmq/rabbitmq.conf b/sf-docker/special/high-availability/server2/sf_dependencies/etc_rmq/rabbitmq.conf new file mode 100644 index 00000000..020a9cc5 --- /dev/null +++ b/sf-docker/special/high-availability/server2/sf_dependencies/etc_rmq/rabbitmq.conf @@ -0,0 +1,8 @@ +## Consumer timeout +## If a message delivered to a consumer has not been acknowledge before this timer +## triggers the channel will be force closed by the broker. This ensure that +## faultly consumers that never ack will not hold on to messages indefinitely. +## 6 hours = 21600000 ms +consumer_timeout = 21600000 + +mqtt.allow_anonymous = false \ No newline at end of file diff --git a/sf-docker/special/high-availability/server3/.env b/sf-docker/special/high-availability/server3/.env new file mode 100644 index 00000000..76b7546d --- /dev/null +++ b/sf-docker/special/high-availability/server3/.env @@ -0,0 +1,47 @@ +# RMQ config +RabbitMQ__Hostname=rmq3 +RabbitMQ__Username=guest +RabbitMQ__Password=guest +RabbitMQ__VirtualHost=/ +RabbitMQ__Port=5672 +RabbitMQ__UseSsl=false + +# Database config +#Database__DbEngine=MsSql +#ConnectionStrings__CoreDbContext=Server=mssql;Database=SmartFace;User ID=sa;Password=Test1234;TrustServerCertificate=true; +Database__DbEngine=PgSql +ConnectionStrings__CoreDbContext=Server=pgsql;Database=smartface;Username=postgres;Password=Test1234;Trust Server Certificate=true; + +# S3 config +S3Bucket__Endpoint=http://minio-proxy:9000 +S3Bucket__BucketName=inno-smartface +S3Bucket__AccessKey=minioadmin +S3Bucket__SecretKey=minioadmin + +# Set true when a Jaeger tracing is required +AppSettings__USE_JAEGER_APP_SETTINGS=false + +# Jaeger tracing endpoint. 'jaeger' is the name of included docker container. +# If targeting outside SmartFace docker, change to remote URL +JAEGER_AGENT_HOST=jaeger + +# API config - we use port 80 in docker and forward it as needed +Hosting__Host=http://0.0.0.0 +Hosting__Port=80 + +# we override the default generation of preview ports for camera in favor of static configuration +CameraDefaults__PreviewPort=30000 + +# Using NoSql database +NoSqlDataStorageDisabled=false + +# Using template for Gstreamer pipeline +GstPipelineTemplate=uridecodebin uri={0} source::latency=0 ! queue max-size-buffers=1 leaky=downstream ! nvvideoconvert ! video/x-raw, format=(string)BGRx ! videoconvert ! video/x-raw, format=(string)BGR ! appsink + +# Registry, must end with a forward slash `/` +REGISTRY=registry.gitlab.com/innovatrics/smartface/ + +# Version +SF_VERSION=v5_4.18.1 +AC_VERSION=v5_1.8.0 +SFS_VERSION=v5_1.15.0 diff --git a/sf-docker/special/high-availability/server3/.env.sfac b/sf-docker/special/high-availability/server3/.env.sfac new file mode 100644 index 00000000..f311821b --- /dev/null +++ b/sf-docker/special/high-availability/server3/.env.sfac @@ -0,0 +1,47 @@ +FilterConfiguration__FaceOrderConfiguration__Enabled=false +FilterConfiguration__FaceOrderConfiguration__Order=1 + +FilterConfiguration__OpeningDebounceConfiguration__OpeningDebounceEnabled=true +FilterConfiguration__OpeningDebounceConfiguration__OpeningDebounceMs=4000 + +FilterConfiguration__BlockingDebounceConfiguration__BlockingDebounceEnabled=true +FilterConfiguration__BlockingDebounceConfiguration__BlockingDebounceMs=4000 + +FilterConfiguration__ExclusiveCameraConfiguration__Enabled=true +FilterConfiguration__ExclusiveCameraConfiguration__ExclusivityMs=5000 + +FilterConfiguration__NotIdentifiedPersonConfiguration__Enabled=true +FilterConfiguration__NotIdentifiedPersonConfiguration__RoamingLimitTimeMs=3000 + +FilterConfiguration__BlacklistsConfiguration__Enabled=true +FilterConfiguration__BlacklistsConfiguration__Blacklists__0=firt_black_list_id +FilterConfiguration__BlacklistsConfiguration__Blacklists__1=second_black_list_id +FilterConfiguration__BlacklistsConfiguration__Blacklists__2=third_black_list_id + +FilterConfiguration__FaceMaskConfiguration__Enabled=false +FilterConfiguration__FaceMaskConfiguration__DenyingDebounceMs=4000 + +FilterConfiguration__IntentionalAccessConfiguration__Enabled=false +FilterConfiguration__IntentionalAccessConfiguration__AlwaysOpenForFaceAreaPercentLargerThan=7 +FilterConfiguration__IntentionalAccessConfiguration__RequiredFaceApproachingRatePercent=0.4 + +FilterConfiguration__StreamGroupsConfiguration__Enabled=true +FilterConfiguration__StreamGroupsConfiguration__GroupOpeningDebounceMs=3000 + +FilterConfiguration__SpoofCheckConfiguration__Enabled=false +FilterConfiguration__SpoofCheckConfiguration__DenyingDebounceMs=4000 + +# Set true when a Jaeger tracing is required +AppSettings__0__Key=USE_JAEGER_APP_SETTINGS +AppSettings__0__Value=false + +AppSettings__1__Key=JAEGER_SAMPLER_TYPE +AppSettings__1__Value=const + +AppSettings__2__Key=JAEGER_SAMPLER_PARAM +AppSettings__2__Value=1 + +# Jaeger tracing endpoint. 'jaeger' is the name of included docker container. +# If targeting outside SmartFace docker, change to remote URL +AppSettings__3__Key=JAEGER_AGENT_HOST +AppSettings__3__Value=jaeger \ No newline at end of file diff --git a/sf-docker/special/high-availability/server3/.env.sfstation b/sf-docker/special/high-availability/server3/.env.sfstation new file mode 100644 index 00000000..cf0d5ab5 --- /dev/null +++ b/sf-docker/special/high-availability/server3/.env.sfstation @@ -0,0 +1,96 @@ +# IP address, where SmartFace Station server will bind to +HOST=0.0.0.0 + +# Port number, where SmartFace Station server will bind to +PORT=8000 + +# Full addresses to SmartFace Server APIs +# CORE API example: http://[sf-server-host]:[port]/api/v1 +CORE_API_ROOT=http://SFApi:80/api/v1 + +# ODATA API example: http://[sf-server-host]:[port] +ODATA_API_ROOT=http://SFODataApi:80 + +# ZERO_MQ_HOST example: [sf-server-host] +ZERO_MQ_HOST=SFBase + +# Full address to SmartFace Server GraphQL APIs +GRAPHQL_ROOT=http://SFGraphQLApi:80/graphql + +# example: CAM_PREVIEW_HOST_[camera.serviceName]=[sf-camera-host] +CAM_PREVIEW_HOST_SFCAM1=SFCam1 +CAM_PREVIEW_HOST_SFCAM2=SFCam2 +CAM_PREVIEW_HOST_SFCAM3=SFCam3 +CAM_PREVIEW_HOST_SFCAM4=SFCam4 +CAM_PREVIEW_HOST_SFCAM5=SFCam5 + +# Address to Access Controller gRPC endpoint +# Example: [sf-server-host]:[port] +ACCESS_CONTROLLER_ADDRESS=SFAccessController:80 + +# Comma separated Watchlist IDs used as a global blacklists +BLACKLIST_WATCHLIST_IDS=abcdabcd-abcd-1234-abcd-abcdabcdacd + +# Whether to run with Keycloak authentication server or not +ENABLE_AUTHENTICATION=false + +# Full URL address to Keycloak's users management (if empty no url will be shown in webapp configuration) +KEYCLOAK_ADMIN_URL=http://keycloak-host:8080/auth/admin + +# In case of unauthorize access user will be redirected to provided URL (eg. keycloack login) +# If URL is not provided No access page will be shown +UNAUTHORIZE_ACCESS_REDIRECTION_URL=http://keycloak.login + +# Score to percentage conversion parameters +SCORE_CONVERSION_LOWER_LIMIT=20 +SCORE_CONVERSION_LOWER_LIMIT_PERCENTAGE=30 +SCORE_CONVERSION_UPPER_LIMIT=40 +SCORE_CONVERSION_UPPER_LIMIT_PERCENTAGE=90 + +# DOT camera parameters (HTTPS is required) +DOT_FACE_CAMERA_ENABLED=false +DOT_FACE_CAMERA_FACE_CENTER_LIMIT=0.2 +DOT_FACE_CAMERA_FACE_CONFIDENCE=0.06 + +# Wether to run with HTTPS authentication server or not +HTTPS_ENABLED=false +HTTPS_HOST_NAME= +HTTPS_KEY_FILE=server.key +HTTPS_CERT_FILE=server.cert + +# Setup for S3 / MinIO API +S3_ENDPOINT=http://127.0.0.1:9000 +S3_ACCESS_KEY=minioadmin +S3_SECRET_KEY=minioadmin +S3_REGION=eu-west-1 +S3_BUCKET=inno-smartface +# If we are using s3/minio over https this determine if certificate needs to be valid or not +# for http version of s3/minio needs to be set to false +S3_SKIP_SSL=false +# Presigned URL expiration in seconds +S3_URL_EXPIRATION=300 # 5 minutes +# Create bucket if it doesn't exist already +S3_PRECREATE_BUCKET=true + +# Add optional labels to watclist member (key is used in API requests, label is visual representation of key and used only in station frontend) +# WATCHLIST_MEMBER_KEY_0=date +# WATCHLIST_MEMBER_LABEL_0=Date of birth +# WATCHLIST_MEMBER_KEY_1=tax_number +# WATCHLIST_MEMBER_LABEL_1=Tax number +# WATCHLIST_MEMBER_KEY_2=phone +# WATCHLIST_MEMBER_LABEL_2=Phone number + +# Optional roles are used for locking specified part of frontend for given roles +# Claim name is "Group mapper name" specified in Keycloak or "cognito:groups" in Cognito +# ROLES_CLAIM_NAME=sf_roles +# ROLE_KEY_ADMIN=/admin +# ROLE_KEY_SECURITY_SUPERVISOR=/security_supervisor +# ROLE_KEY_SECURITY_OPERATOR=/security_operator +# ROLE_KEY_ACCESS_SUPERVISOR=/access_supervisor +# ROLE_KEY_ACCESS_OPERATOR=/access_operator +# ROLE_KEY_INVESTIGATION_SUPERVISOR=/investigation_supervisor +# ROLE_KEY_INVESTIGATION_OPERATOR=/investigation_operator +# ROLE_KEY_SECURITY_ADMIN=/security_admin +# ROLE_KEY_ACCESS_ADMIN=/access_admin +# ROLE_KEY_INVESTIGATION_ADMIN=/investigation_admin +# FORCED_ROLE_NAME_0=/admin diff --git a/sf-docker/special/high-availability/server3/docker-compose.yml b/sf-docker/special/high-availability/server3/docker-compose.yml new file mode 100644 index 00000000..efa96d26 --- /dev/null +++ b/sf-docker/special/high-availability/server3/docker-compose.yml @@ -0,0 +1,263 @@ +version: "3.4" +services: + sf-group: + image: ${REGISTRY}sf-grouping:${SF_VERSION} + container_name: SFGroup + command: --serviceName SFGroup + restart: unless-stopped + environment: + - RabbitMQ__Hostname + - RabbitMQ__Username + - RabbitMQ__Password + - RabbitMQ__Port + - ConnectionStrings__CoreDbContext + - Database__DbEngine + - AppSettings__Log_RollingFile_Enabled=false + - AppSettings__USE_JAEGER_APP_SETTINGS + - JAEGER_AGENT_HOST + - S3Bucket__Endpoint + - S3Bucket__BucketName + - S3Bucket__AccessKey + - S3Bucket__SecretKey + - NoSqlDataStorageDisabled + volumes: + - "./iengine.lic:/etc/innovatrics/iengine.lic" + + sf-cam-7: + image: ${REGISTRY}sf-cam:${SF_VERSION} + container_name: SFCam7 + command: --serviceName SFCam7 + ports: + - 30007:${CameraDefaults__PreviewPort} + restart: unless-stopped + environment: + - RabbitMQ__Hostname + - RabbitMQ__Username + - RabbitMQ__Password + - RabbitMQ__Port + - ConnectionStrings__CoreDbContext + - Database__DbEngine + - AppSettings__Log_RollingFile_Enabled=false + - AppSettings__USE_JAEGER_APP_SETTINGS + - JAEGER_AGENT_HOST + - S3Bucket__Endpoint + - S3Bucket__BucketName + - S3Bucket__AccessKey + - S3Bucket__SecretKey + # - GstPipelineTemplate + # - Gpu__GpuNeuralRuntime=Tensor + volumes: + - "./iengine.lic:/etc/innovatrics/iengine.lic" + # - "/var/tmp/innovatrics/tensor-rt:/var/tmp/innovatrics/tensor-rt" + #runtime: nvidia + + detector: + image: ${REGISTRY}sf-detector:${SF_VERSION} + container_name: SFDetectCpu + restart: unless-stopped + environment: + - RabbitMQ__Hostname + - RabbitMQ__Username + - RabbitMQ__Password + - RabbitMQ__Port + - AppSettings__Log_RollingFile_Enabled=false + - AppSettings__USE_JAEGER_APP_SETTINGS + - JAEGER_AGENT_HOST + # - Gpu__GpuEnabled=true + # - Gpu__GpuNeuralRuntime=Tensor + volumes: + - "./iengine.lic:/etc/innovatrics/iengine.lic" + # - "/var/tmp/innovatrics/tensor-rt:/var/tmp/innovatrics/tensor-rt" + #runtime: nvidia + + pedestrian-detector: + image: ${REGISTRY}sf-pedestrian-detector:${SF_VERSION} + container_name: SFPedestrianDetectCpu + restart: unless-stopped + environment: + - RabbitMQ__Hostname + - RabbitMQ__Username + - RabbitMQ__Password + - RabbitMQ__Port + - AppSettings__Log_RollingFile_Enabled=false + - AppSettings__USE_JAEGER_APP_SETTINGS + - JAEGER_AGENT_HOST + # - Gpu__GpuEnabled=true + # - Gpu__GpuNeuralRuntime=Tensor + volumes: + - "./iengine.lic:/etc/innovatrics/iengine.lic" + # - "/var/tmp/innovatrics/tensor-rt:/var/tmp/innovatrics/tensor-rt" + #runtime: nvidia + + extractor: + image: ${REGISTRY}sf-extractor:${SF_VERSION} + container_name: SFExtractCpu + restart: unless-stopped + environment: + - RabbitMQ__Hostname + - RabbitMQ__Username + - RabbitMQ__Password + - RabbitMQ__Port + - AppSettings__Log_RollingFile_Enabled=false + - AppSettings__USE_JAEGER_APP_SETTINGS + - JAEGER_AGENT_HOST + # - Gpu__GpuEnabled=true + # - Gpu__GpuNeuralRuntime=Tensor + volumes: + - "./iengine.lic:/etc/innovatrics/iengine.lic" + # - "/var/tmp/innovatrics/tensor-rt:/var/tmp/innovatrics/tensor-rt" + #runtime: nvidia + + matcher: + image: ${REGISTRY}sf-matcher:${SF_VERSION} + container_name: SFWatchlistMatcher + restart: unless-stopped + environment: + - RabbitMQ__Hostname + - RabbitMQ__Username + - RabbitMQ__Password + - RabbitMQ__Port + - ConnectionStrings__CoreDbContext + - Database__DbEngine + - AppSettings__Log_RollingFile_Enabled=false + - AppSettings__USE_JAEGER_APP_SETTINGS + - JAEGER_AGENT_HOST + volumes: + - "./iengine.lic:/etc/innovatrics/iengine.lic" + cpuset: "0" + + face-matcher: + image: ${REGISTRY}sf-face-matcher:${SF_VERSION} + container_name: SFFaceMatcher + restart: unless-stopped + environment: + - RabbitMQ__Hostname + - RabbitMQ__Username + - RabbitMQ__Password + - RabbitMQ__Port + - ConnectionStrings__CoreDbContext + - Database__DbEngine + - AppSettings__Log_RollingFile_Enabled=false + - AppSettings__USE_JAEGER_APP_SETTINGS + - JAEGER_AGENT_HOST + volumes: + - "./iengine.lic:/etc/innovatrics/iengine.lic" + + liveness: + image: ${REGISTRY}sf-liveness:${SF_VERSION} + container_name: SFLiveness + restart: unless-stopped + environment: + - RabbitMQ__Hostname + - RabbitMQ__Username + - RabbitMQ__Password + - RabbitMQ__Port + - AppSettings__Log_RollingFile_Enabled=false + - AppSettings__USE_JAEGER_APP_SETTINGS + - JAEGER_AGENT_HOST + # - Gpu__GpuEnabled=true + # - Gpu__GpuNeuralRuntime=Tensor + volumes: + - "./iengine.lic:/etc/innovatrics/iengine.lic" + # - "/var/tmp/innovatrics/tensor-rt:/var/tmp/innovatrics/tensor-rt" + #runtime: nvidia + + video-aggregator: + image: ${REGISTRY}sf-video-aggregator:${SF_VERSION} + container_name: SFVideoDataAggregator + restart: unless-stopped + environment: + - RabbitMQ__Hostname + - RabbitMQ__Username + - RabbitMQ__Password + - RabbitMQ__Port + - ConnectionStrings__CoreDbContext + - Database__DbEngine + - AppSettings__Log_RollingFile_Enabled=false + - AppSettings__USE_JAEGER_APP_SETTINGS + - JAEGER_AGENT_HOST + - S3Bucket__Endpoint + - S3Bucket__BucketName + - S3Bucket__AccessKey + - S3Bucket__SecretKey + - NoSqlDataStorageDisabled + volumes: + - "./iengine.lic:/etc/innovatrics/iengine.lic" + + video-collector: + image: ${REGISTRY}sf-video-collector:${SF_VERSION} + container_name: SFVideoDataCollector + restart: unless-stopped + environment: + - RabbitMQ__Hostname + - RabbitMQ__Username + - RabbitMQ__Password + - RabbitMQ__Port + - ConnectionStrings__CoreDbContext + - Database__DbEngine + - AppSettings__Log_RollingFile_Enabled=false + - AppSettings__USE_JAEGER_APP_SETTINGS + - JAEGER_AGENT_HOST + - S3Bucket__Endpoint + - S3Bucket__BucketName + - S3Bucket__AccessKey + - S3Bucket__SecretKey + - NoSqlDataStorageDisabled + volumes: + - "./iengine.lic:/etc/innovatrics/iengine.lic" + + video-reader: + image: ${REGISTRY}sf-video-reader:${SF_VERSION} + container_name: SFVideoReader + restart: unless-stopped + environment: + - RabbitMQ__Hostname + - RabbitMQ__Username + - RabbitMQ__Password + - RabbitMQ__Port + - AppSettings__Log_RollingFile_Enabled=false + - AppSettings__USE_JAEGER_APP_SETTINGS + - S3Bucket__Endpoint + - S3Bucket__BucketName + - S3Bucket__AccessKey + - S3Bucket__SecretKey + - JAEGER_AGENT_HOST + volumes: + - "./iengine.lic:/etc/innovatrics/iengine.lic" + + body-parts-detector: + image: ${REGISTRY}sf-body-parts-detector:${SF_VERSION} + container_name: SFBodyPartsDetectCpu + restart: unless-stopped + environment: + - RabbitMQ__Hostname + - RabbitMQ__Username + - RabbitMQ__Password + - RabbitMQ__Port + - AppSettings__Log_RollingFile_Enabled=false + - AppSettings__USE_JAEGER_APP_SETTINGS + - JAEGER_AGENT_HOST + volumes: + - "./iengine.lic:/etc/innovatrics/iengine.lic" + + edge-stream-processor: + image: ${REGISTRY}sf-edge-stream-processor:${SF_VERSION} + container_name: SFEdgeStreamProcessor + restart: unless-stopped + environment: + - RabbitMQ__Hostname + - RabbitMQ__Username + - RabbitMQ__Password + - RabbitMQ__Port + - ConnectionStrings__CoreDbContext + - Database__DbEngine + - AppSettings__Log_RollingFile_Enabled=false + - AppSettings__Log_RabbitMq_Enabled + - NoSqlDataStorageDisabled + volumes: + - "./iengine.lic:/etc/innovatrics/iengine.lic" + +networks: + default: + external: + name: HighAvailabilityClusterNetwork diff --git a/sf-docker/special/high-availability/server3/run.sh b/sf-docker/special/high-availability/server3/run.sh new file mode 100644 index 00000000..e4cdb386 --- /dev/null +++ b/sf-docker/special/high-availability/server3/run.sh @@ -0,0 +1,91 @@ +#!/bin/bash + +set -x +set -e + +if [ ! -f iengine.lic ]; then + echo "License file not found. Please make sure that the license file is present in the current directory." >&2 + exit 1 +fi + +COMPOSE_COMMAND="docker compose" + +set +e + +$COMPOSE_COMMAND version + +if [ $? -ne 0 ]; then + COMPOSE_COMMAND="docker-compose" + $COMPOSE_COMMAND version + if [ $? -ne 0 ]; then + echo "No compose command found. Please install docker compose" >&2 + exit 1 + fi +fi + +set -e +# HighAvailabilityClusterNetwork is used so that sf-dependencies and sf containers can communicate +# this can fail if the network already exists, but we don't mind that +docker network create HighAvailabilityClusterNetwork || true + +# start dependencies of SF - MsSql, RMQ and minio +$COMPOSE_COMMAND -f sf_dependencies/docker-compose.yml up -d + +# sleep to wait for the dependencies to start up +sleep 10 + +# load version and registry from .env +VERSION=$(grep -E ^SF_VERSION .env | cut -d '=' -f2 | cut -d$'\r' -f1) +REGISTRY=$(grep -E ^REGISTRY .env | cut -d '=' -f2 | cut -d$'\r' -f1) + +# we use the DB engine that will be used by SF to create and migrate the DB +# to switch DB engine, change the .env file +DB_ENGINE=$(grep -E ^Database__DbEngine .env | cut -d '=' -f2 | cut -d$'\r' -f1) + +# load RabbitMQ properties from .env +RMQ_HOST=$(grep -E ^RabbitMQ__Hostname .env | cut -d '=' -f2 | cut -d$'\r' -f1) +RMQ_USER=$(grep -E ^RabbitMQ__Username .env | cut -d '=' -f2 | cut -d$'\r' -f1) +RMQ_PASS=$(grep -E ^RabbitMQ__Password .env | cut -d '=' -f2 | cut -d$'\r' -f1) +RMQ_VHOST=$(grep -E ^RabbitMQ__VirtualHost .env | cut -d '=' -f2 | cut -d$'\r' -f1) +RMQ_PORT=$(grep -E ^RabbitMQ__Port .env | cut -d '=' -f2 | cut -d$'\r' -f1) +RMQ_SSL=$(grep -E ^RabbitMQ__UseSsl .env | cut -d '=' -f2 | cut -d$'\r' -f1) + +S3_ENDPOINT=$(grep -E ^S3Bucket__Endpoint .env | cut -d '=' -f2 | cut -d$'\r' -f1) +S3_ACCESS=$(grep -E ^S3Bucket__AccessKey .env | cut -d '=' -f2 | cut -d$'\r' -f1) +S3_SECRET=$(grep -E ^S3Bucket__SecretKey .env | cut -d '=' -f2 | cut -d$'\r' -f1) +S3_BUCKET=$(grep -E ^S3Bucket__BucketName .env | cut -d '=' -f2 | cut -d$'\r' -f1) +# set correct hostname to sfstation env file +sed -i "s/S3_ENDPOINT=.*/S3_ENDPOINT=http:\/\/$(hostname):9000/g" .env.sfstation + +echo $VERSION +echo $REGISTRY + +# create mqtt user for rmq mqtt plugin +docker exec -it rmq3 /opt/rabbitmq/sbin/rabbitmqctl add_user mqtt mqtt || true +docker exec -it rmq3 /opt/rabbitmq/sbin/rabbitmqctl set_user_tags mqtt administrator || true +docker exec -it rmq3 /opt/rabbitmq/sbin/rabbitmqctl set_permissions -p "/" mqtt ".*" ".*" ".*" || true + +docker exec -it rmq3 /opt/rabbitmq/sbin/rabbitmqctl stop_app +docker exec -it rmq3 /opt/rabbitmq/sbin/rabbitmqctl reset +docker exec -it rmq3 /opt/rabbitmq/sbin/rabbitmqctl join_cluster rabbit@rmq1 +docker exec -it rmq3 /opt/rabbitmq/sbin/rabbitmqctl start_app + +if [[ "$DB_ENGINE" == "MsSql" ]]; then + # create SmartFace database in MsSql + docker exec mssql /opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P Test1234 -Q "CREATE DATABASE SmartFace" || true + # run database migration to current version + docker run --rm --name admin_migration --network HighAvailabilityClusterNetwork ${REGISTRY}sf-admin:${VERSION} run-migration -p 5 -c "Server=mssql;Database=SmartFace;User ID=sa;Password=Test1234;" -dbe $DB_ENGINE --rmq-host ${RMQ_HOST} --rmq-user ${RMQ_USER} --rmq-pass ${RMQ_PASS} --rmq-virtual-host ${RMQ_VHOST} --rmq-port ${RMQ_PORT} --rmq-use-ssl ${RMQ_SSL} +elif [[ "$DB_ENGINE" == "PgSql" ]]; then + # create SmartFace database in PgSql + docker exec pgsql psql -U postgres -c "CREATE DATABASE smartface" || true + # run database migration to current version + docker run --rm --name admin_migration --network HighAvailabilityClusterNetwork ${REGISTRY}sf-admin:${VERSION} run-migration -p 5 -c "Server=pgsql;Database=smartface;Username=postgres;Password=Test1234;Trust Server Certificate=true;" -dbe $DB_ENGINE --rmq-host ${RMQ_HOST} --rmq-user ${RMQ_USER} --rmq-pass ${RMQ_PASS} --rmq-virtual-host ${RMQ_VHOST} --rmq-port ${RMQ_PORT} --rmq-use-ssl ${RMQ_SSL} +else + echo "Unknown DB engine: ${DB_ENGINE}!" >&2 + exit 1 +fi + +docker run --rm --name s3-bucket-create --network HighAvailabilityClusterNetwork ${REGISTRY}sf-admin:${VERSION} ensure-s3-bucket-exists --endpoint "$S3_ENDPOINT" --access-key "$S3_ACCESS" --secret-key "$S3_SECRET" --bucket-name "$S3_BUCKET" + +# finally start SF images +$COMPOSE_COMMAND up -d --force-recreate \ No newline at end of file diff --git a/sf-docker/special/high-availability/server3/sf_dependencies/.erlang.cookie b/sf-docker/special/high-availability/server3/sf_dependencies/.erlang.cookie new file mode 100644 index 00000000..bd41cba7 --- /dev/null +++ b/sf-docker/special/high-availability/server3/sf_dependencies/.erlang.cookie @@ -0,0 +1 @@ +12345 \ No newline at end of file diff --git a/sf-docker/special/high-availability/server3/sf_dependencies/docker-compose.yml b/sf-docker/special/high-availability/server3/sf_dependencies/docker-compose.yml new file mode 100644 index 00000000..e7e1f53e --- /dev/null +++ b/sf-docker/special/high-availability/server3/sf_dependencies/docker-compose.yml @@ -0,0 +1,30 @@ +version: '3' +services: + rmq3: + image: "rabbitmq:3.10.2-management" + container_name: rmq3 + expose: + - "15672" + - "5672" + - "1883" + - "4369" + - "25672" + ports: + - "15679:15672" + environment: + RABBITMQ_NODENAME: rabbit@rmq3 + RABBITMQ_CONFIG_FILE: /etc/rabbitmq/external/rabbitmq.conf + RABBITMQ_ENABLED_PLUGINS_FILE: /etc/rabbitmq/external/enabled_plugins + volumes: + - ./.erlang.cookie:/var/lib/rabbitmq/.erlang.cookie + - ./etc_rmq/:/etc/rabbitmq/external + - rmqdata:/var/lib/rabbitmq + restart: unless-stopped + +volumes: + rmqdata: + +networks: + default: + external: + name: HighAvailabilityClusterNetwork \ No newline at end of file diff --git a/sf-docker/special/high-availability/server3/sf_dependencies/etc_rmq/enabled_plugins b/sf-docker/special/high-availability/server3/sf_dependencies/etc_rmq/enabled_plugins new file mode 100644 index 00000000..288b0ae2 --- /dev/null +++ b/sf-docker/special/high-availability/server3/sf_dependencies/etc_rmq/enabled_plugins @@ -0,0 +1 @@ +[rabbitmq_management,rabbitmq_mqtt,rabbitmq_prometheus,rabbitmq_federation]. \ No newline at end of file diff --git a/sf-docker/special/high-availability/server3/sf_dependencies/etc_rmq/rabbitmq.conf b/sf-docker/special/high-availability/server3/sf_dependencies/etc_rmq/rabbitmq.conf new file mode 100644 index 00000000..020a9cc5 --- /dev/null +++ b/sf-docker/special/high-availability/server3/sf_dependencies/etc_rmq/rabbitmq.conf @@ -0,0 +1,8 @@ +## Consumer timeout +## If a message delivered to a consumer has not been acknowledge before this timer +## triggers the channel will be force closed by the broker. This ensure that +## faultly consumers that never ack will not hold on to messages indefinitely. +## 6 hours = 21600000 ms +consumer_timeout = 21600000 + +mqtt.allow_anonymous = false \ No newline at end of file