Custom CoreDNS Runbook
I recently left my k3s cluster turned off for a week or so. When I turned it back on, the k3s.differentpla.net
DNS wasn’t working. Let’s figure it out and maybe write a runbook for the next time.
Problem: Server Not Found
Browsing to https://nginx.k3s.differentpla.net/
from my Windows laptop fails with “Server Not Found”, rather than the expected nginx placeholder.
Approach
There are a number of things that could be broken:
- Client DNS resolution on Windows.
- DNS server on CoreDNS.
- Load Balancer.
- nginx not running?
- Something else?
Let’s start ruling these out.
Investigation: DNS
It’s always DNS.
If I try nslookup nginx.k3s.differentpla.net
from Windows, the query times out. This suggests that it’s a DNS problem.
You’ll recall that the DNS query initially goes to the router, which forwards it to a NodePort
service on the cluster.
Let’s see if directly querying CoreDNS on the cluster works:
$ dig +short -p 32053 @rpi401 nginx.k3s.differentpla.net
192.168.28.11
It does. Our problem is therefore (probably) somewhere between the router and the cluster. If it hadn’t worked, we would have needed to dig into pod status, etc.
Annoyingly, Synology SRM uses Busybox; it doesn’t include dig
, and the nslookup
implementation doesn’t allow
specifying an alternative port number, so we’re kinda stuck.
The DNS forwarding is controlled by the /etc/dhcpd/dhcpd-k3s-dns.conf
file, which looks like this:
server=/k3s.differentpla.net/192.168.28.181#32053
So it’s forwarding the query to 192.168.28.181:32053
. Is that the correct IP address?
SynologyRouter> nslookup rpi401 localhost
Server: 127.0.0.1
Address 1: 127.0.0.1 localhost
Name: rpi401
Address 1: 192.168.28.180
No; it’s not. Seems the IP address of rpi401
changed. Presumably because the DHCP lease expired while the cluster was turned off.
Potential Fix: Use hostname when forwarding DNS?
I considered changing the forwarding rule to use the name, rather than the IP address, like this:
# This won't work.
server=/k3s.differentpla.net/rpi401#32053
But it doesn’t work:
SynologyRouter> nslookup rpi401
nslookup: can't resolve 'rpi401'
Fix: DHCP reservation
So it looks like we’ll have to set up a DHCP reservation for (at least) the control plane node (rpi401) of our cluster. That’s a relatively simple fix in the Synology SRM user interface.
- Log into SRM.
- Open “Network Center”.
- Go to the “Local Network” section.
- In the “DHCP Clients” tab, verify that nothing’s using the
.181
IP address.- This step is to avoid editing the DNS forwarding on the router, because that requires announcing a maintenance window (for restarting dnsmasq on the router) to the family. Fortunately, this address wasn’t in use.
- Grab the MAC/DUID for
rpi401
. - In the “DHCP Reservation” tab, add a reservation. You’ll need the MAC/DUID from the previous step (or you can grab it from the node with
ip addr show dev eth0
). - This doesn’t work: Renew the node’s IP address with
sudo networkctl renew eth0
. - Restart networking on the pod with
systemctl restart systemd-networkd
. This will kill your SSH session.
With any luck, the node will now have the reserved (.181
) IP address.
Problem: DNS still broken
The node now has the correct IP address, but the dig
command from above is now broken:
$ dig +short -p 32053 @rpi401 nginx.k3s.differentpla.net
...hangs...
According to kubectl --namespace k3s-dns get all
, the pod is running and the service is correct. Everything should be
fine. For now, I’m going to assume that the changing IP address confused CoreDNS. Maybe deleting and recreating the pod
will fix it?
It didn’t.
According to kubectl --namespace k3s-dns get pods -o wide
, the pod is running on rpi404
. Does that work?
$ dig +short -p 32053 @rpi404 nginx.k3s.differentpla.net
192.168.29.11
Yes; it does. Obviously the NodePort service is messed up. Let’s try deleting and recreating it:
$ kubectl --namespace k3s-dns delete service k3s-dns
service "k3s-dns" deleted
$ kubectl apply -f k3s-dns/svc.yaml
service/k3s-dns created
$ kubectl --namespace k3s-dns get service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
k3s-dns NodePort 10.43.108.230 <none> 53:32053/TCP,53:32053/UDP 3s
Nope:
$ dig +short -p 32053 @rpi401 nginx.k3s.differentpla.net
...hangs...
Yeah; it’s still broken. If this were a production cluster, I’d be a bit less gung-ho, but it’s not, so I’m gonna just
restart the rpi401
node. Of course, if this were a production cluster, I’d have production-grade DNS, and this wouldn’t be necessary.
It takes about 90 seconds for the node to restart, but that seems to fix it.
Lessons
- If you’re relying on an IP address not changing, make sure it doesn’t change. Consider fixed (reserved) IP addresses.
- Kubernetes doesn’t seem to care if you restart nodes. It just keeps chugging.
- It does care if you reconfigure the network under its feet.
- You’re still going to need monitoring.