kubenetes源码分析之DNS(五)

上一篇介绍服务怎样存储和同步,现在说一下怎样提供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的最前端,提供服务。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

柳清风09

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值