Surveillance System Wiki
Overview
This surveillance system is designed to process video feeds using a distributed Edge-to-Cloud architecture. Its primary goal is to identify and alert residents and authorities about dangerous animals detected in video footage. The system integrates edge devices (for real-time processing) and cloud servers (for intensive tasks like object recognition), ensuring quick and accurate responses.
Table of Contents
- Overview
- System Components
- Docker Compose Tutorial
-
Deploying on K3S using Enoslib on Grid'5000
- Introduction
- Step 0: Prerequisites
- Step 1: Initialize Logging
- Step 2: Cluster Resource Configuration
- Step 3: Kubernetes Setup
- Step 4: Label Nodes
- Step 5: Docker Registry Secret
- Step 6: Send Files to Cluster
- Step 7: Helm Installation and Prometheus Setup
- Step 8: Chaos Mesh Installation
- Step 9: Patch Prometheus Service
- Step 10: Fetch Webpage Hosts
- Step 11: Token Creation and Cleanup
- Conclusion
System Components
Camera
- Function: Captures video frames, resizes them for optimized processing, and serializes and transmits them to the Motion Detection service.
-
Key Features:
- Handles video sequences based on detected animal types.
- Configurable appearance frequency for specific events.
- Tracks FPS rate and integrates with TracerProvider for distributed tracing.
- Connection: Maintains a persistent TCP connection for frame transmission.
Motion Detection
- Function: Processes frames from the Camera to detect significant motion and forwards relevant frames to Object Recognition.
-
Key Features:
- Motion detection using grayscale and Gaussian blur.
- Real-time performance monitoring of CPU usage, frame processing time, and FPS.
- Integrates with TracerProvider for tracing frame reception, processing, and transmission.
- Connection: Listens for incoming frames from the Camera and sends processed frames to Object Recognition.
Object Recognizer
- Function: Uses YOLO to detect objects in frames and tracks performance metrics like processing time and response time.
-
Key Features:
- YOLO v3 for object detection.
- Distributed tracing for end-to-end monitoring.
- Supports multiple clients with concurrency.
- Connection: Listens for incoming frames from the Motion Detection service and processes them asynchronously.
Other Components
OpenTelemetry Collector
- Function: Collects, processes, and exports telemetry data (traces, metrics, logs).
-
Metrics Sent:
- Collects data from Camera, Motion Detection, Object Recognition.
- Sends telemetry data to Prometheus or other backends for visualization.
cAdvisor
- Function: Monitors container resource usage (CPU, memory, network).
-
Metrics Sent:
- CPU, memory, network I/O, disk I/O, container lifespan metrics.
Node Exporter
- Function: Exports hardware and system performance metrics from Linux systems.
-
Metrics Sent:
- CPU load, memory usage, disk utilization, network stats, and system uptime.
Prometheus
- Function: Scrapes and stores metrics from various exporters and services.
-
Metrics Collected:
- Application, service, and system-level metrics (e.g., FPS, processing time, system performance).
Services Environment Variables
-
Object Recognizer:
No environment variables are specified for this service at the moment. The type of model will be introduced in future updates. -
Motion Detector:
-
INDEX
: A unique identifier assigned to each motion detector instance (e.g.,1
,2
,3
). This helps distinguish between multiple motion detectors in the system, ensuring proper management and identification. -
OR_HOST
: The hostname of the Object Recognizer service (default:object_recognizer
). This specifies the location of the Object Recognizer service that the motion detector will send detected frames to for object identification. -
OR_PORT
: The network port on which the Object Recognizer service is listening (default:9999
). This ensures communication between the motion detector and object recognizer services through the correct port.
-
-
Camera:
-
CAMERA
: If set totrue
, it processes stored footage; otherwise, a link to live streaming sources must be provided. This determines whether the camera service reads pre-recorded footage or requires a live feed from streaming sources to work. -
ANIMAL_NAME
: The name of the animal being monitored by the camera (e.g.,tiger
,bear
,wolf
). Specifying the animal name helps evaluate the accuracy of the recognition algorithm by tracking the correct target in the footage, which is crucial for assessing detection performance. -
APPEARANCE_RATE
: The frequency at which the animal appears in the footage (in frames per minute). This provides an estimate of how often the animal is expected to appear and helps flood the Object Recognizer with many frames to test its performance under high load. -
MDHOST
: The hostname of the associated Motion Detector (e.g.,motion_detector_1
,motion_detector_2
). This links the camera to the correct motion detector service so that captured footage can be processed for motion detection. -
MDPORT
: The port on which the associated Motion Detector is listening (default:9998
). This specifies the communication port between the camera and motion detector for seamless data transfer. -
INDEX
: A unique identifier for each camera instance (e.g.,1
,2
,3
). This differentiates between multiple camera instances in the system, ensuring they can be tracked, managed, and analyzed individually.
-
Docker Compose Tutorial
Step 0: Prerequisites
-
Install Docker & Docker Compose:
Docker | Docker Compose -
Install Git:
Git Downloads -
Basic Docker Knowledge:
Review Docker Docs.
How’s that?
Step 1: Build Docker Images for Services
-
Clone the repository:
First, clone the repository to your local machine:git clone https://gitlab.inria.fr/sikaddou/surveillance-system-edge-to-cloud-video-processing.git cd surveillance-system-edge-to-cloud-video-processing
-
Build the Docker images locally:
You don't need to navigate to each service's directory individually. From the root of the cloned repository, run the following commands to build the Docker images for each service:docker build -t camera:latest ./services/camera docker build -t motion_detector:latest ./services/motion_detector docker build -t object_recognizer:latest ./services/object_recognizer
These commands will automatically find the
Dockerfile
in each service's directory (./services/camera
,./services/motion_detector
, and./services/object_recognizer
). Thelatest
tag is used to mark the most recent image. -
(Optional) Push the images to your Docker repository:
If you want to make the images available remotely, you can push them to your Docker Hub or GitHub Container Registry. Follow these steps:-
Tag the images for your repository: Replace
<your-username>
with your Docker Hub or GitHub username, and<repository>
with the desired image repository name.docker tag camera:latest <your-username>/camera:latest docker tag motion_detector:latest <your-username>/motion_detector:latest docker tag object_recognizer:latest <your-username>/object_recognizer:latest
-
Log in to your Docker registry:
docker login
Enter your credentials when prompted.
-
Push the images:
docker push <your-username>/camera:latest docker push <your-username>/motion_detector:latest docker push <your-username>/object_recognizer:latest
Once pushed, these images will be available in your registry and can be pulled by others using:
docker pull <your-username>/camera:latest docker pull <your-username>/motion_detector:latest docker pull <your-username>/object_recognizer:latest
-
docker-compose.yml
Step 2: Create or Update Services Environment Variables
-
Object Recognizer:
No environment variables are specified for this service at the moment. The type of model will be introduced in future updates. -
Motion Detector:
-
INDEX
: A unique identifier for each motion detector instance (e.g.,1
,2
,3
). -
OR_HOST
: The hostname of the Object Recognizer service (default:object_recognizer
). -
OR_PORT
: The port on which the Object Recognizer service is listening (default:9999
).
-
-
Camera:
-
CAMERA
:If set totrue
, it reads stored footage; otherwise, a link to the streaming sources must be provided. -
ANIMAL_NAME
: The name of the animal being monitored by the camera (e.g.,tiger
,bear
,wolf
). -
APPEARANCE_RATE
: The frequency at which the animal appears in the footage (in frames per minute). -
MDHOST
: The hostname of the associated Motion Detector (e.g.,motion_detector_1
,motion_detector_2
,motion_detector_3
). -
MDPORT
: The port on which the associated Motion Detector is listening (default:9998
). -
INDEX
: A unique identifier for each camera instance (e.g.,1
,2
,3
).
-
You can find a complete example configuration in the deploy/docker-compose
directory. Ensure the docker-compose.yml
file is properly set up before deployment.
Step 3: Deploy with Docker Compose
-
Navigate to the deployment directory:
cd deploy/docker-compose
-
Build and start the services:
docker-compose up -d --build --force-recreate
-
(Optional) Stop and remove existing containers and volumes:
docker-compose down --volumes --remove-orphans
Would you like additional details or further simplifications?
Step 4: Verify the Deployment
-
Check the status of running containers: You can check if the containers are running properly with the following command:
docker ps
-
Access the services:
-
Access Jaeger UI: http://localhost:16686
-
Access Zipkin UI: http://localhost:9411
-
Access Prometheus UI: http://localhost:9090
-
Access cAdvisor UI: http://localhost:8080
-
Access Object Recognizer Interface: http://localhost:5000
-
Deploying on K3S using Enoslib on Grid'5000
This tutorial will walk you through the steps required to deploy a Kubernetes cluster on K3s using Enoslib on the Grid'5000 (G5k) infrastructure. The focus is on deploying the surveillance system, which includes components such as the Camera, Motion Detection, and Object Recognizer. These steps cover cluster configuration, deployment of Kubernetes resources, Helm setup, Prometheus and Chaos Mesh installation, and additional tasks for monitoring and resilience testing of the system.
Step 0: Prerequisites
- Grid'5000 account and access to the infrastructure.
- enoslib installed on your local machine. ssh installed on your local machine.
Step 1: Initialize Logging
First, initialize the logging for the deployment process.
import enoslib as en
from datetime import datetime
# Initialize logging
_ = en.init_logging()
# Generate a timestamp for the job name
timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
job_name = f"usecase_{timestamp}"
Step 2: Cluster Resource Configuration
Define the configuration for the cluster resources on Grid'5000. This will specify the number of machines for each role (master, agent, etc.).
cluster = "parasilo"
conf = (
en.VMonG5kConf
.from_settings(job_name=job_name, walltime="04:00:00")
.add_machine(roles=["master"], cluster=cluster, number=1, flavour="large")
.add_machine(roles=["agent", "object_recognizer"], cluster=cluster, number=1, flavour_desc={"core": 8, "mem": 8192})
.add_machine(roles=["agent", "motion_detector"], cluster=cluster, number=3, flavour_desc={"core": 4, "mem": 4096})
.add_machine(roles=["agent", "camera"], cluster=cluster, number=3, flavour_desc={"core": 1, "mem": 1024})
.finalize()
)
# Initialize the provider
provider = en.VMonG5k(conf)
roles, networks = provider.init()
en.wait_for(roles)
Step 3: Kubernetes Setup
Deploy the K3s cluster and ensure that it’s set up correctly.
# Initialize K3s with master and agent nodes
k3s = en.K3s(master=roles["master"], agent=roles["agent"])
k3s.deploy()
# Create a tunnel to the head node
print("Create a tunnel from your local machine to the head node:")
print(f"ssh -NL 8001:{roles['master'][0].address}:8001 {G5K_username}@access.grid5000.fr")
Step 4: Label Nodes
Label your nodes with specific attributes based on their roles (cloud, edge, camera).
def label_nodes(node_names, labels):
label_str = ",".join(f"{key}={value}" for key, value in labels.items())
for node in node_names:
command = f"kubectl label nodes {node} {label_str} --overwrite"
try:
result = en.run_command(command, roles=roles['master'])
print(f"Successfully labeled {node} with {label_str}")
except subprocess.CalledProcessError as e:
print(f"Failed to label {node}. Error: {e.stderr.decode('utf-8')}")
# Label nodes
label_nodes([str(node.alias) for node in roles["object_recognizer"]], {"pos": "cloud"})
label_nodes([str(node.alias) for node in roles["motion_detector"]], {"pos": "edge"})
label_nodes([str(node.alias) for node in roles["camera"]], {"pos": "camera"})
Step 5: Docker Registry Secret
Create a Docker registry secret with anonymized credentials to authenticate with Docker Hub.
docker_username = "username_placeholder"
docker_password = "password_placeholder"
docker_email = "email_placeholder"
# Create the Docker registry secret
en.run_command(f"kubectl create secret docker-registry dockerhub-secret \
--docker-username={docker_username} \
--docker-password={docker_password} \
--docker-email={docker_email}", roles=roles['master'])
Step 6: Send Files to Cluster
Transfer necessary configuration files to the cluster using scp
.
import os
def send_file(file_path, file_name):
scp_command = f"scp {file_path} root@{roles['master'][0].address}:{file_name}"
os.system(f"ssh-keygen -f /home/{G5k_username} /.ssh/known_hosts -R {roles['master'][0].address}")
os.system(scp_command)
return scp_command
# Send configuration files to the cluster
local_directory = "deploy/G5k/K3S/config"
for root, dirs, files in os.walk(local_directory):
for file_name in files:
send_file(local_directory + file_name, file_name)
# Apply Kubernetes manifests
en.run_command("kubectl apply -f deployement.yaml", roles=roles['master'])
en.run_command("kubectl apply -f configmap.yaml", roles=roles['master'])
Step 7: Helm Installation and Prometheus Setup
Install Helm, add Prometheus charts, and deploy Prometheus for monitoring.
with en.actions(roles=roles["master"]) as a:
a.raw("curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3")
a.raw("chmod 700 get_helm.sh")
a.raw("./get_helm.sh")
# Install Prometheus
a.raw("helm --kubeconfig /etc/rancher/k3s/k3s.yaml repo add prometheus-community https://prometheus-community.github.io/helm-charts")
a.raw("helm --kubeconfig /etc/rancher/k3s/k3s.yaml repo update")
a.raw("helm --kubeconfig /etc/rancher/k3s/k3s.yaml install prometheus prometheus-community/prometheus -n default --set grafana.enabled=True -f costum-values.yaml")
a.raw("helm --kubeconfig /etc/rancher/k3s/k3s.yaml upgrade --kubeconfig /etc/rancher/k3s/k3s.yaml prometheus prometheus-community/prometheus --namespace default --set prometheus-node-exporter.service.port=9500")
Step 8: Chaos Mesh Installation
Install Chaos Mesh using Helm for fault injection and resilience testing.
with en.actions(roles=roles["master"]) as a:
a.raw("helm --kubeconfig /etc/rancher/k3s/k3s.yaml repo add chaos-mesh https://charts.chaos-mesh.org")
a.raw("helm --kubeconfig /etc/rancher/k3s/k3s.yaml repo update")
a.raw("helm --kubeconfig /etc/rancher/k3s/k3s.yaml install chaos-mesh chaos-mesh/chaos-mesh --set chaosDaemon.runtime=containerd --set chaosDaemon.containerdSocket=/run/containerd/containerd.sock -n default")
a.raw("kubectl apply -f rbac.yaml")
a.raw("kubectl create token account-default-admin-eechh")
a.raw('kubectl patch svc chaos-dashboard -n default -p \'{"spec": {"ports": [{"name": "http", "protocol": "TCP", "port": 2333, "targetPort": 2333, "nodePort": 30312}]}}\'')
Step 9: Patch Prometheus Service
Expose Prometheus service on a NodePort for web access.
with en.actions(roles=roles["master"]) as a:
a.raw('kubectl patch svc prometheus-server -n default -p \'{"spec": {"type": "NodePort", "ports": [{"name": "http", "port": 80, "targetPort": 9090, "nodePort": 30090}]}}\'')
Step 10: Fetch Webpage Hosts
Retrieve the host IP of Prometheus and Chaos Dashboard services.
def get_host(service):
results = en.run_command(f"kubectl get pods -n kube-system -l app={service}", roles=roles['master'])
import re
pattern = r"host='([^']*)'"
match = re.search(pattern, str(results))
if match:
host = match.group(1)
print("Extracted host:", host)
else:
print("Host not found")
return None
results = en.run_command(f"kubectl describe node {host}", roles=roles['master'])
pattern = r"InternalIP:\s*([\d.]+)"
match = re.search(pattern, str(results))
if match:
return match.group(1)
else:
print("Host not found")
return None
# Fetch the Prometheus and Chaos Dashboard IPs
url = f"http://{get_host('prometheus')}:30090"
print(f"Prometheus web page host: {url}")
url = f"http://{get_host('chaos-dashboard')}:30312"
print(f"Chaos-mesh web page host: {url}")
Step 11: Token Creation and Cleanup
Create the necessary tokens and perform cleanup after the job is complete.
results = en.run_command("kubectl create token account-default-admin-eechh", roles=roles["master"])
for res in results:
print(res.payload['stdout'])
# Cleanup the resources
provider.destroy()
Conclusion
By following the steps above, you have successfully deployed the surveillence system on Kubernetes cluster using K3s on Grid'5000, set up monitoring with Prometheus, fault injection with Chaos Mesh, and labeled nodes for efficient management.