kubernetesdnsubuntu

Kubernetes Split DNS on Ubuntu 24.04

Kubernetes Split DNS on Ubuntu 24.04

Using Kubernetes kube-dns as a Resolver on Ubuntu 24.04 (systemd‑resolved Split DNS)

Overview

Modern Ubuntu systems (including Ubuntu 24.04) use systemd-resolved to manage DNS resolution.
When working on a Kubernetes node or DevOps workstation, it is extremely useful to resolve:

*.svc.cluster.local
*.cluster.local

directly from the host machine.

This allows engineers to access services like:

grafana.monitoring.svc.cluster.local
prometheus.monitoring.svc.cluster.local
zabbix-server.monitoring.svc.cluster.local

without relying on kubectl port-forward.

This article shows how to configure split DNS so:

Domain DNS Server


cluster.local Kubernetes kube-dns svc.cluster.local Kubernetes kube-dns ts.net Tailscale DNS Internet domains Public DNS (Google, etc.)


Architecture

Below is the DNS architecture after configuration.

flowchart TD

APP[Application / CLI Tools]

APP --> RESOLVER[systemd-resolved<br>127.0.0.53]

RESOLVER -->|*.cluster.local| KUBEDNS[Kubernetes CoreDNS<br>10.96.0.10]

RESOLVER -->|*.ts.net| TAILSCALE[Tailscale DNS<br>100.100.100.100]

RESOLVER -->|Public domains| GOOGLE[Public DNS<br>8.8.8.8]

Environment

Example environment used in this guide:

Component Value


OS Ubuntu 24.04 Resolver systemd-resolved Kubernetes DNS 10.96.0.10 Internet DNS 8.8.8.8 Tailscale DNS 100.100.100.100


Step 1 --- Find kube-dns Service IP

Retrieve the kube-dns service IP from Kubernetes.

kubectl -n kube-system get svc kube-dns

Example output:

NAME       TYPE        CLUSTER-IP   PORT(S)
kube-dns   ClusterIP   10.96.0.10   53/UDP,53/TCP

This IP is the DNS endpoint inside the Kubernetes cluster.


Step 2 --- Configure systemd-resolved Split DNS

Create a resolver override configuration.

sudo mkdir -p /etc/systemd/resolved.conf.d
sudo nano /etc/systemd/resolved.conf.d/kubernetes.conf

Add:

[Resolve]
DNS=10.96.0.10
Domains=~cluster.local ~svc.cluster.local

Important detail:

~domain

means routing domain.

It tells systemd-resolved:

Only forward queries matching these domains to this DNS server.


Step 3 --- Restart the Resolver

sudo systemctl restart systemd-resolved

Step 4 --- Verify DNS Configuration

Run:

resolvectl status

Expected output:

Global
Current DNS Server: 10.96.0.10
DNS Domain: ~cluster.local ~svc.cluster.local

You should also see your regular DNS servers for network interfaces:

Link wlo1
DNS Servers: 8.8.8.8 8.8.4.4

and optionally:

Link tailscale0
DNS Servers: 100.100.100.100

DNS Resolution Flow

The DNS resolution flow now looks like this:

sequenceDiagram

participant App
participant Resolved as systemd-resolved
participant KubeDNS as kube-dns
participant PublicDNS as Public DNS
participant Tailscale as Tailscale DNS

App->>Resolved: grafana.monitoring.svc.cluster.local
Resolved->>KubeDNS: Forward query
KubeDNS-->>Resolved: Service IP
Resolved-->>App: Response

App->>Resolved: google.com
Resolved->>PublicDNS: Query
PublicDNS-->>Resolved: Response
Resolved-->>App: Response

App->>Resolved: host.ts.net
Resolved->>Tailscale: Query
Tailscale-->>Resolved: Response
Resolved-->>App: Response

Step 5 --- Test Kubernetes DNS

Test service resolution.

resolvectl query kubernetes.default.svc.cluster.local

or

dig kubernetes.default.svc.cluster.local

Example result:

10.96.0.1

Access Services Directly

Once configured, you can access Kubernetes services directly from the host.

Example:

curl http://grafana.monitoring.svc.cluster.local

or

curl http://prometheus.monitoring.svc.cluster.local

This dramatically simplifies debugging workflows.


Optional Enhancement --- Pod DNS

You can also add support for Pod DNS records.

Edit:

sudo nano /etc/systemd/resolved.conf.d/kubernetes.conf

Update:

[Resolve]
DNS=10.96.0.10
Domains=~cluster.local ~svc.cluster.local ~pod.cluster.local

Restart:

sudo systemctl restart systemd-resolved

This allows resolving:

10-244-1-5.default.pod.cluster.local

Benefits of this Setup

✔ Resolve Kubernetes services from your host
✔ No need for port-forwarding
✔ Works with multi-network setups
✔ Supports VPN DNS (Tailscale)
✔ Clean split DNS architecture


Final DNS Architecture

flowchart LR

UserApp --> LocalResolver[systemd-resolved]

LocalResolver -->|cluster.local| KubeDNS[CoreDNS]
LocalResolver -->|ts.net| TailscaleDNS[Tailscale DNS]
LocalResolver -->|internet| PublicDNS[Google DNS]

KubeDNS --> KubernetesCluster[Kubernetes Services]

Conclusion

Using systemd-resolved split DNS with Kubernetes enables a very powerful workflow for DevOps engineers.

You gain:

  • direct service discovery
  • simplified debugging
  • faster operations workflows
  • clean integration with VPN and public DNS

This approach is widely used by platform engineers managing Kubernetes clusters at scale.

Enjoyed this post?

Get the next one in your inbox — only when I ship something worth reading.

Newsletter form not configured.

Or follow on Substack for the newsletter.

Comments via GitHub Discussions

Comments not configured. Set GISCUS env vars to enable.