Monitoring et Logging Docker
MONITORING
Section titled “MONITORING”Des métriques très dynamiques à surveiller
Section titled “Des métriques très dynamiques à surveiller”Conteneur:├─ CPU Usage (%)├─ Memory Usage (MB/GB)├─ Memory Limit├─ Network I/O (MB/s)├─ Disk I/O (MB/s)└─ Nombre de processus
Cluster Swarm:├─ Nombre de nœuds actifs├─ Services en état "Running"├─ Réplicas démarrés vs désirés└─ Ressources disponibles par nœudSolutions de Monitoring
Section titled “Solutions de Monitoring”2.1 Docker Stats (Natif - Basique)
Section titled “2.1 Docker Stats (Natif - Basique)”# Voir les stats en temps réeldocker stats
# Format personnalisédocker stats --format "table {{.Container}}\t{{.CPUPerc}}\t{{.MemUsage}}"
# Stats d'un service Swarmdocker service ps myapp --format "table {{.Name}}\t{{.Node}}\t{{.CurrentState}}"cAdvisor (Google - Simple)
Section titled “cAdvisor (Google - Simple)”Caractéristiques :
- Interface web basique
- Métriques en temps réel
- Historique limité (quelques minutes)
- Export vers Prometheus
- Se déploie en mode global (1 instance par nœud)
Interface : http://localhost:8080
Prometheus + Grafana (Standard Industrie) ⭐
Section titled “Prometheus + Grafana (Standard Industrie) ⭐”Architecture :
┌──────────────┐ ┌─────────────┐ ┌──────────┐│ Containers │────▶│ Prometheus │────▶│ Grafana ││ + cAdvisor │ │ (Métriques)│ │ (UI) │└──────────────┘ └─────────────┘ └──────────┘ │ ▼ ┌──────────────┐ │ Alertmanager │ │ (Alertes) │ └──────────────┘Composants :
- Prometheus : Collecte et stockage des métriques (TSDB)
- Grafana : Visualisation et dashboards
- Alertmanager : Gestion et routage des alertes
- cAdvisor : Export des métriques conteneurs
Exemples de règles d’Alerte
Section titled “Exemples de règles d’Alerte”alert-rules.yml :
groups: - name: container_alerts interval: 30s rules: # Alerte CPU élevé - alert: HighCPUUsage expr: rate(container_cpu_usage_seconds_total[5m]) * 100 > 80 for: 5m labels: severity: warning annotations: summary: "CPU élevé sur {{ $labels.name }}" description: "{{ $labels.name }} utilise {{ $value }}% CPU"
# Alerte Mémoire élevée - alert: HighMemoryUsage expr: (container_memory_usage_bytes / container_spec_memory_limit_bytes) * 100 > 90 for: 5m labels: severity: critical annotations: summary: "Mémoire critique sur {{ $labels.name }}" description: "{{ $labels.name }} utilise {{ $value }}% de sa limite"
# Alerte conteneur down - alert: ContainerDown expr: up == 0 for: 2m labels: severity: critical annotations: summary: "Conteneur {{ $labels.job }} est down" description: "Le conteneur ne répond plus depuis 2 minutes"
# Alerte réplicas insuffisants - alert: ServiceReplicasMismatch expr: docker_swarm_service_replicas_running < docker_swarm_service_replicas_desired for: 5m labels: severity: warning annotations: summary: "Service {{ $labels.service }} manque de réplicas"Dashboards Grafana Recommandés
Section titled “Dashboards Grafana Recommandés”Dashboard ID à importer:├─ 193 : Docker and System Monitoring├─ 11600 : Docker Swarm & Container Overview├─ 893 : Docker & System Monitoring (cAdvisor)└─ 15798 : Docker Swarm Monitoring (complet)Importer un dashboard :
- Grafana → Dashboards → Import
- Entrer l’ID (ex: 11600)
- Sélectionner la source Prometheus
Comparaison Solutions Monitoring
Section titled “Comparaison Solutions Monitoring”| Solution | Complexité | Historique | Alertes | UI | Clustering |
|---|---|---|---|---|---|
| docker stats | ⭐ | ❌ | ❌ | CLI | ✅ |
| cAdvisor | ⭐⭐ | Minutes | ❌ | Basique | ✅ |
| Prometheus+Grafana | ⭐⭐⭐⭐ | ✅ 30j+ | ✅ | Excellente | ✅ |
| Datadog (SaaS) | ⭐⭐ | ✅ Illimité | ✅ | Excellente | ✅ |
| New Relic (SaaS) | ⭐⭐ | ✅ Illimité | ✅ | Excellente | ✅ |
Recommandation : Prometheus + Grafana pour production (gratuit, puissant, standard industrie)
LOGGING
Section titled “LOGGING”Concepts Fondamentaux
Section titled “Concepts Fondamentaux”Types de Logs
Section titled “Types de Logs”Application:├─ stdout/stderr (console)├─ Fichiers dans le conteneur└─ Logs applicatifs structurés (JSON)
Docker:├─ Container logs (docker logs)├─ Docker daemon logs└─ Swarm orchestration logs
Système:├─ Kernel logs (dmesg)├─ System logs (syslog)└─ Audit logsLe Problème avec les Conteneurs
Section titled “Le Problème avec les Conteneurs”Problèmes:├─ Logs éparpillés sur plusieurs nœuds├─ Conteneurs éphémères = perte de logs├─ Volumes de logs énormes└─ Difficile de corréler les événements
Solution: Centralisation des logs├─ Collecter depuis tous les conteneurs├─ Stocker dans un système centralisé├─ Indexer pour recherche rapide└─ Visualiser et analyserArchitecture Générique de Logging
Section titled “Architecture Générique de Logging”┌─────────────┐│ Application │──┐│ (stdout) │ │└─────────────┘ │ │ ┌──────────┐ ┌─────────┐ ┌────────────┐┌─────────────┐ ├───▶│ Collecte │───▶│ Stockage│───▶│Visualisation││ Application │──┘ │ (Agent) │ │ (Index) │ │ (UI) ││ (logs file) │ └──────────┘ └─────────┘ └────────────┘└─────────────┘ │ ▼ ┌──────────────┐ │ Transformation│ │ (Parsing) │ └──────────────┘Composants :
- Collecte : Récupère les logs (Filebeat, Fluentd, Promtail)
- Transformation : Parse et enrichit (Logstash, Fluentd)
- Stockage : Indexe et stocke (Elasticsearch, Loki)
- Visualisation : Interface de recherche (Kibana, Grafana)
Configuration Docker Logging Driver
Section titled “Configuration Docker Logging Driver”Au Niveau du Daemon
Section titled “Au Niveau du Daemon”/etc/docker/daemon.json :
{ "log-driver": "json-file", "log-opts": { "max-size": "10m", "max-file": "3", "labels": "production_status", "env": "os,customer" }}Au Niveau du Conteneur
Section titled “Au Niveau du Conteneur”services: myapp: image: myapp:latest logging: driver: json-file options: max-size: "10m" max-file: "5" labels: "service,environment"Drivers Disponibles
Section titled “Drivers Disponibles”| Driver | Usage | Performance |
|---|---|---|
json-file | Par défaut, fichiers JSON | Moyenne |
syslog | Envoi vers syslog | Bonne |
journald | Systemd journald | Bonne |
fluentd | Envoi vers Fluentd | Moyenne |
gelf | Graylog | Bonne |
local | Optimisé performances | Excellente |
none | Pas de logs | N/A |
Stack EFK (Elasticsearch + Fluentd + Kibana)
Section titled “Stack EFK (Elasticsearch + Fluentd + Kibana)”Architecture
Section titled “Architecture”┌──────────────┐│ Conteneurs ││ (stdout) │└──────┬───────┘ │ ▼┌──────────────┐ ┌──────────────┐ ┌─────────┐│ Fluentd │───▶│Elasticsearch │───▶│ Kibana ││ (Collecte + │ │ (Stockage + │ │ (UI) ││ Transform) │ │ Indexation)│ │ │└──────────────┘ └──────────────┘ └─────────┘Caractéristiques :
- Fluentd : Collecteur léger et flexible
- Elasticsearch : Moteur de recherche full-text distribué
- Kibana : Interface de visualisation puissante
- Ressources : 4-8GB RAM minimum
Configuration Fluentd
Section titled “Configuration Fluentd”fluentd.conf :
<source> @type forward port 24224 bind 0.0.0.0</source>
# Parser les logs JSON<filter docker.**> @type parser key_name log <parse> @type json </parse></filter>
# Enrichir avec des métadonnées<filter docker.**> @type record_transformer <record> hostname "#{Socket.gethostname}" tag ${tag} </record></filter>
# Envoyer vers Elasticsearch<match docker.**> @type elasticsearch host elasticsearch port 9200 logstash_format true logstash_prefix docker flush_interval 5s</match>Configurer les Conteneurs pour Fluentd
Section titled “Configurer les Conteneurs pour Fluentd”services: myapp: image: myapp:latest logging: driver: fluentd options: fluentd-address: localhost:24224 tag: docker.myapp fluentd-async-connect: "true"Stack ELK avec Filebeat
Section titled “Stack ELK avec Filebeat”Architecture
Section titled “Architecture”┌──────────────┐│ Conteneurs ││ (log files) │└──────┬───────┘ │ ▼┌──────────────┐ ┌──────────┐ ┌──────────────┐ ┌────────┐│ Filebeat │───▶│ Logstash │───▶│Elasticsearch │───▶│ Kibana ││ (Collecte) │ │(Transform)│ │ (Stockage) │ │ (UI) │└──────────────┘ └──────────┘ └──────────────┘ └────────┘Différence avec Fluentd :
- Filebeat : Plus léger, spécialisé fichiers
- Logstash : Parsing très puissant mais gourmand
- Ressources : 6-12GB RAM minimum
Configuration Filebeat
Section titled “Configuration Filebeat”filebeat.yml :
filebeat.inputs: # Logs des conteneurs Docker - type: container paths: - '/var/lib/docker/containers/*/*.log' processors: - add_docker_metadata: host: "unix:///var/run/docker.sock"
# Enrichissementprocessors: - add_host_metadata: ~ - add_cloud_metadata: ~
# Output vers Logstashoutput.logstash: hosts: ["logstash:5044"]
# Ou directement vers Elasticsearch (plus simple)# output.elasticsearch:# hosts: ["elasticsearch:9200"]
logging.level: infoConfiguration Logstash
Section titled “Configuration Logstash”logstash.conf :
input { beats { port => 5044 }}
filter { # Parser les logs JSON if [message] =~ /^\{.*\}$/ { json { source => "message" } }
# Parser les timestamps date { match => ["timestamp", "ISO8601"] target => "@timestamp" }
# Extraire des champs depuis les logs grok { match => { "message" => "%{COMBINEDAPACHELOG}" } }
# Nettoyer les champs inutiles mutate { remove_field => ["agent", "ecs", "host"] }}
output { elasticsearch { hosts => ["elasticsearch:9200"] index => "docker-logs-%{+YYYY.MM.dd}" }
# Debug (optionnel) stdout { codec => rubydebug }}Stack PLG (Promtail + Loki + Grafana)
Section titled “Stack PLG (Promtail + Loki + Grafana)”Architecture
Section titled “Architecture”┌──────────────┐│ Conteneurs ││ (stdout) │└──────┬───────┘ │ ▼┌──────────────┐ ┌──────────┐ ┌─────────┐│ Promtail │───▶│ Loki │───▶│ Grafana ││ (Collecte) │ │(Stockage)│ │ (UI) │└──────────────┘ └──────────┘ └─────────┘Philosophie Loki :
- Ne parse PAS les logs (contrairement à ELK)
- Indexe uniquement les labels (metadata)
- Recherche en texte brut très rapide
- Consomme 10× moins de ressources qu’Elasticsearch
- Ressources : 1-2GB RAM seulement
Configuration Loki
Section titled “Configuration Loki”loki-config.yml :
auth_enabled: false
server: http_listen_port: 3100
ingester: lifecycler: ring: kvstore: store: inmemory replication_factor: 1 chunk_idle_period: 15m chunk_retain_period: 30s
schema_config: configs: - from: 2020-10-24 store: boltdb-shipper object_store: filesystem schema: v11 index: prefix: index_ period: 24h
storage_config: boltdb_shipper: active_index_directory: /loki/index cache_location: /loki/cache shared_store: filesystem filesystem: directory: /loki/chunks
limits_config: retention_period: 720h # 30 jours enforce_metric_name: false reject_old_samples: true reject_old_samples_max_age: 168h
chunk_store_config: max_look_back_period: 0s
table_manager: retention_deletes_enabled: true retention_period: 720hConfiguration Promtail
Section titled “Configuration Promtail”promtail-config.yml :
server: http_listen_port: 9080 grpc_listen_port: 0
positions: filename: /tmp/positions.yaml
clients: - url: http://loki:3100/loki/api/v1/push
scrape_configs: # Logs des conteneurs Docker - job_name: docker docker_sd_configs: - host: unix:///var/run/docker.sock refresh_interval: 5s relabel_configs: # Extraire le nom du conteneur - source_labels: ['__meta_docker_container_name'] regex: '/(.*)' target_label: 'container' # Extraire l'image - source_labels: ['__meta_docker_container_image'] target_label: 'image' # Extraire le service Swarm - source_labels: ['__meta_docker_container_label_com_docker_swarm_service_name'] target_label: 'service' # Extraire le nœud - source_labels: ['__meta_docker_container_label_com_docker_swarm_node_id'] target_label: 'node_id' pipeline_stages: # Parser les logs JSON - json: expressions: level: level timestamp: timestamp message: message # Extraire le timestamp - timestamp: source: timestamp format: RFC3339 # Labelliser par niveau - labels: level:Configuration Datasource Grafana
Section titled “Configuration Datasource Grafana”grafana-datasources.yml :
apiVersion: 1
datasources: - name: Loki type: loki access: proxy url: http://loki:3100 isDefault: true jsonData: maxLines: 1000Comparaison des Stacks de Logging
Section titled “Comparaison des Stacks de Logging”| Critère | EFK (Fluentd) | ELK (Filebeat) | PLG (Loki) |
|---|---|---|---|
| Complexité | ⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐ |
| Ressources | 4-8GB RAM | 6-12GB RAM | 1-2GB RAM |
| Parsing | ✅ Puissant | ✅ Très puissant | ❌ Basique |
| Indexation | ✅ Full-text | ✅ Full-text | 🔸 Labels uniquement |
| Vitesse recherche | Rapide | Rapide | Très rapide |
| Coût stockage | Élevé | Élevé | Faible |
| Scalabilité | ✅ Bonne | ✅ Excellente | ✅ Excellente |
| Courbe apprentissage | Moyenne | Difficile | Facile |
| Intégration Grafana | ⚠️ Via plugin | ⚠️ Via plugin | ✅ Native |
Requêtes de Recherche
Section titled “Requêtes de Recherche”Kibana (ELK/EFK)
Section titled “Kibana (ELK/EFK)”# Recherche simplecontainer.name: "webapp"
# Recherche avec wildcardmessage: "error*"
# Combinaison AND/ORcontainer.name: "webapp" AND level: "error"
# Range temporel@timestamp: [now-1h TO now]
# AggrégationCOUNT(container.name) GROUP BY container.nameLoki (LogQL)
Section titled “Loki (LogQL)”# Tous les logs d'un service{service="webapp"}
# Filtrage par niveau{service="webapp"} |= "error"
# Recherche regex{service="webapp"} |~ "error|warning"
# Exclusion{service="webapp"} != "debug"
# Parsing JSON{service="webapp"} | json | level="error"
# Métriques (rate)rate({service="webapp"}[5m])
# Count par containersum(count_over_time({job="docker"}[5m])) by (container)