Skip to content

Instantly share code, notes, and snippets.

@kelseyhightower
Last active February 11, 2019 20:37
Show Gist options
  • Star 6 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kelseyhightower/5e43e93d3633edaf52de0046be5edbd9 to your computer and use it in GitHub Desktop.
Save kelseyhightower/5e43e93d3633edaf52de0046be5edbd9 to your computer and use it in GitHub Desktop.
// Compile with:
// GOOS=linux go build -a --ldflags '-extldflags "-static"' -tags netgo -installsuffix netgo -o dns-example main.go
//
// Run on Kubernetes. Example resolv.conf
//
// # /etc/reslov.conf
// search default.svc.cluster.local svc.cluster.local cluster.local google.internal c.hightowerlabs.internal
// nameserver 10.179.240.10
// options ndots:5
//
// Results in the following error:
// $ curl -O https://storage.googleapis.com/hightowerlabs/dns-example
// $ chmod +x dns-example
// $ ./dns-example
// 2016/10/25 16:11:46 lookup kubernetes.default.svc.cluster.local: unrecognized address
//
// But this works:
// $ dig +short kubernetes.default.svc.cluster.local
// 10.179.240.1
//
// While dig works it does not respect resolv.conf or the search domain list. So this does not work
// $ dig kubernetes
package main
import (
"log"
"fmt"
"net"
)
func main() {
ips, err := net.LookupAddr("kubernetes.default.svc.cluster.local")
if err != nil {
log.Fatal(err)
}
for _, ip := range ips {
fmt.Println(ip)
}
}
@kelseyhightower
Copy link
Author

The issue on the Go side is well documented: https://golang.org/pkg/net

By default the pure Go resolver is used, because a blocked DNS request consumes only a goroutine, while a blocked C call consumes an operating system thread. When cgo is available, the cgo-based resolver is used instead under a variety of conditions: on systems that do not let programs make direct DNS requests (OS X), when the LOCALDOMAIN environment variable is present (even if empty), when the RES_OPTIONS or HOSTALIASES environment variable is non-empty, when the ASR_CONFIG environment variable is non-empty (OpenBSD only), when /etc/resolv.conf or /etc/nsswitch.conf specify the use of features that the Go resolver does not implement, and when the name being looked up ends in .local or is an mDNS name.

The big issue here is that Kubernetes leverages .local for cluster services.

@thockin
Copy link

thockin commented Oct 25, 2016

We followed the lead of skydns and others. The fact that only the Go resolver does this says that, while it may be technically right, it is wrong.

Also: dig +search is your friend

@kelseyhightower
Copy link
Author

Looks like this is working as desired with the following code update:

package main

import (
    "log"
    "fmt"
    "net"
)

func main() {
    ips, err := net.LookupHost("kubernetes")
    if err != nil {
        log.Fatal(err)
    }
    for _, ip := range ips {
        fmt.Println(ip)
    }
}

Need to use LookupHost not LookupAddr

@kelseyhightower
Copy link
Author

This may have been fixed in 1.7.x

@kelseyhightower
Copy link
Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment