Implement metrics with Grafana and Prometheus

This commit adds two services, `grafana` and `prometheus`, and sets up
some existing services (`dovecot` and `prosody`) to expose metrics into
Grafana. In addition, systemd services have been added to facilitate
registering metrics for services into Prometheus, as well as
automatically provisioning Grafana dashboards based on static JSON
representations.

This work will continue to evolve as more services gain proper Grafana
dashboards, and Loki is also integrated for access to the systemd
journal.
This commit is contained in:
Alex Palaistras 2022-04-25 20:12:06 +01:00
parent 4aba8f73c2
commit 011650105b
24 changed files with 179 additions and 5 deletions

View File

@ -20,6 +20,8 @@ ignition:
- local: service/navidrome/spec.ign
- local: service/rclone/spec.ign
- local: service/hugo/spec.ign
- local: service/prometheus/spec.ign
- local: service/grafana/spec.ign
- local: private/spec.ign
passwd:

View File

@ -21,6 +21,8 @@ ignition:
- local: service/navidrome/spec.ign
- local: service/rclone/spec.ign
- local: service/hugo/spec.ign
- local: service/prometheus/spec.ign
- local: service/grafana/spec.ign
- local: private/spec.ign
passwd:

View File

@ -23,6 +23,8 @@ ignition:
- local: service/coturn/spec.ign
- local: service/rclone/spec.ign
- local: service/hugo/spec.ign
- local: service/prometheus/spec.ign
- local: service/grafana/spec.ign
passwd:
users:
@ -117,6 +119,14 @@ systemd:
[Service]
Environment=UPSTREAM_HOST=writefreely UPSTREAM_PORT=8080
- name: nginx-proxy-http@metrics.localhost.service
enabled: true
dropins:
- name: grafana-upstream.conf
contents: |
[Service]
Environment=UPSTREAM_HOST=grafana UPSTREAM_PORT=8080
- name: letsencrypt-dns-register@localhost.service
enabled: true
dropins:

View File

@ -0,0 +1,5 @@
service stats {
inet_listener http {
port = 9900
}
}

View File

@ -1,7 +1,8 @@
[Unit]
Description=Dovecot POP3/IMAP Server
Wants=container-build@%N.service container-volume@%N.service mariadb.service rspamd.service
Wants=container-build@%N.service container-volume@%N.service mariadb.service rspamd.service grafana-dashboard@dovecot.service
After=container-build@%N.service container-volume@%N.service mariadb.service rspamd.service
Before=grafana-dashboard@dovecot.service
[Service]
Type=notify

View File

@ -0,0 +1,3 @@
[Unit]
Wants=prometheus-service-register@dovecot:9900.service
After=prometheus-service-register@dovecot:9900.service

View File

@ -0,0 +1,2 @@
FROM docker.io/grafana/grafana:8.5.0
COPY container/config /etc/grafana

View File

@ -0,0 +1,15 @@
[paths]
# Folder used for static provisioning of dependencies.
provisioning = /etc/grafana/provisioning
[server]
# The HTTP port to use.
http_port = 8080
[log]
# Only log to standard output.
mode = console
[analytics]
# Disable anonymous usage collection.
reporting_enabled = false

View File

@ -0,0 +1,10 @@
# Service dashboards provisioned by services.
apiVersion: 1
providers:
- name: 'Services'
folder: 'Services'
type: file
disableDeletion: true
allowUiUpdates: false
options:
path: /var/lib/grafana/dashboards

View File

@ -0,0 +1,7 @@
apiVersion: 1
datasources:
- name: Prometheus
type: prometheus
url: http://prometheus:9090
isDefault: true
editable: false

12
service/grafana/spec.bu Normal file
View File

@ -0,0 +1,12 @@
variant: fcos
version: 1.3.0
storage:
trees:
- path: /etc/coreos-home-server/grafana
local: service/grafana/
- path: /etc/systemd/system
local: service/grafana/systemd/
systemd:
units:
- name: grafana.service
enabled: true

View File

@ -0,0 +1,16 @@
[Unit]
Description=Register Grafana Dashboard for %I
Wants=grafana.service
After=grafana.service
ConditionPathExists=%E/coreos-home-server/%i/service/%p.json
[Service]
Type=oneshot
RemainAfterExit=true
SyslogIdentifier=%N
ExecStartPre=/bin/podman exec grafana mkdir -p /var/lib/grafana/dashboards
ExecStart=/bin/podman cp %E/coreos-home-server/%i/service/%p.json grafana:/var/lib/grafana/dashboards/%i.json
ExecStop=/bin/podman exec grafana rm -f /var/lib/grafana/dashboards/%i.json
[Install]
WantedBy=multi-user.target

View File

@ -0,0 +1,17 @@
[Unit]
Description=Grafana Visualization and Analytics
Wants=container-build@%N.service container-volume@%N.service prometheus.service
After=container-build@%N.service container-volume@%N.service prometheus.service
[Service]
Type=notify
NotifyAccess=all
SyslogIdentifier=%N
Restart=on-failure
Environment=PODMAN_SYSTEMD_UNIT=%n
ExecStart=/bin/podman run --replace --name %N --net internal --sdnotify=conmon --volume %N:/var/lib/%N:z localhost/%N:latest
ExecStop=/bin/podman stop --ignore --time 10 %N
ExecStopPost=/bin/podman rm --ignore --force %N
[Install]
WantedBy=multi-user.target

View File

@ -160,7 +160,7 @@ virtual_mailbox_domains = mysql:/etc/postfix/mysql-domains.cf
virtual_uid_maps = static:5000
virtual_gid_maps = static:5000
# Pass messages through 'opendkim' and 'rmilter'.
# Pass messages through 'rspamd'.
smtpd_milters = ${POSTFIX_MAIL_MILTER_PATH}
milter_protocol = 6
milter_mail_macros = i {mail_addr} {client_addr} {client_name} {auth_authen}

View File

@ -0,0 +1,2 @@
FROM docker.io/prom/prometheus:v2.35.0
COPY container/config /etc/prometheus

View File

@ -0,0 +1,6 @@
scrape_configs:
- job_name: prometheus
honor_labels: true
file_sd_configs:
- files:
- /etc/prometheus/service.d/*.yml

View File

@ -0,0 +1,4 @@
# Service Discovery Configuration for Prometheus
Any file with an extension of `.yml` placed in this directory will be included as part of the
Prometheus service discovery configuration.

View File

@ -0,0 +1,3 @@
# Service discovery configuration for dynamic host.
- targets:
- "${SERVICE_HOST}"

View File

@ -0,0 +1,12 @@
variant: fcos
version: 1.3.0
storage:
trees:
- path: /etc/coreos-home-server/prometheus
local: service/prometheus/
- path: /etc/systemd/system
local: service/prometheus/systemd/
systemd:
units:
- name: prometheus.service
enabled: true

View File

@ -0,0 +1,19 @@
[Unit]
Description=Register Prometheus Metrics for %I
Wants=prometheus.service
After=prometheus.service
[Service]
Type=oneshot
RemainAfterExit=true
SyslogIdentifier=%N
Environment=SERVICE_HOST=%i
Environment=PROMETHEUS_CONF=%E/coreos-home-server/prometheus/service/%p.yml.template
ExecStart=/bin/sh -c "envsubst '$SERVICE_HOST' < ${PROMETHEUS_CONF} > /tmp/%i.yml"
ExecStartPost=/bin/sh -c 'podman cp --archive=false /tmp/%i.yml prometheus:/etc/prometheus/service.d/%i.yml && rm -f /tmp/%i.yml'
ExecStartPost=/bin/podman exec prometheus sh -c 'kill -HUP $(pidof prometheus)'
ExecStop=/bin/podman exec --user=root prometheus rm -f /etc/prometheus/service.d/%i.yml
ExecStopPost=/bin/podman exec prometheus sh -c 'kill -HUP $(pidof prometheus)'
[Install]
WantedBy=multi-user.target

View File

@ -0,0 +1,20 @@
[Unit]
Description=Prometheus Systems and Service Monitoring
Wants=container-build@%N.service container-volume@%N.service
After=container-build@%N.service container-volume@%N.service
[Service]
Type=notify
NotifyAccess=all
SyslogIdentifier=%N
Restart=on-failure
Environment=PODMAN_SYSTEMD_UNIT=%n
ExecStart=/bin/podman run --replace --name %N --net internal --sdnotify=conmon \
--volume %N:/%N:z \
--volume %N-service:/etc/%N/service.d:z \
localhost/%N:latest
ExecStop=/bin/podman stop --ignore --time 10 %N
ExecStopPost=/bin/podman rm --ignore --force %N
[Install]
WantedBy=multi-user.target

View File

@ -68,6 +68,7 @@ modules_enabled = {
-- HTTP modules
"websocket"; -- XMPP over WebSockets
"http_openmetrics"; -- Enables metrics collection in OpenMetrics-compatible format.
-- Other specific functionality
"conversejs"; -- Web-based frontend for XMPP
@ -169,7 +170,9 @@ turn_external_secret = os.getenv("PROSODY_TURN_SECRET") or ""
-- Uncomment to enable statistics
-- For more info see https://prosody.im/doc/statistics
-- statistics = "internal"
statistics = "internal"
statistics_interval = "manual"
openmetrics_allow_cidr = "10.89.0.0/16"
-- Certificates
-- Every virtual host and component needs a certificate so that clients and

View File

@ -0,0 +1,3 @@
[Unit]
Wants=prometheus-service-register@prosody:5280.service
After=prometheus-service-register@prosody:5280.service

View File

@ -1,7 +1,7 @@
[Unit]
Description=Prosody XMPP server
Wants=container-build@%N.service container-volume@%N.service dovecot.service
After=container-build@%N.service container-volume@%N.service dovecot.service
Wants=container-build@%N.service container-volume@%N.service dovecot.service grafana-dashboard@prosody.service
After=container-build@%N.service container-volume@%N.service dovecot.service grafana-dashboard@prosody.service
[Service]
Type=notify