scout: stop the dhclient/tailscaled resolv.conf fight and give k3s a stable resolv.conf #16

Open
opened 2026-10-17 01:28:41 +11:00 by myagent · 0 comments
Collaborator

Follow-up from #15 / docs/forgejo-runner-dns.md. Not urgent; the runner-side fix in #15 already covers the job failures.

Problem

On scout, two dhclients (enp88s0, enp2s0f0) rewrite /etc/resolv.conf on every DHCP renewal (~25 min) and tailscaled rewrites it back: 423 "trample" cycles and 395 health(warnable=resolv-conf-overwritten) warnings in 7 days (journalctl -u tailscaled | grep -i trampled). At the moment of each cycle the file is briefly empty (current contents: "").

Consequence for the cluster: whatever the file says when a pod sandbox is created is what kubelet bakes in. Today k3s's CoreDNS has exactly one . upstream — tailscaled's MagicDNS forwarder 100.100.100.100, which resolves over DoH to NextDNS — so every pod's external DNS has no redundancy. CoreDNS metrics since 2026-03-29: 4,443 failed health checks against that upstream, 16,266 queries served while it was marked down, 15,597 SERVFAILs to clients.

Proposed

  1. Stop dhclient writing resolv.conf (e.g. supersede domain-name-servers / make_resolv_conf(){ :; } hook, or let tailscaled own it via --accept-dns + a resolvconf-aware setup). Pick whichever keeps the host's MagicDNS working.
  2. Give kubelet a stable file: /etc/rancher/k3s/config.yaml → resolv-conf: /etc/rancher/k3s/resolv.conf (k3s v1.33.6 has the flag), containing e.g. the NextDNS anycast addresses DHCP already hands out (45.90.28.145, 45.90.30.145) plus search tuatara-puffin.ts.net so pod behaviour is unchanged. Restart k3s, then kubectl -n kube-system rollout restart deploy/coredns.
  3. /etc/rancher/k3s/config.yaml is hand-managed today; consider bringing it (or at least the resolv.conf) under ansible/.

Caveat

CoreDNS does not fail over on an upstream SERVFAIL answer (only on timeouts/unreachable), so this helps outages of the tailscaled path but is not a substitute for the runner's own fallback nameservers from #15.

Verify

kubectl -n kube-system port-forward deploy/coredns 9153 then curl -s localhost:9153/metrics | grep -E 'proxy_healthcheck|SERVFAIL' — the to= label should show the new upstreams and the health-check failure counter should stop growing.

Follow-up from #15 / `docs/forgejo-runner-dns.md`. Not urgent; the runner-side fix in #15 already covers the job failures. ## Problem On scout, two `dhclient`s (enp88s0, enp2s0f0) rewrite `/etc/resolv.conf` on every DHCP renewal (~25 min) and tailscaled rewrites it back: 423 "trample" cycles and 395 `health(warnable=resolv-conf-overwritten)` warnings in 7 days (`journalctl -u tailscaled | grep -i trampled`). At the moment of each cycle the file is briefly empty (`current contents: ""`). Consequence for the cluster: whatever the file says when a pod sandbox is created is what kubelet bakes in. Today k3s's CoreDNS has exactly **one** `.` upstream — tailscaled's MagicDNS forwarder `100.100.100.100`, which resolves over DoH to NextDNS — so every pod's external DNS has no redundancy. CoreDNS metrics since 2026-03-29: 4,443 failed health checks against that upstream, 16,266 queries served while it was marked down, 15,597 SERVFAILs to clients. ## Proposed 1. Stop dhclient writing resolv.conf (e.g. `supersede domain-name-servers` / `make_resolv_conf(){ :; }` hook, or let tailscaled own it via `--accept-dns` + a resolvconf-aware setup). Pick whichever keeps the host's MagicDNS working. 2. Give kubelet a stable file: `/etc/rancher/k3s/config.yaml` → `resolv-conf: /etc/rancher/k3s/resolv.conf` (k3s v1.33.6 has the flag), containing e.g. the NextDNS anycast addresses DHCP already hands out (`45.90.28.145`, `45.90.30.145`) plus `search tuatara-puffin.ts.net` so pod behaviour is unchanged. Restart k3s, then `kubectl -n kube-system rollout restart deploy/coredns`. 3. `/etc/rancher/k3s/config.yaml` is hand-managed today; consider bringing it (or at least the resolv.conf) under `ansible/`. ## Caveat CoreDNS does not fail over on an upstream **SERVFAIL** answer (only on timeouts/unreachable), so this helps outages of the tailscaled path but is not a substitute for the runner's own fallback nameservers from #15. ## Verify `kubectl -n kube-system port-forward deploy/coredns 9153` then `curl -s localhost:9153/metrics | grep -E 'proxy_healthcheck|SERVFAIL'` — the `to=` label should show the new upstreams and the health-check failure counter should stop growing.
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
sophie/homelab#16
No description provided.