# 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=`; 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 () kubectl -n argos-core get endpoints -o wide # Revisa selector del Service y labels del Pod # Logs kubectl -n argos-core logs -f deploy/ # Reinicios controlados kubectl -n argos-core rollout restart deploy/ # 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 `**: 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.