añadido Argos Core

This commit is contained in:
2025-08-20 01:16:53 +02:00
parent 550d5fbe52
commit d973225012
17 changed files with 550 additions and 151 deletions

199
argos/readme.md Normal file
View 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 **ondemand**.
---
## 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)** + **certmanager**: TLS para el panel; HTTP01 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).
* **certmanager** + `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 HTTP01 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.