Mehdi Assabbane
← Tous les articles

Centraliser les logs Docker avec Elasticsearch, Filebeat et Kibana

Mehdi Assabbane ·

Introduction

Quand un incident survient, la première question est toujours la même : que disent les journaux ? Sur un serveur avec une dizaine de conteneurs, la réponse passe par autant de docker logs, des journaux qui disparaissent quand un conteneur est recréé, et aucune vue d'ensemble.

Centraliser les journaux résout ces trois problèmes : tout est au même endroit, conservé indépendamment des conteneurs, et consultable par recherche. La pile ELK (Elasticsearch, Logstash, Kibana), aujourd'hui souvent appelée Elastic Stack, est la solution la plus répandue. Pour des journaux Docker, on remplace généralement Logstash par Filebeat, plus léger :

  • Filebeat lit les journaux des conteneurs et les envoie ;
  • Elasticsearch les indexe et les stocke ;
  • Kibana permet de les rechercher et de les visualiser.

L'architecture

 conteneurs ──► fichiers de journaux Docker ──► Filebeat ──► Elasticsearch ──► Kibana ──► vous

Par défaut, Docker écrit la sortie de chaque conteneur dans un fichier JSON sous /var/lib/docker/containers/. Filebeat lit ces fichiers, ajoute les métadonnées du conteneur (nom, image, labels) et envoie le tout à Elasticsearch.

Prérequis système

Elasticsearch exige un réglage du noyau :

sudo sysctl -w vm.max_map_count=262144
echo 'vm.max_map_count=262144' | sudo tee /etc/sysctl.d/99-elasticsearch.conf

La première commande augmente immédiatement le nombre de zones mémoire qu'un processus peut utiliser ; la seconde rend le réglage permanent au redémarrage.

Prévoyez aussi de la mémoire : Elasticsearch a besoin d'au moins 1 à 2 Go réservés pour lui seul sur un petit serveur.

Le fichier Docker Compose

Créez un répertoire logs/ avec un fichier .env :

ELASTIC_PASSWORD=un-mot-de-passe-long-et-aleatoire
KIBANA_PASSWORD=un-autre-mot-de-passe-long-et-aleatoire
STACK_VERSION=<version>

Remplacez <version> par la même version stable pour les trois produits Elastic : ils doivent toujours être à la même version. Protégez ce fichier (chmod 600 .env).

Puis le docker-compose.yml :

services:
  elasticsearch:
    image: docker.elastic.co/elasticsearch/elasticsearch:${STACK_VERSION}
    environment:
      - discovery.type=single-node
      - xpack.security.enabled=true
      - ELASTIC_PASSWORD=${ELASTIC_PASSWORD}
      - ES_JAVA_OPTS=-Xms1g -Xmx1g
    volumes:
      - es-data:/usr/share/elasticsearch/data
    ports:
      - "127.0.0.1:9200:9200"
    restart: unless-stopped

  kibana:
    image: docker.elastic.co/kibana/kibana:${STACK_VERSION}
    environment:
      - ELASTICSEARCH_HOSTS=http://elasticsearch:9200
      - ELASTICSEARCH_USERNAME=kibana_system
      - ELASTICSEARCH_PASSWORD=${KIBANA_PASSWORD}
    ports:
      - "127.0.0.1:5601:5601"
    depends_on:
      - elasticsearch
    restart: unless-stopped

  filebeat:
    image: docker.elastic.co/beats/filebeat:${STACK_VERSION}
    user: root
    command: ["filebeat", "-e", "--strict.perms=false"]
    environment:
      - ELASTIC_PASSWORD=${ELASTIC_PASSWORD}
    volumes:
      - ./filebeat.yml:/usr/share/filebeat/filebeat.yml:ro
      - /var/lib/docker/containers:/var/lib/docker/containers:ro
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - filebeat-data:/usr/share/filebeat/data
    depends_on:
      - elasticsearch
    restart: unless-stopped

volumes:
  es-data:
  filebeat-data:

Points importants :

  • La sécurité est activée (xpack.security.enabled=true) : Elasticsearch exige un mot de passe. Ne la désactivez jamais, même « temporairement ».
  • ES_JAVA_OPTS fixe la mémoire d'Elasticsearch à 1 Go ; ajustez selon votre serveur (environ la moitié de la mémoire qui lui est dédiée).
  • Les ports sont limités à 127.0.0.1 : accès par tunnel SSH ou reverse proxy authentifié uniquement.
  • Filebeat tourne en root pour lire les journaux Docker, et le socket Docker est monté en lecture seule pour récupérer les métadonnées des conteneurs. Ce socket donne un accès étendu à Docker : n'utilisez que l'image officielle.
  • Pour un usage réel, l'étape suivante consiste à activer TLS entre les composants ; la documentation Elastic décrit la génération des certificats.

La configuration de Filebeat

filebeat.yml :

filebeat.inputs:
  - type: filestream
    id: docker-containers
    paths:
      - /var/lib/docker/containers/*/*.log
    parsers:
      - container: ~
    prospector.scanner.symlinks: true

processors:
  - add_docker_metadata: ~

output.elasticsearch:
  hosts: ["http://elasticsearch:9200"]
  username: elastic
  password: ${ELASTIC_PASSWORD}
  • L'entrée filestream avec le parseur container décode le format JSON des journaux Docker.
  • add_docker_metadata ajoute le nom du conteneur, l'image et les labels à chaque ligne, ce qui permet de filtrer par conteneur dans Kibana.
  • Pour simplifier, Filebeat utilise ici le compte elastic. En production, créez un compte dédié avec uniquement les droits d'écriture nécessaires.

Démarrer

cd logs
docker compose up -d elasticsearch

Démarre Elasticsearch seul, le temps de configurer le compte de Kibana.

source .env
curl -s -u "elastic:$ELASTIC_PASSWORD" -X POST \
  http://localhost:9200/_security/user/kibana_system/_password \
  -H 'Content-Type: application/json' \
  -d "{\"password\":\"$KIBANA_PASSWORD\"}"

Définit le mot de passe du compte système kibana_system, utilisé par Kibana pour se connecter à Elasticsearch. Une réponse {} signifie que l'opération a réussi.

docker compose up -d
docker compose logs -f filebeat

Démarre Kibana et Filebeat, puis affiche les journaux de Filebeat pour vérifier qu'il se connecte bien à Elasticsearch (Ctrl+C pour quitter).

ssh -L 5601:localhost:5601 utilisateur@votre-serveur

Depuis votre poste, ouvre un tunnel vers Kibana, accessible ensuite sur http://localhost:5601 avec le compte elastic.

Rechercher dans Kibana

Dans Discover, sélectionnez la vue de données Filebeat, puis utilisez le langage de requête KQL :

container.name : "nginx" and message : *error*

Lignes du conteneur nginx contenant « error ».

container.image.name : *postgres* and not message : *checkpoint*

Journaux des conteneurs PostgreSQL, en excluant le bruit des points de contrôle.

Enregistrez les recherches utiles et construisez un tableau de bord avec, par exemple, le nombre d'erreurs par conteneur dans le temps.

Maîtriser l'espace disque

Les journaux grossissent vite. Deux réglages sont essentiels :

  • Côté Elasticsearch, définissez une durée de rétention avec une politique de cycle de vie des index (ILM) ou de flux de données : suppression automatique au-delà de 30 jours, par exemple.
  • Côté Docker, limitez la taille des fichiers de journaux locaux, sans quoi ils peuvent remplir le disque du serveur. Dans /etc/docker/daemon.json :
{
  "log-driver": "json-file",
  "log-opts": { "max-size": "50m", "max-file": "3" }
}

Limite chaque conteneur à trois fichiers de 50 Mo. Le réglage s'applique aux conteneurs créés après le redémarrage de Docker.

Checklist

  • vm.max_map_count réglé et rendu permanent.
  • Même version pour Elasticsearch, Kibana et Filebeat.
  • Sécurité Elasticsearch activée, mots de passe robustes dans un .env protégé.
  • Ports limités à 127.0.0.1, accès par tunnel ou proxy authentifié.
  • Journaux de tous les conteneurs visibles dans Kibana.
  • Politique de rétention configurée.
  • Taille des journaux Docker locaux limitée.
  • Étape suivante planifiée : TLS et compte Filebeat dédié.

FAQ

ELK n'est-il pas trop lourd pour un petit serveur ? Elasticsearch demande de la mémoire. Sur un serveur modeste, une alternative plus légère comme Grafana Loki peut être plus adaptée, surtout si vous utilisez déjà Grafana. ELK reste plus puissant pour la recherche plein texte et l'analyse.

Faut-il Logstash ? Pas pour commencer. Filebeat suffit pour collecter et envoyer les journaux Docker. Logstash devient utile pour des transformations complexes ou des sources multiples.

Les journaux contiennent des données personnelles. Est-ce un problème ? Ils peuvent en contenir (adresses IP, identifiants, e-mails). Au regard du RGPD, limitez la durée de conservation, restreignez les accès et évitez de journaliser des données sensibles dans vos applications.

Comment centraliser les journaux de plusieurs serveurs ? Installez Filebeat sur chaque serveur et faites-les tous envoyer vers le même Elasticsearch, idéalement à travers un réseau privé et avec TLS activé.

Conclusion

Centraliser ses journaux transforme le diagnostic d'un incident : on passe de la fouille serveur par serveur à une recherche unique.

  1. Déployez la pile avec la sécurité activée et sans exposition publique.
  2. Limitez l'espace disque dès le premier jour, côté Elasticsearch et côté Docker.
  3. Construisez quelques recherches et tableaux de bord autour des erreurs de vos applications critiques.

Sources officielles