Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix srv record lookup #26393

Merged
merged 2 commits into from
Jun 4, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 3 additions & 0 deletions build/kube-dns/Changelog
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
## Version 1.2 (Fri May 27 2016 Tim Hockin <thockin@google.com>)
- First Changelog entry

## Version 1.3 (Fri June 3 2016 Prashanth.B <beeps@google.com>)
- Fixed SRV record lookup (issue #26116)
2 changes: 1 addition & 1 deletion build/kube-dns/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
# Default registry, arch and tag. This can be overwritten by arguments to make
PLATFORM?=linux
ARCH?=amd64
TAG?=1.2
TAG?=1.3
REGISTRY?=gcr.io/google_containers

GOLANG_VERSION=1.6
Expand Down
10 changes: 5 additions & 5 deletions cluster/saltbase/salt/kube-dns/skydns-rc.yaml.base
Original file line number Diff line number Diff line change
Expand Up @@ -21,27 +21,27 @@
apiVersion: v1
kind: ReplicationController
metadata:
name: kube-dns-v13
name: kube-dns-v14
namespace: kube-system
labels:
k8s-app: kube-dns
version: v13
version: v14
kubernetes.io/cluster-service: "true"
spec:
replicas: __PILLAR__DNS__REPLICAS__
selector:
k8s-app: kube-dns
version: v13
version: v14
template:
metadata:
labels:
k8s-app: kube-dns
version: v13
version: v14
kubernetes.io/cluster-service: "true"
spec:
containers:
- name: kubedns
image: gcr.io/google_containers/kubedns-amd64:1.2
image: gcr.io/google_containers/kubedns-amd64:1.3
resources:
# TODO: Set memory limits when we've profiled the container for large
# clusters, then set request = limit to keep this container in
Expand Down
10 changes: 5 additions & 5 deletions cluster/saltbase/salt/kube-dns/skydns-rc.yaml.in
Original file line number Diff line number Diff line change
Expand Up @@ -21,27 +21,27 @@
apiVersion: v1
kind: ReplicationController
metadata:
name: kube-dns-v13
name: kube-dns-v14
namespace: kube-system
labels:
k8s-app: kube-dns
version: v13
version: v14
kubernetes.io/cluster-service: "true"
spec:
replicas: {{ pillar['dns_replicas'] }}
selector:
k8s-app: kube-dns
version: v13
version: v14
template:
metadata:
labels:
k8s-app: kube-dns
version: v13
version: v14
kubernetes.io/cluster-service: "true"
spec:
containers:
- name: kubedns
image: gcr.io/google_containers/kubedns-amd64:1.2
image: gcr.io/google_containers/kubedns-amd64:1.3
resources:
# TODO: Set memory limits when we've profiled the container for large
# clusters, then set request = limit to keep this container in
Expand Down
10 changes: 5 additions & 5 deletions cluster/saltbase/salt/kube-dns/skydns-rc.yaml.sed
Original file line number Diff line number Diff line change
Expand Up @@ -21,27 +21,27 @@
apiVersion: v1
kind: ReplicationController
metadata:
name: kube-dns-v13
name: kube-dns-v14
namespace: kube-system
labels:
k8s-app: kube-dns
version: v13
version: v14
kubernetes.io/cluster-service: "true"
spec:
replicas: $DNS_REPLICAS
selector:
k8s-app: kube-dns
version: v13
version: v14
template:
metadata:
labels:
k8s-app: kube-dns
version: v13
version: v14
kubernetes.io/cluster-service: "true"
spec:
containers:
- name: kubedns
image: gcr.io/google_containers/kubedns-amd64:1.2
image: gcr.io/google_containers/kubedns-amd64:1.3
resources:
# TODO: Set memory limits when we've profiled the container for large
# clusters, then set request = limit to keep this container in
Expand Down
1 change: 0 additions & 1 deletion hack/verify-flags/known-flags.txt
Original file line number Diff line number Diff line change
Expand Up @@ -469,4 +469,3 @@ watch-only
whitelist-override-label
windows-line-endings
www-prefix

75 changes: 55 additions & 20 deletions pkg/dns/dns.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import (
"time"

etcd "github.com/coreos/etcd/client"
"github.com/golang/glog"
"github.com/miekg/dns"
skymsg "github.com/skynetservices/skydns/msg"
kapi "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/endpoints"
Expand All @@ -38,6 +38,8 @@ import (
"k8s.io/kubernetes/pkg/util/validation"
"k8s.io/kubernetes/pkg/util/wait"
"k8s.io/kubernetes/pkg/watch"

"github.com/golang/glog"
)

const (
Expand All @@ -61,6 +63,15 @@ const (
// never change. So we expire the cache and retrieve a node once every 180 seconds.
// The value is chosen to be neither too long nor too short.
nodeCacheTTL = 180 * time.Second

// default priority used for service records
defaultPriority = 10

// default weight used for service records
defaultWeight = 10

// default TTL used for service records
defaultTTL = 30
)

type KubeDNS struct {
Expand Down Expand Up @@ -213,6 +224,7 @@ func assertIsService(obj interface{}) (*kapi.Service, bool) {

func (kd *KubeDNS) newService(obj interface{}) {
if service, ok := assertIsService(obj); ok {
glog.V(4).Infof("Add/Updated for service %v", service.Name)
// if ClusterIP is not set, a DNS entry should not be created
if !kapi.IsServiceIPSet(service) {
kd.newHeadlessService(service)
Expand Down Expand Up @@ -276,17 +288,26 @@ func (kd *KubeDNS) getServiceFromEndpoints(e *kapi.Endpoints) (*kapi.Service, er
return nil, fmt.Errorf("got a non service object in services store %v", obj)
}

// fqdn constructs the fqdn for the given service. subpaths is a list of path
// elements rooted at the given service, ending at a service record.
func (kd *KubeDNS) fqdn(service *kapi.Service, subpaths ...string) string {
domainLabels := append(append(kd.domainPath, serviceSubdomain, service.Namespace, service.Name), subpaths...)
return dns.Fqdn(strings.Join(reverseArray(domainLabels), "."))
}

func (kd *KubeDNS) newPortalService(service *kapi.Service) {
subCache := NewTreeCache()
recordValue, recordLabel := getSkyMsg(service.Spec.ClusterIP, 0)
subCache.setEntry(recordLabel, recordValue)
subCache.setEntry(recordLabel, recordValue, kd.fqdn(service, recordLabel))

// Generate SRV Records
for i := range service.Spec.Ports {
port := &service.Spec.Ports[i]
if port.Name != "" && port.Protocol != "" {
srvValue := kd.generateSRVRecordValue(service, int(port.Port))
subCache.setEntry(recordLabel, srvValue, "_"+strings.ToLower(string(port.Protocol)), "_"+port.Name)

l := []string{"_" + strings.ToLower(string(port.Protocol)), "_" + port.Name}
subCache.setEntry(recordLabel, srvValue, kd.fqdn(service, append(l, recordLabel)...), l...)
}
}
subCachePath := append(kd.domainPath, serviceSubdomain, service.Namespace)
Expand Down Expand Up @@ -315,12 +336,14 @@ func (kd *KubeDNS) generateRecordsForHeadlessService(e *kapi.Endpoints, svc *kap
if hostLabel, exists := getHostname(address, podHostnames); exists {
endpointName = hostLabel
}
subCache.setEntry(endpointName, recordValue)
subCache.setEntry(endpointName, recordValue, kd.fqdn(svc, endpointName))
for portIdx := range e.Subsets[idx].Ports {
endpointPort := &e.Subsets[idx].Ports[portIdx]
if endpointPort.Name != "" && endpointPort.Protocol != "" {
srvValue := kd.generateSRVRecordValue(svc, int(endpointPort.Port), endpointName)
subCache.setEntry(endpointName, srvValue, "_"+strings.ToLower(string(endpointPort.Protocol)), "_"+endpointPort.Name)

l := []string{"_" + strings.ToLower(string(endpointPort.Protocol)), "_" + endpointPort.Name}
subCache.setEntry(endpointName, srvValue, kd.fqdn(svc, append(l, endpointName)...), l...)
}
}
}
Expand Down Expand Up @@ -390,7 +413,11 @@ func (kd *KubeDNS) newHeadlessService(service *kapi.Service) error {
return nil
}

func (kd *KubeDNS) Records(name string, exact bool) ([]skymsg.Service, error) {
// Records responds with DNS records that match the given name, in a format
// understood by the skydns server. If "exact" is true, a single record
// matching the given name is returned, otherwise all records stored under
// the subtree matching the name are returned.
func (kd *KubeDNS) Records(name string, exact bool) (retval []skymsg.Service, err error) {
glog.Infof("Received DNS Request:%s, exact:%v", name, exact)
trimmed := strings.TrimRight(name, ".")
segments := strings.Split(trimmed, ".")
Expand Down Expand Up @@ -420,9 +447,8 @@ func (kd *KubeDNS) Records(name string, exact bool) ([]skymsg.Service, error) {
kd.cacheLock.RLock()
defer kd.cacheLock.RUnlock()
records := kd.cache.getValuesForPathWithWildcards(path...)
retval := []skymsg.Service{}
for _, val := range records {
retval = append(retval, *(val.(*skymsg.Service)))
retval = append(retval, *val)
}
glog.Infof("records:%v, retval:%v, path:%v", records, retval, path)
if len(retval) > 0 {
Expand All @@ -438,6 +464,7 @@ func (kd *KubeDNS) Records(name string, exact bool) ([]skymsg.Service, error) {
return nil, etcd.Error{Code: etcd.ErrorCodeKeyNotFound}
}

// ReverseRecords performs a reverse lookup for the given name.
func (kd *KubeDNS) ReverseRecord(name string) (*skymsg.Service, error) {
glog.Infof("Received ReverseRecord Request:%s", name)

Expand Down Expand Up @@ -494,21 +521,29 @@ func (kd *KubeDNS) getPodIP(path []string) (string, error) {
return "", fmt.Errorf("Invalid IP Address %v", ip)
}

// Returns record in a format that SkyDNS understands.
// Also return the hash of the record.
func getSkyMsg(ip string, port int) (*skymsg.Service, string) {
msg := &skymsg.Service{
Host: ip,
Port: port,
Priority: 10,
Weight: 10,
Ttl: 30,
}
func hashServiceRecord(msg *skymsg.Service) string {
s := fmt.Sprintf("%v", msg)
h := fnv.New32a()
h.Write([]byte(s))
hash := fmt.Sprintf("%x", h.Sum32())
glog.Infof("DNS Record:%s, hash:%s", s, hash)
return fmt.Sprintf("%x", h.Sum32())
}

func newServiceRecord(ip string, port int) *skymsg.Service {
return &skymsg.Service{
Host: ip,
Port: port,
Priority: defaultPriority,
Weight: defaultWeight,
Ttl: defaultTTL,
}
}

// Returns record in a format that SkyDNS understands.
// Also return the hash of the record.
func getSkyMsg(ip string, port int) (*skymsg.Service, string) {
msg := newServiceRecord(ip, port)
hash := hashServiceRecord(msg)
glog.Infof("DNS Record:%s, hash:%s", fmt.Sprintf("%v", msg), hash)
return msg, fmt.Sprintf("%x", hash)
}

Expand Down