diff --git a/cluster/addons/dns/README.md b/cluster/addons/dns/README.md index e32b6596dfd..5030593c2b4 100644 --- a/cluster/addons/dns/README.md +++ b/cluster/addons/dns/README.md @@ -13,6 +13,11 @@ crashes or scheduling changes). This maps well to DNS, which has a long history of clients that, on purpose or on accident, do not respect DNS TTLs (see previous remark about Pod IPs changing). +## DNS Name format for Services +Services get a DNS name with the format my-svc.my-namespace.svc.cluster.local +'svc' should not be used a namespace label to avoid conflicts. +The old format of my-svc.my-namespace.cluster.local has been deprecated. + ## How do I find the DNS server? The DNS server itself runs as a Kubernetes Service. This gives it a stable IP address. When you run the SkyDNS service, you want to assign a static IP to use for @@ -35,12 +40,12 @@ example, see `cluster/gce/config-default.sh`. ```shell ENABLE_CLUSTER_DNS=true DNS_SERVER_IP="10.0.0.10" -DNS_DOMAIN="kubernetes.local" +DNS_DOMAIN="cluster.local" DNS_REPLICAS=1 ``` This enables DNS with a DNS Service IP of `10.0.0.10` and a local domain of -`kubernetes.local`, served by a single copy of SkyDNS. +`cluster.local`, served by a single copy of SkyDNS. If you are not using a supported cluster setup, you will have to replicate some of this yourself. First, each kubelet needs to run with the following flags diff --git a/cluster/addons/dns/kube2sky/Makefile b/cluster/addons/dns/kube2sky/Makefile index 23474bc71c8..15853c9038d 100644 --- a/cluster/addons/dns/kube2sky/Makefile +++ b/cluster/addons/dns/kube2sky/Makefile @@ -4,7 +4,7 @@ .PHONY: all kube2sky container push clean test -TAG = 1.5 +TAG = 1.6 PREFIX = gcr.io/google_containers all: container diff --git a/cluster/addons/dns/kube2sky/kube2sky.go b/cluster/addons/dns/kube2sky/kube2sky.go index 784986d517f..913e1a34612 100644 --- a/cluster/addons/dns/kube2sky/kube2sky.go +++ b/cluster/addons/dns/kube2sky/kube2sky.go @@ -204,10 +204,14 @@ func newKubeClient() (*kclient.Client, error) { return kclient.New(config) } -func buildNameString(service, namespace, domain string) string { +func buildOldNameString(service, namespace, domain string) string { return fmt.Sprintf("%s.%s.%s.", service, namespace, domain) } +func buildNewServiceNameString(service, namespace, domain string) string { + return fmt.Sprintf("%s.%s.svc.%s.", service, namespace, domain) +} + // Returns a cache.ListWatch that gets all changes to services. func createServiceLW(kubeClient *kclient.Client) *cache.ListWatch { return cache.NewListWatchFromClient(kubeClient, "services", kapi.NamespaceAll, kSelector.Everything()) @@ -215,15 +219,20 @@ func createServiceLW(kubeClient *kclient.Client) *cache.ListWatch { func (ks *kube2sky) newService(obj interface{}) { if s, ok := obj.(*kapi.Service); ok { - name := buildNameString(s.Name, s.Namespace, ks.domain) + //TODO(artfulcoder) stop adding and deleting old-format string for service + name := buildOldNameString(s.Name, s.Namespace, ks.domain) ks.mutateEtcdOrDie(func() error { return ks.addDNS(name, s) }) + name1 := buildNewServiceNameString(s.Name, s.Namespace, ks.domain) + ks.mutateEtcdOrDie(func() error { return ks.addDNS(name1, s) }) } } func (ks *kube2sky) removeService(obj interface{}) { if s, ok := obj.(*kapi.Service); ok { - name := buildNameString(s.Name, s.Namespace, ks.domain) + name := buildOldNameString(s.Name, s.Namespace, ks.domain) ks.mutateEtcdOrDie(func() error { return ks.removeDNS(name) }) + name1 := buildNewServiceNameString(s.Name, s.Namespace, ks.domain) + ks.mutateEtcdOrDie(func() error { return ks.removeDNS(name1) }) } } diff --git a/cluster/addons/dns/kube2sky/kube2sky_test.go b/cluster/addons/dns/kube2sky/kube2sky_test.go index bfcd5668cd0..5098ec88482 100644 --- a/cluster/addons/dns/kube2sky/kube2sky_test.go +++ b/cluster/addons/dns/kube2sky/kube2sky_test.go @@ -49,8 +49,9 @@ func (ec *fakeEtcdClient) Delete(path string, recursive bool) (*etcd.Response, e } const ( - testDomain = "cluster.local" - basePath = "/skydns/local/cluster" + testDomain = "cluster.local" + basePath = "/skydns/local/cluster" + serviceSubDomain = "svc" ) func newKube2Sky(ec etcdClient) *kube2sky { @@ -61,25 +62,12 @@ func newKube2Sky(ec etcdClient) *kube2sky { } } -func TestAddNoServiceIP(t *testing.T) { - const ( - testService = "testService" - testNamespace = "default" - ) - ec := &fakeEtcdClient{make(map[string]string)} - k2s := newKube2Sky(ec) - service := kapi.Service{ - ObjectMeta: kapi.ObjectMeta{ - Name: testNamespace, - Namespace: testNamespace, - }, - } - k2s.newService(&service) - assert.Empty(t, ec.writes) +func getEtcdOldStylePath(name, namespace string) string { + return path.Join(basePath, namespace, name) } -func getEtcdPath(name, namespace string) string { - return path.Join(basePath, namespace, name) +func getEtcdNewStylePath(name, namespace string) string { + return path.Join(basePath, serviceSubDomain, namespace, name) } type hostPort struct { @@ -100,6 +88,39 @@ func getHostPortFromString(data string) (*hostPort, error) { return &res, err } +func assertDnsServiceEntryInEtcd(t *testing.T, ec *fakeEtcdClient, serviceName, namespace string, expectedHostPort *hostPort) { + oldStyleKey := getEtcdOldStylePath(serviceName, namespace) + val, exists := ec.writes[oldStyleKey] + require.True(t, exists) + actualHostPort, err := getHostPortFromString(val) + require.NoError(t, err) + assert.Equal(t, actualHostPort, expectedHostPort) + + newStyleKey := getEtcdNewStylePath(serviceName, namespace) + val, exists = ec.writes[newStyleKey] + require.True(t, exists) + actualHostPort, err = getHostPortFromString(val) + require.NoError(t, err) + assert.Equal(t, actualHostPort, expectedHostPort) +} + +func TestHeadlessService(t *testing.T) { + const ( + testService = "testService" + testNamespace = "default" + ) + ec := &fakeEtcdClient{make(map[string]string)} + k2s := newKube2Sky(ec) + service := kapi.Service{ + ObjectMeta: kapi.ObjectMeta{ + Name: testNamespace, + Namespace: testNamespace, + }, + } + k2s.newService(&service) + assert.Empty(t, ec.writes) +} + func TestAddSinglePortService(t *testing.T) { const ( testService = "testService" @@ -122,13 +143,8 @@ func TestAddSinglePortService(t *testing.T) { }, } k2s.newService(&service) - expectedKey := getEtcdPath(testService, testNamespace) expectedValue := getHostPort(&service) - val, exists := ec.writes[expectedKey] - require.True(t, exists) - actualValue, err := getHostPortFromString(val) - require.NoError(t, err) - assert.Equal(t, actualValue, expectedValue) + assertDnsServiceEntryInEtcd(t, ec, testService, testNamespace, expectedValue) } func TestUpdateSinglePortService(t *testing.T) { @@ -153,16 +169,11 @@ func TestUpdateSinglePortService(t *testing.T) { }, } k2s.newService(&service) - assert.Len(t, ec.writes, 1) + assert.Len(t, ec.writes, 2) service.Spec.PortalIP = "0.0.0.0" k2s.newService(&service) - expectedKey := getEtcdPath(testService, testNamespace) expectedValue := getHostPort(&service) - val, exists := ec.writes[expectedKey] - require.True(t, exists) - actualValue, err := getHostPortFromString(val) - require.NoError(t, err) - assert.Equal(t, actualValue, expectedValue) + assertDnsServiceEntryInEtcd(t, ec, testService, testNamespace, expectedValue) } func TestDeleteSinglePortService(t *testing.T) { @@ -188,7 +199,9 @@ func TestDeleteSinglePortService(t *testing.T) { } // Add the service k2s.newService(&service) - assert.Len(t, ec.writes, 1) + // two entries should get created, one with the svc subdomain (new-style) + // , and one without the svc subdomain (old-style) + assert.Len(t, ec.writes, 2) // Delete the service k2s.removeService(&service) assert.Empty(t, ec.writes) diff --git a/cluster/addons/dns/skydns-rc.yaml.in b/cluster/addons/dns/skydns-rc.yaml.in index 015cd28cdad..d4fa2614053 100644 --- a/cluster/addons/dns/skydns-rc.yaml.in +++ b/cluster/addons/dns/skydns-rc.yaml.in @@ -30,7 +30,7 @@ spec: - -initial-cluster-token - skydns-etcd - name: kube2sky - image: gcr.io/google_containers/kube2sky:1.5 + image: gcr.io/google_containers/kube2sky:1.6 args: # command = "/kube2sky" - -domain={{ pillar['dns_domain'] }} diff --git a/test/e2e/dns.go b/test/e2e/dns.go index 749134215b5..ef4bc37345c 100644 --- a/test/e2e/dns.go +++ b/test/e2e/dns.go @@ -72,6 +72,8 @@ var _ = Describe("DNS", func() { // TODO: Spin up a separate test service and test that dns works for that service. namesToResolve := []string{ "kubernetes-ro.default", + "kubernetes-ro.default.svc", + "kubernetes-ro.default.svc.cluster.local", "kubernetes-ro.default.cluster.local", "google.com", }