Par exemple, lorsque vous visitez ce blog, un journal enregistre et stocke les informations telles que l'adresse IP, les pages consultées, les codes de retour du serveur et d'autres informations utiles à un administrateur système.

Ces informations sont généralement stockées au format texte mais peuvent également être sauvegardées ou centralisées dans des bases de données.

Traefik utilise pour la création de ses logs, le format standardisé Common Log Format ( CLF ). Ce format étant standard, les fichiers peuvent être facilement analysés par divers outils d'analyses de logs ( Webalizer ou Analog par exemple ).

Il est toutefois possible de modifier quelques informations renvoyées par Traefik dans ses logs. Nous aurons l'occasion de voir comment au cours de cet article.

Nous allons dans notre cas, stocker nos logs dans une base ElasticSearch à l'aide de l'outil Filebeat et visualiser le tout à l'aide de Kibana.

Traefik : Activer les access logs

Dans un premier temps, il est nécessaire d'activer les access logs dans la configuration statique de Traefik.

Effectivement cette génération de logs n'est pas activé par défaut et il est nécessaire de la paramétrer.

🚩Comme d'habitude, je mets à disposition l'intégralité des configurations de cet article sur github. 🚩

Je vais activer les logs dans mon fichier de configuration traefik.yml :

accessLog:
  filePath: "/var/log/traefik/access.log"
  fields:
    defaultMode: keep
    headers:
      defaultMode: keep

Je vais ajouter un volume dans mon fichier de configuration docker-compose.yml afin de stocker ces informations :

version: '3.7'
services:
  traefik:
    image: traefik:2.2
    container_name: traefik
    restart: always
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - ./traefik.yml:/etc/traefik/traefik.yml:ro
      - ./custom/:/etc/traefik/custom/:ro
      - traefik_ssl:/letsencrypt
    networks:
      - traefik

À ce moment là, si vous relancez vos containers, vos logs devraient être présents dans le dossier /var/log/traefik/access.log. Pour les consulter sur l'hôte, vous pouvez regarder dans le dossier /var/lib/docker/volumes/traefik_logs/_data.

Si vous êtes attentif, un détail présent dans les logs devrait vous poser un petit problème. Rassurez-vous, rien de grave : Le timestamp ( l'horodatage ) des logs est sur le temps UTC.

Une petite modification de nos précédents fichiers peut corriger ceci rapidement. Dans le fichier docker-compose.yml :

version: '3.7'
services:
  traefik:
    image: traefik:2.2
    container_name: traefik
    restart: always
    ports:
      - "80:80"
      - "443:443"
    environment:
      - "TZ=Europe/Paris" #ajout d'une variable de TimeZone
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - /usr/share/zoneinfo:/usr/share/zoneinfo:ro   #ajout du fichier zoneinfo
      - ./traefik.yml:/etc/traefik/traefik.yml:ro
      - ./custom/:/etc/traefik/custom/:ro
      - traefik_log:/var/log/traefik/
      - traefik_ssl:/letsencrypt
    networks:
      - traefik

Et dans le fichier traefik.yml :

accessLog:
  filePath: "/var/log/traefik/access.log"
  fields:
    defaultMode: keep
    names:
      StartUTC: drop
    headers:
      defaultMode: keep

Cette fois, nos logs seront bien à l'heure française ! Nous allons pouvoir envoyer ces informations à notre base de données.

ElasticSearch, Filebeat et Kibana

Expliquons tout d'abord à quoi servent ces trois éléments :

  • ElasticSearch : C'est notre base de données, elle est de type NoSQL et sa particularité est de pouvoir indexer des documents fortement orientés textes ( Comme des journaux d'événements par exemple 😂 ). C'est un moteur de recherche personnalisable.
  • Filebeat : Est un agent de transfert, il va lire nos logs Traefik pour les transférer dans la base de données.
  • Kibana : L'interface graphique qui va nous permettre d'effectuer des recherches sur notre base de données.

Il va donc être nécessaire de lancer ces trois composants sur notre machine ! Il est bien évidement possible d'utiliser des images Docker pour ça !

Commençons avec la base de données ElasticSearch :

version: '3.7'
services:
  elasticsearch:
    image: docker.elastic.co/elasticsearch/elasticsearch:7.6.1
    container_name: elasticsearch
    volumes:
      - es_data:/usr/share/elasticsearch/data
    environment:
      - ES_JAVA_OPTS=-Xms512m -Xmx512m
      - discovery.type=single-node
      - transport.host=localhost
      - transport.tcp.port=9300
      - http.port=9200
      - http.host=0.0.0.0
    ulimits:
      memlock:
        soft: -1
        hard: -1
    networks:
      - elastic

⚠️ Dans le cadre de cet article, je ne vais pas mettre en "cluster" la base ElasticSearch. Si vous souhaitez réaliser cet ajout dans un environnement de production, il faudra faire le nécessaire ⚠️

J'utilise justement la variable d'environnement suivante afin de faire tourner le service sur un seul noeud :

  - discovery.type=single-node

Je vais créer un volume pour le stockage des données :

volumes:
  - es_data:/usr/share/elasticsearch/data

Pour les autres options vous pouvez trouver plus d'explications sur la page dédiée à l'utilisation d'ElasticSearch sur Docker : https://www.elastic.co/guide/en/elasticsearch/reference/current/docker.html

Nous allons ensuite procéder de la même façon pour ajouter Filebeat :

  kibana:
    image: docker.elastic.co/kibana/kibana:7.6.1
    container_name: kibana
    labels:
      - "traefik.enable=true"
      - "traefik.docker.network=traefik"
      - "traefik.http.routers.kibana.entrypoints=websecure"
      - "traefik.http.routers.kibana.rule=Host(`kibana.domaine.com`)"
      - "traefik.http.services.kibana.loadbalancer.server.port=5601"
    environment:
      ELASTICSEARCH_HOSTS: 'http://ELASTICSEARCH:9200'
      ELASTICSEARCH_USERNAME: 'elastic'
      ELASTICSEARCH_PASSWORD: 'changeme'
      XPACK_MONITORING_ENABLED: 'false'
    networks:
      - elastic
      - traefik

Encore une fois, les accès d'ElasticSearch sont normalement à modifier. J'utilise ici les accès par défauts.

⚠️ Si vous suivez ce tutoriel à la lettre, votre interface Kibana sera accessible à tout le monde. Vous pouvez la sécuriser en ajoutant un middleware avec login et mot de passe et même une restriction par adresse IP ⚠️

Voici mon fichier custom/middlewares.yml avec ces restrictions :

http:
  middlewares:
      my-auth:
        basicAuth:
          users:
            - "lfache:XXXXXX"

Il ne s'agit pas de la façon la plus "propre" de générer le mot de passe mais j'utilise souvent l'image docker registry pour ça :

  • docker run --rm --entrypoint htpasswd registry:2 -Bbn username password

Je vais modifier la déclaration du service Kibana en conséquence avec la prise en compte de mon nouveau middleware :

  kibana:
    image: docker.elastic.co/kibana/kibana:7.6.1
    container_name: kibana
    labels:
      - "traefik.enable=true"
      - "traefik.docker.network=traefik"
      - "traefik.http.routers.kibana.entrypoints=websecure"
      - "traefik.http.routers.kibana.middlewares=my-auth@file"
      - "traefik.http.routers.kibana.rule=Host(`kibana.domaine.com`)"
      - "traefik.http.services.kibana.loadbalancer.server.port=5601"
    environment:
      ELASTICSEARCH_HOSTS: 'http://ELASTICSEARCH:9200'
      ELASTICSEARCH_USERNAME: 'elastic'
      ELASTICSEARCH_PASSWORD: 'changeme'
      XPACK_MONITORING_ENABLED: 'false'
    networks:
      - elastic
      - traefik

Configuration de Filebeat

Filebeat est donc l'utilitaire qui va venir lire nos logs et les envoyer à ElasticSearch. Voici la déclaration de ce service :

  filebeat:
    image: "docker.elastic.co/beats/filebeat:7.6.1"
    container_name: filebeat
    volumes:
      - traefik_log:/var/log/traefik/
      - filebeat_data:/usr/share/filebeat/data
      - ./filebeat.yml:/usr/share/filebeat/filebeat.yml:ro
    networks:
      - elastic

Nous allons utiliser le volume commun des journaux entre Traefik et Filebeat :

volumes:
  - traefik_log:/var/log/traefik/

Enfin je vais utiliser un fichier de configuration pour définir la configuration du module Traefik et définir mon serveur ElasticSearch :

output.elasticsearch:
  hosts: ["elasticsearch:9200"]
  indices:
    - index: "filebeat-%{[agent.version]}-%{+yyyy.MM.dd}"

filebeat.modules:
  - module: traefik
    access:
      enabled: true
      var.paths: ["/var/log/traefik/access.log*"]

Filebeat offre cet avantage d'être vraiment simple de mise en place...

Visualiser ses logs

Voila, il ne vous reste plus qu'à lancer l'intégralité de la stack. Il faut commencer par traefik avec lequel je joins un service whoami basique pour réaliser nos tests.

Vous pouvez donc lancer les services de la façon suivante :

docker-compose up -d traefik whoami

Et enfin la stack EFK que j'ai mis dans le dossier elasticsearch :

docker-compose up -d 

Vous pouvez maintenant vous rendre sur la page http://kibana.domaine.com pour accéder à votre interface.

Lors de la première connexion, il faudra créer votre index dans kibana :

Vous pourrez ensuite visualiser vos logs.


J'utilise Filebeat depuis peu mais j'ai très longtemps utiliser Logstash avec les drivers GELF de Docker pour envoyer les logs à ElasticSearch. Mais cette solution avait un défaut particulier. Une fois pris dans le pipe GELF, on ne peut plus consulter les logs en ligne de commande facilement. C'est pourquoi j'utilise dorénavant Filebeat qui permet de garder cette souplesse.

Nous venons donc de mettre en place un système nous permettant de stocker nos access logs de Traefik grâce aux outils ElasticSearch, Filebeat et Kibana. Cette solution est loin d'être la seule et unique solution que nous pouvons envisager. Elle a du moins le mérite d'être facile à mettre en œuvre.

D'autres solutions existent et notre solution peut même s'en servir pour s'améliorer. Si vous visualisez vos logs sur Kibana, vous allez vite vous rendre compte que Kibana lui même remonte beaucoup de logs... Et certaines informations ne sont peut être pas pertinentes !?

Nous allons peut-être justement pouvoir utiliser logstash en plus dans notre environnement. Afin d'effectuer certains filtrages, ou travailler notre log avant de le stocker. Voir même de créer des alertes de sécurité pour notre système...

Et vous quel système de surveillance mettez-vous en place derrière votre centralisation de logs ? 😊

En tout cas  n'hésitez pas à m'apporter des remarques ou des commentaires sur Twitter, c'est toujours un plaisir d'avoir des retours et des échanges !