Understanding Kubernetes DNS and SRV-Based Service Discovery#

I have been reading about Kubernetes DNS and going through its official specification available on GitHub Kubernetes DNS specification

After studying the documentation, I understood how Kubernetes performs internal service discovery using DNS. This led me to an interesting idea.

Can I build my own client-server application where the client only resolves a service name and protocol (like _servicename._tcp or _servicename._udp), and automatically retrieves the port from DNS, without hardcoding the server address and port number?

The answer is yes, using SRV records.

Deep Dive into SRV Records (RFC 2782)#

To understand this better, I read the official SRV RFC 2782.

From RFC 2782, I learned that SRV records contain:

  • Priority
  • Weight
  • Port
  • Target (hostname)

The format:

 _service._proto.domain TTL IN SRV priority weight port target

How Priority Works#

  • Lower number = higher priority
  • Clients MUST try the lowest priority first
  • Higher priority numbers act as failover

Example:

_test._udp.0xmm.in. 1800 IN SRV 9  25 8888 hello3.0xmm.in.
_test._udp.0xmm.in. 1800 IN SRV 10 10 8888 hello1.0xmm.in.
_test._udp.0xmm.in. 1800 IN SRV 20 15 8888 hello2.0xmm.in.

In this case:

  • Priority 9 is preferred over 10
  • Priority 10 is preferred over 20

If hello3 is unreachable, the client moves to priority 10.

This provides DNS-based failover.

How Weight Works#

Weight is used only among records with the same priority.

Higher weight = higher probability of being selected.

Example:

_test._udp.0xmm.in. 1800 IN SRV 10 5  8888 hello1.0xmm.in.
_test._udp.0xmm.in. 1800 IN SRV 10 15 8888 hello2.0xmm.in.

Here:

  • Both have priority 10
  • Weight 15 has higher selection probability than weight 5

Selection is done proportionally:

hello1 → 5/(10+5) = 25%
hello2 → 15/(10+15) = 75%

This enables DNS-based load balancing.

Special Case: Weight = 0#

From RFC 2782:

Domain administrators SHOULD use Weight 0 when there isn’t any server selection to do. In the presence of records containing weights greater than 0, records with weight 0 should have a very small chance of being selected.

Building DNS-Based Load Balancing#

Using priority and weight together, we can design failover systemand load balancing mechanism

Example:

_test._udp.0xmm.in. 1800 IN SRV 9  25 8888 hello3.0xmm.in.
_test._udp.0xmm.in. 1800 IN SRV 10 10 8888 hello1.0xmm.in.
_test._udp.0xmm.in. 1800 IN SRV 20 15 8888 hello2.0xmm.in.

Behavior:

  1. Client selects priority 9
  2. If unreachable → try priority 10
  3. If unreachable → try priority 20

This creates automatic failover logic at the DNS level.

Retrieving Port and Target#

package main
import (
	"fmt"
	"net"
)
func main() {
	_, addrs, err := net.LookupSRV("test", "udp", "0xmm.in")
	if err != nil {
		fmt.Println("Error:", err)
		return
	}
	for _, a := range addrs {
		fmt.Printf("host=%s port=%d\n", a.Target, a.Port)
	}
}

Example output:

host=hello2.0xmm.in. port=8888
host=hello1.0xmm.in. port=8888

above can be same used for tcp based service/protocol

net.LookupSRV():

  • Returns SRV records sorted by priority
  • Does NOT automatically perform weighted random selection
  • Does NOT automatically perform failover
  • Your application must implement connection retry logic

Final thought#

By using SRV records:

  • No need to hardcode server address
  • No need to hardcode port number

:wq for now, until next time.