Admin

DevOps

Prometheus for K8s: Custom Exporters & Recording Rules

Master Prometheus custom exporters & recording rules for Kubernetes monitoring. Learn to collect any metric, optimize alerts, and enhance observability.

By Sujay SinghPublished: September 2, 202613 min read61 views✓ Fact Checked
Prometheus for K8s: Custom Exporters & Recording Rules
Prometheus for K8s: Custom Exporters & Recording Rules

Overview: Elevating Kubernetes Monitoring with Custom Exporters and Recording Rules

As a senior technology writer at TechNews Venture, I’ve witnessed firsthand the transformative power of Prometheus in modern cloud-native environments, particularly within Kubernetes. Prometheus has become the de facto standard for monitoring, offering a robust, pull-based model for collecting metrics. While out-of-the-box exporters like Node Exporter and Kube-state-metrics provide essential infrastructure and Kubernetes-specific metrics, they often fall short when it comes to capturing the intricate details of custom applications, business logic, or integrating with specialized, non-standard systems. This is where **Prometheus custom exporters** become indispensable. Custom exporters bridge the gap between your unique application insights and Prometheus's powerful metric collection capabilities. They allow you to expose application-specific metrics – think transaction rates, user session counts, queue depths for proprietary systems, or even the health of legacy components – in a format that Prometheus can easily scrape and ingest. Without custom exporters, critical operational intelligence often remains siloed within application logs or inaccessible proprietary interfaces, hindering comprehensive observability. Beyond metric collection, the sheer volume and complexity of data in a large Kubernetes cluster can make querying and visualizing insights challenging. This is where **Prometheus recording rules** step in as a powerful optimization tool. Recording rules allow you to pre-compute frequently used or computationally expensive PromQL expressions and store their results as new time series data. This not only significantly speeds up dashboard loading times and ad-hoc queries but also simplifies complex PromQL for end-users, making monitoring more accessible and efficient. In this detailed article, we will delve into the practical implementation of both custom exporters and recording rules within a Kubernetes ecosystem. We'll walk through building a simple Python-based custom exporter, deploying it to Kubernetes, ensuring Prometheus scrapes its metrics, and then defining and applying recording rules to derive meaningful, pre-aggregated insights. By the end, you'll have a clear understanding of how to extend Prometheus's capabilities to monitor virtually anything and optimize your PromQL queries for peak performance.

Prerequisites

Before we dive into the implementation, ensure you have the following tools and foundational knowledge in place:
  • Kubernetes Cluster: A running Kubernetes cluster (e.g., Minikube, kind, GKE, EKS, AKS). For this article, we'll assume a standard cluster environment.
  • kubectl: The Kubernetes command-line tool, configured to connect to your cluster.
  • Helm: The Kubernetes package manager, version 3.x, installed on your local machine. We'll use Helm to deploy the Prometheus stack.
  • Docker Desktop/Daemon: Docker installed and running on your local machine to build and push the custom exporter's Docker image. You'll need access to a Docker registry (e.g., Docker Hub, GCR, ECR) to push your image.
  • Prometheus Installation: A Prometheus instance running in your Kubernetes cluster, preferably deployed via the kube-prometheus-stack Helm chart, which includes the Prometheus Operator for managing ServiceMonitors and PrometheusRules.
  • Basic Understanding: Familiarity with Kubernetes concepts (Deployments, Services, Pods, Namespaces), Prometheus fundamentals (metrics, targets, PromQL), and basic Python programming.
If you don't have Prometheus installed, you can quickly deploy the `kube-prometheus-stack` using Helm:

helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm repo update
kubectl create namespace monitoring
helm install prometheus prometheus-community/kube-prometheus-stack -n monitoring --version 58.4.0 # Use a recent stable version
This command will deploy Prometheus, Grafana, Alertmanager, and other components into the `monitoring` namespace, which we will use throughout this guide.

Step-by-Step Implementation

This section will guide you through building a custom exporter, deploying it to Kubernetes, and then defining and applying recording rules.

1. Building a Custom Prometheus Exporter (Python Example)

We'll create a simple Python application that exposes custom metrics using the `prometheus_client` library. Our exporter will simulate an application generating requests and track its uptime. First, create a directory for your exporter:

mkdir custom-exporter-app
cd custom-exporter-app
Create a `requirements.txt` file:

# requirements.txt
prometheus_client==0.20.0
Next, create `exporter.py`:

# exporter.py
from prometheus_client import start_http_server, Counter, Gauge
import random
import time
import os
import signal
import sys

# Define metrics
# Counter: A cumulative metric that only ever goes up.
APP_REQUESTS_TOTAL = Counter('app_requests_total', 'Total number of simulated application requests.')
# Gauge: A metric that can go up and down.
APP_UPTIME_SECONDS = Gauge('app_uptime_seconds', 'Uptime of the application in seconds.')
APP_CUSTOM_VALUE = Gauge('app_custom_value', 'A custom, fluctuating value metric for demonstration.')

# Store the start time to calculate uptime
start_time = time.time()

# Graceful shutdown handler
def signal_handler(sig, frame):
    print('Shutting down exporter...')
    sys.exit(0)

signal.signal(signal.SIGINT, signal_handler)
signal.signal(signal.SIGTERM, signal_handler)

def simulate_app_activity():
    """Simulates some application activity and updates metrics."""
    APP_REQUESTS_TOTAL.inc() # Increment total requests
    APP_UPTIME_SECONDS.set(time.time() - start_time) # Update uptime
    APP_CUSTOM_VALUE.set(random.uniform(10.0, 90.0)) # Update custom gauge with a random value

    # Simulate processing time
    time.sleep(random.uniform(0.1, 0.5))

if __name__ == '__main__':
    # Exporter will listen on the port specified by the PORT environment variable, default to 8000
    exporter_port = int(os.getenv('PORT', 8000))
    start_http_server(exporter_port)
    print(f"Prometheus exporter listening on port {exporter_port}")

    # Continuously simulate activity
    while True:
        simulate_app_activity()
Now, create a `Dockerfile` to containerize our exporter:

# Dockerfile
FROM python:3.9-slim-buster

WORKDIR /app

# Install dependencies
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

# Copy the exporter script
COPY exporter.py .

# Expose the port Prometheus will scrape
EXPOSE 8000

# Run the exporter
CMD ["python", "exporter.py"]
Build your Docker image. Replace `sujay-tech` with your Docker Hub username or preferred registry prefix.

docker build -t sujay-tech/custom-app-exporter:v1.0.0 .
Push the image to your container registry:

docker push sujay-tech/custom-app-exporter:v1.0.0

2. Deploying the Custom Exporter to Kubernetes

We'll deploy our custom exporter as a Kubernetes Deployment, expose it with a Service, and then instruct Prometheus to scrape its metrics using a ServiceMonitor (leveraging the Prometheus Operator). Create a file named `custom-exporter-manifests.yaml`:

# custom-exporter-manifests.yaml
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: custom-app-exporter
  namespace: monitoring # Deploy in the same namespace as Prometheus
  labels:
    app: custom-app-exporter
spec:
  replicas: 1
  selector:
    matchLabels:
      app: custom-app-exporter
  template:
    metadata:
      labels:
        app: custom-app-exporter
    spec:
      containers:
      - name: exporter
        image: sujay-tech/custom-app-exporter:v1.0.0 # Use your pushed image
        imagePullPolicy: Always # Ensure latest image is pulled
        ports:
        - containerPort: 8000
          name: http-metrics
        env:
        - name: PORT
          value: "8000"
        resources:
          limits:
            cpu: "100m"
            memory: "128Mi"
          requests:
            cpu: "50m"
            memory: "64Mi"
---
apiVersion: v1
kind: Service
metadata:
  name: custom-app-exporter
  namespace: monitoring # In the same namespace
  labels:
    app: custom-app-exporter
spec:
  selector:
    app: custom-app-exporter
  ports:
    - protocol: TCP
      port: 8000
      targetPort: http-metrics # Match containerPort name
      name: http-metrics
  type: ClusterIP
---
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  name: custom-app-exporter
  namespace: monitoring # ServiceMonitor should be in the same namespace as Prometheus
  labels:
    app: custom-app-exporter
    release: prometheus # This label is crucial for kube-prometheus-stack to discover it
spec:
  selector:
    matchLabels:
      app: custom-app-exporter # Selects the Service created above
  endpoints:
  - port: http-metrics # Refers to the named port in the Service
    interval: 15s # How often Prometheus should scrape
    path: /metrics # Default path for Prometheus metrics
  namespaceSelector:
    matchNames:
    - monitoring # The namespace where the Service is located
Apply these manifests to your Kubernetes cluster:

kubectl apply -f custom-exporter-manifests.yaml -n monitoring
Verify that the pod is running:

kubectl get pods -l app=custom-app-exporter -n monitoring
You should see output similar to:

NAME                                 READY   STATUS    RESTARTS   AGE
custom-app-exporter-7f6c77d4c9-abcde   1/1     Running   0          2m
Now, access the Prometheus UI (usually via `kubectl port-forward` or an Ingress). If using `kube-prometheus-stack`, you can port-forward the Prometheus service:

kubectl --namespace monitoring port-forward svc/prometheus-kube-prometheus-prometheus 9090:9090
Navigate to `http://localhost:9090/targets` in your browser. You should see `custom-app-exporter` listed as a healthy target under the `servicemonitor/monitoring/custom-app-exporter` job. In the Prometheus UI, go to the "Graph" tab and query for `app_requests_total` or `app_uptime_seconds`. You should see your custom metrics appearing and changing over time.

3. Implementing Recording Rules

Now that our custom metrics are being scraped, let's create some recording rules to pre-aggregate and simplify them. We'll define rules to calculate the rate of requests per minute and the average custom value over a 5-minute window. Create a file named `custom-recording-rules.yaml`:

# custom-recording-rules.yaml
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
  name: custom-app-recording-rules
  namespace: monitoring # Rules are typically managed in the same namespace as Prometheus
  labels:
    prometheus: k8s # This label is critical for kube-prometheus-stack to discover rules
    role: recording-rules
spec:
  groups:
  - name: custom-app.rules # A logical group for your rules
    interval: 30s # How often the rules in this group should be evaluated
    rules:
    - record: app_requests_per_minute # The name of the new metric to be recorded
      expr: sum(rate(app_requests_total[1m])) by (namespace, pod) * 60 # Calculate requests per minute
      labels:
        severity: info # Example label, useful for filtering or alerting
    - record: app_custom_value_average_5m
      expr: avg_over_time(app_custom_value[5m]) # Calculate the 5-minute average of our custom value
      labels:
        severity: info
    - record: app_uptime_ratio
      expr: app_uptime_seconds / (time() - app_uptime_seconds offset 1m) # Simple uptime ratio example
      labels:
        severity: info
Before applying, it's good practice to validate your PromQL rules using `promtool`:

# You might need to download promtool or use the one from your Prometheus container
# Example to get promtool from a running Prometheus pod:
# kubectl cp -n monitoring prometheus-prometheus-kube-prometheus-prometheus-0:/bin/promtool ./promtool
# chmod +x ./promtool

# Now, validate:
./promtool check rules custom-recording-rules.yaml
If there are no errors, apply the recording rules to your cluster:

kubectl apply -f custom-recording-rules.yaml -n monitoring
The Prometheus Operator will detect this `PrometheusRule` resource and configure Prometheus to evaluate these rules. This might take a minute or two. Verify the rules in the Prometheus UI by navigating to `http://localhost:9090/rules`. You should see your `custom-app.rules` group and the newly defined recording rules. Now, you can query your new, pre-aggregated metrics, `app_requests_per_minute` and `app_custom_value_average_5m`, which will be faster and simpler than running the raw PromQL expressions every time.

app_requests_per_minute
app_custom_value_average_5m
These metrics are now stored as their own time series, ready for faster querying, dashboarding, and alerting.

Security Considerations

When extending Prometheus with custom exporters and recording rules, security should always be a paramount concern.
  • Exporter Security

    • Least Privilege: Ensure your custom exporter runs with the minimal necessary permissions within its container and Kubernetes Pod. Avoid running as root.
    • Network Policies: Implement Kubernetes Network Policies to restrict access to your exporter's `/metrics` endpoint. Only allow your Prometheus server to scrape it.
      
      apiVersion: networking.k8s.io/v1
      kind: NetworkPolicy
      metadata:
        name: allow-prometheus-to-custom-exporter
        namespace: monitoring
      spec:
        podSelector:
          matchLabels:
            app: custom-app-exporter
        ingress:
        - from:
          - podSelector:
              matchLabels:
                app.kubernetes.io/name: prometheus # Adjust label if your Prometheus has a different one
          ports:
          - protocol: TCP
            port: 8000 # Your exporter's port
        policyTypes:
        - Ingress
                      
    • Data Sensitivity: Be extremely cautious about what data you expose via metrics. Avoid exposing Personally Identifiable Information (PII) or sensitive business data. If truly unavoidable, consider mTLS for metric scraping, though this adds significant complexity and is generally discouraged for metrics.
    • Image Security: Use minimal base images (e.g., `python:3.9-slim-buster`) to reduce attack surface. Regularly scan your Docker images for vulnerabilities using tools like Trivy or Clair.
    • Dependency Vulnerabilities: Keep your exporter's dependencies (like `prometheus_client`) updated to patch known security vulnerabilities.
  • Prometheus and Recording Rule Security

    • RBAC: Ensure your Prometheus deployment has appropriate Kubernetes Role-Based Access Control (RBAC) permissions. It needs `get`, `list`, `watch` permissions for Pods, Services, Endpoints, and Custom Resources like `ServiceMonitor` and `PrometheusRule` in relevant namespaces.
    • Access to Prometheus UI: Secure access to the Prometheus UI, especially if it's exposed externally. Use an Ingress with authentication (e.g., OAuth2-Proxy) or VPN access.
    • Rule Integrity: Store your recording rules in version control (Git) and manage their deployment through a secure CI/CD pipeline to prevent unauthorized modifications.

Best Practices

To maximize the effectiveness and maintainability of your Prometheus custom exporters and recording rules, adhere to these best practices:
  • Custom Exporter Design

    • Simplicity and Statelessness: Keep your exporters as simple and stateless as possible. Their primary role is to expose metrics, not to perform complex business logic.
    • Dedicated `/metrics` Endpoint: Always expose metrics on the standard `/metrics` HTTP endpoint. If you must use a different path, ensure your ServiceMonitor or Prometheus scrape configuration reflects it.
    • Standard Client Libraries: Use official Prometheus client libraries for your chosen language. They handle metric types, exposition formats, and concurrent access correctly.
    • Metric Naming Conventions: Follow Prometheus metric naming best practices (e.g., `_total` for counters, `_seconds` for durations, `_bytes` for sizes). Use consistent prefixes for your application metrics (e.g., `app_`).
    • Meaningful Labels: Use labels to add dimensionality to your metrics (e.g., `app_requests_total{method="GET", path="/api/v1/data"}`). Avoid high-cardinality labels (labels with many unique values) as they can explode Prometheus's memory usage and storage.
    • Graceful Shutdown: Implement graceful shutdown handlers in your exporter to ensure metrics are properly flushed or state is cleaned up before termination.
    • Resource Limits: Define CPU and memory requests/limits for your exporter Pods to prevent them from consuming excessive cluster resources.
  • Recording Rule Management

    • Validation with promtool: Always validate your recording rules using `promtool check rules` before deploying them to production. This catches syntax errors and ensures PromQL validity.
    • Clear Naming: Give your recorded metrics clear, descriptive names that indicate their origin and aggregation (e.g., `app_requests_total_rate_1m`, `database_query_duration_p99`).
    • Strategic Aggregation: Don't pre-aggregate every possible metric. Focus on metrics that are frequently queried, computationally expensive, or used in dashboards and alerts. Over-using recording rules can consume significant storage and CPU resources in Prometheus.
    • Interval Alignment: Align your recording rule evaluation intervals with the data points you intend to capture. For example, calculating a 5-minute average might warrant an evaluation interval of 1 minute.
    • Version Control: Store all your `PrometheusRule` YAML definitions in a version control system (like Git) alongside your application code.
    • Monitor Rule Performance: Prometheus exposes internal metrics about rule evaluation performance (e.g., `prometheus_engine_evaluation_duration_seconds`). Monitor these to ensure your rules aren't causing performance bottlenecks.
  • General Best Practices

    • Automated Deployment: Integrate the deployment of your custom exporters and recording rules into your CI/CD pipelines.
    • Documentation: Document your custom metrics, their meaning, and any associated recording rules. This is crucial for onboarding new team members and troubleshooting.
    • Testing: Write tests for your custom exporter code to ensure it correctly exposes metrics and handles various scenarios.

FAQ

1. When should I use a custom exporter instead of existing ones?

You should consider a custom exporter when existing, off-the-shelf Prometheus exporters (like Node Exporter, Kube-state-metrics, cAdvisor) do not provide the specific metrics you need. This typically applies to:
  • Application-specific business logic: E.g., number of active user sessions, failed login attempts, processing queue depth for a unique microservice.
  • Integration with proprietary or legacy systems: When you need to pull metrics from a system that doesn't natively expose Prometheus format, or has a unique API.
  • Exposing internal application state: Metrics derived from an application's internal state that is not easily inferred from standard system metrics.
If the metrics can be derived from existing system or Kubernetes-level data, or if there's an existing exporter for your technology (e.g., MySQL Exporter, Redis Exporter), it's always better to use those first.

2. What's the performance impact of many recording rules?

While recording rules are designed to improve query performance, having too many or overly complex rules can have a negative impact on Prometheus itself. Each recording rule evaluation consumes CPU and memory resources from the Prometheus server. If you have thousands of rules or rules that query vast amounts of raw data over long time ranges, Prometheus's rule evaluation engine can become a bottleneck.

Best practices include:
  • Only create rules for frequently queried or computationally intensive expressions.
  • Keep the evaluation interval (`interval` in the rule group) appropriate for the data's volatility.
  • Monitor Prometheus's own metrics like `prometheus_engine_evaluation_duration_seconds` to identify any performance degradation caused by rule evaluation.
  • Use `promtool check rules` to catch any obvious performance anti-patterns in your PromQL.

3. Can I secure my custom exporter's `/metrics` endpoint with authentication?

While
📧

Enjoyed this article?

Get articles like this delivered to your inbox daily. Join 10,000+ tech professionals.

Written By

Sujay Singh

Technology Expert / Cloud Architect at Virtual Venture covering AI, cloud computing, cybersecurity, and emerging tech trends.

Sources & References

• Official company announcements and press releases

• Industry reports from Gartner, IDC, and Statista

• Peer-reviewed research and technical documentation

• On-record statements from industry experts

Last verified: September 2, 2026

Fact-checked by TechNews Venture editorial team

Leave a Comment

Comments are moderated and will appear after review.