Docker Monitoring mit Prometheus

Aus Laub-Home Wiki

Diese Anleitung beschäftigt sich mit der meist verbreitetsten Methode ein Monitoring für Docker und natürlich auch den Host einzurichten. Warum man das braucht, ganz klar um zu sehen, wie es dem Host nach dem Deployment von euren Containern geht und zu sehen, wieviel Ressourcenhunger die einzelnen Container mit sich bringen. So sieht man auch ob ein Host ausgelastet ist, oder ob gar noch mehr Container auf ihm laufen können. Ein proaktives Alerting sorgt dafür, das man rechtzeitig informiert wird, sollte irgendeine Ressource ausgehen (RAM, CPU, Storage). Für dieses Monitoring wird als Basis Prometheus verwendet, welches die Host Informationen durch den node-exporter und die docker Informationen durch Googles cAdvisor bekommt. Für hübsche Grafiken und ein Alerting auf diese sorgt dann grafana. Wir bauen uns das Ganze hier via Docker-Compose Projekt zusammen und setzen in Grafana dann ein kleines Dashboard ein, das ich mir zusammengeklickt habe. Das Alerting geschieht dann via E-Mail. Auch hier nutze ich wieder den NGINX SSL Reverse Proxy für Docker Container um Grafana sicher nach außen freizugeben. Zusätzlich kann man seine Webseiten (sogar die SSL Zertifikate) mittel blackbox-exporter überwachen und in Grafana einbinden.


Vorbereitung

Zuerst legen wir den Compose Projekt Ordner an und springen in Ihn hinein:

mkdir -p /opt/monitoring/data/prometheus
cd /opt/monitoring

Dann brauchen wir die prometheus Konfigurationsdatei, welche sich mit den beiden Daten Crawlern (node-exporter und cAdvisor) verbindet. einfach die Datei mit untenstehendem Inhalt anlegen: /opt/monitoring/data/prometheus/prometheus.yml

global:
  scrape_interval: 15s
  evaluation_interval: 15s
  external_labels:
      monitor: 'vs'
rule_files:
scrape_configs:
  - job_name: 'nodeexporter'
    static_configs:
      - targets: ['nodeexporter:9100']

  - job_name: 'cadvisor'
    static_configs:
      - targets: ['cadvisor:8080']

Nun richten wir einen vHost für den NGINX SSL Reverse Proxy für Docker Container ein:

Ich nutze hierfür eine eigene Subdomain: monitoring.domain.tld

Also legen wir eine Konfigdatei hierzu an:

/opt/nginxproxy/data/nginx/conf/monitoring.domain.tld.conf

server {
  listen 80;
  listen [::]:80;
  server_name monitoring.domain.tld;

  return 301 https://$host$request_uri;
}
server {
  listen 443 ssl;
  listen [::]:443 ssl;
  server_name monitoring.domain.tld;

  ssl_certificate /etc/letsencrypt/live/monitoring.domain.tld/fullchain.pem;
  ssl_certificate_key /etc/letsencrypt/live/monitoring.domain.tld/privkey.pem;

  include /etc/nginx/conf.d/includes/site-defaults.conf;
  include /etc/nginx/conf.d/includes/cert_bot.conf;
  expires $expires;

  location / {
      proxy_pass http://127.0.0.1:8070/;
      proxy_set_header Host $http_host;
      proxy_set_header X-Real-IP $remote_addr;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header X-Forwarded-Proto $scheme;
      client_max_body_size 0;
      #include /etc/nginx/conf.d/includes/proxy_cache.conf;
  }
  # security headers
  add_header X-Robots-Tag none;
  add_header Strict-Transport-Security "max-age=15768000;";
  add_header X-Content-Type-Options nosniff;
  add_header X-XSS-Protection "1; mode=block";
  add_header X-Download-Options noopen;
  add_header X-Frame-Options "sameorigin";
  add_header X-Permitted-Cross-Domain-Policies none;
  add_header Referrer-Policy strict-origin;
}

Nun generieren wir das SSL Zertifikat.

cd /opt/nginxproxy
echo "monitoring.domain.tld" >> domains.txt
./generate-certs.sh

Danach sollte der NGINX mit der neuen vhost online sein.

Docker Compose Projekt

Nun legen wir die Konfigurationen für das Compose Projekt an. Im .env File geben wir an, das der Interne Port 3000 nach außen an localhost Port 8070 gebunden wird.

/opt/monitoring/.env

# Config File for Monitoring Application

# Port Configuration
INT_PORT=3000
BIND_TO=127.0.0.1:8070

# Timezone
TZ=Europe/Berlin

In unserer Compose Projekt Datei passiert folgendes:

  • Wir starten den node-exporter, welcher die wichtigen Dateisysteme read only gemountet und konfiguriert bekommt.
  • Das selbe Spiel bei cAdvisor
  • Prometheus wird mit der vorhin angelegten Konfigurationsdatei anschließend gestartet
  • Grafana bekommt noch ein persistentes Volume und die Environment Variablen für den SMTP Server
  • Das Label dient dazu, das Watchtower automatisch aktualisiert

Also einfach die Datei mit dem folgenden Inhalt anlegen

/opt/monitoring/docker-compose.yml

version: '3.7'

services:
  prometheus: 
    image: prom/prometheus:latest
    depends_on:
      - nodeexporter
      - cadvisor
    volumes:
      - data_monitoring_prometheus:/prometheus
      - ./data/prometheus/prometheus.yml:/etc/prometheus/prometheus.yml
    restart: always
    environment:
      TZ: ${TZ}
    labels:
        com.centurylinklabs.watchtower.enable: "true"
    networks:
      backend-mo:
        aliases:
          - prometheus

  nodeexporter:
    image: prom/node-exporter:latest
    restart: always
    volumes:
      - /proc:/host/proc:ro
      - /sys:/host/sys:ro
      - /:/rootfs:ro
    command:
      - '--path.procfs=/host/proc'
      - '--path.sysfs=/host/sys'
      - '--path.rootfs=/rootfs'
      - '--collector.filesystem.ignored-mount-points="^(/rootfs|/host|)/(sys|proc|dev|host|etc)($$|/)"'
      - '--collector.filesystem.ignored-fs-types="^(sys|proc|auto|cgroup|devpts|ns|au|fuse\.lxc|mqueue)(fs|)$$"'
    environment:
      TZ: ${TZ}
    labels:
        com.centurylinklabs.watchtower.enable: "true"
    networks:
      backend-mo:
        aliases:
          - nodeexporter

  cadvisor:
    image: gcr.io/google-containers/cadvisor:latest
    restart: always
    volumes:
      - /:/rootfs:ro
      - /var/run:/var/run:rw
      - /sys:/sys:ro
      - /var/lib/docker/:/var/lib/docker:ro
    environment:
      TZ: ${TZ}
    command:
      - --housekeeping_interval=15s
      - --global_housekeeping_interval=15s  
    labels:
        com.centurylinklabs.watchtower.enable: "true"
    networks:
      backend-mo:
        aliases:
          - cadvisor

  renderer:
    image: grafana/grafana-image-renderer:latest
    restart: always
    ports:
      - 8081
    environment:
      ENABLE_METRICS: 'true'
    labels:
        com.centurylinklabs.watchtower.enable: "true"
    networks:
      backend-mo:
        aliases:
          - renderer

  grafana:
    image: grafana/grafana:latest
    depends_on:
      - prometheus
    ports:
      - ${BIND_TO}:${INT_PORT}
    restart: always
    volumes:
      - data_monitoring_grafana:/var/lib/grafana
    user: "0" # USER ID des Docker Users anpassen
    environment:
      - TZ= ${TZ}
      - GF_SMTP_ENABLED=true
      - GF_SMTP_HOST=mx.yourdomain.tld:465
      - GF_SMTP_USER=monitoring@yourdomain.tld
      - GF_SMTP_PASSWORD=MAILLPASSWORD
      - GF_SMTP_FROM_ADDRESS=monitoring@yourdomain.tld
      - GF_RENDERING_SERVER_URL=http://renderer:8081/render
      - GF_RENDERING_CALLBACK_URL=http://grafana:3000/
      - GF_LOG_FILTERS=rendering:debug
    labels:
        com.centurylinklabs.watchtower.enable: "true"
    networks:
      frontend-mo:
      backend-mo:
        aliases:
          - grafana

volumes:
  data_monitoring_grafana:
  data_monitoring_prometheus:

networks:
  frontend-mo:
    driver: bridge
    driver_opts:
      com.docker.network.bridge.name: br-monitoringfe
  backend-mo:
    driver: bridge
    driver_opts:
      com.docker.network.bridge.name: br-monitoringbe

Zu guter Letzt deployen wir unseren Monitoring Stack:

cd /opt/monitoring
docker-compose up -d

Konfiguration Grafana

Nach dem alles gestartet wurde sollte der Aufruf unserer URL, den Grafana Login zeigen:

  • https://monitoring.domain.tld

Hier loggen wir uns mit dem Standard Benutzer und Passwort admin / admin ein und werden direkt aufgefordert das Kennwort zu ändern. Machen und Merken ;-)

Der Nächste schritt ist es Prometheus als Datenquelle einzurichten:

1. Add Data Source
2. Prometheus auswählen
3. als URL: http://prometheus:9090

Save & Test und fertig. Nun ist alles wie gewünscht konfiguriert. Ihr könnt nun ein eigenes Dashboard bauen oder, ein fertiges herunterladen. Zu empfehlen wäre hier auf jeden Fall folgendes für den Node-Exporter:

Einfach auf Dashboards - Manage gehen und bei Import die Dashboard Nummer eingeben. Es gibt unter https://grafana.com/grafana/dashboards eine Ganze Menge an Dashboards, auch für Docker. Ich habe allerdings ein eigenes zusammengeklickt.

Grafana Dashboard


Ich habe mir ein eigenes Grafana Dashboard für Docker und System mit Alerting auf RAM, CPU, LOAD und Festplatte gebaut. Dies stelle ich hier zur Verfügung. Es sieht dann in etwa so aus wie in den nachfolgenden Screenshots:

Für den Dashboard Import kann entweder die Datei heruntergeladen werden, oder Untenstehendes via copy and paste genutzt eingefügt werden.

Download: Datei:Dashboard-by-ala.json

Copy&Paste: Grafana Docker and System Monitoring Dashboard

Webseiten Monitoring

Möchte man zusätzlich noch seine Webseiten mit Prometheus und Grafana überwachen, braucht man noch zusätzlich den blackbox_exporter. Auch diesen gibt es als Docker Image und muss nur in unser Compose Projekt eingefügt werden. Doch als erstes legen wir die Konfigurationsdatei hierfür an:

mkdir /opt/monitoring/data/blackbox/

/opt/monitoring/data/blackbox/blackbox.yml

modules:
  http_2xx:
    prober: http
    http:
      preferred_ip_protocol: "ipv4"
  http_post_2xx:
    prober: http
    http:
      method: POST
      preferred_ip_protocol: "ipv4"

nun binden wir den blackbox-exporter in unser bestehendes docker-compose.yml

... depends_on - blackbox hinzufügen

services:
  prometheus: 
    image: prom/prometheus:latest
    depends_on:
      - nodeexporter
      - cadvisor
      - blackbox


... Nach dem node-exporter

  blackbox:
    image: prom/blackbox-exporter:latest
    restart: always
    volumes:
      - ./data/blackbox/blackbox.yml:/etc/blackbox_exporter/config.yml
    environment:
      TZ: ${TZ}
    labels:
        com.centurylinklabs.watchtower.enable: "true"
    networks:
      backend-mo:
        aliases:
          - blackbox
          
... vor cAdvisor

Das war es schon. nun einfach wie immer das Projekt neu deployen:

docker-compose up -d

In Grafana selbst habe ich folgendes Dashboard benutzt was ohne große Anpassungen funktioniert:

Wenn nun alles passt, solltet ihr folgendes sehen:

Man kann dann noch Alerts einrichten, ganz wie man möchte.

Hohe CPU Last durch cAdvisor

Bei mir kam es durch cAdvisor zu einer sehr hohen CPU Last durch den Prozess. top zeigte fast dauerhaft 10-20% CPU Auslastung an. Nachdem ich im docker-compose.yml die beiden Parameter --housekeeping_interval=15s --global_housekeeping_interval=15sübergeben habe ist die Last auf 1-3% gesunken. Es gibt noch mehr Parameter, die man übergeben kann. Das docker-compose.yml sollte dann wie folgte aussehen:

...

  cadvisor:
    #image: google/cadvisor:latest
    image: gcr.io/google-containers/cadvisor:latest
    restart: always
    volumes:
      - /:/rootfs:ro
      - /var/run:/var/run:rw
      - /sys:/sys:ro
      - /var/lib/docker/:/var/lib/docker:ro
    environment:
      TZ: ${TZ}
    command:
      - --housekeeping_interval=15s
      - --global_housekeeping_interval=15s
      #- --allow_dynamic_housekeeping=true
      #- --disable_metrics=disk,tcp,udp
      #- --docker_only
    labels:
        com.centurylinklabs.watchtower.enable: "true"
    networks:
      backend-mo:
        aliases:
          - cadvisor

...

Quellen