Cambiar tema

Gestión de logs de Docker en la práctica: del driver a la recolección centralizada

Easton editorial illustration: 容器日志源, DRIVER 选择器, ROTATE 线轴, COLLECT 归档库

El móvil vibró. Alerta de disco en el servidor de producción, umbral al 85%.

Me levanté, abrí el portátil y entré por SSH. df -h: en la partición raíz solo quedaba un 12% libre. Tras revisar todo, el culpable estaba en /var/lib/docker/containers: un contenedor Nginx que llevaba dos semanas en marcha y cuyo archivo de log ya pesaba 12 GB.

Docker no limita el tamaño de los logs por defecto, y mucha gente no lo sabe. Ese contenedor generaba decenas de miles de líneas de acceso al día; el driver json-file las registraba todas fielmente, y en dos semanas el disco quedó lleno.

Borré ese archivo de log y añadí rotación a todos los contenedores. La cosa se alargó hasta las cuatro de la madrugada.

Después dediqué una semana a ordenar la gestión de logs de Docker: elección de driver, parámetros de rotación y recolección centralizada en entornos con muchos contenedores. Este artículo resume lo que aprendí en ese incidente.

1. Panorama de los drivers de logs de Docker

Primero, un concepto básico: los logs del contenedor no se escriben al azar; un «driver de logs» decide adónde van y cómo se almacenan.

Docker soporta varios drivers, cada uno con su escenario. Por defecto usa json-file: guarda stdout y stderr en un archivo local en JSON, en /var/lib/docker/containers/<ID-contenedor>/<ID-contenedor>-json.log.

json-file es simple: sin configuración extra, formato uniforme y lectura directa con docker logs. El problema: sin límite de tamaño por defecto. Un contenedor que corre mucho tiempo acumula logs hasta reventar el disco.

Esta tabla resume seis drivers habituales:

DriverEscenarioSoporte estructuradoServicio externoImpacto en rendimiento
json-fileDesarrollo, despliegue en un solo hostSí (JSON automático)NoBajo
syslogInfra syslog empresarial existenteNo (requiere parseo)Sí (rsyslog)Bajo
journaldEntorno systemdParcialNoBajo
fluentdObservabilidad cloud-native, recolección centralizadaSí (tag personalizado)Sí (servicio Fluentd)Medio
gelfUsuarios de GraylogSí (Graylog)Medio
noneDesactivar logs, contenedores temporalesNoNoNinguno

json-file y syslog son los más comunes. json-file para depuración local y despliegues ligeros; syslog cuando ya tienes rsyslog o syslog-ng y quieres enviar logs a un sistema central.

journald delega en systemd journal. En servidores gestionados con systemd (casi cualquier Linux moderno), puedes consultar con journalctl.

fluentd y gelf apuntan a recolección centralizada. fluentd puede enviar a Elasticsearch, Kafka, almacenamiento en la nube, etc.; gelf es el formato de Graylog. Requieren un servicio de recolección aparte, útil en clústeres con muchos contenedores.

none desactiva los logs por completo. Para tareas batch o contenedores efímeros donde el log no importa, ahorra recursos.

¿Cómo elegir?

Despliegue en un solo host o desarrollo: json-file con rotación (siguiente sección). Empresa con syslog: syslog, reutilizando la infra. Clúster con logs centralizados: fluentd o Loki (más abajo). Contenedor temporal sin logs útiles: none.

2. Rotación de logs en la práctica

Volvamos al problema inicial: un log de 12 GB. ¿Cómo evitarlo? Parámetros de rotación.

json-file admite tres parámetros clave:

  • max-size: tamaño máximo de un archivo. Al superarlo, Docker crea uno nuevo y renombra los anteriores. Ej.: max-size=10m → 10 MB por archivo.
  • max-file: cuántos archivos históricos conservar. Al superar el límite, se borra el más antiguo. Ej.: max-file=3 → hasta 3 históricos + el actual.
  • compress: comprimir archivos rotados. Por defecto false; true ahorra disco con un poco más de CPU.

La combinación controla el espacio en disco. Con max-size=10m, max-file=3, el máximo ronda 30 MB (menos si comprimes).

Configuración: global vs por contenedor

Puedes definir la rotación en tres niveles:

1. Configuración global (daemon.json)

Para todos los contenedores, de una vez. En /etc/docker/daemon.json:

{
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "10m",
    "max-file": "3",
    "compress": "true"
  }
}

Reinicia el daemon: sudo systemctl restart docker. Los contenedores nuevos heredan la config.

Nota: solo afecta a contenedores creados después. Los existentes hay que tratarlos aparte o recrearlos.

2. Por contenedor (docker run)

Para parámetros específicos:

docker run -d \
  --name nginx \
  --log-driver json-file \
  --log-opt max-size=50m \
  --log-opt max-file=5 \
  --log-opt compress=true \
  nginx:alpine

En aplicaciones de mucho tráfico puedes ampliar, p. ej. max-size=50m, max-file=10.

3. Docker Compose

Lo más habitual en producción:

version: "3.9"
services:
  webapp:
    image: webapp:latest
    logging:
      driver: "json-file"
      options:
        max-size: "10m"
        max-file: "3"
        compress: "true"

  nginx:
    image: nginx:alpine
    logging:
      driver: "json-file"
      options:
        max-size: "50m"
        max-file: "5"

Cada servicio puede tener su propia config.

Valores recomendados en producción

La guía práctica de SigNoz (2024) sugiere:

  • Desarrollo/pruebas: max-size=10m, max-file=3, suficiente.
  • Tráfico medio: max-size=50m, max-file=5, más historial para diagnóstico.
  • Alto tráfico: max-size=100m, max-file=10, para no perder historial por rotación demasiado agresiva.

Los números exactos dependen de tu caso. El principio: equilibrar capacidad de disco e importancia de los logs. Disco holgado y logs críticos → retén más; disco justo y logs secundarios → aprieta.

3. Comparación de recolección centralizada

La rotación en un solo host basta a veces. Con decenas de contenedores repartidos en varias máquinas, investigar implica entrar en cada servidor y ejecutar docker logs uno a uno.

La recolección centralizada agrupa todo en un solo sitio: almacenamiento y consulta unificados.

Hay tres enfoques principales:

Stack ELK (Elasticsearch + Logstash + Kibana)

ELK lleva años siendo referencia. Logstash ingiere, Elasticsearch indexa y almacena, Kibana visualiza y consulta.

Ventajas: búsqueda full-text, consultas complejas, gráficos, ecosistema maduro. Inconvenientes: mucho consumo. Elasticsearch suele usar varios GB de RAM; Logstash también pesa y su configuración tiene curva de aprendizaje.

Encaja en grandes empresas con equipo de operaciones, mucho volumen y necesidad de consultas avanzadas.

EFK (Fluentd en lugar de Logstash)

Variante de ELK con Fluentd. Más ligero (cientos de MB de RAM), muchos plugins, varias fuentes y destinos.

Más limpio que Logstash en configuración, pero Elasticsearch sigue siendo pesado. Consumo global aún alto; equipos medianos-grandes.

Loki + Promtail + Grafana

Loki (Grafana Labs) no indexa el texto completo: indexa etiquetas (nombre de contenedor, aplicación, etc.) y guarda el contenido comprimido. Las consultas usan patrones tipo grep, con rendimiento suficiente en la práctica.

Resultado: pocos cientos de MB de RAM y almacenamiento más barato que Elasticsearch. Promtail es el agente de recolección; Grafana es la interfaz, integrada con Loki.

Muy adecuado para cloud-native y Kubernetes. Equipos pequeños con presupuesto ajustado: buena relación coste/beneficio.

Tabla comparativa

SoluciónVentajasDesventajasEscalaCoste
ELKPotente, consultas flexibles, ecosistema maduroAlto consumo, config compleja, almacenamiento caroGran empresaAlto
EFKFluentd ligero, muchos pluginsElasticsearch sigue pesadoMediana-grandeMedio-alto
LokiMuy ligero, bajo coste, cloud-nativeConsultas más limitadas, no ideal para full-textPequeña/K8sBajo

¿Cómo decidir?

  • Equipo pequeño (< 10 personas), presupuesto limitado: Loki. Despliegue simple, pocos recursos, Grafana amigable.
  • Equipo mediano (10-50), algo de operaciones: Loki o EFK según volumen.
  • Gran empresa con operaciones dedicadas: ELK. Funcionalidad y ecosistema justifican la inversión.

Si ya monitorizas con Grafana, Loki encaja de forma natural: métricas y logs en la misma interfaz.

4. Errores comunes en producción

Para cerrar, varios fallos que yo cometí y conviene evitar.

1. Olvidar la rotación y llenar el disco

El más frecuente. Se despliega sin pensar en logs; meses después, alerta de disco y archivos de decenas de GB.

Recomendación: valores por defecto en daemon.json para contenedores nuevos. No confíes en acordarte de --log-opt en cada docker run: la gente olvida; la config no.

2. Perder logs al reiniciar contenedores

Con json-file, al eliminar el contenedor se borran los logs. Si reinicias con docker rm + docker run en lugar de docker restart, pierdes el historial.

Problema al investigar un crash de madrugada: el contenedor ya se recreó y los logs anteriores desaparecieron.

Recomendación:

  • Usa docker restart cuando baste con reiniciar el proceso.
  • Para apps críticas, envía logs con fluentd o syslog a almacenamiento externo.
  • Haz backup periódico de logs importantes en producción.

3. Dirección de Fluentd incorrecta

Con el driver fluentd, los logs van por TCP a Fluentd. Si la dirección falla, el contenedor arranca igual pero no se recogen logs: crees que están centralizados y se pierden en el camino.

Ejemplo:

docker run -d \
  --log-driver fluentd \
  --log-opt fluentd-address=127.0.0.1:24224 \
  --log-opt tag="docker.&#123;&#123;.Name&#125;&#125;" \
  my-web-app

fluentd-address debe coincidir con donde escucha Fluentd. Puerto por defecto 24224, TCP.

Diagnóstico:

  • Comprueba que Fluentd corre: curl http://localhost:24224 o netstat -tlnp | grep 24224.
  • docker inspect &lt;ID-contenedor&gt; para ver el driver configurado.
  • Revisa los logs de Fluentd por tráfico entrante de Docker.

4. Monitorización y alertas

Configurar no basta; hay que vigilar.

Dos métricas clave:

  • Espacio en disco: tamaño de /var/lib/docker/containers de forma periódica. Alerta, p. ej. por encima de 10 GB.
  • Latencia de logs: en recolección centralizada, latencia de escritura en Fluentd o Loki. Retrasos altos pueden indicar red o cuello de botella en almacenamiento.

Prometheus + Grafana, o un script con Cron para revisiones simples.

Resumen

Puntos clave de la gestión de logs en Docker:

  1. Driver: json-file lo más general; syslog con infra empresarial; fluentd para centralizar.
  2. Rotación: max-size + max-file; global en daemon.json o por contenedor/Compose.
  3. Centralización: Loki para equipos pequeños; ELK para escala y presupuesto mayores.
  4. Evitar problemas: rotación por defecto, no perder logs al recrear, verificar Fluentd, monitorizar disco.

Plantilla rápida:

// /etc/docker/daemon.json
{
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "10m",
    "max-file": "3",
    "compress": "true"
  }
}

Acción: si aún no tienes rotación, revísalo ahora. Mira si hay logs enormes en /var/lib/docker/containers, añade parámetros en daemon.json y reinicia Docker. Son minutos que te ahorran levantarte a las dos de la madrugada por un disco lleno.

Configuración de rotación de logs de Docker

Configura la rotación de logs de contenedores Docker para evitar que los archivos saturen el disco

⏱️ Estimated time: 10 min

  1. 1

    Step 1: Comprobar el estado actual de los logs

    Ejecuta estos comandos para ver el uso de logs de los contenedores:

    ```bash
    # Ver tamaño total del directorio de logs
    du -sh /var/lib/docker/containers

    # Ver tamaño de logs por contenedor
    docker ps -q | xargs -I {} sh -c 'echo -n "{}: "; docker inspect --format="{{.LogPath}}" {} | xargs du -sh 2>/dev/null || echo "N/A"'
    ```

    Si algún contenedor supera 1 GB, conviene configurar la rotación.
  2. 2

    Step 2: Configurar rotación global por defecto

    Edita `/etc/docker/daemon.json` y añade la configuración del driver de logs:

    ```json
    {
    "log-driver": "json-file",
    "log-opts": {
    "max-size": "10m",
    "max-file": "3",
    "compress": "true"
    }
    }
    ```

    Parámetros:
    - max-size: 10 MB máximo por archivo
    - max-file: conservar 3 archivos históricos
    - compress: comprimir archivos antiguos para ahorrar espacio
  3. 3

    Step 3: Reiniciar Docker para aplicar

    Reinicia el servicio para que la configuración surta efecto:

    ```bash
    sudo systemctl restart docker
    ```

    **Nota**: la configuración global solo aplica a contenedores nuevos; los existentes hay que recrearlos o configurarlos por separado.
  4. 4

    Step 4: Verificar la configuración

    Crea un contenedor de prueba para comprobar que la configuración funciona:

    ```bash
    # Crear contenedor de prueba
    docker run -d --name test-nginx nginx:alpine

    # Ver configuración de logs
    docker inspect --format='{{.HostConfig.LogConfig}}' test-nginx
    ```

    La salida debe mostrar los parámetros `max-size=10m,max-file=3`.
  5. 5

    Step 5: Limpiar logs de contenedores antiguos (opcional)

    Si los logs de contenedores existentes son demasiado grandes, puedes limpiarlos manualmente:

    ```bash
    # Método 1: vaciar el archivo de log (sin reiniciar el contenedor)
    sudo truncate -s 0 $(docker inspect --format='{{.LogPath}}' nombre-contenedor)

    # Método 2: recrear el contenedor (recomendado)
    docker rm -f nombre-contenedor
    docker run ... # recrear con parámetros de log
    ```

    Tras recrear, el nuevo contenedor heredará la configuración global.

FAQ

¿Cuál es el driver de logs por defecto de Docker y por qué no limita el tamaño?
Docker usa json-file por defecto: escribe stdout y stderr del contenedor en archivos locales en formato JSON. No limita el tamaño por defecto para preservar la integridad de los logs y no perder información de diagnóstico. Eso hace que los logs de contenedores de larga duración crezcan sin límite; hay que configurar la rotación manualmente.
¿Cómo combinar max-size y max-file de forma razonable?
Combinaciones recomendadas: desarrollo `max-size=10m, max-file=3` (≈30 MB total); producción `max-size=50m, max-file=5` (≈250 MB); aplicaciones de alto tráfico `max-size=100m, max-file=10` (≈1 GB). El equilibrio depende de la capacidad del disco y de cuánto historial necesites para investigar incidentes.
¿Los logs siguen ahí tras eliminar el contenedor? ¿Cómo persistirlos?
Con json-file, al eliminar el contenedor se borran también los archivos de log. Para persistir: 1) usar drivers fluentd/syslog hacia almacenamiento externo; 2) hacer backup periódico de `/var/lib/docker/containers`; 3) usar `docker restart` en lugar de eliminar y recrear para reiniciar.
¿ELK o Loki? ¿Cuál conviene a un equipo pequeño?
Equipos pequeños (&lt;10 personas): Loki — despliegue simple, cientos de MB de RAM, bajo costo de almacenamiento e integración fluida con Grafana. ELK es potente pero consume muchos recursos (Elasticsearch suele usar varios GB de RAM); encaja en grandes empresas con equipo de operaciones. Si ya usas Grafana para monitorización, Loki encaja de forma natural.
¿Qué pasa si la dirección de Fluentd está mal configurada? ¿Cómo diagnosticarlo?
Con la dirección incorrecta el contenedor arranca con normalidad, pero los logs no se recogen y puedes descubrir la pérdida solo al investigar. Pasos: 1) comprobar que Fluentd escucha `netstat -tlnp | grep 24224`; 2) revisar la config del contenedor `docker inspect --format='{{.HostConfig.LogConfig}}' ID-contenedor`; 3) ver en los logs de Fluentd si llega tráfico desde Docker.
¿Cómo aplicar nueva rotación de logs a contenedores existentes?
La config global en `daemon.json` solo afecta a contenedores nuevos. Para los existentes: 1) recrear (recomendado): `docker rm -f nombre` y volver a crear; 2) por contenedor: `docker update --log-opt max-size=10m nombre` (algunos parámetros admiten actualización en caliente); 3) vaciar manualmente: `truncate -s 0 $(docker inspect --format='{{.LogPath}}' nombre)`.
¿Cómo monitorizar el uso de disco de los logs de Docker?
Opciones: 1) script simple + Cron con `du -sh /var/lib/docker/containers` y alerta al superar umbral; 2) Prometheus + node_exporter para uso de disco; 3) métricas del propio sistema de logs (Loki/Fluentd, latencia de escritura). Define alertas de disco (p. ej. aviso por encima de 10 GB) para evitar incidentes a altas horas.

8 min de lectura · Publicado el: 30 abr 2026 · Actualizado el: 21 ago 2026

Comentarios

Inicia sesión con GitHub para dejar un comentario

Easton BlogEaston Blog