NameserverNameserverGolangNameserver
 
DNS解析过程
 
Golangnet.ResolverLookupHost(ctx context.Context, host string) (addrs []string, err error)
 
hostsresolv.confnameservernameservernameservernameserver
 
/etc/resolv.confnameserverkubernetessidecarservicednsPolicyClusterFirst
 
自定义Nameserver
 
GolangNameserverResolverhttpClientDialContext()
 
Resolver
 
// 默认dialer
dialer := &net.Dialer{
		Timeout: 1 * time.Second,
}
// 定义resolver
resolver := &net.Resolver{
	Dial: func(ctx context.Context, network, address string) (net.Conn, error) {
		return dialer.DialContext(ctx, "tcp", nameserver) // 通过tcp请求nameserver解析域名
	},
}
 
Dialer
 
type Dialer struct {
	dialer     *net.Dialer
	resolver   *net.Resolver
	nameserver string
}
// NewDialer create a Dialer with user's nameserver.
func NewDialer(dialer *net.Dialer, nameserver string) (*Dialer, error) {
	conn, err := dialer.Dial("tcp", nameserver)
	if err != nil {
		return nil, err
	}
	defer conn.Close()
	return &Dialer{
		dialer: dialer,
		resolver: &net.Resolver{
			Dial: func(ctx context.Context, network, address string) (net.Conn, error) {
				return dialer.DialContext(ctx, "tcp", nameserver)
			},
		},
		nameserver: nameserver, // 用户设置的nameserver
	}, nil
}
// DialContext connects to the address on the named network using
// the provided context.
func (d *Dialer) DialContext(ctx context.Context, network, address string) (net.Conn, error) {
	host, port, err := net.SplitHostPort(address)
	if err != nil {
		return nil, err
	}
	ips, err := d.resolver.LookupHost(ctx, host) // 通过自定义nameserver查询域名
	for _, ip := range ips {
    // 创建链接
		conn, err := d.dialer.DialContext(ctx, network, ip+":"+port)
		if err == nil {
			return conn, nil
		}
	}
	return d.dialer.DialContext(ctx, network, address)
}
 
httpClientDialContext()
 
ndialer, _ := NewDialer(dialer, nameserver)
client := &http.Client{
  Transport: &http.Transport{
    DialContext:         ndialer.DialContext,
    TLSHandshakeTimeout: 10 * time.Second,
  },
  Timeout: timeout,
}
 
总结
 
NameserverDailer