diff options
| author | Paul Buetow <paul@buetow.org> | 2025-12-28 16:29:46 +0200 |
|---|---|---|
| committer | Paul Buetow <paul@buetow.org> | 2025-12-28 16:29:46 +0200 |
| commit | b0abd815be8b147eacc979bb89b7300a716c4f31 (patch) | |
| tree | 6530b86727ffa0e57e523786a2c9541fd8b29d64 /f3s/tempo | |
| parent | 49086b43aeebfd3fdd06cd330cca8130d32e5202 (diff) | |
Add Grafana Tempo distributed tracing with demo application
- Deploy Grafana Tempo in monolithic mode for distributed tracing
- Configure Tempo with OTLP receivers (gRPC:4317, HTTP:4318)
- Set up 10Gi filesystem storage with 7-day retention
- Integrate Tempo datasource in Grafana with traces-to-logs and traces-to-metrics correlation
- Update Grafana Alloy to collect and forward traces
- Add OTLP receiver configuration to alloy-values.yaml
- Configure batch processor for efficient trace forwarding to Tempo
- Patch Alloy service to expose OTLP ports 4317/4318
- Create demo tracing application (frontend, middleware, backend)
- Implement three-tier Python Flask application with OpenTelemetry instrumentation
- Auto-instrument with OpenTelemetry for Flask and requests libraries
- Push Docker images to private registry (registry.lan.buetow.org:30001)
- Deploy via Helm chart with Traefik ingress at tracing-demo.f3s.buetow.org
- Update Grafana configuration in prometheus/persistence-values.yaml
- Add Tempo to additionalDataSources for automatic provisioning
Files added:
- tempo/values.yaml: Tempo Helm chart configuration
- tempo/persistent-volumes.yaml: Storage configuration (10Gi PV/PVC)
- tempo/datasource-configmap.yaml: Grafana datasource with correlations
- tempo/Justfile: Installation automation
- tempo/README.md: Documentation
- tracing-demo/docker/frontend/: Python Flask frontend with OTel
- tracing-demo/docker/middleware/: Python Flask middleware with OTel
- tracing-demo/docker/backend/: Python Flask backend with OTel
- tracing-demo/helm-chart/: Kubernetes deployments, services, ingress
- tracing-demo/docker-image-Justfile: Docker build/push automation
- tracing-demo/Justfile: Helm deployment automation
- tracing-demo/README.md: Documentation
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Diffstat (limited to 'f3s/tempo')
| -rw-r--r-- | f3s/tempo/Justfile | 33 | ||||
| -rw-r--r-- | f3s/tempo/README.md | 182 | ||||
| -rw-r--r-- | f3s/tempo/datasource-configmap.yaml | 47 | ||||
| -rw-r--r-- | f3s/tempo/persistent-volumes.yaml | 31 | ||||
| -rw-r--r-- | f3s/tempo/values.yaml | 76 |
5 files changed, 369 insertions, 0 deletions
diff --git a/f3s/tempo/Justfile b/f3s/tempo/Justfile new file mode 100644 index 0000000..361f5c6 --- /dev/null +++ b/f3s/tempo/Justfile @@ -0,0 +1,33 @@ +# Grafana Tempo deployment automation +# Following the pattern from Loki Justfile + +install: + helm repo add grafana https://grafana.github.io/helm-charts || true + helm repo update + kubectl apply -f persistent-volumes.yaml + helm install tempo grafana/tempo --namespace monitoring -f values.yaml + kubectl apply -f datasource-configmap.yaml + +uninstall: + kubectl delete -f datasource-configmap.yaml || true + helm uninstall tempo --namespace monitoring || true + kubectl delete -f persistent-volumes.yaml || true + +upgrade: + helm upgrade tempo grafana/tempo --namespace monitoring -f values.yaml + kubectl apply -f datasource-configmap.yaml + +status: + kubectl get pods -n monitoring -l app.kubernetes.io/name=tempo + kubectl get svc -n monitoring -l app.kubernetes.io/name=tempo + kubectl get pvc -n monitoring tempo-data-pvc + +logs: + kubectl logs -n monitoring -l app.kubernetes.io/name=tempo --tail=100 -f + +check: + @echo "Checking Tempo readiness..." + kubectl exec -n monitoring $(kubectl get pod -n monitoring -l app.kubernetes.io/name=tempo -o jsonpath='{.items[0].metadata.name}') -- wget -qO- http://localhost:3200/ready + @echo "" + @echo "Checking OTLP ports..." + kubectl exec -n monitoring $(kubectl get pod -n monitoring -l app.kubernetes.io/name=tempo -o jsonpath='{.items[0].metadata.name}') -- netstat -ln | grep -E ':(4317|4318|3200)' diff --git a/f3s/tempo/README.md b/f3s/tempo/README.md new file mode 100644 index 0000000..ee59311 --- /dev/null +++ b/f3s/tempo/README.md @@ -0,0 +1,182 @@ +# Grafana Tempo - Distributed Tracing + +Grafana Tempo deployment for the f3s Kubernetes cluster in monolithic mode. + +## Overview + +- **Deployment Mode**: Monolithic (all components in one process) +- **Storage Backend**: Filesystem (local storage on hostPath) +- **Storage Size**: 10Gi +- **Retention**: 7 days (168h) +- **Namespace**: `monitoring` + +## Components + +- **Tempo**: Distributed tracing backend +- **OTLP Receivers**: Accepts traces via gRPC (4317) and HTTP (4318) +- **Query Frontend**: Query interface on port 3200 +- **Grafana Datasource**: Auto-discovered via ConfigMap label + +## Architecture + +``` +Applications → Alloy (OTLP collector) → Tempo → Grafana +``` + +## Installation + +```bash +just install +``` + +This will: +1. Add Grafana Helm repo and update +2. Create PersistentVolume and PersistentVolumeClaim +3. Install Tempo via Helm +4. Create Grafana datasource ConfigMap + +## Configuration + +### values.yaml + +- Monolithic mode configuration +- OTLP receivers on ports 4317 (gRPC) and 4318 (HTTP) +- Local filesystem storage at `/var/tempo/traces` +- Resource limits: 2Gi memory, 1 CPU + +### persistent-volumes.yaml + +- PV: `tempo-data-pv` at `/data/nfs/k3svolumes/tempo/data` +- PVC: `tempo-data-pvc` (10Gi, ReadWriteOnce) + +### datasource-configmap.yaml + +- Auto-discovered by Grafana sidecar +- Enables traces-to-logs correlation with Loki +- Enables traces-to-metrics correlation with Prometheus +- Enables service graph visualization + +## Grafana Integration + +The datasource is automatically discovered by Grafana through the ConfigMap with label `grafana_datasource: "1"`. + +To access traces in Grafana: +1. Navigate to Explore +2. Select "Tempo" datasource +3. Use Search or TraceQL queries + +### Example TraceQL Queries + +``` +# Find all traces from demo app +{ resource.service.namespace = "tracing-demo" } + +# Find slow requests (>200ms) +{ duration > 200ms } + +# Find errors +{ status = error } + +# Find traces from specific service +{ resource.service.name = "frontend" } +``` + +## Verification + +Check that Tempo is running: +```bash +just status +``` + +Check Tempo readiness and OTLP ports: +```bash +just check +``` + +View logs: +```bash +just logs +``` + +## Sending Traces + +Applications should send traces to Alloy's OTLP receivers: +- gRPC: `alloy.monitoring.svc.cluster.local:4317` +- HTTP: `alloy.monitoring.svc.cluster.local:4318` + +Alloy forwards traces to Tempo at `tempo.monitoring.svc.cluster.local:4317`. + +## Maintenance + +### Upgrade + +```bash +just upgrade +``` + +### Uninstall + +```bash +just uninstall +``` + +### Check Storage Usage + +```bash +kubectl exec -n monitoring $(kubectl get pod -n monitoring -l app.kubernetes.io/name=tempo -o jsonpath='{.items[0].metadata.name}') -- df -h /var/tempo +``` + +## Troubleshooting + +### Tempo pod not starting + +Check events: +```bash +kubectl describe pod -n monitoring -l app.kubernetes.io/name=tempo +``` + +Check PVC binding: +```bash +kubectl get pvc -n monitoring tempo-data-pvc +``` + +### No traces appearing + +1. Verify Alloy is forwarding traces: +```bash +kubectl logs -n monitoring -l app.kubernetes.io/name=alloy | grep -i tempo +``` + +2. Check Tempo logs: +```bash +just logs +``` + +3. Verify OTLP receivers are listening: +```bash +just check +``` + +### Grafana datasource not appearing + +1. Check ConfigMap exists: +```bash +kubectl get cm -n monitoring tempo-grafana-datasource --show-labels +``` + +2. Check Grafana sidecar logs: +```bash +kubectl logs -n monitoring $(kubectl get pod -n monitoring -l app.kubernetes.io/name=grafana -o jsonpath='{.items[0].metadata.name}') -c grafana-sc-datasources +``` + +3. Restart Grafana pod if needed: +```bash +kubectl delete pod -n monitoring -l app.kubernetes.io/name=grafana +``` + +## References + +- [Grafana Tempo Documentation](https://grafana.com/docs/tempo/latest/) +- [Tempo Helm Chart](https://github.com/grafana/helm-charts/tree/main/charts/tempo) +- [OpenTelemetry Protocol (OTLP)](https://opentelemetry.io/docs/specs/otlp/) +- [TraceQL Query Language](https://grafana.com/docs/tempo/latest/traceql/) diff --git a/f3s/tempo/datasource-configmap.yaml b/f3s/tempo/datasource-configmap.yaml new file mode 100644 index 0000000..00fb972 --- /dev/null +++ b/f3s/tempo/datasource-configmap.yaml @@ -0,0 +1,47 @@ +# Grafana Datasource ConfigMap for Tempo +# Auto-discovered by Grafana sidecar via label grafana_datasource: "1" +# Enables traces-to-logs and traces-to-metrics correlation + +apiVersion: v1 +kind: ConfigMap +metadata: + name: tempo-grafana-datasource + namespace: monitoring + labels: + grafana_datasource: "1" # Must be string "1" for auto-discovery +data: + tempo-datasource.yaml: |- + apiVersion: 1 + datasources: + - name: "Tempo" + type: tempo + uid: tempo + url: http://tempo.monitoring.svc.cluster.local:3200 + access: proxy + isDefault: false + editable: true + jsonData: + httpMethod: GET + # Enable traces-to-logs correlation with Loki + tracesToLogsV2: + datasourceUid: 'loki' + spanStartTimeShift: '-1h' + spanEndTimeShift: '1h' + filterByTraceID: false + filterBySpanID: false + tags: ['cluster', 'namespace', 'pod', 'app'] + # Enable traces-to-metrics correlation with Prometheus + tracesToMetrics: + datasourceUid: 'prometheus' + # Enable service graph visualization + serviceMap: + datasourceUid: 'prometheus' + # Enable node graph for visualization + nodeGraph: + enabled: true + # Enable search + search: + hide: false + # Enable Loki search integration + lokiSearch: + datasourceUid: 'loki' diff --git a/f3s/tempo/persistent-volumes.yaml b/f3s/tempo/persistent-volumes.yaml new file mode 100644 index 0000000..fc4c378 --- /dev/null +++ b/f3s/tempo/persistent-volumes.yaml @@ -0,0 +1,31 @@ +# Persistent Volume and Claim for Grafana Tempo trace storage +# Following the pattern from Loki deployment +# Storage: 10Gi at /data/nfs/k3svolumes/tempo/data + +apiVersion: v1 +kind: PersistentVolume +metadata: + name: tempo-data-pv +spec: + capacity: + storage: 10Gi + volumeMode: Filesystem + accessModes: + - ReadWriteOnce + persistentVolumeReclaimPolicy: Retain + hostPath: + path: /data/nfs/k3svolumes/tempo/data + type: DirectoryOrCreate +--- +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: tempo-data-pvc + namespace: monitoring +spec: + storageClassName: "" # Empty for manual binding to PV + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 10Gi diff --git a/f3s/tempo/values.yaml b/f3s/tempo/values.yaml new file mode 100644 index 0000000..d118b63 --- /dev/null +++ b/f3s/tempo/values.yaml @@ -0,0 +1,76 @@ +# Grafana Tempo - Monolithic Mode Configuration +# Following the pattern from Loki SingleBinary deployment + +tempo: + # Retention policy for traces (7 days) + retention: 168h + + # Storage configuration - Local filesystem backend + # This is required for monolithic mode + storage: + trace: + backend: local + local: + path: /var/tempo/traces + wal: + path: /var/tempo/wal + + # Distributor configuration with OTLP receivers + # Bind to 0.0.0.0 to avoid Tempo 2.7+ localhost-only binding issue + receivers: + otlp: + protocols: + grpc: + endpoint: 0.0.0.0:4317 + http: + endpoint: 0.0.0.0:4318 + + # Query frontend configuration + # Enabled by default in monolithic mode + +# Persistence configuration using hostPath PV +# Matches the pattern from Loki deployment +persistence: + enabled: true + size: 10Gi + storageClassName: "" # Empty string for manual PV binding + accessModes: + - ReadWriteOnce + +# Service configuration +# Expose OTLP ports and query endpoint +service: + type: ClusterIP + +# Resource limits to prevent runaway resource usage +# Adjusted for monolithic deployment +resources: + limits: + cpu: 1000m + memory: 2Gi + requests: + cpu: 500m + memory: 1Gi + +# Security context following best practices +# Using non-root user +securityContext: + fsGroup: 10001 + runAsUser: 10001 + runAsGroup: 10001 + runAsNonRoot: true + +# Disable components not needed in monolithic mode +gateway: + enabled: false + +# Monitoring integration with Prometheus +# Enables ServiceMonitor for automatic scraping +serviceMonitor: + enabled: true + labels: + release: prometheus + +# Test pod disabled to reduce overhead +test: + enabled: false |
