mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-24 04:06:03 +00:00
Merge pull request #30931 from Clarifai/ext-svc-ref-dns
Automatic merge from submit-queue Add ExternalName kube-dns e2e test ExternalName allows kubedns to return CNAME records for external services. No proxying is involved. Built on top of and includes #30599 See original issue at https://github.com/kubernetes/kubernetes/issues/13748 Feature tracking at https://github.com/kubernetes/features/issues/33 The e2e test is at least as comprehensive as the one for headless services (namely, only to some degree) ```release-note Add ExternalName services as CNAME references to external ones ```
This commit is contained in:
commit
36a6aee27f
@ -44,7 +44,7 @@ spec:
|
||||
spec:
|
||||
containers:
|
||||
- name: kubedns
|
||||
image: gcr.io/google_containers/kubedns-amd64:1.6
|
||||
image: gcr.io/google_containers/kubedns-amd64:1.7
|
||||
resources:
|
||||
# TODO: Set memory limits when we've profiled the container for large
|
||||
# clusters, then set request = limit to keep this container in
|
||||
|
@ -44,7 +44,7 @@ spec:
|
||||
spec:
|
||||
containers:
|
||||
- name: kubedns
|
||||
image: gcr.io/google_containers/kubedns-amd64:1.6
|
||||
image: gcr.io/google_containers/kubedns-amd64:1.7
|
||||
resources:
|
||||
# TODO: Set memory limits when we've profiled the container for large
|
||||
# clusters, then set request = limit to keep this container in
|
||||
|
@ -44,7 +44,7 @@ spec:
|
||||
spec:
|
||||
containers:
|
||||
- name: kubedns
|
||||
image: gcr.io/google_containers/kubedns-amd64:1.6
|
||||
image: gcr.io/google_containers/kubedns-amd64:1.7
|
||||
resources:
|
||||
# TODO: Set memory limits when we've profiled the container for large
|
||||
# clusters, then set request = limit to keep this container in
|
||||
|
143
test/e2e/dns.go
143
test/e2e/dns.go
@ -164,7 +164,18 @@ func createProbeCommand(namesToResolve []string, hostEntries []string, ptrLookup
|
||||
return probeCmd, fileNames
|
||||
}
|
||||
|
||||
// createTargetedProbeCommand returns a command line that performs a DNS lookup for a specific record type
|
||||
func createTargetedProbeCommand(nameToResolve string, lookup string, fileNamePrefix string) (string, string) {
|
||||
fileName := fmt.Sprintf("%s_udp@%s", fileNamePrefix, nameToResolve)
|
||||
probeCmd := fmt.Sprintf("dig +short +tries=12 +norecurse %s %s > /results/%s", nameToResolve, lookup, fileName)
|
||||
return probeCmd, fileName
|
||||
}
|
||||
|
||||
func assertFilesExist(fileNames []string, fileDir string, pod *api.Pod, client *client.Client) {
|
||||
assertFilesContain(fileNames, fileDir, pod, client, false, "")
|
||||
}
|
||||
|
||||
func assertFilesContain(fileNames []string, fileDir string, pod *api.Pod, client *client.Client, check bool, expected string) {
|
||||
var failed []string
|
||||
|
||||
framework.ExpectNoError(wait.Poll(time.Second*2, time.Second*60, func() (bool, error) {
|
||||
@ -173,9 +184,10 @@ func assertFilesExist(fileNames []string, fileDir string, pod *api.Pod, client *
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
var contents []byte
|
||||
for _, fileName := range fileNames {
|
||||
if subResourceProxyAvailable {
|
||||
_, err = client.Get().
|
||||
contents, err = client.Get().
|
||||
Namespace(pod.Namespace).
|
||||
Resource("pods").
|
||||
SubResource("proxy").
|
||||
@ -183,7 +195,7 @@ func assertFilesExist(fileNames []string, fileDir string, pod *api.Pod, client *
|
||||
Suffix(fileDir, fileName).
|
||||
Do().Raw()
|
||||
} else {
|
||||
_, err = client.Get().
|
||||
contents, err = client.Get().
|
||||
Prefix("proxy").
|
||||
Resource("pods").
|
||||
Namespace(pod.Namespace).
|
||||
@ -194,6 +206,9 @@ func assertFilesExist(fileNames []string, fileDir string, pod *api.Pod, client *
|
||||
if err != nil {
|
||||
framework.Logf("Unable to read %s from pod %s: %v", fileName, pod.Name, err)
|
||||
failed = append(failed, fileName)
|
||||
} else if check && strings.TrimSpace(string(contents)) != expected {
|
||||
framework.Logf("File %s from pod %s contains '%s' instead of '%s'", fileName, pod.Name, string(contents), expected)
|
||||
failed = append(failed, fileName)
|
||||
}
|
||||
}
|
||||
if len(failed) == 0 {
|
||||
@ -226,7 +241,7 @@ func validateDNSResults(f *framework.Framework, pod *api.Pod, fileNames []string
|
||||
framework.Failf("Failed to get pod %s: %v", pod.Name, err)
|
||||
}
|
||||
// Try to find results for each expected name.
|
||||
By("looking for the results for each expected name from probiers")
|
||||
By("looking for the results for each expected name from probers")
|
||||
assertFilesExist(fileNames, "results", pod, f.Client)
|
||||
|
||||
// TODO: probe from the host, too.
|
||||
@ -234,6 +249,33 @@ func validateDNSResults(f *framework.Framework, pod *api.Pod, fileNames []string
|
||||
framework.Logf("DNS probes using %s succeeded\n", pod.Name)
|
||||
}
|
||||
|
||||
func validateTargetedProbeOutput(f *framework.Framework, pod *api.Pod, fileNames []string, value string) {
|
||||
|
||||
By("submitting the pod to kubernetes")
|
||||
podClient := f.Client.Pods(f.Namespace.Name)
|
||||
defer func() {
|
||||
By("deleting the pod")
|
||||
defer GinkgoRecover()
|
||||
podClient.Delete(pod.Name, api.NewDeleteOptions(0))
|
||||
}()
|
||||
if _, err := podClient.Create(pod); err != nil {
|
||||
framework.Failf("Failed to create %s pod: %v", pod.Name, err)
|
||||
}
|
||||
|
||||
framework.ExpectNoError(f.WaitForPodRunning(pod.Name))
|
||||
|
||||
By("retrieving the pod")
|
||||
pod, err := podClient.Get(pod.Name)
|
||||
if err != nil {
|
||||
framework.Failf("Failed to get pod %s: %v", pod.Name, err)
|
||||
}
|
||||
// Try to find the expected value for each expected name.
|
||||
By("looking for the results for each expected name from probers")
|
||||
assertFilesContain(fileNames, "results", pod, f.Client, true, value)
|
||||
|
||||
framework.Logf("DNS probes using %s succeeded\n", pod.Name)
|
||||
}
|
||||
|
||||
func verifyDNSPodIsRunning(f *framework.Framework) {
|
||||
systemClient := f.Client.Pods(api.NamespaceSystem)
|
||||
By("Waiting for DNS Service to be Running")
|
||||
@ -249,18 +291,23 @@ func verifyDNSPodIsRunning(f *framework.Framework) {
|
||||
framework.ExpectNoError(framework.WaitForPodRunningInNamespace(f.Client, &pod))
|
||||
}
|
||||
|
||||
func createServiceSpec(serviceName string, isHeadless bool, selector map[string]string) *api.Service {
|
||||
func createServiceSpec(serviceName, externalName string, isHeadless bool, selector map[string]string) *api.Service {
|
||||
headlessService := &api.Service{
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Name: serviceName,
|
||||
},
|
||||
Spec: api.ServiceSpec{
|
||||
Ports: []api.ServicePort{
|
||||
{Port: 80, Name: "http", Protocol: "TCP"},
|
||||
},
|
||||
Selector: selector,
|
||||
},
|
||||
}
|
||||
if externalName != "" {
|
||||
headlessService.Spec.Type = api.ServiceTypeExternalName
|
||||
headlessService.Spec.ExternalName = externalName
|
||||
} else {
|
||||
headlessService.Spec.Ports = []api.ServicePort{
|
||||
{Port: 80, Name: "http", Protocol: "TCP"},
|
||||
}
|
||||
}
|
||||
if isHeadless {
|
||||
headlessService.Spec.ClusterIP = "None"
|
||||
}
|
||||
@ -295,8 +342,8 @@ var _ = framework.KubeDescribe("DNS", func() {
|
||||
hostEntries := []string{hostFQDN, dnsTestPodHostName}
|
||||
wheezyProbeCmd, wheezyFileNames := createProbeCommand(namesToResolve, hostEntries, "", "wheezy", f.Namespace.Name)
|
||||
jessieProbeCmd, jessieFileNames := createProbeCommand(namesToResolve, hostEntries, "", "jessie", f.Namespace.Name)
|
||||
By("Running these commands on wheezy:" + wheezyProbeCmd + "\n")
|
||||
By("Running these commands on jessie:" + jessieProbeCmd + "\n")
|
||||
By("Running these commands on wheezy: " + wheezyProbeCmd + "\n")
|
||||
By("Running these commands on jessie: " + jessieProbeCmd + "\n")
|
||||
|
||||
// Run a pod which probes DNS and exposes the results by HTTP.
|
||||
By("creating a pod to probe DNS")
|
||||
@ -310,7 +357,7 @@ var _ = framework.KubeDescribe("DNS", func() {
|
||||
testServiceSelector := map[string]string{
|
||||
"dns-test": "true",
|
||||
}
|
||||
headlessService := createServiceSpec(dnsTestServiceName, true, testServiceSelector)
|
||||
headlessService := createServiceSpec(dnsTestServiceName, "", true, testServiceSelector)
|
||||
_, err := f.Client.Services(f.Namespace.Name).Create(headlessService)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
defer func() {
|
||||
@ -319,7 +366,7 @@ var _ = framework.KubeDescribe("DNS", func() {
|
||||
f.Client.Services(f.Namespace.Name).Delete(headlessService.Name)
|
||||
}()
|
||||
|
||||
regularService := createServiceSpec("test-service-2", false, testServiceSelector)
|
||||
regularService := createServiceSpec("test-service-2", "", false, testServiceSelector)
|
||||
regularService, err = f.Client.Services(f.Namespace.Name).Create(regularService)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
defer func() {
|
||||
@ -341,8 +388,8 @@ var _ = framework.KubeDescribe("DNS", func() {
|
||||
|
||||
wheezyProbeCmd, wheezyFileNames := createProbeCommand(namesToResolve, nil, regularService.Spec.ClusterIP, "wheezy", f.Namespace.Name)
|
||||
jessieProbeCmd, jessieFileNames := createProbeCommand(namesToResolve, nil, regularService.Spec.ClusterIP, "jessie", f.Namespace.Name)
|
||||
By("Running these commands on wheezy:" + wheezyProbeCmd + "\n")
|
||||
By("Running these commands on jessie:" + jessieProbeCmd + "\n")
|
||||
By("Running these commands on wheezy: " + wheezyProbeCmd + "\n")
|
||||
By("Running these commands on jessie: " + jessieProbeCmd + "\n")
|
||||
|
||||
// Run a pod which probes DNS and exposes the results by HTTP.
|
||||
By("creating a pod to probe DNS")
|
||||
@ -360,7 +407,7 @@ var _ = framework.KubeDescribe("DNS", func() {
|
||||
}
|
||||
serviceName := "dns-test-service-2"
|
||||
podHostname := "dns-querier-2"
|
||||
headlessService := createServiceSpec(serviceName, true, testServiceSelector)
|
||||
headlessService := createServiceSpec(serviceName, "", true, testServiceSelector)
|
||||
_, err := f.Client.Services(f.Namespace.Name).Create(headlessService)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
defer func() {
|
||||
@ -374,8 +421,8 @@ var _ = framework.KubeDescribe("DNS", func() {
|
||||
namesToResolve := []string{hostFQDN}
|
||||
wheezyProbeCmd, wheezyFileNames := createProbeCommand(namesToResolve, hostNames, "", "wheezy", f.Namespace.Name)
|
||||
jessieProbeCmd, jessieFileNames := createProbeCommand(namesToResolve, hostNames, "", "jessie", f.Namespace.Name)
|
||||
By("Running these commands on wheezy:" + wheezyProbeCmd + "\n")
|
||||
By("Running these commands on jessie:" + jessieProbeCmd + "\n")
|
||||
By("Running these commands on wheezy: " + wheezyProbeCmd + "\n")
|
||||
By("Running these commands on jessie: " + jessieProbeCmd + "\n")
|
||||
|
||||
// Run a pod which probes DNS and exposes the results by HTTP.
|
||||
By("creating a pod to probe DNS")
|
||||
@ -388,4 +435,68 @@ var _ = framework.KubeDescribe("DNS", func() {
|
||||
|
||||
validateDNSResults(f, pod1, append(wheezyFileNames, jessieFileNames...))
|
||||
})
|
||||
|
||||
It("should provide DNS for ExternalName services", func() {
|
||||
// Create a test ExternalName service.
|
||||
By("Creating a test externalName service")
|
||||
serviceName := "dns-test-service-3"
|
||||
externalNameService := createServiceSpec(serviceName, "foo.example.com", false, nil)
|
||||
_, err := f.Client.Services(f.Namespace.Name).Create(externalNameService)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
defer func() {
|
||||
By("deleting the test externalName service")
|
||||
defer GinkgoRecover()
|
||||
f.Client.Services(f.Namespace.Name).Delete(externalNameService.Name)
|
||||
}()
|
||||
|
||||
hostFQDN := fmt.Sprintf("%s.%s.svc.cluster.local", serviceName, f.Namespace.Name)
|
||||
wheezyProbeCmd, wheezyFileName := createTargetedProbeCommand(hostFQDN, "CNAME", "wheezy")
|
||||
jessieProbeCmd, jessieFileName := createTargetedProbeCommand(hostFQDN, "CNAME", "jessie")
|
||||
By("Running these commands on wheezy: " + wheezyProbeCmd + "\n")
|
||||
By("Running these commands on jessie: " + jessieProbeCmd + "\n")
|
||||
|
||||
// Run a pod which probes DNS and exposes the results by HTTP.
|
||||
By("creating a pod to probe DNS")
|
||||
pod1 := createDNSPod(f.Namespace.Name, wheezyProbeCmd, jessieProbeCmd, true)
|
||||
|
||||
validateTargetedProbeOutput(f, pod1, []string{wheezyFileName, jessieFileName}, "foo.example.com.")
|
||||
|
||||
// Test changing the externalName field
|
||||
By("changing the externalName to bar.example.com")
|
||||
_, err = updateService(f.Client, f.Namespace.Name, serviceName, func(s *api.Service) {
|
||||
s.Spec.ExternalName = "bar.example.com"
|
||||
})
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
wheezyProbeCmd, wheezyFileName = createTargetedProbeCommand(hostFQDN, "CNAME", "wheezy")
|
||||
jessieProbeCmd, jessieFileName = createTargetedProbeCommand(hostFQDN, "CNAME", "jessie")
|
||||
By("Running these commands on wheezy: " + wheezyProbeCmd + "\n")
|
||||
By("Running these commands on jessie: " + jessieProbeCmd + "\n")
|
||||
|
||||
// Run a pod which probes DNS and exposes the results by HTTP.
|
||||
By("creating a second pod to probe DNS")
|
||||
pod2 := createDNSPod(f.Namespace.Name, wheezyProbeCmd, jessieProbeCmd, true)
|
||||
|
||||
validateTargetedProbeOutput(f, pod2, []string{wheezyFileName, jessieFileName}, "bar.example.com.")
|
||||
|
||||
// Test changing type from ExternalName to ClusterIP
|
||||
By("changing the service to type=ClusterIP")
|
||||
_, err = updateService(f.Client, f.Namespace.Name, serviceName, func(s *api.Service) {
|
||||
s.Spec.Type = api.ServiceTypeClusterIP
|
||||
s.Spec.ClusterIP = "127.1.2.3"
|
||||
s.Spec.Ports = []api.ServicePort{
|
||||
{Port: 80, Name: "http", Protocol: "TCP"},
|
||||
}
|
||||
})
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
wheezyProbeCmd, wheezyFileName = createTargetedProbeCommand(hostFQDN, "A", "wheezy")
|
||||
jessieProbeCmd, jessieFileName = createTargetedProbeCommand(hostFQDN, "A", "jessie")
|
||||
By("Running these commands on wheezy: " + wheezyProbeCmd + "\n")
|
||||
By("Running these commands on jessie: " + jessieProbeCmd + "\n")
|
||||
|
||||
// Run a pod which probes DNS and exposes the results by HTTP.
|
||||
By("creating a third pod to probe DNS")
|
||||
pod3 := createDNSPod(f.Namespace.Name, wheezyProbeCmd, jessieProbeCmd, true)
|
||||
|
||||
validateTargetedProbeOutput(f, pod3, []string{wheezyFileName, jessieFileName}, "127.1.2.3")
|
||||
})
|
||||
})
|
||||
|
@ -83,7 +83,7 @@ var _ = framework.KubeDescribe("PetSet [Slow] [Feature:PetSet]", func() {
|
||||
|
||||
BeforeEach(func() {
|
||||
By("creating service " + headlessSvcName + " in namespace " + ns)
|
||||
headlessService := createServiceSpec(headlessSvcName, true, labels)
|
||||
headlessService := createServiceSpec(headlessSvcName, "", true, labels)
|
||||
_, err := c.Services(ns).Create(headlessService)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
})
|
||||
|
Loading…
Reference in New Issue
Block a user