用coredns快速实现xip.io的功能

最近大家在内部测试Kubernetes上层服务,Ingress、Open vSwitch乱飞,于是大家需要使用hostname,比如test.172.3.1.100.xip.cloud.com,要有个dns能将这个地址解析为172.3.1.100,xip是外部网站,大家总觉得别扭 (test.172.3.1.100.xip.io),需要在内部也实现一个,于是就直接写起来。

go get github.com/coredns/coredns

得到源代码并编译好。
扫一眼源代码结构,懒得从头自己写external plugin了,plugin.cfg包含了etcd也不会用到,直接把它改成xip的形式吧。etcd会根据dns查询的hostname去使用etcd的client查询数据,我们只要把client那层干掉,直接解析hostname,把ip抓出来,返回就好了。

grep下etcd client,定位到plugin/etcd/etcd.go

diff --git a/plugin/etcd/etcd.go b/plugin/etcd/etcd.go
index 493764f..f4e8f38 100644
--- a/plugin/etcd/etcd.go
+++ b/plugin/etcd/etcd.go
@@ -3,10 +3,11 @@ package etcd

 import (
        "context"
-       "encoding/json"
+       //"encoding/json"
        "errors"
        "fmt"
        "strings"
+       "strconv"
        "time"

        "github.com/coredns/coredns/plugin"
@@ -69,92 +70,47 @@ func (e *Etcd) IsNameError(err error) bool {
        return err == errKeyNotFound
 }

+func check_number(num string) bool {
+       i, err := strconv.Atoi(num)
+       if (err != nil) { return false }
+       if (i < 0 || i > 255) { return false }
+       return true
+}
+
 // Records looks up records in etcd. If exact is true, it will lookup just this
 // name. This is used when find matches when completing SRV lookups for instance.
 func (e *Etcd) Records(state request.Request, exact bool) ([]msg.Service, error) {
        name := state.Name()
-
-       path, star := msg.PathWithWildcard(name, e.PathPrefix)
-       r, err := e.get(path, true)
-       if err != nil {
-               return nil, err
        // e.g. 配置`etcd x.com`,当查询`127.0.0.1.x.com`时返回`127.0.0.1`
+       suffix := ""
+       if (len(e.Zones) > 0) {
+               suffix = "." + e.Zones[0]
+       }
+       if (len(suffix) > len(name)) {
+               return nil, fmt.Errorf("'%s' is longer than '%s'", suffix, name)
+       }
+       prefix := name[0:len(name) - len(suffix)]
        // 检查是ip v4的地址
+       t := strings.Split(prefix, ".")
+       n := len(t)
+        if (n < 4) {
+               return nil, fmt.Errorf("'%s' is not valid", name)
+        }
+       t = t[n - 4:n]
+       if (!check_number(t[0]) || !check_number(t[1]) || !check_number(t[2]) || !check_number(t[3])) {
+               return nil, fmt.Errorf("'%s' is not valid", name)
        }
-       segments := strings.Split(msg.Path(name, e.PathPrefix), "/")
-       return e.loopNodes(r.Kvs, segments, star)
+       host := strings.Join(t, ".")
+       fmt.Println("test:", name, host)
+       bx := make([]msg.Service, 0)
+       bx = append(bx, msg.Service{Host: host, Priority: 500, TTL: 32})
+       return bx, nil
 }

 // remove used code
 func (e *Etcd) get(path string, recursive bool) (*etcdcv3.GetResponse, error) {
-       ctx, cancel := context.WithTimeout(e.Ctx, etcdTimeout)
-       defer cancel()
-       if recursive == true {
-               if !strings.HasSuffix(path, "/") {
-                       path = path + "/"
-               }
-               r, err := e.Client.Get(ctx, path, etcdcv3.WithPrefix())
-               if err != nil {
-                       return nil, err
-               }
-               if r.Count == 0 {
-                       path = strings.TrimSuffix(path, "/")
-                       r, err = e.Client.Get(ctx, path)
-                       if err != nil {
-                               return nil, err
-                       }
-                       if r.Count == 0 {
-                               return nil, errKeyNotFound
-                       }
-               }
-               return r, nil
-       }
-
-       r, err := e.Client.Get(ctx, path)
-       if err != nil {
-               return nil, err
-       }
-       if r.Count == 0 {
-               return nil, errKeyNotFound
-       }
-       return r, nil
+       return nil, nil
 }

 func (e *Etcd) loopNodes(kv []*mvccpb.KeyValue, nameParts []string, star bool) (sx []msg.Service, err error) {
-       bx := make(map[msg.Service]bool)
-Nodes:
-       for _, n := range kv {
-               if star {
-                       s := string(n.Key)
-                       keyParts := strings.Split(s, "/")
-                       for i, n := range nameParts {
-                               if i > len(keyParts)-1 {
-                                       // name is longer than key
-                                       continue Nodes
-                               }
-                               if n == "*" || n == "any" {
-                                       continue
-                               }
-                               if keyParts[i] != n {
-                                       continue Nodes
-                               }
-                       }
-               }
-               serv := new(msg.Service)
-               if err := json.Unmarshal(n.Value, serv); err != nil {
-                       return nil, fmt.Errorf("%s: %s", n.Key, err.Error())
-               }
-               b := msg.Service{Host: serv.Host, Port: serv.Port, Priority: serv.Priority, Weight: serv.Weight, Text: serv.Text, Key: string(n.Key)}
-               if _, ok := bx[b]; ok {
-                       continue
-               }
-               bx[b] = true
-
-               serv.Key = string(n.Key)
-               serv.TTL = e.TTL(n, serv)
-               if serv.Priority == 0 {
-                       serv.Priority = priority
-               }
-               sx = append(sx, *serv)
-       }
-       return sx, nil
+       return nil, nil
 }

go build github.com/coredns/coredns 编译,运行,yes,搞定。

然后因为内部dns在*.cloud.com是定位服务ip的,就是说我们的配置里有file xxx.db cloud.com;如果再加个配置etcd xip.cloud.com,在进行nslookup www.127.0.0.1.xip.cloud.com查询时总会NXDOWN。发现coredns plugin的chain处理顺序不是按照配置文件里写的顺序,查查官方文档 https://coredns.io/manual/explugins/ 处理顺序是plugin.cfg里的顺序,把etcd移动上去:

diff --git a/plugin.cfg b/plugin.cfg
index 6a8ad0e..dc0c2ed 100644
--- a/plugin.cfg
+++ b/plugin.cfg
@@ -44,10 +44,10 @@ hosts:hosts
 route53:route53
 federation:federation
 kubernetes:kubernetes
+etcd:etcd
 file:file
 auto:auto
 secondary:secondary
-etcd:etcd
 loop:loop
 forward:forward
 proxy:proxy

go generate github.com/coredns/coredns 然后 go build github.com/coredns/coredns编译,再运行,好了,所有都正常了;这样既可以查询service.cloud.com,又可以查询*.<ip>.xip.cloud.com了。结束。

发布了51 篇原创文章 · 获赞 37 · 访问量 20万+

猜你喜欢

转载自blog.csdn.net/prog_6103/article/details/81207238
今日推荐