kubenetes源码分析之DNS(五)

来源:互联网 发布:压缩文件破解软件 编辑:程序博客网 时间:2024/06/01 08:33

上一篇介绍服务怎样存储和同步,现在说一下怎样提供DNS服务的。startSkyDNSServer启动DNS域名解析服务

func (d *KubeDNSServer) startSkyDNSServer() {    glog.V(0).Infof("Starting SkyDNS server (%v:%v)", d.dnsBindAddress, d.dnsPort)    skydnsConfig := &server.Config{        Domain:  d.domain,        DnsAddr: fmt.Sprintf("%s:%d", d.dnsBindAddress, d.dnsPort),    }    if d.nameServers != "" {        for _, nameServer := range strings.Split(d.nameServers, ",") {            r, _ := regexp.Compile(":\\d+$")            if !r.MatchString(nameServer) {                nameServer = nameServer + ":53"            }            if err := validateHostAndPort(nameServer); err != nil {                glog.Fatalf("nameserver is invalid: %s", err)            }            skydnsConfig.Nameservers = append(skydnsConfig.Nameservers, nameServer)        }    }    server.SetDefaults(skydnsConfig)    s := server.New(d.kd, skydnsConfig)    if err := metrics.Metrics(); err != nil {        glog.Fatalf("Skydns metrics error: %s", err)    } else if metrics.Port != "" {        glog.V(0).Infof("Skydns metrics enabled (%v:%v)", metrics.Path, metrics.Port)    } else {        glog.V(0).Infof("Skydns metrics not enabled")    }    go s.Run()}

server启动后启动监听vendor/github.com/skynetservices/skydns/server/server.go

s.group.Add(1)        go func() {            defer s.group.Done()            if err := dns.ListenAndServe(s.config.DnsAddr, "tcp", mux); err != nil {                fatalf("%s", err)            }        }()        dnsReadyMsg(s.config.DnsAddr, "tcp")        s.group.Add(1)        go func() {            defer s.group.Done()            if err := dns.ListenAndServe(s.config.DnsAddr, "udp", mux); err != nil {                fatalf("%s", err)            }        }()        dnsReadyMsg(s.config.DnsAddr, "udp")

具体执行DNS解析的方式是func (s *server) ServeDNS(w dns.ResponseWriter, req *dns.Msg) 由于代码较长我只列出部分:

if q.Qclass == dns.ClassCHAOS {        if q.Qtype == dns.TypeTXT {            switch name {            case "authors.bind.":                fallthrough            case s.config.Domain:                hdr := dns.RR_Header{Name: q.Name, Rrtype: dns.TypeTXT, Class: dns.ClassCHAOS, Ttl: 0}                authors := []string{"Erik St. Martin", "Brian Ketelsen", "Miek Gieben", "Michael Crosby"}                for _, a := range authors {                    m.Answer = append(m.Answer, &dns.TXT{Hdr: hdr, Txt: []string{a}})                }                for j := 0; j < len(authors)*(int(dns.Id())%4+1); j++ {                    q := int(dns.Id()) % len(authors)                    p := int(dns.Id()) % len(authors)                    if q == p {                        p = (p + 1) % len(authors)                    }                    m.Answer[q], m.Answer[p] = m.Answer[p], m.Answer[q]                }                return            case "version.bind.":                fallthrough            case "version.server.":                hdr := dns.RR_Header{Name: q.Name, Rrtype: dns.TypeTXT, Class: dns.ClassCHAOS, Ttl: 0}                m.Answer = []dns.RR{&dns.TXT{Hdr: hdr, Txt: []string{Version}}}                return            case "hostname.bind.":                fallthrough            case "id.server.":                // TODO(miek): machine name to return                hdr := dns.RR_Header{Name: q.Name, Rrtype: dns.TypeTXT, Class: dns.ClassCHAOS, Ttl: 0}                m.Answer = []dns.RR{&dns.TXT{Hdr: hdr, Txt: []string{"localhost"}}}                return            }        }        // still here, fail        m.SetReply(req)        m.SetRcode(req, dns.RcodeServerFailure)        return    }    switch q.Qtype {    case dns.TypeNS:        if name != s.config.Domain {            break        }        // Lookup s.config.DnsDomain        records, extra, err := s.NSRecords(q, s.config.dnsDomain)        if isEtcdNameError(err, s) {            m = s.NameError(req)            return        }        m.Answer = append(m.Answer, records...)        m.Extra = append(m.Extra, extra...)    case dns.TypeA, dns.TypeAAAA:        records, err := s.AddressRecords(q, name, nil, bufsize, dnssec, false)        if isEtcdNameError(err, s) {            m = s.NameError(req)            return        }        m.Answer = append(m.Answer, records...)    case dns.TypeTXT:        records, err := s.TXTRecords(q, name)        if isEtcdNameError(err, s) {            m = s.NameError(req)            return        }        m.Answer = append(m.Answer, records...)    case dns.TypeCNAME:        records, err := s.CNAMERecords(q, name)        if isEtcdNameError(err, s) {            m = s.NameError(req)            return        }        m.Answer = append(m.Answer, records...)    case dns.TypeMX:        records, extra, err := s.MXRecords(q, name, bufsize, dnssec)        if isEtcdNameError(err, s) {            m = s.NameError(req)            return        }        m.Answer = append(m.Answer, records...)        m.Extra = append(m.Extra, extra...)    default:        fallthrough // also catch other types, so that they return NODATA    case dns.TypeSRV:        records, extra, err := s.SRVRecords(q, name, bufsize, dnssec)        if err != nil {            if isEtcdNameError(err, s) {                m = s.NameError(req)                return            }            logf("got error from backend: %s", err)            if q.Qtype == dns.TypeSRV { // Otherwise NODATA                m = s.ServerFailure(req)                return

这些都是组织Answer的部分,eg:如果服务请求类型是TypeSRV,则通过SRVRecords这个方法去获取,方法里面又通过services, err := s.backend.Records(name, false)获取Record,这个backend就是之前kd,pkg/dns/dns.go

`func (kd *KubeDNS) Records(name string, exact bool) (retval []skymsg.Service, err error) {    glog.V(3).Infof("Query for %q, exact: %v", name, exact)    trimmed := strings.TrimRight(name, ".")    segments := strings.Split(trimmed, ".")    isFederationQuery := false    federationSegments := []string{}    if !exact && kd.isFederationQuery(segments) {        glog.V(3).Infof("Received federation query, trying local service first")        // Try querying the non-federation (local) service first. Will try        // the federation one later, if this fails.        isFederationQuery = true        federationSegments = append(federationSegments, segments...)        // To try local service, remove federation name from segments.        // Federation name is 3rd in the segment (after service name and        // namespace).        segments = append(segments[:2], segments[3:]...)    }    path := util.ReverseArray(segments)    records, err := kd.getRecordsForPath(path, exact)    if err != nil {        return nil, err    }    if isFederationQuery {        return kd.recordsForFederation(records, path, exact, federationSegments)    } else if len(records) > 0 {        glog.V(4).Infof("Records for %v: %v", name, records)        return records, nil    }    glog.V(3).Infof("No record found for %v", name)    return nil, etcd.Error{Code: etcd.ErrorCodeKeyNotFound}}

当查询到Record之后,最终返回到通过下面代码返回到服务请求者:

    defer func() {        metrics.ReportRequestCount(req, metrics.Auth)        metrics.ReportDuration(m, start, metrics.Auth)        metrics.ReportErrorCount(m, metrics.Auth)        if m.Rcode == dns.RcodeServerFailure {            if err := w.WriteMsg(m); err != nil {                logf("failure to return reply %q", err)            }            return        }        // Set TTL to the minimum of the RRset and dedup the message, i.e. remove identical RRs.        m = s.dedup(m)        minttl := s.config.Ttl        if len(m.Answer) > 1 {            for _, r := range m.Answer {                if r.Header().Ttl < minttl {                    minttl = r.Header().Ttl                }            }            for _, r := range m.Answer {                r.Header().Ttl = minttl            }        }        if dnssec {            if s.config.PubKey != nil {                m.AuthenticatedData = true                s.Denial(m)                s.Sign(m, bufsize)            }        }        if send := s.overflowOrTruncated(w, m, int(bufsize), metrics.Auth); send {            return        }        s.rcache.InsertMessage(cache.Key(q, dnssec, tcp), m)        if err := w.WriteMsg(m); err != nil {            logf("failure to return reply %q", err)        }    }()

ok,这就是kubedns里面内置的skydns,提供域名解析服务的。但每次都要这样查询,系统的性能会有问题,所以kubernetes又设计了dnsmasq,接下来的blog会介绍这个缓存组件,它是DNS解析的第一站,是放在kubedns的最前端,提供服务。

0 0