SSD Nodes Learn 🎉 VPS dès $5.50/mois
Guides Matt ConnorPar Matt Connor

Gestion des logs auto-hébergée sur un seul VPS

Comparez journald, logrotate, Loki et OpenSearch sur un seul VPS : RAM minimale, recherche, stockage et règles de rétention pour choisir sans surdimensionner.

Ce que coûte réellement la gestion de journaux auto-hébergée sur un seul VPS

La gestion de journaux auto-hébergée sur un seul VPS (serveur privé virtuel) se résume à une question : avez-vous besoin d’un cluster de recherche, ou d’une rotation des journaux et de grep ? La plupart des guides des fournisseurs commencent par 3 nœuds et 12 GB de RAM, avant même qu’une seule ligne de journal soit envoyée. Sur un seul serveur, cette réponse est inutile. La comparaison ci-dessous porte donc sur ce que chaque option exige d’une petite machine avant de stocker quoi que ce soit.

Si vous administrez 1 ou 2 serveurs et souhaitez savoir ce qui s’est passé mardi dernier, systemd-journald et logrotate suffisent déjà. Vous pouvez alors vous arrêter après la section suivante. Si plusieurs machines doivent envoyer leurs journaux au même endroit, avec une recherche sur plusieurs semaines, Grafana Loki convient à une petite machine, car il indexe les labels et non le texte des lignes. Elasticsearch et OpenSearch fournissent une véritable recherche en texte intégral. Ils la facturent en mémoire, car le heap de la JVM (machine virtuelle Java) possède une valeur minimale que vous ne pouvez pas réduire.

Commencez par journald : c’est généralement là que l’on s’arrête

systemd-journald est déjà actif sur tous les serveurs Ubuntu ou Debian actuels. Il capture la sortie standard de chaque unité de service, les messages du kernel et tout ce qui est envoyé à syslog. Quatre commandes couvrent la plupart des incidents.

journalctl -u nginx.service --since "2026-08-14 09:00" --until "2026-08-14 10:00"
journalctl -p err -b
journalctl -f -u ssh.service
journalctl --disk-usage

La dernière affiche une ligne comme Archived and active journals take up 1.1G in the file system.. C’est cette valeur qui détermine si vous avez besoin d’autre chose. Si elle indique quelques centaines de mégaoctets et que vous trouvez ce dont vous avez besoin avec -u et --since, vous avez terminé.

La persistance du journal après un redémarrage dépend de Storage= et de l’existence de /var/log/journal. Avec le paramètre courant Storage=auto, journald écrit dans /var/log/journal lorsque ce répertoire existe, et dans /run/log/journal lorsqu’il n’existe pas. /run est stocké en mémoire. Sur une machine dépourvue de ce répertoire, tous les journaux sont donc effacés au redémarrage, précisément au moment où vous voulez les consulter. Les images Ubuntu incluent ce répertoire. Les images minimales et celles basées sur des conteneurs ne l’incluent souvent pas.

ls -d /var/log/journal
sudo mkdir -p /var/log/journal
sudo systemctl restart systemd-journald
journalctl --disk-usage

Après le redémarrage, journalctl --disk-usage doit indiquer une taille inférieure à /var/log/journal, et non à /run. Les valeurs par défaut sont déjà limitées, ce qui explique principalement pourquoi journald constitue une vraie solution et non un simple recours. La page de manuel journald.conf définit SystemMaxUse= à 10 % de la taille du système de fichiers et SystemKeepFree= à 15 %, avec un plafond de 4G pour chaque valeur calculée par défaut. SystemMaxFileSize= vaut par défaut un huitième de SystemMaxUse=, avec un plafond de 128M ; vous conservez donc normalement sept fichiers ayant fait l’objet d’une rotation. MaxRetentionSec= vaut par défaut 0, ce qui désactive la suppression fondée sur l’ancienneté. Relisez cette dernière valeur par défaut : dans sa configuration initiale, le journal est limité uniquement par sa taille, jamais par son ancienneté.

[Journal]
Storage=persistent
SystemMaxUse=2G
MaxRetentionSec=30day

Écrivez cette valeur dans /etc/systemd/journald.conf.d/99-size.conf, redémarrez journald, puis vérifiez que journalctl --disk-usage se rapproche de votre nouvelle limite. Pour récupérer l’espace immédiatement plutôt que d’attendre la prochaine rotation, exécutez sudo journalctl --vacuum-size=500M ou sudo journalctl --vacuum-time=14d. Les deux commandes affichent chaque fichier supprimé. Une exécution silencieuse signifie donc qu’il n’y avait rien à supprimer.

Tout ce qui se trouve en dehors du journal, par exemple /var/log/nginx/access.log, relève de logrotate, qui s’exécute chaque jour avec un timer systemd. Un problème mérite d’être connu, car il ressemble à un bug dans df. Après une rotation, l’ancien fichier disparaît de la liste du répertoire alors que le daemon le maintient ouvert. df -h indique donc que le disque est plein, tandis que du -sh /var/log indique une occupation bien moindre. L’espace n’est récupéré que lorsque le processus rouvre son journal, ce que permet la ligne de reload postrotate dans la configuration. sudo lsof -nP +L1 liste les fichiers supprimés qui sont toujours ouverts et indique le processus qui maintient chacun d’eux ouvert. Testez une règle sans rien modifier avec sudo logrotate -d /etc/logrotate.d/nginx.

Envoyer les journaux de plusieurs serveurs vers un collecteur unique

Dès que vous administrez plusieurs machines, gérer plusieurs serveurs Linux à la fois devient plus simple lorsque leurs journaux arrivent au même endroit. rsyslog est déjà installé sur la plupart des distributions. Le collecteur central le plus simple consiste donc à utiliser un fichier sur chaque émetteur.

*.* action(type="omfwd" target="logs.example.com" port="514" protocol="tcp")

Enregistrez cette configuration dans /etc/rsyslog.d/50-forward.conf, vérifiez-la avec sudo rsyslogd -N1, qui valide la configuration puis se termine sans rien démarrer, et redémarrez ensuite rsyslog. Sur le collecteur, activez l’entrée TCP.

module(load="imtcp")
input(type="imtcp" port="514")

Deux avertissements, tous deux d’ordre pratique. Le syslog standard ne fournit ni chiffrement ni authentification. Toute machine pouvant atteindre le port 514 peut donc injecter des lignes de journal qui semblent provenir de votre serveur. Liez ce service à un réseau privé ou à un VPN, puis filtrez le port avec le pare-feu. Ensuite, la file d’attente de l’action par défaut se trouve en mémoire. Si le collecteur est inaccessible, la file se remplit et les messages sont abandonnés sans qu’aucune copie ne soit conservée. Pour ce cas, rsyslog documente une file d’attente assistée par disque dans son tutoriel sur la transmission fiable.

Pourquoi la stack ELK ne tient pas sur un petit VPS

ELK désigne Elasticsearch pour le stockage et la recherche, Logstash pour le pipeline d’ingestion et Kibana pour l’interface. La limite vient du heap JVM, qui est défini avant l’arrivée du moindre log.

La documentation d’Elastic recommande de définir le heap à 50 % au maximum de la mémoire totale disponible pour chaque nœud Elasticsearch, car le processus utilise également des buffers off heap et dépend du cache de fichiers du système d’exploitation pour lire rapidement les fichiers d’index. Ainsi, un heap de 2 GB implique une machine de 4 GB, avant même de prendre en compte Kibana et la charge pour laquelle le serveur a réellement été acheté. Elastic précise également qu’Elasticsearch dimensionne automatiquement le heap selon les rôles du nœud et la mémoire totale. Sur une petite machine, le heap est donc réduit, puis le processus passe son temps à effectuer du garbage collection.

Logstash est la partie qui dépasse directement le budget d’une petite machine. La page consacrée aux paramètres JVM de Logstash recommande elle-même un heap d’au moins 4GB et d’au plus 8GB pour une ingestion classique. Cela représente la totalité d’un VPS de 4 GB pour un seul processus au milieu du pipeline.

ChartDocumented JVM heap settings, from each project's own docs
The data behind this chart
[
  {
    "label": "Loki plus Alloy (no JVM)",
    "documented_heap_mb": 0
  },
  {
    "label": "OpenSearch demo compose",
    "documented_heap_mb": 512
  },
  {
    "label": "OpenSearch production example",
    "documented_heap_mb": 2048
  },
  {
    "label": "Logstash recommended minimum",
    "documented_heap_mb": 4096
  }
]

Ce sont les valeurs publiées par chaque projet dans sa propre documentation. Elles ne proviennent pas de mesures réalisées sur une machine de test, et votre charge de travail peut les modifier. Le fichier compose d’exemple d’OpenSearch définit 512 MB par nœud pour une démonstration et 2048 MB dans son exemple de production, tandis que la limite basse recommandée pour Logstash est de 4096 MB. La colonne du heap affiche 0 pour Loki et Alloy, car ce sont des programmes Go qui n’ont pas de heap JVM à réserver. Toute la différence tient dans ce nombre : un composant JVM réserve cette mémoire, que des logs arrivent ou non.

Si vous voulez malgré tout utiliser la stack Elastic sur un seul petit serveur, supprimez Logstash et envoyez directement les logs vers Elasticsearch avec un collector léger. Logstash sert à parser et transformer les données à grande échelle. Sur une seule machine, vous pouvez effectuer ce travail en périphérie ou le supprimer.

Elasticsearch et OpenSearch nécessitent également d’augmenter vm.max_map_count à 262144, car ils utilisent le memory mapping pour les fichiers d’index et que la limite par défaut de Linux est trop basse. Un conteneur qui s’arrête quelques secondes après son démarrage sur une machine fraîchement installée est généralement confronté à ce problème, et à rien d’autre.

OpenSearch ou Elasticsearch : lequel pouvez-vous déployer ?

Voici un bref historique des licences, car il détermine ce que vous avez le droit d’exécuter. En janvier 2021, Elastic a abandonné la licence Apache 2.0 pour Elasticsearch et Kibana au profit d’un modèle double reposant sur la SSPL (Server Side Public License) et l’Elastic License 2.0. AWS a créé un fork du dernier code sous Apache 2.0 sous le nom OpenSearch, qui reste sous Apache 2.0. En septembre 2024, Elastic a ajouté l’AGPLv3 (GNU Affero General Public License version 3) comme autre option pour le code source libre. Pour une seule personne qui auto-héberge sur un seul VPS, toutes ces licences autorisent ce que vous faites. Les restrictions deviennent importantes lorsque vous proposez le logiciel à d’autres personnes sous forme de service géré.

Sur une petite machine, la différence pratique est moins importante que ne le laisse penser cet historique, car les deux produits reposent sur le même moteur. Les noms diffèrent : la gestion du cycle de vie des index s’appelle ISM (index state management) dans OpenSearch et ILM (index lifecycle management) dans Elasticsearch. En août 2026, OpenSearch 2.12 et les versions ultérieures refusent de démarrer si aucun mot de passe administrateur n’a été défini lors de la première exécution.

sudo sysctl -w vm.max_map_count=262144
printf 'vm.max_map_count = 262144\n' | sudo tee /etc/sysctl.d/99-opensearch.conf
docker run -d -p 9200:9200 -p 9600:9600 -e "discovery.type=single-node" \
  -e "OPENSEARCH_INITIAL_ADMIN_PASSWORD=<custom-admin-password>" \
  opensearchproject/opensearch:latest

La ligne sysctl -w applique le paramètre immédiatement, et le fichier dans /etc/sysctl.d/ est la partie qui subsiste après un redémarrage. Vérifiez que le conteneur a démarré avec curl -k -u admin:<password> https://localhost:9200. Il répond en HTTPS avec un certificat de démonstration ; -k désactive donc la vérification, et une réponse saine est un petit bloc JSON indiquant le nom du cluster et la version. La page d’installation d’OpenSearch indique également aux utilisateurs de Docker Desktop d’allouer au moins 4 GB de mémoire à l’hôte, ce qui donne une bonne indication des ressources attendues par le processus.

Loki reste léger : des labels au lieu d’un index de texte intégral

Loki conserve un index sur les labels et stocke les lignes de journal sous forme de chunks compressés. Une requête sélectionne d’abord les streams, puis filtre le texte. {unit="ssh.service"} |= "Failed password" sélectionne le stream à partir de son label, puis parcourt ces chunks à la recherche de la chaîne. Le contenu d’une ligne n’est pas indexé. L’ingestion reste donc peu coûteuse et Loki n’a pas d’index inversé à conserver en mémoire. Le coût est reporté au moment des requêtes. C’est un bon compromis lorsque vous savez généralement quel service vous examinez.

La documentation de Grafana recommande le mode monolithique, c’est-à-dire l’exécution de Loki dans un seul processus avec -target=all, pour des volumes de lecture et d’écriture faibles, jusqu’à environ 20GB par jour. Un VPS reste largement dans cette limite.

Le piège concerne la cardinalité des labels. Chaque combinaison distincte de valeurs de labels constitue un stream, et le nombre de streams détermine la taille utilisée par Loki en mémoire et dans l’index. Un label contenant une adresse IP client ou un identifiant de requête crée un stream par valeur. Un serveur web très sollicité peut donc produire des dizaines de milliers de streams en une journée, jusqu’à ce que le processus grossisse et que le kernel l’arrête. Limitez les labels à des valeurs que vous pourriez compter sur papier : unité, hôte, job, niveau. Placez les détails variables dans la ligne elle-même. Une expression de filtre pourra les rechercher au moment de la requête.

Installer Loki et Alloy sur un même VPS

Deux processus assurent le fonctionnement. Loki stocke les logs et répond aux requêtes. Grafana Alloy lit les logs et les envoie. Promtail était auparavant utilisé pour l’envoi des logs. Il a atteint sa fin de vie le 2 mars 2026. Les nouvelles installations utilisent donc Alloy, et l’exemple Docker fourni par Loki contient désormais une configuration Alloy.

wget https://raw.githubusercontent.com/grafana/loki/v3.7.0/cmd/loki/loki-local-config.yaml -O loki-config.yaml

Lisez ce fichier avant de l’utiliser. Il définit path_prefix: /tmp/loki avec des chunks sous /tmp/loki/chunks, ce qui convient pour une démonstration, mais pas pour un serveur : rien de ce qui se trouve sous /tmp du conteneur ne survit à sa recréation. Votre historique disparaît donc à la prochaine mise à jour de l’image. Configurez-le avec un chemin que vous montez.

common:
  instance_addr: 127.0.0.1
  path_prefix: /loki
  storage:
    filesystem:
      chunks_directory: /loki/chunks
      rules_directory: /loki/rules
  replication_factor: 1
  ring:
    kvstore:
      store: inmemory
docker volume create loki-data
docker run --name loki -d \
  -v $(pwd):/mnt/config -v loki-data:/loki \
  -p 127.0.0.1:3100:3100 \
  grafana/loki:3.7.0 -config.file=/mnt/config/loki-config.yaml
curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:3100/ready

La dernière commande doit afficher 200, car /ready renvoie HTTP 200 dès que Loki est prêt à accepter du trafic. Toute autre réponse signifie que le processus démarre encore ou que la configuration a été rejetée. docker logs loki indique laquelle de ces situations s’est produite. Deux détails de la commande de lancement sont intentionnels. Le port est publié uniquement sur 127.0.0.1, car la configuration d’exemple contient auth_enabled: false et Loki ne fournit aucune authentification utilisateur native. Toute machine pouvant atteindre le port 3100 peut donc lire tous les logs et en écrire de faux. Laissez le service sur loopback, ou placez-le derrière un VPN ou un reverse proxy avec authentification. Le volume nommé est important, car l’image s’exécute avec l’utilisateur loki et l’UID 10001. Un répertoire hôte monté en bind et appartenant à root ne serait pas accessible en écriture depuis le conteneur.

sudo apt-get update && sudo apt-get install -y gpg wget
sudo mkdir -p /etc/apt/keyrings/
sudo wget -O /etc/apt/keyrings/grafana.asc https://apt.grafana.com/gpg-full.key
echo "deb [signed-by=/etc/apt/keyrings/grafana.asc] https://apt.grafana.com stable main" \
  | sudo tee /etc/apt/sources.list.d/grafana.list
sudo apt-get update
sudo apt-get install -y alloy

Alloy lit /etc/alloy/config.alloy. Cette configuration récupère le journal system et un ensemble de fichiers, puis envoie les deux à l’instance Loki locale.

loki.write "local" {
  endpoint {
    url = "http://127.0.0.1:3100/loki/api/v1/push"
  }
}

loki.relabel "journal" {
  forward_to = []
  rule {
    source_labels = ["__journal__systemd_unit"]
    target_label  = "unit"
  }
}

loki.source.journal "read" {
  forward_to    = [loki.write.local.receiver]
  relabel_rules = loki.relabel.journal.rules
  labels        = {job = "systemd-journal", host = "app-01"}
}

local.file_match "nginx" {
  path_targets = [{"__path__" = "/var/log/nginx/*.log", "job" = "nginx", "host" = "app-01"}]
}

loki.source.file "nginx" {
  targets    = local.file_match.nginx.targets
  forward_to = [loki.write.local.receiver]
}

La règle de relabeling copie le champ du journal __journal__systemd_unit dans un label nommé unit. C’est ce qui permet ensuite d’utiliser {unit="ssh.service"}. Sans cette règle, le nom de l’unité se trouve dans l’entrée et non dans un label. Vous ne pouvez donc pas filtrer dessus, et chaque requête doit tout parcourir.

sudo systemctl reload alloy
systemctl show -p User alloy
sudo journalctl -n 5
sudo -u alloy journalctl -n 5

C’est à cette étape que la plupart des configurations bloquent. Alloy s’exécute avec son propre compte de service, et non avec root. La lecture du journal system nécessite d’appartenir au groupe systemd-journal, tandis que les fichiers sous /var/log/nginx appartiennent au groupe adm sur Debian et Ubuntu. Remplacez l’identifiant du compte affiché par systemctl show dans la dernière commande. Si elle renvoie beaucoup moins d’entrées que lorsqu’elle est exécutée avec root, ce compte ne peut pas lire le journal system. Loki reste alors vide, même si votre configuration est correcte. Ajoutez les groupes, puis redémarrez avec sudo usermod -aG systemd-journal,adm alloy suivi de sudo systemctl restart alloy.

curl -G -s "http://127.0.0.1:3100/loki/api/v1/query_range" \
  --data-urlencode 'query={job="systemd-journal"}' \
  --data-urlencode 'limit=5' | jq '.data.result | length'

Un nombre supérieur à 0 signifie que des streams possèdent ce label et contiennent des entrées. La valeur 0 signifie qu’aucune donnée n’est encore arrivée avec ce label. Un paramètre par défaut explique une fausse alerte fréquente : loki.source.journal définit max_age sur 7h. Au démarrage initial, Alloy lit donc les sept dernières heures du journal, mais rien de plus ancien. Pour disposer d’une interface graphique, exécutez Grafana sur le même serveur et configurez une data source Loki vers http://127.0.0.1:3100.. Les logs de conteneurs nécessitent une autre source : Alloy détecte les conteneurs Docker en cours d’exécution et les suit, comme dans l’exemple de démarrage de Loki. Sur un cluster k3s à un seul nœud sur un VPS, cette tâche se déplace vers le répertoire des logs des pods écrit par kubelet.

Rétention : choisissez le moment où vos journaux sont supprimés

Presque personne ne choisit une durée de rétention avant que le disque soit plein. Le choix se fait alors à 3 heures du matin, avec le service à l’arrêt. Décidez-la dès le premier jour en répondant à deux questions : jusqu’à quelle date consultez-vous réellement les journaux, et que devez-vous encore conserver lors de l’analyse d’un incident le mois prochain ? Pour un serveur unique, une durée de 14 à 30 jours répond généralement aux deux besoins.

Loki ne supprime absolument rien tant que vous n’avez pas activé le compactor. La rétention est désactivée par défaut. Cela surprend les utilisateurs dont le volume s’est rempli alors que retention_period restait dans la configuration sans aucun effet.

limits_config:
  retention_period: 744h

compactor:
  working_directory: /loki/retention
  compaction_interval: 10m
  retention_enabled: true
  retention_delete_delay: 2h
  retention_delete_worker_count: 150
  delete_request_store: filesystem

744h correspondent à 31 jours. Quatre règles documentées régissent ce bloc :

  • La rétention est appliquée par le compactor, et la documentation de Grafana recommande d’exécuter le compactor avec une seule instance. Sur un VPS unique, cela se fait automatiquement.
  • La durée de rétention minimale est de 24h, et la rétention ne fonctionne que lorsque la période d’indexation est de 24h. L’exemple schema_config utilise déjà period: 24h ; ne modifiez pas ce paramètre.
  • delete_request_store est requis lorsque retention_enabled est défini sur true. Il indique le store qui conserve les demandes de suppression. Sur un nœud unique utilisant un système de fichiers, il correspond donc à object_store: filesystem, déjà présent dans le schéma.
  • Les chunks sont d’abord marqués, puis supprimés après retention_delete_delay, soit 2h ici. L’espace libre revient donc plus tard que ne le laisse penser la politique. Ne jugez pas le réglage en consultant df seulement cinq minutes après un reload.

OpenSearch supprime des index entiers, et non des lignes individuelles. C’est pourquoi les index de journaux sont créés chaque jour. Une politique ISM fait passer un index par plusieurs états, puis le supprime lorsqu’il est assez ancien. Un ism_template applique la politique aux nouveaux index, afin que vous n’ayez pas à vous en souvenir.

Politique ISM qui supprime les index de journaux après 14 jours
{
  "policy": {
    "description": "delete log indexes after 14 days",
    "default_state": "hot",
    "states": [
      {
        "name": "hot",
        "actions": [],
        "transitions": [
          { "state_name": "delete", "conditions": { "min_index_age": "14d" } }
        ]
      },
      {
        "name": "delete",
        "actions": [ { "delete": {} } ],
        "transitions": []
      }
    ],
    "ism_template": { "index_patterns": ["logs-*"], "priority": 100 }
  }
}

Créez-la avec une requête PUT vers _plugins/_ism/policies/logs-retention. Le template s’applique aux index créés après l’existence de la politique. Tout ce qui se trouve déjà sur le disque doit donc recevoir la politique manuellement.

Quel que soit le système utilisé, une durée de rétention n’est efficace que si elle s’accompagne d’un contrôle de l’espace libre. Supprimer les journaux après 14 jours ne vous aidera pas si 10 jours de journaux remplissent déjà le volume. Associez donc la politique à la surveillance de l’état du disque sur un VPS et à une alerte lorsque l’espace utilisé atteint 80 %.

Espace disque par Go de journaux

La réponse exacte dépend de vos lignes et de vos champs. Mesurez donc la consommation sur vos propres données au lieu de vous fier à un ratio publié. Les mécanismes sont suffisamment différents pour permettre de prévoir la tendance. OpenSearch et Elasticsearch écrivent un index inversé pour chaque champ indexé, en plus du document stocké. Les données écrites sur le disque occupent donc plus d’espace que le texte brut, et chaque replica multiplie cette consommation. Sur un nœud unique, définissez le nombre de replicas sur 0, car un replica shard sur le même nœud ne peut pas survivre à la défaillance de ce nœud. Le laisser à 1 double l’espace disque et maintient définitivement l’état de santé du cluster à yellow. Loki écrit des chunks compressés ainsi qu’un petit index de labels. Son empreinte disque suit donc la taille compressée des lignes.

sudo du -sh /var/lib/docker/volumes/loki-data/_data
curl -k -u admin:<password> "https://localhost:9200/_cat/indices?v&h=index,docs.count,store.size"

Exécutez la commande correspondant à votre cas pendant deux jours consécutifs. La différence correspond à votre croissance quotidienne. Multipliez-la par le nombre de jours de rétention, ajoutez environ 30 % de marge pour la compaction et les merges, puis comparez le résultat au volume disponible. Si l’espace est insuffisant, réduisez la rétention avant d’acheter un disque supplémentaire, car un volume plus grand ne fait que repousser le même problème de quelques semaines.

Ce qui casse en premier sur une petite machine

La mémoire vient en premier. Le tueur OOM (out of memory) du kernel sélectionne un processus volumineux, et le plus gros processus sur une machine de logs est la JVM. journalctl -k | grep -i "killed process" affiche l’arrêt forcé avec le nom du processus entre crochets. Le processus tué n’est pas toujours la stack de logs : sshd ou votre base de données peuvent être sélectionnés à la place. C’est ainsi qu’une expérimentation de logging peut mettre hors service l’application dont vous vouliez consulter les logs. Définissez des plafonds explicites pour les conteneurs afin que l’échec se produise à l’endroit choisi, ce que permettent les limites mémoire dans Docker Compose.

Le disque vient ensuite, et les moteurs de recherche échouent d’une manière spécifique et reconnaissable. Elasticsearch et OpenSearch surveillent l’utilisation du disque à plusieurs niveaux. Le low watermark est fixé à 85 % et le high watermark à 90 %. Au flood stage de 95 %, chaque index dont un shard se trouve sur ce nœud reçoit le bloc index.blocks.read_only_allow_delete, puis les écritures échouent avec blocked by: [FORBIDDEN/12/index read-only / allow delete (api)]. Le bloc est supprimé lorsque l’utilisation repasse sous le high watermark. Libérez d’abord de l’espace, puis supprimez le bloc manuellement uniquement s’il persiste.

curl -k -u admin:<password> -X PUT "https://localhost:9200/_all/_settings" \
  -H 'Content-Type: application/json' \
  -d '{"index.blocks.read_only_allow_delete": null}'

Loki échoue plus discrètement. Il ne passe pas en mode read-only. Un volume plein se manifeste donc par des pushes en échec chez l’émetteur et des trous dans les résultats de requête. Le problème de cardinalité se traduit par une augmentation lente de la mémoire plutôt que par une erreur. Surveillez régulièrement la taille du répertoire chunks, et non après un incident.

Le dernier type d’échec consiste à injecter les mauvaises données. Un système de logs n’est pas un système de métriques : échantillonner la charge CPU toutes les 10 secondes et la stocker sous forme de texte coûte cher à conserver et rend les graphiques peu pratiques. Cette tâche revient plutôt à un serveur de supervision Zabbix sur Ubuntu 24.04. Les exceptions applicatives nécessitent un regroupement, une déduplication et une vue de stack trace. C’est le rôle de un outil de suivi des erreurs auto-hébergé. Savoir que le site est indisponible est encore une autre tâche, à laquelle répond une page de disponibilité et de statut telle qu’Uptime Kuma. Réservez le système de logs aux lignes de texte qu’une personne doit lire.

FAQ

Ai-je besoin d’Elasticsearch pour rechercher dans les journaux de mon serveur ?

Pas pour un ou deux serveurs. journalctl filtre déjà par unité, priorité, boot et plage horaire, et les fichiers alternés répondent à grep et zgrep. Un cluster de recherche justifie sa consommation mémoire lorsque vous avez de nombreuses machines, lorsque vous devez effectuer simultanément une recherche en texte libre sur toutes ces machines ou lorsque plusieurs personnes ont besoin d’une interface partagée. En deçà, journald avec une limite de taille et une durée de conservation fournit le même service sans RAM supplémentaire.

De combien de RAM ai-je besoin pour gérer mes journaux en auto-hébergement ?

Utilisez les chiffres publiés par chaque projet plutôt qu’une règle générale. Loki et Alloy sont des programmes Go qui ne nécessitent pas de réserver un heap à l’avance, et Grafana documente Loki en mode monolithique jusqu’à environ 20GB par jour. Le fichier compose d’exemple d’OpenSearch définit un heap de 512 MB pour une démonstration et de 2 GB dans son exemple de production. Elastic indique que le heap doit rester inférieur ou égal à 50% de la mémoire totale : un heap de 2 GB nécessite donc une machine de 4 GB avant même d’ajouter Kibana. La documentation de Logstash recommande à elle seule au moins 4GB de heap. Ces valeurs correspondent à des configurations documentées, pas à des benchmarks. Mesurez donc votre propre charge avant de dimensionner votre offre.

Quelle est la différence réelle entre Loki et OpenSearch pour les journaux ?

Le modèle d’indexation. Loki indexe uniquement les labels et conserve le contenu des journaux sous forme de blocs compressés analysés au moment de la requête. Les écritures sont donc peu coûteuses, mais les requêtes larges coûtent davantage. OpenSearch indexe le contenu des champs. La recherche en texte intégral arbitraire est donc rapide, mais l’index consomme de la mémoire et du disque. Choisissez Loki lorsque vous connaissez le service et la plage horaire concernés. Choisissez OpenSearch lorsque vous devez rechercher du texte que vous ne pouvez pas prévoir à l’avance.

Combien de temps dois-je conserver les journaux sur un VPS ?

Définissez la durée avant que le disque ne l’impose à votre place. Configurez-la à un seul endroit par système : MaxRetentionSec= et SystemMaxUse= pour journald, retention_period avec le compactor activé pour Loki, et une règle ISM avec min_index_age pour OpenSearch. Pour la plupart des configurations sur un seul serveur, 14 à 30 jours couvrent le débogage et l’analyse des incidents. Tout ce qui doit être conservé plus longtemps doit être copié hors de la machine, car un journal conservé uniquement sur le serveur qui est tombé en panne ne constitue pas un enregistrement.

Promtail est-il toujours la solution à utiliser pour envoyer les journaux vers Loki ?

Non. Promtail est arrivé en fin de vie le 2 March 2026, et Grafana Alloy le remplace. L’exemple d’installation Docker fourni par Loki inclut désormais une configuration Alloy, et Grafana fournit un convertisseur qui transforme une configuration Promtail existante en syntaxe Alloy. Une installation Promtail existante continue de fonctionner, mais ne reçoit plus de correctifs. Traitez donc la migration comme une opération de maintenance plutôt que comme une mise à niveau que vous pourriez repousser indéfiniment.

#logging#loki#opensearch#journald#supervision