tutorial

How to Monitor CoreDNS in Kubernetes with Vigilmon (DNS Reliability + Alerts)

CoreDNS is the default cluster DNS in every modern Kubernetes deployment. Every service discovery lookup, every inter-pod connection, every pod-to-external h...

CoreDNS is the default cluster DNS in every modern Kubernetes deployment. Every service discovery lookup, every inter-pod connection, every pod-to-external hostname resolution flows through it. When CoreDNS degrades — even partially — the blast radius is enormous: health checks time out, readiness probes fail, and entire application tiers silently disconnect from their dependencies.

Internal metrics from CoreDNS's built-in Prometheus endpoint tell you a lot, but they tell you nothing when the CoreDNS pods themselves are unreachable. This tutorial shows you how to layer Vigilmon external uptime monitoring on top of your CoreDNS observability stack so you catch DNS failures from the outside in.


Why CoreDNS needs external monitoring

The CoreDNS Prometheus plugin exports detailed per-plugin metrics, and you can build dashboards around query error rates, cache hit ratios, and upstream resolver latency. But internal monitoring has a blind spot: it depends on the same cluster DNS it's measuring.

External monitoring catches what internal tooling misses:

  • CoreDNS pods crash-looping — the ReplicaSet eventually recovers, but DNS resolution fails cluster-wide for 30–120 seconds; external checks catch the gap immediately
  • ConfigMap corruption — a bad Corefile edit makes CoreDNS reject queries silently; internal dashboards stay green because the metrics server is still up
  • Upstream resolver timeouts — your pods can't resolve external hostnames but internal service discovery works fine; internal Prometheus misses this entirely
  • Resource exhaustion — CoreDNS runs out of memory and starts dropping queries while appearing healthy to the node
  • Node-level DNS (NodeLocal DNSCache) failure — the per-node DNS cache stops forwarding; a request hitting that node fails while the CoreDNS Deployment metrics look fine

External monitoring from Vigilmon gives you a ground-truth check from outside the cluster — the DNS availability your workloads actually experience.


What you'll need

  • A Kubernetes cluster with CoreDNS (v1.9 or later recommended)
  • kubectl access with cluster-admin or sufficient RBAC to read Deployments and Services
  • A free Vigilmon account — no credit card required

Step 1: Verify CoreDNS metrics are exposed

CoreDNS ships with the prometheus plugin enabled by default. Confirm it's active:

kubectl get configmap coredns -n kube-system -o yaml | grep prometheus
# Should show: prometheus :9153

Port-forward to inspect available metrics:

kubectl port-forward -n kube-system deployment/coredns 9153:9153 &
curl -s http://localhost:9153/metrics | grep -E "^coredns_"

Key metrics to monitor internally:

coredns_dns_requests_total          # total queries by type and zone
coredns_dns_responses_total         # responses by rcode (NOERROR, SERVFAIL, NXDOMAIN)
coredns_forward_requests_total      # upstream forwarder queries
coredns_forward_request_duration_seconds  # upstream resolver latency
coredns_cache_hits_total            # cache hit ratio numerator
coredns_cache_misses_total          # cache miss ratio numerator

Useful Prometheus alert rules:

# High SERVFAIL rate — DNS is returning errors
- alert: CoreDNSHighServfailRate
  expr: |
    rate(coredns_dns_responses_total{rcode="SERVFAIL"}[5m]) /
    rate(coredns_dns_responses_total[5m]) > 0.05
  for: 2m
  labels:
    severity: critical
  annotations:
    summary: "CoreDNS SERVFAIL rate above 5%"

# Upstream resolver latency spike
- alert: CoreDNSForwarderLatencyHigh
  expr: |
    histogram_quantile(0.99,
      rate(coredns_forward_request_duration_seconds_bucket[5m])
    ) > 2
  for: 5m
  labels:
    severity: warning
  annotations:
    summary: "CoreDNS upstream resolver p99 latency > 2s"

# Cache hit ratio degraded
- alert: CoreDNSLowCacheHitRatio
  expr: |
    rate(coredns_cache_hits_total[10m]) /
    (rate(coredns_cache_hits_total[10m]) + rate(coredns_cache_misses_total[10m])) < 0.3
  for: 10m
  labels:
    severity: warning
  annotations:
    summary: "CoreDNS cache hit ratio below 30%"

Step 2: Expose a health endpoint for external checks

CoreDNS's health plugin exposes an HTTP health endpoint. Confirm it's enabled:

kubectl get configmap coredns -n kube-system -o yaml | grep health
# Should show: health

If missing, edit the ConfigMap to add it:

kubectl edit configmap coredns -n kube-system

Your Corefile should include:

.:53 {
    errors
    health {
       lameduck 5s
    }
    ready
    kubernetes cluster.local in-addr.arpa ip6.arpa {
       pods insecure
       fallthrough in-addr.arpa ip6.arpa
       ttl 30
    }
    prometheus :9153
    forward . /etc/resolv.conf
    cache 30
    loop
    reload
    loadbalance
}

The health plugin listens on port 8080 by default. Expose it via a NodePort or LoadBalancer Service for external access:

apiVersion: v1
kind: Service
metadata:
  name: coredns-health
  namespace: kube-system
spec:
  selector:
    k8s-app: kube-dns
  ports:
    - name: health
      port: 8080
      targetPort: 8080
      nodePort: 32053
  type: NodePort
kubectl apply -f coredns-health-svc.yaml

Test the endpoint:

curl http://<NODE_IP>:32053/health
# Returns: OK

Step 3: Add CoreDNS checks in Vigilmon

Log in to Vigilmon and add HTTP monitors for each CoreDNS health endpoint:

  1. Click Add MonitorHTTP(S)
  2. Set URL to http://<NODE_IP>:32053/health
  3. Set check interval to 60 seconds
  4. Set expected keyword to OK
  5. Enable alert notifications for your team

If you have multiple control-plane nodes running CoreDNS, add one monitor per node IP. This catches node-level failures that a single endpoint check would miss.

For the ready endpoint (returns 200 only when CoreDNS is fully initialized):

curl http://<NODE_IP>:32053/ready
# Returns: OK when all plugins are loaded

Add a second Vigilmon monitor pointing to /ready with keyword OK — this catches stuck plugin initialization which /health alone doesn't surface.


Step 4: Validate the alert path end-to-end

Simulate a CoreDNS failure to confirm Vigilmon fires before your internal alerting:

# Scale CoreDNS to zero
kubectl scale deployment coredns -n kube-system --replicas=0

# Confirm DNS resolution breaks
kubectl run -it --rm debug --image=busybox --restart=Never -- nslookup kubernetes.default.svc.cluster.local

Vigilmon should alert within one to two check intervals (60–120 seconds). Check your notification channel — Slack, PagerDuty, email, or webhook — and then restore CoreDNS:

kubectl scale deployment coredns -n kube-system --replicas=2

Recommended monitoring checklist

| Signal | Source | Threshold | |--------|--------|-----------| | Query SERVFAIL rate | CoreDNS Prometheus | > 5% over 2 min | | Upstream forwarder p99 latency | CoreDNS Prometheus | > 2 s | | Cache hit ratio | CoreDNS Prometheus | < 30% | | Health endpoint reachability | Vigilmon (external) | Any downtime | | Ready endpoint reachability | Vigilmon (external) | Any downtime | | CoreDNS pod count | Kubernetes metrics | < desired replicas |


Conclusion

CoreDNS is the DNS backbone of your Kubernetes cluster. Combining its built-in Prometheus metrics with Vigilmon's external uptime checks gives you complete DNS observability: internal signals catch query-level degradation before it becomes an outage, while Vigilmon confirms end-to-end reachability from outside the cluster — the view your application pods actually experience.

Set up your first CoreDNS monitor at vigilmon.online in under five minutes.

Monitor your app with Vigilmon

Free plan — 5 monitors, no credit card required. Up and running in 60 seconds.

Start free →