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
- kubenetes源码分析之DNS(五)
- kubenetes源码分析之DNS(一)
- kubenetes源码分析之DNS(二)
- kubenetes源码分析之DNS(三)
- kubenetes源码分析之DNS(四)
- kubenetes源码分析之DNS(六)
- kubenetes源码分析之DNS(七)
- kubenetes源码分析之DNS(八)
- elasticsearch源码分析之Transport(五)
- elasticsearch源码分析之Transport(五)
- Harbor 源码分析之状态机(五)
- leveldb源码分析之五
- contiki 源码分析之sys(五)(core / sys)
- Android FM模块学习之四源码分析(五)
- Spark源码分析之五:Task调度(一)
- KVM虚拟化源码分析之KVM_TOOLS(五)
- Harbor 源码分析之仓库同步(五)
- LevelDB源码分析之五:skiplist(1)
- 敏捷软件开发宣言
- 分布式案例补充--zookeeper
- 使用第三方推送功能变相实现一些即时通讯操作
- Try disabling Instant Run
- 索引
- kubenetes源码分析之DNS(五)
- [android]JPush自定义通知栏
- LintCode 32 最小子串覆盖
- 两个一位数组能否排序一个另一个跟着排序?
- 关于Flex 布局。
- 一铭server7运行自动化测试(ltp, audittest)
- 2016-2017前端面试题
- linux下.bashrc文件修改和生效
- Spring的各个模块与导包原则