Experimental: Redfish BMC Power Monitoring
October 14, 2025 · View on GitHub
⚠️ EXPERIMENTAL FEATURE WARNING
This feature is experimental and has no stability guarantees:
- Configuration format may change in future versions
- Metrics names and labels may evolve
- Suitable for controlled environments and testing only
- Not recommended for production use without thorough testing
Overview
Enable platform-level power monitoring by configuring Kepler to collect power data from your BMCs via Redfish API. Platform metrics (kepler_platform_watts) are exposed separately from workload attribution metrics.
Prerequisites
- PowerMonitor deployed - Kepler operator and PowerMonitor resource running
- BMC Access - Network connectivity to BMC endpoints from Kepler pods
- BMC Credentials - Username and password with read access to power metrics
Setup Guide
Step 1: Deploy PowerMonitor with Redfish Configuration
Deploy your PowerMonitor configured to use Redfish. The PowerMonitor references a ConfigMap and Secret that you'll create in the next steps:
# File: hack/examples/redfish-powermonitor.yaml
apiVersion: kepler.system.sustainable.computing.io/v1alpha1
kind: PowerMonitor
metadata:
name: power-monitor
spec:
kepler:
deployment:
# Deploy to all Linux nodes
nodeSelector:
kubernetes.io/os: linux
# Tolerate all taints to run on all nodes
tolerations:
- operator: Exists
# Mount the Secret containing BMC credentials (will be created after namespace exists)
secrets:
- name: redfish-secret
mountPath: /etc/kepler/secrets/redfish
readOnly: true
config:
# Standard Kepler configuration
logLevel: info
sampleRate: 5s
metricLevels:
- node
- pod
# Reference the ConfigMap that enables Redfish (will be created after namespace exists)
additionalConfigMaps:
- name: enable-redfish
Apply the PowerMonitor:
kubectl apply -f hack/examples/redfish-powermonitor.yaml
The Kepler operator will create the power-monitor namespace and begin reconciling the PowerMonitor.
Expected State: The PowerMonitor conditions will show Reconciled: False and Available: False at this point because the referenced ConfigMap and Secret don't exist yet. This is normal and expected.
Step 2: Wait for Namespace Creation
Wait for the operator to create the power-monitor namespace:
kubectl wait --for=jsonpath='{.status.phase}'=Active namespace/power-monitor --timeout=60s
Step 3: Create Kepler Configuration ConfigMap
Create the ConfigMap that enables Redfish in Kepler:
# File: hack/examples/redfish-configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: enable-redfish
namespace: power-monitor
data:
config.yaml: |
experimental:
platform:
redfish:
# Enable Redfish BMC power monitoring
enabled: true
# Node identifier - auto-resolves from Kubernetes if not specified
# Must match a key in the 'nodes' section of redfish.yaml
nodeName: "" # Leave empty to auto-detect from Kubernetes node name
# Path to BMC configuration file (mounted from Secret)
configFile: /etc/kepler/secrets/redfish/redfish.yaml
# HTTP timeout for BMC requests
httpTimeout: 5s
Apply the ConfigMap:
kubectl apply -f hack/examples/redfish-configmap.yaml
Step 4: Create BMC Credentials Secret
Create the Secret containing your BMC configuration:
# File: hack/examples/redfish-secret.yaml
apiVersion: v1
kind: Secret
metadata:
name: redfish-secret
namespace: power-monitor
type: Opaque
stringData:
redfish.yaml: |
# Node to BMC mapping
# Key: Node identifier (must match Kubernetes node name or PowerMonitor nodeName)
# Value: BMC identifier that references an entry in the 'bmcs' section
nodes:
worker-1: bmc-worker-1
worker-2: bmc-worker-2
worker-3: bmc-worker-3
# BMC connection details
bmcs:
bmc-worker-1:
endpoint: https://bmc-worker-1.example.com
username: monitoring-user
password: "SecurePassword123!"
insecure: false # Set to true only for development/testing
bmc-worker-2:
endpoint: https://192.168.1.101
username: monitoring-user
password: "SecurePassword456!"
insecure: false
bmc-worker-3:
endpoint: https://192.168.1.102:8443 # Custom port
username: admin
password: "SecurePassword789!"
insecure: false
Apply the Secret:
kubectl apply -f hack/examples/redfish-secret.yaml
Security Note: Never commit BMC credentials to git. Use proper secret management (Sealed Secrets, External Secrets Operator, Vault).
What happens next: Creating the Secret triggers the operator's reconcile loop. The operator will redeploy Kepler with the Redfish configuration. The PowerMonitor status conditions will update:
- Reconciled: Changes from
FalsetoTrue - Available: Changes from
FalsetoTrue
Step 5: Verify Deployment
Check PowerMonitor status conditions:
# Check Reconciled condition
kubectl get powermonitor power-monitor -o jsonpath='{.status.conditions[?(@.type=="Reconciled")].status}'
# Check Available condition
kubectl get powermonitor power-monitor -o jsonpath='{.status.conditions[?(@.type=="Available")].status}'
Expected output: Both should return True
Check Kepler pods are running:
kubectl get pods -n power-monitor
Check Kepler logs for Redfish initialization:
kubectl logs -n power-monitor daemonset/power-monitor | grep -i redfish
Expected log output:
level=INFO msg="BMC configuration loaded" service=experimental.redfish node_name=kind-worker bmc_id=mock-bmc endpoint=http://172.18.0.1:28001
level=INFO msg="Successfully initialized power reader" service=experimental.redfish node_name=kind-worker
level=INFO msg="Successfully connected to BMC" service=experimental.redfish node_name=kind-worker
Configuration Reference
Main Configuration (ConfigMap)
experimental:
platform:
redfish:
enabled: true # Enable Redfish monitoring
nodeName: "" # Auto-resolves from Kubernetes
configFile: "/path/to/redfish.yaml" # Path to mounted Secret
httpTimeout: 5s # BMC request timeout
Configuration Options:
- enabled: Enable/disable Redfish monitoring (default:
false) - nodeName: Node identifier for BMC mapping (auto-resolves if empty)
- Priority: CLI flag → Kubernetes node name → hostname
- configFile: Path to BMC configuration YAML (must point to mounted Secret)
- httpTimeout: Maximum time to wait for BMC responses (default:
5s)
BMC Configuration (Secret)
nodes:
<node-id>: <bmc-id> # Map node to BMC
bmcs:
<bmc-id>:
endpoint: "https://bmc.example.com"
username: "monitoring-user"
password: "secure-password"
insecure: false # TLS verification
Node-to-BMC Mapping:
-
One-to-One: Each bare metal node has its own BMC
nodes: worker-1: bmc-worker-1 worker-2: bmc-worker-2 -
Many-to-One: Multiple VMs share the same bare metal BMC
nodes: vm-worker-1: shared-bmc vm-worker-2: shared-bmc vm-worker-3: shared-bmc -
Blade Servers: Multiple blades sharing chassis BMC
nodes: blade-1: chassis-bmc-1 blade-2: chassis-bmc-1 blade-3: chassis-bmc-1
Metrics
Redfish monitoring exposes kepler_platform_watts metrics with platform-level power consumption from BMCs. For complete metric documentation, see the Kepler Metrics Reference.
Validation
Step 1: Check Metrics Endpoint
Verify Kepler is exposing platform metrics:
Method 1: From inside the pod (recommended for testing):
kubectl exec -n power-monitor daemonset/power-monitor -- curl -s http://localhost:28282/metrics | grep kepler_platform_watts
Method 2: Using port-forward:
kubectl port-forward -n power-monitor daemonset/power-monitor 28282:28282
# In another terminal:
curl http://localhost:28282/metrics | grep kepler_platform_watts
Expected output:
# HELP kepler_platform_watts Current platform power in watts from BMC (PowerSubsystem or deprecated Power API)
# TYPE kepler_platform_watts gauge
kepler_platform_watts{bmc_id="mock-bmc",chassis_id="1U",node_name="kind-worker",source="redfish",source_id="PS1",source_name="Power Supply 1",source_type="PowerSupply"} 245
kepler_platform_watts{bmc_id="mock-bmc",chassis_id="2U",node_name="kind-worker",source="redfish",source_id="PS1",source_name="Power Supply 1",source_type="PowerSupply"} 345
Step 2: Query Prometheus
If using Prometheus, verify metrics are being scraped:
kubectl port-forward -n monitoring svc/prometheus 9090:9090
Navigate to http://localhost:9090 and query:
kepler_platform_watts
Security Notes
Important: Never commit BMC credentials to git in plaintext. Use Kubernetes Secrets or external secret management solutions (Sealed Secrets, External Secrets Operator, Vault) to protect BMC credentials.
Troubleshooting
PowerMonitor Shows Degraded Status
Symptom: PowerMonitor conditions show Reconciled: False and Available: False after initial deployment
Cause: This is expected behavior when the PowerMonitor is created before the ConfigMap and Secret exist.
Solution: Continue with steps 3 and 4 to create the ConfigMap and Secret. Both conditions will automatically transition to True once both resources are created and Kepler is successfully redeployed.
Verify status transition:
# Watch the status change
kubectl get powermonitor power-monitor -w
# Check both conditions
kubectl get powermonitor power-monitor -o jsonpath='{.status.conditions[?(@.type=="Reconciled")]}'
kubectl get powermonitor power-monitor -o jsonpath='{.status.conditions[?(@.type=="Available")]}'
Kepler Pods Crashing
Symptom: Kepler pods show CrashLoopBackOff status
Diagnosis:
Check pod logs for initialization errors:
kubectl logs -n power-monitor daemonset/power-monitor --tail=50 | grep -i "error\|fatal"
Common Causes:
-
BMC connectivity issues - Pods fail to connect to BMC during initialization
- Error:
failed to connect to BMC at http://... - Solution: See DNS Resolution Failures or BMC Connection Errors
- Error:
-
Missing or invalid Secret - Secret not mounted or has invalid YAML
- Error:
failed to load BMC configuration - Solution: Verify Secret exists and has correct structure
- Error:
-
Node name mismatch - Node name doesn't match any entry in Secret's
nodessection- Error:
node not found in redfish configuration - Solution: See Node Not Found in Configuration
- Error:
No Platform Metrics
Symptom: kepler_platform_watts metrics not present
Solutions:
-
Check Kepler logs:
kubectl logs -n power-monitor daemonset/power-monitor | grep -i redfish -
Verify Secret is mounted:
kubectl exec -n power-monitor daemonset/power-monitor -- ls -la /etc/kepler/secrets/redfish/ -
Verify configuration:
kubectl exec -n power-monitor daemonset/power-monitor -- cat /etc/kepler/secrets/redfish/redfish.yaml -
Check metrics from inside pod:
kubectl exec -n power-monitor daemonset/power-monitor -- curl -s http://localhost:28282/metrics | grep kepler_platform_watts
BMC Connection Errors
Symptom: Logs show "connection refused" or "timeout"
Solutions:
-
Test BMC connectivity from pod:
kubectl exec -n power-monitor daemonset/power-monitor -- curl -k https://<bmc-endpoint>/redfish/v1/ -
Check network policies:
kubectl get networkpolicy -n power-monitor -
Verify BMC endpoint configuration:
- Ensure endpoint URL is correct
- Check port is accessible
- Verify DNS resolution if using hostnames
DNS Resolution Failures
Symptom: Logs show "dial tcp: lookup host.docker.internal: no such host" or similar DNS errors
Cause: DNS names like host.docker.internal may not resolve inside Kubernetes pods
Solutions:
-
For Kind clusters with mock BMC server:
Use the Kind network gateway IP instead of
host.docker.internal:# Get Kind network gateway IP docker network inspect kind | jq '.[0].IPAM.Config[0].Gateway'Update your Secret to use the gateway IP:
bmcs: mock-bmc: endpoint: http://172.18.0.1:28001 # Use gateway IP, not host.docker.internal username: "" password: "" insecure: true -
For production BMCs:
-
Use IP addresses instead of hostnames if DNS is unreliable
-
Verify DNS resolution from within the pod:
kubectl exec -n power-monitor daemonset/power-monitor -- nslookup <bmc-hostname>
-
Authentication Errors
Symptom: Logs show "401 Unauthorized" or "403 Forbidden"
Solutions:
-
Test credentials manually:
curl -k -u username:password https://<bmc-endpoint>/redfish/v1/Chassis -
Verify Secret content:
kubectl get secret redfish-secret -n power-monitor -o jsonpath='{.data.redfish\.yaml}' | base64 -d -
Check BMC user permissions:
- Ensure user has permission to read power metrics
- Some BMCs require specific roles (e.g., "Operator" on Dell iDRAC)
Node Not Found in Configuration
Symptom: Logs show "node not found in redfish configuration"
Solutions:
-
Check node name matches:
kubectl get nodes kubectl get powermonitor power-monitor -o jsonpath='{.spec.kepler.config.experimental.platform.redfish.nodeName}' -
Verify nodes section in Secret:
kubectl get secret redfish-secret -n power-monitor -o jsonpath='{.data.redfish\.yaml}' | base64 -d | grep -A 10 "nodes:"
Secret or ConfigMap Not Found
Symptom: Logs show "configmap not found" or "secret not found"
Cause: Secret or ConfigMap created in wrong namespace
Solution:
-
Verify resources exist in power-monitor namespace:
kubectl get configmap enable-redfish -n power-monitor kubectl get secret redfish-secret -n power-monitor -
If in wrong namespace, delete and recreate:
# Delete from wrong namespace kubectl delete configmap enable-redfish -n <wrong-namespace> kubectl delete secret redfish-secret -n <wrong-namespace> # Recreate in correct namespace kubectl apply -f hack/examples/redfish-configmap.yaml kubectl apply -f hack/examples/redfish-secret.yaml
Important: All resources (Secret, ConfigMap, PowerMonitor) must be in the same namespace where Kepler is deployed (power-monitor by default).
Limitations
Current experimental implementation has these limitations:
- Power-only metrics: No energy counters (
_joules_total) due to on-demand collection - Basic caching: Simple staleness-based cache (could be enhanced)
- Synchronous collection: BMC queries happen during Prometheus scrape (mitigated by caching)
- No resilience patterns: Basic retry logic only (no circuit breaker)
Future Enhancements
Planned improvements for future versions:
- Background collection with enhanced caching
- Circuit breaker patterns for BMC failures
- Integration with external secret stores (Vault, AWS Secrets Manager)
- Energy counter derivation from power readings
- Sub-component power zones (fans, storage, network)
- Additional authentication methods
Related Documentation
- PowerMonitor Guide - Complete PowerMonitor configuration
- Custom ConfigMaps Guide - Using additionalConfigMaps
- Kepler Redfish Proposal - Technical design document
Getting Help
- Issues: GitHub Issues
- Discussions: GitHub Discussions
- Kepler Docs: Kepler Documentation