Search code examples
godnsconsulsrv

Fetching Cosul SRV records in golang


I have a Main application and multiple worker nodes, which are registered in consul. I want to send data to the worker nodes, by load balancing. Using the consul API for golang, I'm able to get the available Services on the main application.

But, I'm unable to get DNS SRV records in my golang application.

As mention in this thread, How can I read consul SRV records in my go application?, I tried github.com/miekg/dns, but it didn't work. Also, I tried using github.com/benschw/consul-clb-go, as:

c := clb.NewClb("127.0.0.1", "8600", clb.Random)

srvRecord := "Processor" + ".service.consul"
address, err := c.GetAddress(srvRecord)
if err != nil {
    fmt.Println(err)
}
fmt.Println(address)

It gives me this error:

panic: runtime error: index out of range [0] with length 0

Also,I tried using the net package as follows:

resolver := &net.Resolver{
    Dial: func(ctx context.Context, network, address string) (net.Conn, error) {
        return (&net.Dialer{}).DialContext(ctx, network, "127.0.0.1:8600")
    },
}
_, addrs, err := resolver.LookupSRV(
    context.Background(), "Processor", "tcp", "consul",
)
if err != nil {
    fmt.Printf("Error : %v", err)
}
fmt.Println(addrs)

It returns:

Error : lookup _Processor._tcp.consul: dnsquery: DNS name does not exist.[]

I also tried adding "service" to the query string, but it also returned the same error.

But, dig returns correctly:

C:\Users\Sude>dig @127.0.0.1 -p 8600 Processor.service.consul SRV

; <<>> DiG 9.8.8 <<>> @127.0.0.1 -p 8600 Processor.service.consul SRV
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 62807
;; flags: qr aa rd; QUERY: 1, ANSWER: 3, AUTHORITY: 0, ADDITIONAL: 0
;; WARNING: recursion requested but not available

;; QUESTION SECTION:
;Processor.service.consul.      IN      SRV

;; ANSWER SECTION:
Processor.service.consul. 0     IN      SRV     1 1 8001 localhost.
Processor.service.consul. 0     IN      SRV     1 1 8005 localhost.
Processor.service.consul. 0     IN      SRV     1 1 8004 localhost.

;; Query time: 0 msec
;; SERVER: 127.0.0.1#8600(127.0.0.1)
;; WHEN: Sat Jun 27 09:37:05 India Standard Time 2020
;; MSG SIZE  rcvd: 129

How could I Read these records inside my go application?

Also, is there any function in Go Consul API to get load-balanced endpoints? It would also be sufficient.


Solution

  • I found the solution after going through the Consul Golang API docs. The best way is to use PreparedQueries:

    preparedQuery := consul.PreparedQuery()
    queryID, _, err := pq.Create(&consulapi.PreparedQueryDefinition{
        Name: "DnsQuery",
        Service: consulapi.ServiceQuery{
            Service:     "Processor",
            OnlyPassing: true,
        },
    }, &consulapi.WriteOptions{})
    if err != nil {
        fmt.Println(err)
    }
    
    res, _, _ := preparedQuery.Execute(queryID, &consulapi.QueryOptions{})
    for _, node := range res.Nodes {
        fmt.Println(node.Service.Address, node.Service.Port)
    }
    

    res.Nodes is a slice of the service endpoints.