Autor: Francisco

  • Herramientas de monitoreo para homelab: vnStat, cAdvisor, Netdata y más

    Un recorrido por las herramientas de monitoreo de red y contenedores más comunes en un homelab, desde lo más simple (vnStat) hasta stacks completos de observabilidad (Prometheus + Grafana), pasando por opciones intermedias que dan buena visibilidad sin tanta configuración.

    1. vnStat: monitoreo básico de tráfico de red

    vnStat es un contador de tráfico ligero que corre como servicio en segundo plano, acumulando estadísticas de consumo por interfaz sin necesidad de capturar paquetes activamente — esto lo hace muy liviano en recursos comparado con herramientas de captura en tiempo real.

    Verificar que esté funcionando

    sudo systemctl status vnstat
    sudo systemctl start vnstat
    sudo systemctl enable vnstat

    Consultar tráfico

    vnstat              # resumen general
    vnstat -h            # por horas
    vnstat -d            # por días
    vnstat -w            # por semanas
    vnstat -m            # por meses
    vnstat -l            # en tiempo real (modo "live")
    vnstat -i ens6       # interfaz específica
    vnstat -i ens6 -hg   # gráfico horario en texto
    vnstat --iflist      # listar interfaces monitoreadas

    Interpretando las interfaces detectadas

    En un host con Docker, vnstat --iflist típicamente muestra algo como:

    ens6
    docker0
    veth55b218c
    vetha4d99c4
    vethcb08ffb
    InterfazDescripción
    ens6Interfaz de red física principal del servidor
    docker0Bridge virtual principal que usa Docker por defecto
    vethXXXXInterfaces virtuales, una por cada contenedor conectado al bridge

    2. Docker: comandos básicos de inspección

    # Contenedores activos
    docker ps
    
    # Solo IDs
    docker ps -q
    
    # Detalle completo de un contenedor
    docker inspect <container_id>
    
    # Nombre y MAC address de todos los contenedores activos
    docker ps -q | xargs -n1 docker inspect --format '{{.Id}} - {{.Name}} - {{range .NetworkSettings.Networks}}{{.MacAddress}}{{end}}'
    # Ver todas las interfaces de red del sistema
    ip link show
    ip -o link show   # formato de una línea por interfaz, más fácil de leer en scripts

    3. Monitoreo por proceso o por conexión

    nethogs — tráfico por proceso

    Muestra qué proceso específico está generando el tráfico de red, en tiempo real — útil para identificar qué aplicación está consumiendo ancho de banda cuando no está claro a simple vista:

    sudo apt install nethogs
    sudo nethogs ens6

    iftop — tráfico por conexión

    En vez de agrupar por proceso, muestra el tráfico desglosado por cada conexión activa (IP origen/destino), ordenado por consumo — más útil para identificar con qué host específico se está intercambiando más datos:

    sudo apt install iftop
    sudo iftop -i ens6

    4. La limitación real de Docker: sin historial por contenedor

    Un punto importante a entender: Docker no mantiene estadísticas históricas por contenedor de forma nativa. Las interfaces vethXXXXXX son temporales — se crean y destruyen dinámicamente con cada contenedor, cambian de nombre al reiniciarlo, y por diseño no suelen quedar registradas de forma persistente en herramientas como vnStat. Esto significa que, si se necesita saber «cuánto tráfico consumió tal contenedor la semana pasada», vnStat por sí solo no puede responder esa pregunta — para eso hacen falta herramientas específicas de monitoreo de contenedores.

    docker stats: métricas en tiempo real, sin historial

    docker stats

    Muestra CPU, RAM, tráfico de red (Network I/O) y disco por contenedor, pero solo mientras el comando está corriendo — no guarda ningún historial una vez que se cierra la terminal.

    5. cAdvisor: métricas Docker con algo de historial

    cAdvisor (Container Advisor, de Google) sí guarda un historial reciente de métricas por contenedor y las expone en una interfaz web propia, sin necesidad de configurar nada adicional:

    docker run \
      --detach \
      --volume=/:/rootfs:ro \
      --volume=/var/run:/var/run:ro \
      --volume=/sys:/sys:ro \
      --volume=/var/lib/docker/:/var/lib/docker:ro \
      --volume=/dev/disk/:/dev/disk:ro \
      --publish=8080:8080 \
      --name=cadvisor \
      gcr.io/cadvisor/cadvisor:latest

    Acceso vía navegador en http://IP_SERVIDOR:8080. Los volúmenes montados en modo solo lectura (:ro) le dan a cAdvisor visibilidad sobre el sistema de archivos raíz, los procesos, cgroups y discos del host — necesarios para poder atribuir el consumo de recursos a cada contenedor individualmente.

    6. Netdata: monitoreo integral con la instalación más simple

    bash <(curl -Ss https://my-netdata.io/kickstart.sh)

    Acceso en http://IP_SERVIDOR:19999. Netdata destaca por dar visibilidad amplia (CPU, RAM, disco, red, Docker, procesos, servicios, ZFS, temperaturas) con una sola instalación y configuración mínima — es la opción con mejor relación esfuerzo/beneficio para un homelab que no necesita retención de datos a muy largo plazo ni dashboards altamente personalizados.

    Centralizar varios servidores con Netdata Cloud

    sudo netdata-claim.sh \
      -token <TOKEN> \
      -rooms <ROOM_ID> \
      -url https://app.netdata.cloud

    Permite ver el estado de múltiples nodos Netdata desde un único panel centralizado en la nube, sin tener que abrir cada instancia por separado.

    7. Alternativa «enterprise»: Prometheus + Grafana

    Cuando se necesita retención de métricas a largo plazo, dashboards altamente personalizables, y alertas configurables con reglas propias, el stack recomendado combina varias piezas especializadas:

    ComponenteFunción
    PrometheusBase de datos de series temporales que almacena las métricas
    Node ExporterExpone métricas del sistema operativo host para que Prometheus las recolecte
    cAdvisorExpone métricas específicas de contenedores Docker
    GrafanaCapa de visualización, dashboards y alertas sobre los datos de Prometheus

    La diferencia clave frente a Netdata: este stack separa la recolección (exporters), el almacenamiento (Prometheus) y la visualización (Grafana) en piezas independientes — más trabajo de configuración inicial, pero mucho más flexible y con retención de datos configurable a voluntad (semanas, meses), en vez de la ventana más corta que suele manejar Netdata por defecto.

    8. Opción ligera adicional: Glances

    pip install glances[all]
    glances -w

    Acceso en http://IP_SERVIDOR:61208. Glances es una alternativa liviana en Python, útil como panel rápido de estado general del sistema sin necesitar instalar un stack completo.

    Recomendación para un homelab típico

    Para una infraestructura con Proxmox como hipervisor, corriendo Docker y varios contenedores/servicios en un único nodo físico, la mejor relación esfuerzo/beneficio suele ser progresiva:

    1. Netdata — cubre aproximadamente el 80% de lo que normalmente se necesita para administrar un homelab completo, con la instalación más simple de todas.
    2. cAdvisor — se agrega cuando se necesita métricas Docker más detalladas y con algo más de historial que docker stats.
    3. Grafana + Prometheus — se justifica cuando se necesita histórico avanzado, dashboards personalizados a medida, y alertas con reglas propias — el paso natural cuando un homelab crece más allá de unos pocos servicios.
  • Automatizando la conversión de una biblioteca musical con Bash y ffmpeg

    Para aquellos melómanos / audiófilos que tienen amplias colecciones por clasificar y/o reducir una biblioteca musical completa de 320kbps o cualquier tasa de bits a 128kbps para ahorrar espacio en disco, sobretodo este año donde el precio del almacenamiento está en los cielos, tareas de limpiar los nombres de archivo, y hacerlo sobre un share de red (SMB), procesando cientos de álbumes automáticamente sin intervención manual álbum por álbum. Este es el proceso completo, incluyendo los problemas reales que fueron apareciendo y cómo se resolvieron.

    Objetivo

    Convertir MP3 en 320kbps a 128kbps, eliminando además el prefijo numérico típico de pista en el nombre de archivo (01. Artista - Canción.mp3 → Artista - Canción.mp3).

    Comando base con ffmpeg

    for f in *.mp3; do
      ffmpeg -i "$f" -codec:a libmp3lame -b:a 128k "converted/$f"
    done

    -codec:a libmp3lame especifica el códec de audio (el encoder MP3 estándar en ffmpeg), y -b:a 128k fija el bitrate de audio objetivo. El resultado se guarda en una subcarpeta converted/ para no sobrescribir los originales durante las pruebas.

    Eliminando el prefijo numérico con regex

    for f in *.mp3; do
      if [[ "$f" =~ ^[0-9]+\.[[:space:]]*(.+)$ ]]; then
        newname="${BASH_REMATCH[1]}"
      else
        newname="$f"
      fi
      ffmpeg -i "$f" -codec:a libmp3lame -b:a 128k "converted/$newname"
    done

    El regex ^[0-9]+\.[[:space:]]*(.+)$ se lee así: uno o más dígitos al inicio (^[0-9]+), seguido de un punto literal (\.), seguido de cero o más espacios ([[:space:]]*), y captura todo el resto del nombre en un grupo ((.+)$). Funciona igual para prefijos de una, dos o tres cifras — 1., 01., 078. — sin necesitar reglas distintas para cada longitud. ${BASH_REMATCH[1]} es la variable de Bash que guarda el contenido del primer grupo capturado por el regex.

    Dry run: verificar antes de convertir

    Antes de correr la conversión real (que toma tiempo y no es instantánea de revertir), conviene simular el renombrado con un echo para confirmar visualmente que el patrón detecta los nombres correctamente:

    for f in *.mp3; do
      if [[ "$f" =~ ^[0-9]+\.[[:space:]]*(.+)$ ]]; then
        echo "'$f' -> '${BASH_REMATCH[1]}'"
      fi
    done

    Script final: procesar toda la biblioteca de forma recursiva

    Con el patrón ya validado, el script completo recorre todas las subcarpetas del directorio base, maneja álbumes con un nivel extra de subdirectorio (algunos venían con una carpeta duplicada dentro), y evita reprocesar carpetas ya convertidas:

    #!/bin/bash
    BASE="/mnt/hd1/biblio/musica_por_clasificar"
    
    for dir in "$BASE"/*/; do
      dir="${dir%/}"  # quitar slash final
      dirname=$(basename "$dir")
    
      # Carpetas ya procesadas o a saltar
      [[ "$dirname" == "converted" ]] && continue
      [[ "$dirname" == *"Nombre carpeta ya procesada 1"* ]] && continue
      [[ "$dirname" == *"Nombre carpeta ya procesada 2"* ]] && continue
    
      echo "=== Procesando: $dirname ==="
      mkdir -p "$dir/converted"
    
      for f in "$dir"/*.mp3 "$dir"/*/*.mp3; do
        [[ -f "$f" ]] || continue
    
        # Saltar archivos que ya estén dentro de converted/
        [[ "$f" == */converted/* ]] && continue
    
        fname=$(basename "$f")
        if [[ "$fname" =~ ^[0-9]+\.[[:space:]]*(.+)$ ]]; then
          newname="${BASH_REMATCH[1]}"
        else
          newname="$fname"
        fi
        echo "  -> $newname"
        ffmpeg -i "$f" -codec:a libmp3lame -b:a 128k "$dir/converted/$newname" -y -loglevel error
      done
    done
    
    echo "=== LISTO ==="

    Problemas encontrados y sus soluciones

    ProblemaCausaSolución
    El script no hacía nadaMount de gvfs lento o colgadoMontar el share con mount.cifs en vez de gvfs
    «Permiso denegado» al crear converted/Mount CIFS sin permisos de escrituraRemontar especificando uid, gid, dir_mode
    Doble slash //converted/$dir del glob */ ya termina en /dir="${dir%/}" para quitar el slash final antes de concatenar
    ffmpeg reportaba «same as Input #0»El glob */*.mp3 volvía a capturar archivos ya dentro de converted/Agregar la condición [[ "$f" == */converted/* ]] && continue
    Archivo corrupto («No stream»)Un MP3 inválido dentro de la colecciónffmpeg reporta el error y continúa — no bloquea el resto del loop
    Algunos álbumes quedaban sin convertirLos MP3 estaban dentro de una subcarpeta extra anidadaAgregar el glob adicional "$dir"/*/*.mp3 al loop

    Montar un share SMB correctamente para scripting

    Un detalle clave que causó varios de los problemas anteriores: gvfs (el montaje automático que hacen los gestores de archivos gráficos, visible en rutas como /run/user/1000/gvfs/smb-share:...) es inestable para scripts en lote — se cuelga o responde lento bajo cargas de I/O sostenidas. La alternativa confiable es montar el share manualmente con mount.cifs:

    # Crear el punto de montaje
    sudo mkdir -p /mnt/hd1
    
    # Montar con usuario y contraseña
    sudo mount -t cifs //192.168.100.50/hd1 /mnt/hd1 \
      -o username=TU_USUARIO,password=TU_PASSWORD,uid=1000,gid=1000,file_mode=0755,dir_mode=0755
    
    # Montar sin contraseña (share abierto/guest)
    sudo mount -t cifs //192.168.100.50/hd1 /mnt/hd1 \
      -o guest,uid=1000,gid=1000,file_mode=0755,dir_mode=0755
    
    # Verificar que el montaje permite escritura
    touch /mnt/hd1/test.txt && echo "OK escritura" && rm /mnt/hd1/test.txt

    Los parámetros uid y gid son importantes: sin ellos, los archivos montados vía CIFS suelen aparecer con el propietario root por defecto, lo que puede bloquear la escritura para un usuario normal — especificarlos fuerza a que el montaje asigne la propiedad al usuario local correcto.

    Notas técnicas adicionales

    • El regex ^[0-9]+\.[[:space:]]*(.+)$ funciona igual para prefijos de cualquier longitud: 1., 01., 078., etc.
    • -loglevel error en ffmpeg suprime toda la salida de metadata habitual, mostrando solo errores reales — indispensable al procesar miles de archivos, para no inundar la terminal.
    • -y sobrescribe el archivo destino sin preguntar si ya existe, necesario para que el loop corra sin intervención manual.
    • Convertir un MP3 de 128kbps a FLAC o de vuelta a 320kbps no mejora la calidad — la información descartada durante la compresión con pérdida original no se puede recuperar. Reconvertir un archivo ya comprimido a un bitrate mayor solo aumenta el tamaño del archivo, no la calidad de audio real.