Merge pull request #3938 from johngmyers/internal-service

Use ServiceIP for ClusterIP Services with internal-hostname annotation
This commit is contained in:
Kubernetes Prow Robot 2023-09-26 16:55:37 -07:00 committed by GitHub
commit 9ad15cf76f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 35 additions and 16 deletions

View File

@ -25,7 +25,7 @@ The following table documents which sources support which annotations:
| Traefik | | Yes | | Yes | Yes | Yes | | Traefik | | Yes | | Yes | Yes | Yes |
[^1]: Unless the `--ignore-hostname-annotation` flag is specified. [^1]: Unless the `--ignore-hostname-annotation` flag is specified.
[^2]: Only behaves differently than `hostname` for `Service`s of type `LoadBalancer`. [^2]: Only behaves differently than `hostname` for `Service`s of type `ClusterIP` or `LoadBalancer`.
[^3]: Also supported on `Pods` referenced from a headless `Service`'s `Endpoints`. [^3]: Also supported on `Pods` referenced from a headless `Service`'s `Endpoints`.
[^4]: The annotation should be on the `Gateway` [^4]: The annotation should be on the `Gateway`

View File

@ -75,7 +75,8 @@ or the `--publish-host-ip` flag was specified, uses the Pod's `status.hostIP` fi
### ClusterIP (not headless) ### ClusterIP (not headless)
1. If the `--publish-internal-services` flag is specified, uses the `spec.ServiceIP`. 1. If the hostname came from an `external-dns.alpha.kubernetes.io/internal-hostname` annotation
or the `--publish-internal-services` flag was specified, uses the `spec.ServiceIP`.
2. Otherwise, does not create any targets. 2. Otherwise, does not create any targets.

View File

@ -505,7 +505,7 @@ func (sc *serviceSource) generateEndpoints(svc *v1.Service, hostname string, pro
case v1.ServiceTypeClusterIP: case v1.ServiceTypeClusterIP:
if svc.Spec.ClusterIP == v1.ClusterIPNone { if svc.Spec.ClusterIP == v1.ClusterIPNone {
endpoints = append(endpoints, sc.extractHeadlessEndpoints(svc, hostname, ttl)...) endpoints = append(endpoints, sc.extractHeadlessEndpoints(svc, hostname, ttl)...)
} else if sc.publishInternal { } else if useClusterIP || sc.publishInternal {
targets = extractServiceIps(svc) targets = extractServiceIps(svc)
} }
case v1.ServiceTypeNodePort: case v1.ServiceTypeNodePort:

View File

@ -910,7 +910,25 @@ func testServiceSourceEndpoints(t *testing.T) {
expected: []*endpoint.Endpoint{}, expected: []*endpoint.Endpoint{},
}, },
{ {
title: "internal-host annotated services return an endpoint with Cluster IP", title: "internal-host annotated and host annotated clusterip services return an endpoint with Cluster IP",
svcNamespace: "testing",
svcName: "foo",
svcType: v1.ServiceTypeClusterIP,
labels: map[string]string{},
annotations: map[string]string{
hostnameAnnotationKey: "foo.example.org.",
internalHostnameAnnotationKey: "foo.internal.example.org.",
},
clusterIP: "1.1.1.1",
externalIPs: []string{},
lbs: []string{"1.2.3.4"},
serviceTypesFilter: []string{},
expected: []*endpoint.Endpoint{
{DNSName: "foo.internal.example.org", RecordType: endpoint.RecordTypeA, Targets: endpoint.Targets{"1.1.1.1"}},
},
},
{
title: "internal-host annotated loadbalancer services return an endpoint with Cluster IP",
svcNamespace: "testing", svcNamespace: "testing",
svcName: "foo", svcName: "foo",
svcType: v1.ServiceTypeLoadBalancer, svcType: v1.ServiceTypeLoadBalancer,
@ -927,7 +945,7 @@ func testServiceSourceEndpoints(t *testing.T) {
}, },
}, },
{ {
title: "internal-host annotated and host annotated services return an endpoint with Cluster IP and an endpoint with lb IP", title: "internal-host annotated and host annotated loadbalancer services return an endpoint with Cluster IP and an endpoint with lb IP",
svcNamespace: "testing", svcNamespace: "testing",
svcName: "foo", svcName: "foo",
svcType: v1.ServiceTypeLoadBalancer, svcType: v1.ServiceTypeLoadBalancer,
@ -1816,10 +1834,10 @@ func TestServiceSourceNodePortServices(t *testing.T) {
}, },
}, },
}}, }},
podNames: []string{"pod-0"}, podNames: []string{"pod-0"},
nodeIndex: []int{1}, nodeIndex: []int{1},
phases: []v1.PodPhase{v1.PodRunning}, phases: []v1.PodPhase{v1.PodRunning},
conditions: []v1.PodCondition{{Type: v1.PodReady, Status: v1.ConditionFalse}}, conditions: []v1.PodCondition{{Type: v1.PodReady, Status: v1.ConditionFalse}},
deletionTimestamp: []*metav1.Time{{}}, deletionTimestamp: []*metav1.Time{{}},
}, },
{ {
@ -1867,7 +1885,7 @@ func TestServiceSourceNodePortServices(t *testing.T) {
{Type: v1.PodReady, Status: v1.ConditionFalse}, {Type: v1.PodReady, Status: v1.ConditionFalse},
{Type: v1.PodReady, Status: v1.ConditionFalse}, {Type: v1.PodReady, Status: v1.ConditionFalse},
}, },
deletionTimestamp: []*metav1.Time{{},{}}, deletionTimestamp: []*metav1.Time{{}, {}},
}, },
{ {
title: "annotated NodePort services with ExternalTrafficPolicy=Local return pods in Ready & Running state", title: "annotated NodePort services with ExternalTrafficPolicy=Local return pods in Ready & Running state",
@ -1911,7 +1929,7 @@ func TestServiceSourceNodePortServices(t *testing.T) {
{Type: v1.PodReady, Status: v1.ConditionTrue}, {Type: v1.PodReady, Status: v1.ConditionTrue},
{Type: v1.PodReady, Status: v1.ConditionFalse}, {Type: v1.PodReady, Status: v1.ConditionFalse},
}, },
deletionTimestamp: []*metav1.Time{{},{}}, deletionTimestamp: []*metav1.Time{{}, {}},
}, },
{ {
title: "annotated NodePort services with ExternalTrafficPolicy=Local return pods in Ready & Running state & not in Terminating", title: "annotated NodePort services with ExternalTrafficPolicy=Local return pods in Ready & Running state & not in Terminating",
@ -2254,14 +2272,14 @@ func TestServiceSourceNodePortServices(t *testing.T) {
NodeName: tc.nodes[tc.nodeIndex[i]].Name, NodeName: tc.nodes[tc.nodeIndex[i]].Name,
}, },
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Namespace: tc.svcNamespace, Namespace: tc.svcNamespace,
Name: podname, Name: podname,
Labels: tc.labels, Labels: tc.labels,
Annotations: tc.annotations, Annotations: tc.annotations,
DeletionTimestamp: tc.deletionTimestamp[i], DeletionTimestamp: tc.deletionTimestamp[i],
}, },
Status: v1.PodStatus{ Status: v1.PodStatus{
Phase: tc.phases[i], Phase: tc.phases[i],
Conditions: []v1.PodCondition{tc.conditions[i]}, Conditions: []v1.PodCondition{tc.conditions[i]},
}, },
} }