Files
kubernetes/argos/readme.md
2025-08-20 01:16:53 +02:00

200 lines
8.0 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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.