mirror of
https://github.com/coredns/coredns.git
synced 2025-10-27 08:14:18 -04:00
plugin/kubernetes: Add upstream @self and loop count (#1484)
* add upstream @self and loop count * 1st round of feedback * allow argless upstream * update test * readmes * feedback
This commit is contained in:
committed by
Miek Gieben
parent
ee8084a08f
commit
71ee323651
@@ -13,8 +13,8 @@ CoreDNS running the kubernetes plugin can be used as a replacement of kube-dns i
|
||||
cluster. See the [deployment](https://github.com/coredns/deployment) repository for details on [how
|
||||
to deploy CoreDNS in Kubernetes](https://github.com/coredns/deployment/tree/master/kubernetes).
|
||||
|
||||
[stubDomains](http://blog.kubernetes.io/2017/04/configuring-private-dns-zones-upstream-nameservers-kubernetes.html)
|
||||
are implemented via the *proxy* plugin.
|
||||
[stubDomains and upstreamNameservers](http://blog.kubernetes.io/2017/04/configuring-private-dns-zones-upstream-nameservers-kubernetes.html)
|
||||
are implemented via the *proxy* plugin and kubernetes *upstream*. See example below.
|
||||
|
||||
## Syntax
|
||||
|
||||
@@ -36,7 +36,7 @@ kubernetes [ZONES...] {
|
||||
labels EXPRESSION
|
||||
pods POD-MODE
|
||||
endpoint_pod_names
|
||||
upstream ADDRESS...
|
||||
upstream [ADDRESS...]
|
||||
ttl TTL
|
||||
fallthrough [ZONES...]
|
||||
}
|
||||
@@ -80,8 +80,9 @@ kubernetes [ZONES...] {
|
||||
follows: Use the hostname of the endpoint, or if hostname is not set, use the
|
||||
pod name of the pod targeted by the endpoint. If there is no pod targeted by
|
||||
the endpoint, use the dashed IP address form.
|
||||
* `upstream` **ADDRESS [ADDRESS...]** defines the upstream resolvers used for resolving services
|
||||
that point to external hosts (External Services). **ADDRESS** can be an IP, an IP:port, or a path
|
||||
* `upstream` [**ADDRESS**...] defines the upstream resolvers used for resolving services
|
||||
that point to external hosts (aka External Services aka CNAMEs). If no **ADDRESS** is given, CoreDNS
|
||||
will resolve External Services against itself. **ADDRESS** can be an IP, an IP:port, or a path
|
||||
to a file structured like resolv.conf.
|
||||
* `ttl` allows you to set a custom TTL for responses. The default (and allowed minimum) is to use
|
||||
5 seconds, the maximum is capped at 3600 seconds.
|
||||
@@ -129,24 +130,33 @@ kubernetes cluster.local {
|
||||
}
|
||||
~~~
|
||||
|
||||
Here we use the *proxy* plugin to implement stubDomains that forwards `example.org` and
|
||||
`example.com` to another nameserver.
|
||||
|
||||
## stubDomains and upstreamNameservers
|
||||
|
||||
Here we use the *proxy* plugin to implement a stubDomain that forwards `example.local` to the nameserver `10.100.0.10:53`.
|
||||
The *upstream* option in kubernetes means that ExternalName services (CNAMEs) will be resolved using the respective proxy.
|
||||
Also configured is an upstreamNameserver `8.8.8.8:53` that will be used for resolving names that do not fall in `cluster.local`
|
||||
or `example.local`.
|
||||
|
||||
~~~ txt
|
||||
cluster.local {
|
||||
kubernetes {
|
||||
endpoint https://k8s-endpoint:8443
|
||||
tls cert key cacert
|
||||
.:53 {
|
||||
kubernetes cluster.local {
|
||||
upstream
|
||||
}
|
||||
}
|
||||
example.org {
|
||||
proxy . 8.8.8.8:53
|
||||
}
|
||||
example.com {
|
||||
proxy example.local 10.100.0.10:53
|
||||
proxy . 8.8.8.8:53
|
||||
}
|
||||
~~~
|
||||
|
||||
The configuration above represents the following Kube-DNS stubDomains and upstreamNameservers configuration.
|
||||
|
||||
~~~ txt
|
||||
stubDomains: |
|
||||
{“example.local”: [“10.100.0.10:53”]}
|
||||
upstreamNameservers: |
|
||||
[“8.8.8.8:53”]
|
||||
~~~
|
||||
|
||||
## AutoPath
|
||||
|
||||
The *kubernetes* plugin can be used in conjunction with the *autopath* plugin. Using this
|
||||
|
||||
@@ -11,7 +11,8 @@ import (
|
||||
|
||||
// ServeDNS implements the plugin.Handler interface.
|
||||
func (k Kubernetes) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (int, error) {
|
||||
state := request.Request{W: w, Req: r}
|
||||
opt := plugin.Options{}
|
||||
state := request.Request{W: w, Req: r, Context: ctx}
|
||||
|
||||
m := new(dns.Msg)
|
||||
m.SetReply(r)
|
||||
@@ -32,24 +33,24 @@ func (k Kubernetes) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.M
|
||||
|
||||
switch state.QType() {
|
||||
case dns.TypeA:
|
||||
records, err = plugin.A(&k, zone, state, nil, plugin.Options{})
|
||||
records, err = plugin.A(&k, zone, state, nil, opt)
|
||||
case dns.TypeAAAA:
|
||||
records, err = plugin.AAAA(&k, zone, state, nil, plugin.Options{})
|
||||
records, err = plugin.AAAA(&k, zone, state, nil, opt)
|
||||
case dns.TypeTXT:
|
||||
records, err = plugin.TXT(&k, zone, state, plugin.Options{})
|
||||
records, err = plugin.TXT(&k, zone, state, opt)
|
||||
case dns.TypeCNAME:
|
||||
records, err = plugin.CNAME(&k, zone, state, plugin.Options{})
|
||||
records, err = plugin.CNAME(&k, zone, state, opt)
|
||||
case dns.TypePTR:
|
||||
records, err = plugin.PTR(&k, zone, state, plugin.Options{})
|
||||
records, err = plugin.PTR(&k, zone, state, opt)
|
||||
case dns.TypeMX:
|
||||
records, extra, err = plugin.MX(&k, zone, state, plugin.Options{})
|
||||
records, extra, err = plugin.MX(&k, zone, state, opt)
|
||||
case dns.TypeSRV:
|
||||
records, extra, err = plugin.SRV(&k, zone, state, plugin.Options{})
|
||||
records, extra, err = plugin.SRV(&k, zone, state, opt)
|
||||
case dns.TypeSOA:
|
||||
records, err = plugin.SOA(&k, zone, state, plugin.Options{})
|
||||
records, err = plugin.SOA(&k, zone, state, opt)
|
||||
case dns.TypeNS:
|
||||
if state.Name() == zone {
|
||||
records, extra, err = plugin.NS(&k, zone, state, plugin.Options{})
|
||||
records, extra, err = plugin.NS(&k, zone, state, opt)
|
||||
break
|
||||
}
|
||||
fallthrough
|
||||
@@ -57,21 +58,21 @@ func (k Kubernetes) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.M
|
||||
k.Transfer(ctx, state)
|
||||
default:
|
||||
// Do a fake A lookup, so we can distinguish between NODATA and NXDOMAIN
|
||||
_, err = plugin.A(&k, zone, state, nil, plugin.Options{})
|
||||
_, err = plugin.A(&k, zone, state, nil, opt)
|
||||
}
|
||||
|
||||
if k.IsNameError(err) {
|
||||
if k.Fall.Through(state.Name()) {
|
||||
return plugin.NextOrFailure(k.Name(), k.Next, ctx, w, r)
|
||||
}
|
||||
return plugin.BackendError(&k, zone, dns.RcodeNameError, state, nil /* err */, plugin.Options{})
|
||||
return plugin.BackendError(&k, zone, dns.RcodeNameError, state, nil /* err */, opt)
|
||||
}
|
||||
if err != nil {
|
||||
return dns.RcodeServerFailure, err
|
||||
}
|
||||
|
||||
if len(records) == 0 {
|
||||
return plugin.BackendError(&k, zone, dns.RcodeSuccess, state, nil, plugin.Options{})
|
||||
return plugin.BackendError(&k, zone, dns.RcodeSuccess, state, nil, opt)
|
||||
}
|
||||
|
||||
m.Answer = append(m.Answer, records...)
|
||||
|
||||
@@ -14,7 +14,7 @@ import (
|
||||
"github.com/coredns/coredns/plugin/pkg/dnsutil"
|
||||
"github.com/coredns/coredns/plugin/pkg/fall"
|
||||
"github.com/coredns/coredns/plugin/pkg/healthcheck"
|
||||
"github.com/coredns/coredns/plugin/proxy"
|
||||
"github.com/coredns/coredns/plugin/pkg/upstream"
|
||||
"github.com/coredns/coredns/request"
|
||||
|
||||
"github.com/miekg/dns"
|
||||
@@ -31,7 +31,7 @@ import (
|
||||
type Kubernetes struct {
|
||||
Next plugin.Handler
|
||||
Zones []string
|
||||
Proxy proxy.Proxy // Proxy for looking up names during the resolution process
|
||||
Upstream upstream.Upstream
|
||||
APIServerList []string
|
||||
APIProxy *apiProxy
|
||||
APICertAuth string
|
||||
@@ -59,7 +59,6 @@ func New(zones []string) *Kubernetes {
|
||||
k.Namespaces = make(map[string]bool)
|
||||
k.interfaceAddrsFunc = func() net.IP { return net.ParseIP("127.0.0.1") }
|
||||
k.podMode = podModeDisabled
|
||||
k.Proxy = proxy.Proxy{}
|
||||
k.ttl = defaultTTL
|
||||
|
||||
return k
|
||||
@@ -146,7 +145,7 @@ func (k *Kubernetes) primaryZone() string { return k.Zones[k.primaryZoneIndex] }
|
||||
|
||||
// Lookup implements the ServiceBackend interface.
|
||||
func (k *Kubernetes) Lookup(state request.Request, name string, typ uint16) (*dns.Msg, error) {
|
||||
return k.Proxy.Lookup(state, name, typ)
|
||||
return k.Upstream.Lookup(state, name, typ)
|
||||
}
|
||||
|
||||
// IsNameError implements the ServiceBackend interface.
|
||||
|
||||
@@ -9,10 +9,9 @@ import (
|
||||
|
||||
"github.com/coredns/coredns/core/dnsserver"
|
||||
"github.com/coredns/coredns/plugin"
|
||||
"github.com/coredns/coredns/plugin/pkg/dnsutil"
|
||||
"github.com/coredns/coredns/plugin/pkg/parse"
|
||||
"github.com/coredns/coredns/plugin/proxy"
|
||||
|
||||
"github.com/coredns/coredns/plugin/pkg/upstream"
|
||||
"github.com/mholt/caddy"
|
||||
"github.com/miekg/dns"
|
||||
meta "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
@@ -195,14 +194,11 @@ func ParseStanza(c *caddy.Controller) (*Kubernetes, error) {
|
||||
k8s.Fall.SetZonesFromArgs(c.RemainingArgs())
|
||||
case "upstream":
|
||||
args := c.RemainingArgs()
|
||||
if len(args) == 0 {
|
||||
return nil, c.ArgErr()
|
||||
}
|
||||
ups, err := dnsutil.ParseHostPortOrFile(args...)
|
||||
u, err := upstream.NewUpstream(args)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
k8s.Proxy = proxy.NewLookup(ups)
|
||||
k8s.Upstream = u
|
||||
case "ttl":
|
||||
args := c.RemainingArgs()
|
||||
if len(args) == 0 {
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
|
||||
"github.com/coredns/coredns/plugin/pkg/fall"
|
||||
|
||||
"github.com/coredns/coredns/plugin/proxy"
|
||||
"github.com/mholt/caddy"
|
||||
meta "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
@@ -463,7 +464,10 @@ kubernetes cluster.local`,
|
||||
t.Errorf("Test %d: Expected kubernetes controller to be initialized with fallthrough '%v'. Instead found fallthrough '%v' for input '%s'", i, test.expectedFallthrough, k8sController.Fall, test.input)
|
||||
}
|
||||
// upstream
|
||||
foundUpstreams := k8sController.Proxy.Upstreams
|
||||
var foundUpstreams *[]proxy.Upstream
|
||||
if k8sController.Upstream.Forward != nil {
|
||||
foundUpstreams = k8sController.Upstream.Forward.Upstreams
|
||||
}
|
||||
if test.expectedUpstreams == nil {
|
||||
if foundUpstreams != nil {
|
||||
t.Errorf("Test %d: Expected kubernetes controller to not be initialized with upstreams for input '%s'", i, test.input)
|
||||
|
||||
Reference in New Issue
Block a user