Supervision des services — Elasticsearch & Kibana (Minikube)

Objectif : Collecter & visualiser des logs applicatifs

Dans le cadre de l’activité type 3 (ECF DevOps), j’ai mis en place une supervision locale : Elasticsearch (collecte/stockage) + Kibana (visualisation), le tout sur Minikube. Résultat : un pipeline complet pour déployer, accéder, injecter des logs JSON et les filtrer.

Kubernetes Minikube Elasticsearch 7.17 Kibana 7.17 NodePort Namespace: monitoring JSON / cURL KQL Debian 12 VirtualBox
  • Catégorie : DevOps / Observabilité
  • Contexte : VM Debian 12 (VirtualBox), cluster local Minikube
  • Livrables : elasticsearch.yaml, kibana.yaml, exemple de log test-log.json
  • Voir le repository GitHub
Contexte & objectifs

L’objectif était de bâtir une chaîne de supervision locale, reproductible qui prouve la capacité à déployer un moteur de recherche de logs (Elasticsearch), à exposer une interface de consultation (Kibana) et à manipuler de vrais événements JSON (injection & recherche).

  • Sans cloud : tout tourne en local (Minikube) pour éviter les coûts et rester maître de l’environnement.
  • Simple & pédagogique : un namespace dédié monitoring, deux manifests, et des commandes minimales.
  • Traçabilité : chaque étape (deploy, accès, injection, filtre) est testée et capturée.
Architecture & Manifests Kubernetes

1) Elasticsearch — déployé en mode single-node, stockage éphémère (démonstration) :

apiVersion: apps/v1
kind: Deployment
metadata:
  name: elasticsearch
  namespace: monitoring
spec:
  replicas: 1
  selector:
    matchLabels:
      app: elasticsearch
  template:
    metadata:
      labels:
        app: elasticsearch
    spec:
      containers:
      - name: elasticsearch
        image: docker.elastic.co/elasticsearch/elasticsearch:7.17.16
        ports:
        - containerPort: 9200
        env:
        - name: discovery.type
          value: single-node
        - name: ES_JAVA_OPTS
          value: "-Xms512m -Xmx512m"
        volumeMounts:
        - name: esdata
          mountPath: /usr/share/elasticsearch/data
      volumes:
      - name: esdata
        emptyDir: {}
---
apiVersion: v1
kind: Service
metadata:
  name: elasticsearch
  namespace: monitoring
spec:
  selector:
    app: elasticsearch
  ports:
  - port: 9200
    targetPort: 9200
    protocol: TCP
  type: ClusterIP

2) Kibana — connecté au service DNS d’Elasticsearch dans le même namespace :

apiVersion: apps/v1
kind: Deployment
metadata:
  name: kibana
  namespace: monitoring
spec:
  replicas: 1
  selector:
    matchLabels:
      app: kibana
  template:
    metadata:
      labels:
        app: kibana
    spec:
      containers:
      - name: kibana
        image: docker.elastic.co/kibana/kibana:7.17.16
        ports:
        - containerPort: 5601
        env:
        - name: ELASTICSEARCH_HOSTS
          value: "http://elasticsearch.monitoring.svc.cluster.local:9200"
---
apiVersion: v1
kind: Service
metadata:
  name: kibana
  namespace: monitoring
spec:
  selector:
    app: kibana
  ports:
  - protocol: TCP
    port: 5601
    targetPort: 5601
  type: NodePort
Déploiement & accès (Minikube)

Namespace & déploiements :

kubectl create ns monitoring
kubectl apply -f elasticsearch.yaml
kubectl apply -f kibana.yaml
kubectl get pods -n monitoring
kubectl get svc  -n monitoring

Ouvrir Kibana (service NodePort) :

minikube service kibana -n monitoring
# OU : kubectl port-forward svc/kibana -n monitoring 5601:5601
# Puis : http://localhost:5601

Selon la version, Kibana peut demander un token de vérification/enrollement au premier accès. Les captures montrent l’obtention/usage de ce code, le temps de l’initialisation.

Injection des logs & recherche dans Kibana

document JSON (fichier test-log.json) :

{
  "timestamp": "2025-06-09T22:05:00",
  "level": "info",
  "message": "Ceci est un log pour valider l'exercice",
  "service": "api-node",
  "host": "minikube"
}

Injection dans Elasticsearch (index de test) :

curl -X POST "http://<IP_MINIKUBE>:<PORT_NODEPORT_ELASTICSEARCH>/logs-test/_doc" \
  -H "Content-Type: application/json" \
  -d @test-log.json

Découverte dans Kibana :

  • Créer un index pattern : logs-test* (sans champ temporel si le timestamp n’est pas reconnu).
  • Requêtes testées dans Discover (KQL) : level: "info", message: "valider", service: "api-node", *.

Astuce : pour exploiter les graphiques temporels, définir timestamp comme champ de type “Date” (mapping d’index ou via un pipeline d’ingestion).

Problèmes rencontrés & solutions
  • Timestamp non reconnu : création d’un index pattern sans champ temporel pour afficher les documents bruts.
  • Accès navigateur : exposition via NodePort et minikube service pour ouvrir Kibana en local.
  • Ressources limitées : JVM d’Elastic bridée à -Xms512m -Xmx512m pour la VM.
Résultats, nettoyage & enseignements

  • Pipeline opérationnel : Elasticsearch reçoit les événements ; Kibana les filtre et les affiche.
  • Compétences démontrées : manifests K8s, exposition de services, KQL, diagnostic & itérations.

Nettoyage :

kubectl delete -f kibana.yaml
kubectl delete -f elasticsearch.yaml
kubectl delete ns monitoring