blumeops/docs/tutorials/replication/observability-stack.md
Erich Blume b0bac91ca9 Fix frontmatter field name for Quartz date display (#158)
## Summary

- Rename `date-modified` -> `modified` in all 80 docs and the `docs-check-frontmatter` task

Quartz's `CreatedModifiedDate` plugin recognizes `modified`, `lastmod`, `updated`, and `last-modified` — but not `date-modified`. The wrong field name caused Quartz to ignore frontmatter dates entirely and fall through to filesystem timestamps (UTC inside Dagger), showing Feb 12 on pages built late on Feb 11 PST.

## Test plan

- [x] `mise run docs-check-frontmatter` passes
- [ ] Kick off docs release after merge — verify rendered dates match frontmatter values

Reviewed-on: https://forge.ops.eblu.me/eblume/blumeops/pulls/158
2026-02-11 16:45:12 -08:00

5.6 KiB

title modified tags
Observability Stack 2026-02-07
tutorials
replication
observability

Building the Observability Stack

Audiences: Replicator

This tutorial walks through deploying metrics, logs, and dashboards for your homelab - because you can't fix what you can't see.

The Stack

A complete observability solution has three pillars:

Component Purpose BlumeOps Uses
Metrics Numeric measurements over time prometheus
Logs Text output from applications loki
Dashboards Visualization and alerting grafana
Collection Gathering and forwarding data alloy

For BlumeOps specifics, see observability.

Step 1: Create Monitoring Namespace

kubectl create namespace monitoring

Step 2: Deploy Prometheus

Prometheus collects and stores metrics.

Using Helm

helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm install prometheus prometheus-community/prometheus \
  --namespace monitoring \
  --set server.persistentVolume.size=10Gi

Or via ArgoCD

Create an Application pointing to a values file in your repo:

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: prometheus
  namespace: argocd
spec:
  project: default
  source:
    repoURL: https://prometheus-community.github.io/helm-charts
    chart: prometheus
    targetRevision: 25.0.0
    helm:
      values: |
        server:
          persistentVolume:
            size: 10Gi
  destination:
    server: https://kubernetes.default.svc
    namespace: monitoring

Verify

kubectl -n monitoring get pods -l app.kubernetes.io/name=prometheus

Step 3: Deploy Loki

Loki aggregates logs (like Prometheus but for logs).

helm repo add grafana https://grafana.github.io/helm-charts
helm install loki grafana/loki-stack \
  --namespace monitoring \
  --set loki.persistence.enabled=true \
  --set loki.persistence.size=10Gi

This also installs Promtail for log collection from pods.

Step 4: Deploy Grafana

Grafana provides dashboards and visualization.

helm install grafana grafana/grafana \
  --namespace monitoring \
  --set persistence.enabled=true \
  --set persistence.size=1Gi \
  --set adminPassword=admin  # Change this!

Configure Data Sources

After installation, add data sources in Grafana UI or via ConfigMap:

apiVersion: v1
kind: ConfigMap
metadata:
  name: grafana-datasources
  namespace: monitoring
  labels:
    grafana_datasource: "1"
data:
  datasources.yaml: |
    apiVersion: 1
    datasources:
    - name: Prometheus
      type: prometheus
      url: http://prometheus-server.monitoring.svc:80
      isDefault: true
    - name: Loki
      type: loki
      url: http://loki.monitoring.svc:3100

Step 5: Access Grafana

Expose via Tailscale:

kubectl -n monitoring port-forward svc/grafana 3000:80 &
tailscale serve --bg --https 3000 http://localhost:3000

Or create an Ingress.

Default credentials: admin / (password you set or retrieve from secret)

Step 6: Add Dashboards

Import community dashboards from grafana.com/grafana/dashboards:

Dashboard ID Shows
Node Exporter Full 1860 Host metrics
Kubernetes Cluster 7249 Cluster overview
Loki Logs 13639 Log exploration

In Grafana: Dashboards > Import > Enter ID

Step 7: Deploy Alloy (Optional)

Grafana Alloy is a unified collector that replaces multiple agents (Promtail, node_exporter, etc.).

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: alloy
  namespace: argocd
spec:
  project: default
  source:
    repoURL: https://grafana.github.io/helm-charts
    chart: alloy
    targetRevision: 0.1.0
    helm:
      values: |
        alloy:
          configMap:
            content: |
              // Alloy configuration here
  destination:
    server: https://kubernetes.default.svc
    namespace: monitoring

BluemeOps uses Alloy on both indri (for host metrics, via roles) and in the cluster (for pod logs and service probes).

What You Now Have

  • Metrics collection and storage (Prometheus)
  • Log aggregation (Loki)
  • Dashboards and visualization (Grafana)
  • Foundation for alerting

Adding Alerts

Configure alerting rules in Prometheus:

groups:
- name: example
  rules:
  - alert: HighMemoryUsage
    expr: node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes < 0.1
    for: 5m
    labels:
      severity: warning
    annotations:
      summary: "High memory usage detected"

And notification channels in Grafana (email, Slack, PagerDuty, etc.).

Next Steps

  • Create custom dashboards for your services
  • Set up alerting for critical conditions
  • Add service-specific metrics exporters

BluemeOps Specifics

BlumeOps' observability setup includes:

  • Prometheus scraping all services via annotations
  • Loki collecting logs from all pods and indri services
  • Custom dashboards for jellyfin, teslamate, and cluster health
  • alloy running on both host and in-cluster

See observability for full details.

Troubleshooting

Problem Solution
No metrics appearing Check Prometheus targets (/targets endpoint)
No logs in Loki Verify Promtail/Alloy is collecting (/ready endpoint)
Dashboard shows no data Check data source configuration and time range
High storage usage Adjust retention settings in Prometheus/Loki