diff --git a/kubernetes/infrastructure/coredns-config/configmap.yaml b/kubernetes/infrastructure/coredns-config/configmap.yaml index d51bab9e..93d60c6e 100644 --- a/kubernetes/infrastructure/coredns-config/configmap.yaml +++ b/kubernetes/infrastructure/coredns-config/configmap.yaml @@ -15,9 +15,23 @@ data: # (The old Proxmox DNS VIP 10.2.40.53 is DECOMMISSIONED.) 10.96.0.11 is a # pinned ClusterIP of the k8s-gateway Service — avoids DNS-name # resolution during CoreDNS startup. + # Cache tuning mirrors k8s-gateway's (issue #393): the UDM's dnsmasq + # refuses connections in bursts, and because the public renner.uno zone + # has a *.renner.uno wildcard CNAME that matches at every depth, a local + # failure never returns NXDOMAIN — it resolves to the WAN proxy instead. + # Correct answers carry TTL 5 (dnsmasq lease records) while the wrong + # wildcard answer carries TTL 300, so one brief blip pins a wrong answer + # for minutes. `success ... 60` raises the 5s TTL to a 60s floor and + # `serve_stale 1h immediate` keeps serving through an upstream outage. + # NOTE: only cache/serve_stale — the `template` plugin is deliberately NOT + # reintroduced here (it broke cluster DNS in 7a09bad5). renner.uno:53 { errors - cache 30 + cache 300 { + success 9984 300 60 + denial 9984 300 30 + serve_stale 1h immediate + } forward . 10.96.0.11 loop reload diff --git a/kubernetes/infrastructure/k8s-gateway/helmrelease.yaml b/kubernetes/infrastructure/k8s-gateway/helmrelease.yaml index 657c78e0..75564d5c 100644 --- a/kubernetes/infrastructure/k8s-gateway/helmrelease.yaml +++ b/kubernetes/infrastructure/k8s-gateway/helmrelease.yaml @@ -64,8 +64,33 @@ spec: parameters: ":8080" - name: ready parameters: ":8181" + # Survive the UDM's intermittent DNS outages (issue #393). + # + # The UDM's dnsmasq refuses connections in bursts — 330 "connection + # refused" errors in the last 3000 log lines here, on BOTH 10.2.40.1 and + # fd00::1. That alone would only be a blip, but it combines with a + # wildcard trap: the public renner.uno zone has a *.renner.uno CNAME to + # proxy.renner.uno that matches at EVERY depth, so renner.uno never + # returns NXDOMAIN. Any name that fails locally resolves publicly to the + # WAN proxy instead of failing honestly. + # + # The TTLs make it stick: the correct answer is a dnsmasq lease record + # with TTL 5, the wrong wildcard answer has TTL 300 — 60x more durable. + # One 5-second UDM blip therefore pins a wrong answer for 5 minutes. + # + # `success ... 60` clamps that 5s TTL up to a 60s floor, and + # `serve_stale 1h immediate` keeps answering from cache while the + # upstream is refusing connections, so a blip stops becoming a lookup + # failure that the wildcard can capture. + # + # Written on ONE line deliberately: the chart interpolates `parameters` + # into its ConfigMap template, and a multi-line value breaks the YAML + # render ("could not find expected ':'"). Verified with `helm template` + # plus a real `k8s_gateway:1.7.0` container (CoreDNS 1.14.2) before + # merging. For the same reason the forward block is left untouched — + # its options need newlines and cannot be expressed here. - name: cache - parameters: "30" + parameters: "300 { success 9984 300 60 denial 9984 300 30 serve_stale 1h immediate }" - name: loop - name: reload - name: forward