ObservabilityXC · Meta-MonitoringMetaMonitoring
Avoiding Circular Assumptions
What you'll learn
- Define a circular dependency in meta-monitoring as a case where the meta alert path shares state with the production stack it monitors
- Identify the eight common shared dependencies (network, auth, NTP, secrets manager, notification destination, DNS, host OS, cluster) and the failure each introduces
- Apply the dependency-mapping exercise before deploying a meta-monitoring platform to enumerate which axes are truly independent
- Recognise the failure mode where a meta alert fires correctly but is delivered through a path that is itself degraded
- Validate the absence of circular dependencies with a controlled failure test that disables the production stack and confirms the meta still pages
Prerequisites
Verified against Prometheus 2.55.x · Alertmanager 0.28.x · node_exporter 1.8.x · blackbox_exporter 0.26.x · Grafana 11.x · Loki 3.x · Tempo current · OpenTelemetry Collector 0.110.x · Grafana Alloy current · Docker Engine 28.x · Ubuntu 24.04 LTS · Debian 12 (Bookworm) · RHEL / Rocky / AlmaLinux 9.x · 2026-08-13
A page should fire at 02:14. The on-call engineer should receive it at 02:15. The mitigation should start at 02:16. None of that happened, because the meta-Prometheus was hosted on the same Kubernetes cluster as the production stack it was monitoring, and the cluster’s API server was the broken thing.
The dependency chain:
Production stack Cluster API Meta stack
=============== =========== ==========
Prometheus
Alertmanager
Loki ingesters
Tempo distributors
|
| (deployments, ConfigMaps,
| Services, Ingress)
v
K8s API server
|
| (meta-pod runs here,
| meta-ConfigMap lives here)
v
Meta-Prometheus
Meta-Alertmanager
When the API server went down at 02:14, the meta-Prometheus pod
could not refresh its service account token. The pod stayed
running but its federated scrape failed. The meta could not
evaluate its rules. The meta-Alertmanager, also in the same
cluster, also could not authenticate against its own
configuration. The notification destination never received the
MetaPrometheusDown page. The on-call engineer learned about
the outage from a customer at 02:31.
The root cause was not the API server. The root cause was the decision to put the meta inside the cluster it was monitoring. This lesson is about the discipline of seeing those decisions before they happen.
What it is
A circular assumption in meta-monitoring is a deployment where the meta’s ability to alert on a production failure depends on the production stack itself being healthy. The meta is supposed to be the last line of defence; when the meta shares state with the production stack, the last line of defence has the same blast radius as the thing it is defending.
The dependency can be direct (the meta uses a service the production stack provides) or indirect (the meta and the production stack share an upstream dependency). Both are circular; both defeat the meta.
The discipline is to enumerate every shared dependency and eliminate it before declaring the meta complete. The enumeration is a static exercise on a whiteboard; the elimination is operational work.
Why a sysadmin cares
The cost of a circular dependency is the cost of the failure it masks. A meta that cannot detect a production outage is not a meta; it is decoration. The team pays the cost of running it, gets no operational signal from it, and discovers the gap during the next production incident. The discovery is embarrassing and the post-mortem is unsparing.
The shared dependencies recur across every meta-monitoring deployment. The eight most common:
| # | Shared dependency | Failure the meta inherits |
|---|---|---|
| 1 | Network / VLAN | Switch outage takes both layers down |
| 2 | Auth backend (LDAP, OIDC) | Auth outage breaks meta scrape auth |
| 3 | NTP source | Time skew between meta and production |
| 4 | Secrets manager / vault | Vault outage breaks meta credential retrieval |
| 5 | Notification destination | Webhook outage breaks page delivery |
| 6 | DNS | DNS outage breaks meta hostname resolution |
| 7 | Host OS | Kernel panic or OOM takes both layers down |
| 8 | Cluster / orchestration | Control plane outage breaks meta lifecycle |
The first six are easy to miss because each one looks infrastructure-y rather than production-y. The team did not think of the LDAP outage as a meta-monitoring failure; they thought of it as an authentication failure. The post-mortem forced the rethink.
How it works
The mental model is a dependency graph. The meta is the subject; the production stack is the object being monitored. Every edge in the graph that connects the meta to a service that is also depended on by the production stack is a candidate circular dependency.
+-- Production Prometheus
|
Time source (NTP) -------+-- Meta-Prometheus
|
+-- Production Alertmanager
+-- Meta Alertmanager
+-- LDAP / OIDC
|
Auth backend -------------+-- Production Prometheus
|
+-- Meta-Prometheus
+-- (any service that
authenticates users)
+-- PagerDuty / Slack
|
Notification -------------+-- Production Alertmanager
destination |
+-- Meta Alertmanager
The graph makes the circularity obvious when drawn. The operational discipline is to draw it before deploying the meta, not after the post-mortem.
How to configure it
The configuration that prevents circular dependencies is mostly a deployment-shape decision, not a YAML change. The YAML changes that matter are the credential sources, the network ranges, and the notification webhook endpoints.
# /etc/meta-prometheus/prometheus.yml
global:
# Hard-coded IP, not DNS. If the production DNS is down, the
# meta still reaches the production Prometheus. Hard-coding
# the meta's targets is a deliberate separation discipline.
external_labels:
cluster: meta
scrape_configs:
- job_name: prometheus
scheme: https
# Credentials read from a local file on the meta host. The
# meta does not call out to Vault to retrieve them. A Vault
# outage cannot break the meta scrape.
basic_auth:
username: meta-scraper
password_file: /etc/meta-prometheus/secrets/prod-prom.pass
static_configs:
- targets: ['10.40.1.10:9090']
labels: { prometheus_cluster: production }
alerting:
alertmanagers:
# Static IPs again. The meta-Alertmanager is on a known
# IP range that the meta can reach even if production DNS
# is broken.
- static_configs:
- targets: ['10.50.1.10:9093', '10.50.1.11:9093']
# /etc/meta-alertmanager/alertmanager.yml
route:
receiver: meta-platform-pager
receivers:
- name: meta-platform-pager
pagerduty_configs:
# Routing key from a local file. The meta does not
# retrieve the routing key from Vault at runtime.
- routing_key:
from_file: /etc/meta-alertmanager/secrets/pager.key
severity: 'critical'
Reading the configs:
- Hard-coded IPs for both the scrape targets and the Alertmanager targets. The meta does not depend on DNS to reach the things it must reach.
- Credentials read from local files, not retrieved from a secrets manager at scrape time. The meta can run without Vault.
- The notification routing key is also from a local file. A Vault outage cannot stop the meta from paging.
How to validate it
Five checks confirm the absence of circular dependencies.
# SEVERITY: READ-ONLY
# 1. Confirm the meta-Prometheus host does not depend on
# production DNS. From the meta host, resolve a known
# production hostname.
dig +short prod-prometheus.internal
A non-empty answer is fine; the test is whether the meta host requires the answer. Check the meta’s scrape config for hard-coded IPs rather than hostnames.
# SEVERITY: READ-ONLY
# 2. Confirm the meta's credentials are local, not from a
# vault. Inspect the meta's startup configuration.
grep -E 'password_file|api_key_file|routing_key' \
/etc/meta-prometheus/prometheus.yml \
/etc/meta-alertmanager/alertmanager.yml
Every credential should be a *_file reference, not an inline
value or a remote-fetch URL.
# SEVERITY: READ-ONLY
# 3. Confirm the meta Alertmanager is on a separate cluster.
# The peer list should not contain any production
# Alertmanager peers.
curl -s http://meta-alertmanager:9093/api/v1/status \
| jq '.data.cluster.peers[]'
The list should contain only meta-Alertmanager instances.
# SEVERITY: READ-ONLY
# 4. Confirm the meta is not on the same cluster as the
# production stack. If you run Kubernetes, the meta pods
# should be in a separate cluster, or at minimum a separate
# node pool with no production workloads.
kubectl --context=meta get pods -A -o wide \
| grep -v kube-system
kubectl --context=prod get pods -A -o wide \
| grep -v kube-system
The two outputs should have no overlapping nodes.
# SEVERITY: SERVICE-IMPACT (controlled test in maintenance window)
# 5. Run the controlled failure test. Stop the production
# Prometheus for 5 minutes. Confirm the meta still pages.
systemctl stop prometheus # on production host
sleep 300
# After 5 minutes, the meta should have fired
# MetaPrometheusDown and the page should be at the on-call.
# Restart the production Prometheus.
systemctl start prometheus
A page that arrives during the 5-minute window confirms the end-to-end path is free of circular dependencies. An absent page means one of the eight shared dependencies is still in place.
How it can fail
Six circular-dependency failure modes recur.
- Meta on the same K8s cluster as production. Symptom: the cluster API server is down, both the production stack and the meta are degraded, and the meta cannot alert about either. The post-mortem names “shared cluster” as the root cause.
- Meta uses production LDAP for basic_auth credentials.
Symptom: LDAP is down, the meta cannot authenticate against
the production Prometheus
/metrics, and the meta cannot tell that the production Prometheus is up because the scrape fails with 401. - Meta fetches credentials from Vault at scrape time.
Symptom: Vault is down, the meta Prometheus cannot start
because it cannot read its
password_file, and the meta process exits. The meta is silent during the Vault outage. - Meta-Alertmanager pulls routing keys from Vault. Symptom: Vault is down, the meta-Alertmanager cannot push to PagerDuty, and the meta alerts about the production outage never reach the on-call.
- Meta uses DNS to resolve production hostnames. Symptom: production DNS is down, the meta cannot resolve the production Prometheus hostname, and the meta cannot scrape the production stack. Hard-coded IPs would have prevented this.
- Meta shares NTP with production. Symptom: NTP source is unreachable, the meta and production clocks drift apart, and the meta dashboards show the production data as “5 minutes ago” when it is actually current. The investigation chases a non-existent delay.
How to troubleshoot it
When the meta is silent during a production outage, the question is which shared dependency is the cause. Work the eight dependencies in order of failure-mode severity.
- Confirm the meta process is up. If down, the host OS or cluster is the shared dependency. Inspect the meta host’s kernel logs and the cluster’s control-plane status.
- Confirm the meta host can reach the meta Alertmanager. If not, the network is shared. Inspect routing tables and switch state.
- Confirm the meta can authenticate to its scrape targets. If 401 errors appear, the auth backend is shared. Check the meta’s credentials and the auth backend’s status.
- Confirm the meta can resolve its scrape targets. If DNS errors appear, the DNS is shared. Replace hostnames with IPs in the meta’s scrape config.
- Confirm the meta-Alertmanager can reach the notification destination. If webhook errors appear, the secrets manager is shared. Move the routing key to a local file.
- Confirm the meta and production clocks are within one second. If not, NTP is shared. Configure the meta host with a different NTP source.
- Confirm the meta Grafana can render the production data. If not, the Grafana data source is shared. Point the meta Grafana at the meta Prometheus.
- Form a hypothesis. The most common production circular dependency is the cluster (row 1) or the auth backend (row 2). Inspect the meta logs for the exact failure.
Security implications
The circular-dependency discipline interacts with the security discipline in two places.
- Credential storage. Local credential files on the meta
host are simpler than Vault retrieval but require filesystem
permissions. The meta host’s
/etc/meta-prometheus/secrets/directory must be0700, owned by the meta-prometheus user. A compromise of the meta host is a compromise of the meta’s credentials. - Network exposure. Hard-coded IPs across network ranges means the meta’s targets are static. A firewall rule on the meta host that restricts outbound traffic to the production IP ranges only is the right shape. The meta should not have a route to the public internet except for the notification destination.
Performance implications
Hard-coded IPs and local credentials are not performance hazards. They remove a network round-trip and a vault round-trip respectively, both of which are wins.
The performance hazard is the meta’s own clock skew. If the meta host’s clock drifts, the meta’s timestamps on alerts and metrics are wrong. The on-call sees “the alert fired at 02:14” when the meta actually evaluated the rule at 03:14. The investigation follows the wrong timeline.
Production guidance
- Draw the dependency graph before deploying the meta. Whiteboard exercise; ten minutes; saves months of post-mortems.
- Hard-code IPs in the meta’s scrape and alerting configs. DNS is a shared dependency.
- Local credential files, not Vault retrieval. Vault retrieval is a shared dependency.
- Separate NTP source for the meta host, or a separate NTP path that does not depend on the production network.
- Separate Kubernetes cluster for the meta, or at minimum a separate node pool with no production workloads.
- Run the controlled failure test quarterly. The first test almost always reveals a circular dependency the team did not know was there.
Verification
You should now be able to answer:
- What is a circular dependency in meta-monitoring, and how is it different from a shared infrastructure dependency?
- Which eight shared dependencies recur across meta-monitoring deployments?
- Why must the meta use hard-coded IPs rather than DNS for its scrape and alerting targets?
- What is the controlled failure test, and what does it prove?
- What is the first thing to check when the meta is silent during a real production outage?
Quiz
Knowledge check · 8 questions
Q1. What is a circular dependency in meta-monitoring?
Q2. A meta-Prometheus hosted in the same Kubernetes cluster as production, in a different namespace, is free of circular dependencies.
Q3. Which of these are shared dependencies that can create a circular dependency? (Select all that apply.)
Q4. Why must the meta use hard-coded IPs in its scrape config rather than DNS hostnames?
Q5. Name one failure mode introduced by sharing the NTP source between the meta and the production stack.
Q6. What is the right test to confirm the absence of circular dependencies?
Q7. Reading the PagerDuty routing key from Vault at runtime is acceptable because Vault is HA.
Q8. When the meta is silent during a real production outage, what is the first thing to inspect?
Passing score: 75%. Answers are checked in this browser.