mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-30 15:05:27 +00:00
Merge pull request #8501 from ArtfulCoder/kubelet_svc_subdomain
Support old and new style dns service names.
This commit is contained in:
commit
9a316dd409
@ -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
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
.PHONY: all kube2sky container push clean test
|
||||
|
||||
TAG = 1.5
|
||||
TAG = 1.6
|
||||
PREFIX = gcr.io/google_containers
|
||||
|
||||
all: container
|
||||
|
@ -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) })
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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'] }}
|
||||
|
@ -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",
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user