añadido Argos Core
This commit is contained in:
199
argos/readme.md
Normal file
199
argos/readme.md
Normal file
@@ -0,0 +1,199 @@
|
||||
# Argos Core
|
||||
|
||||
**Argos Core** es el backend central de una plataforma de videovigilancia distribuida. Está diseñado para recibir eventos desde **edges** (sitios remotos con Frigate), capturar/ingestar vídeo bajo demanda, almacenarlo de forma fiable y ofrecer un **panel web** seguro para consulta y reproducción, todo **encapsulado en Kubernetes** y oculto tras una **VPN WireGuard**.
|
||||
|
||||
---
|
||||
|
||||
## Visión general
|
||||
|
||||
```text
|
||||
[Edge / Frigate] --(VPN/WG + MQTT eventos)--> [Argos Core]
|
||||
├─ Mosquitto (MQTT)
|
||||
├─ Orchestrator (ingesta clips)
|
||||
│ ├─ Pull clip nativo de Frigate
|
||||
│ └─ Fallback: captura RTSP temporal
|
||||
├─ MediaMTX (live/retransmisión)
|
||||
├─ MinIO (S3, almacenamiento)
|
||||
└─ Panel (FastAPI + Uvicorn)
|
||||
```
|
||||
|
||||
**Objetivo clave:** los edges **no** envían flujo constante; sólo cuando hay evento. El core ingesta y guarda el clip, y ofrece visualización **on‑demand**.
|
||||
|
||||
---
|
||||
|
||||
## Componentes
|
||||
|
||||
* **WireGuard (wg-easy)**: servidor VPN del clúster. Todo el tráfico de edges → core circula por WG.
|
||||
* **Mosquitto** (`eclipse-mosquitto:2`): broker MQTT interno (ClusterIP). Topic de eventos (p. ej. `frigate/events`).
|
||||
* **Orchestrator** (Python):
|
||||
|
||||
* Se suscribe a MQTT.
|
||||
* Tras un evento, intenta **descargar el clip nativo** desde la API del Frigate del edge.
|
||||
* Si no existe, hace **captura RTSP** temporal con `ffmpeg` (duración configurada) contra la cámara/edge.
|
||||
* Sube el resultado a **MinIO** (`s3://argos/...`) y registra metadatos en SQLite embebido.
|
||||
* **MinIO** (S3 compatible): almacenamiento de clips y miniaturas.
|
||||
* **MediaMTX**: redistribución de flujos (RTSP/WHIP/SRT) y posible live view on-demand.
|
||||
* **Panel** (FastAPI/Uvicorn):
|
||||
|
||||
* Lista eventos desde MinIO (sin exponer MinIO: **proxy** de objetos).
|
||||
* Página de reproducción (`/view?key=…`).
|
||||
* Endpoints simples (`/file`, `/api/events`, `/health`).
|
||||
* **CoreDNS**: DNS interno con split-horizon (resolución diferente desde LAN/VPN/cluster cuando aplica).
|
||||
* **Ingress NGINX (interno/externo)** + **cert‑manager**: TLS para el panel; HTTP‑01 servido por el controlador externo.
|
||||
* **MetalLB**: IPs para servicios tipo LoadBalancer en la red `192.168.200.0/24` (p. ej. MediaMTX).
|
||||
|
||||
---
|
||||
|
||||
## Flujo de datos (evento → clip)
|
||||
|
||||
1. **Edge** detecta (Frigate) y publica en **MQTT** `frigate/events`.
|
||||
2. **Orchestrator** recibe el evento, localiza la cámara/edge en su `settings.yaml`.
|
||||
3. Intenta **pull** del **clip nativo** vía API Frigate del edge (VPN).
|
||||
4. Si no hay clip, ejecuta **`ffmpeg`** para capturar **RTSP** temporal (fallback).
|
||||
5. Sube el fichero a **MinIO** con una clave tipo: `camX/YYYY/MM/DD/TS_eventId.mp4` y optional thumb.
|
||||
6. **Panel** lo muestra en la lista y permite reproducir vía `/file?key=…` (stream proxy desde MinIO).
|
||||
|
||||
> Para **live**, MediaMTX publica `/` con `path=<cam>`; puedes incrustar un reproductor WebRTC/RTSP en el panel.
|
||||
|
||||
---
|
||||
|
||||
## Despliegue
|
||||
|
||||
### Requisitos previos
|
||||
|
||||
* Kubernetes operativo con:
|
||||
|
||||
* **MetalLB** (rango `192.168.200.0/24`).
|
||||
* **NGINX Ingress** *interno* y *externo* (split-horizon DNS).
|
||||
* **cert‑manager** + `ClusterIssuer` (p. ej. `letsencrypt-prod`).
|
||||
* **wg-easy** funcionando (con NAT/iptables para alcanzar `200.x`, `0.x`, etc.).
|
||||
|
||||
### Estructura
|
||||
|
||||
```
|
||||
argos/
|
||||
├─ configmaps/ # mediamtx, mosquitto, orchestrator, panel
|
||||
├─ deployments/ # mediamtx, minio, mosquitto, orchestrator, panel
|
||||
├─ ingress/ # minio (opcional), panel (TLS)
|
||||
├─ policies/ # network-policy, allow-same-namespace
|
||||
├─ pvc/ # pvc-minio
|
||||
├─ secrets/ # minio, orchestrator, panel
|
||||
└─ services/ # mediamtx tcp/udp, minio, mosquitto, panel
|
||||
```
|
||||
|
||||
### Variables/Secrets esperados
|
||||
|
||||
* **MinIO** (`secrets/secret-minio.yaml`): `MINIO_ACCESS_KEY`, `MINIO_SECRET_KEY`.
|
||||
* **Orchestrator** (`secrets/secret-orchestrator.yaml`): `MINIO_ENDPOINT`, `MINIO_ACCESS_KEY`, `MINIO_SECRET_KEY`, `MINIO_SECURE`.
|
||||
* **Panel** (`secrets/secret-panel.yaml`): `MINIO_*` y `MINIO_BUCKET`.
|
||||
|
||||
### Servicios y puertos
|
||||
|
||||
* **MinIO**: `ClusterIP` :9000 (API), :9001 (console, opcional). No expuesto fuera.
|
||||
* **Mosquitto**: `ClusterIP` :1883.
|
||||
* **MediaMTX**: `LoadBalancer` (MetalLB) en `192.168.200.16` (RTSP 8554 TCP, WHIP 8889 TCP/HTTP 8880, SRT 8189 UDP).
|
||||
* **Panel**: `ClusterIP` :8000 → Ingress (TLS) `https://argos.panel.c2et.net/` (ajusta FQDN).
|
||||
|
||||
### Kustomize
|
||||
|
||||
```bash
|
||||
kubectl apply -k .
|
||||
```
|
||||
|
||||
> Nota: evitamos `commonLabels` globales para no romper los **selectors**.
|
||||
|
||||
---
|
||||
|
||||
## Configuración relevante
|
||||
|
||||
### Orchestrator (`configmaps/configmap-orchestrator.yaml`)
|
||||
|
||||
* `mqtt.host`: `mosquitto.argos-core.svc.cluster.local`
|
||||
* `mqtt.port`: `1883`
|
||||
* `mqtt.topic`: `frigate/events`
|
||||
* `minio.endpoint`: `minio.argos-core.svc.cluster.local:9000`
|
||||
* `edges`: lista de edges y cámaras (URLs de Frigate, RTSP principal, etc.).
|
||||
|
||||
### Mosquitto (`configmaps/configmap-mosquitto.yaml`)
|
||||
|
||||
* Config mínimo:
|
||||
|
||||
```
|
||||
persistence true
|
||||
persistence_location /mosquitto/data/
|
||||
listener 1883 0.0.0.0
|
||||
allow_anonymous true # RECOMENDACIÓN: pasar a autenticación/TLS más adelante
|
||||
```
|
||||
|
||||
### MediaMTX
|
||||
|
||||
* Ejecutar **sin** `/bin/sh -c …` y pasando **solo** la ruta del YAML como `args`.
|
||||
* Corrige warnings como `sourceOnDemand` según el modo (`publisher` o `record`).
|
||||
|
||||
### MinIO (seguridad/permisos)
|
||||
|
||||
* Ejecuta como **no-root** con `runAsUser: 1000` y un **initContainer** que hace `chown/chmod/ACL` del PVC.
|
||||
* Estrategia de despliegue **Recreate** para evitar doble pod en updates cuando la `readinessProbe` tarda.
|
||||
|
||||
### Ingress + cert-manager
|
||||
|
||||
* El **Certificate** del panel debe forzar el solver HTTP‑01 por el **ingress externo**:
|
||||
|
||||
* Anotación: `acme.cert-manager.io/http01-ingress-class: nginx-external` (o ajusta en `ClusterIssuer`).
|
||||
|
||||
---
|
||||
|
||||
## Operación
|
||||
|
||||
### Comandos útiles
|
||||
|
||||
```bash
|
||||
# Estado general
|
||||
kubectl -n argos-core get pods,svc,ingress,endpoints
|
||||
|
||||
# Endpoints vacíos (<none>)
|
||||
kubectl -n argos-core get endpoints <svc> -o wide
|
||||
# Revisa selector del Service y labels del Pod
|
||||
|
||||
# Logs
|
||||
kubectl -n argos-core logs -f deploy/<nombre>
|
||||
|
||||
# Reinicios controlados
|
||||
kubectl -n argos-core rollout restart deploy/<nombre>
|
||||
|
||||
# Diff del Service en vivo vs manifiesto
|
||||
kubectl -n argos-core get svc argos-panel -o yaml --show-managed-fields=false
|
||||
```
|
||||
|
||||
### Problemas típicos y fixes
|
||||
|
||||
* **Service con `ENDPOINTS <none>`**: selector ≠ labels, o pod **not Ready** (probe fallando). Ajusta selector a `{app: …}` y corrige readiness.
|
||||
* **Dos pods tras update**: rolling update atascado. Usa `strategy: Recreate` mientras estabilizas.
|
||||
* **MinIO `file access denied`**: permisos del PVC. Añade `initContainer` que hace `chown -R 1000:1000 /data` + ACL.
|
||||
* **Mosquitto `Connection refused`** desde Orchestrator: Service sin endpoints o broker no escucha en 1883. Ver logs `mosquitto` y `ss -lnt`.
|
||||
* **Panel `ASGI app not found`**: `uvicorn app:app --app-dir /app` y asegúrate de montar `app.py` con `app = FastAPI()`.
|
||||
* **MediaMTX `unknown flag -c`**: no usar `/bin/sh -c …`; pasar `args: ["/config/mediamtx.yml"]`.
|
||||
|
||||
---
|
||||
|
||||
## Edge (resumen de mañana)
|
||||
|
||||
* **WireGuard** cliente (IP del edge en la VPN; DNS apuntando al core).
|
||||
* **Frigate** en Docker + `mqtt.host=mosquitto.argos-core.svc.cluster.local`.
|
||||
* API de Frigate accesible desde el core por la VPN (p. ej. `http://10.20.0.10:5000`).
|
||||
* Opcional: MediaMTX local si se quiere “empujar” live al core durante la alarma.
|
||||
|
||||
---
|
||||
|
||||
## Seguridad y siguientes pasos
|
||||
|
||||
* Endurecer Mosquitto (usuarios/TLS), MinIO (políticas/buckets versionados), y el Panel (auth detrás de Ingress o login propio).
|
||||
* Métricas y dashboards (Prometheus/Grafana), y mover metadatos a **PostgreSQL** para búsquedas ricas.
|
||||
* Live WebRTC integrado en el panel (MediaMTX WHIP/WHEP).
|
||||
|
||||
---
|
||||
|
||||
## Licencia / Créditos
|
||||
|
||||
* **MediaMTX** (Bluenviron), **MinIO**, **Eclipse Mosquitto**, **Frigate** (en los edges).
|
||||
* Argos Core: composición y orquestación Kubernetes + servicios auxiliares.
|
||||
Reference in New Issue
Block a user