Skip to content

Commit 18d5730

Browse files
committed
feat(dataplane): allow setting DataPlane's NodePort port number
1 parent a98f6e4 commit 18d5730

File tree

8 files changed

+164
-9
lines changed

8 files changed

+164
-9
lines changed

CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,8 @@
5555
[#1409](https://github.com/Kong/gateway-operator/pull/1409)
5656
- Support `NodePort` as ingress service type for `DataPlane`
5757
[#1430](https://github.com/Kong/gateway-operator/pull/1430)
58+
- Allow setting `NodePort` port number for ingress service for `DataPlane`.
59+
[#1516](https://github.com/Kong/gateway-operator/pull/1516)
5860
- Bump default `DataPlane` image to 3.10
5961
Default image changes from `kong` to `kong/kong-gateway`.
6062
[#1405](https://github.com/Kong/gateway-operator/pull/1405)

config/crd/kustomization.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@
22
apiVersion: kustomize.config.k8s.io/v1beta1
33
kind: Kustomization
44
resources:
5-
- https://github.com/kong/kubernetes-configuration/config/crd/gateway-operator?ref=1c6842bc66da6bb32b30be6e1464bfcf04e9e46c # Version is auto-updated by the generating script.
5+
- https://github.com/kong/kubernetes-configuration/config/crd/gateway-operator?ref=ae2932af9c0df395ce023e4c7e901a5caf8ab36e # Version is auto-updated by the generating script.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
apiVersion: gateway-operator.konghq.com/v1beta1
2+
kind: DataPlane
3+
metadata:
4+
name: dataplane-node-port
5+
spec:
6+
deployment:
7+
podTemplateSpec:
8+
spec:
9+
containers:
10+
- name: proxy
11+
# renovate: datasource=docker versioning=docker
12+
image: kong/kong-gateway:3.10
13+
env:
14+
- name: KONG_LOG_LEVEL
15+
value: debug
16+
- name: KONG_PROXY_LISTEN
17+
value: 0.0.0.0:9000 reuseport backlog=16384
18+
- name: KONG_PORT_MAPS
19+
value: 8080:9000
20+
resources:
21+
requests:
22+
memory: "64Mi"
23+
cpu: "250m"
24+
limits:
25+
memory: "1024Mi"
26+
cpu: "1000m"
27+
readinessProbe:
28+
initialDelaySeconds: 1
29+
periodSeconds: 1
30+
network:
31+
services:
32+
ingress:
33+
annotations:
34+
foo: bar
35+
ports:
36+
- name: http
37+
port: 8080
38+
targetPort: 9000
39+
- name: http
40+
port: 8083
41+
targetPort: 9000
42+
nodePort: 30083

controller/dataplane/owned_resources.go

+42-5
Original file line numberDiff line numberDiff line change
@@ -364,11 +364,7 @@ func ensureIngressServiceForDataPlane(
364364
existingService.Spec.Selector = generatedService.Spec.Selector
365365
updated = true
366366
}
367-
if !cmp.Equal(generatedService.Spec.Ports, existingService.Spec.Ports, cmp.FilterPath(func(p cmp.Path) bool {
368-
// We need to check all the service values but the NodePort, as this field is assigned by
369-
// the K8S controlplane components.
370-
return p.Last().String() == ".NodePort"
371-
}, cmp.Ignore())) {
367+
if !comparePorts(existingService.Spec.Ports, generatedService.Spec.Ports, dataPlane) {
372368
existingService.Spec.Ports = generatedService.Spec.Ports
373369
updated = true
374370
}
@@ -385,3 +381,44 @@ func ensureIngressServiceForDataPlane(
385381

386382
return op.Created, generatedService, cl.Create(ctx, generatedService)
387383
}
384+
385+
// comparePorts compares the ports of two services.
386+
// It returns true if the ports are equal, ignoring the NodePort field
387+
// for the ingress service if it was not set in the dataplane spec.
388+
func comparePorts(
389+
a, b []corev1.ServicePort,
390+
dataPlane *operatorv1beta1.DataPlane,
391+
) bool {
392+
if len(a) != len(b) {
393+
return false
394+
}
395+
for i := range a {
396+
if a[i].Name != b[i].Name {
397+
return false
398+
}
399+
if a[i].Protocol != b[i].Protocol {
400+
return false
401+
}
402+
if a[i].Port != b[i].Port {
403+
return false
404+
}
405+
if a[i].TargetPort != b[i].TargetPort {
406+
return false
407+
}
408+
if a[i].AppProtocol != b[i].AppProtocol {
409+
return false
410+
}
411+
412+
if a[i].NodePort != b[i].NodePort {
413+
if dataPlane != nil &&
414+
dataPlane.Spec.Network.Services != nil &&
415+
dataPlane.Spec.Network.Services.Ingress != nil &&
416+
len(dataPlane.Spec.Network.Services.Ingress.Ports) > i &&
417+
dataPlane.Spec.Network.Services.Ingress.Ports[i].NodePort != 0 {
418+
return false
419+
}
420+
}
421+
422+
}
423+
return true
424+
}

controller/dataplane/owned_resources_test.go

+73
Original file line numberDiff line numberDiff line change
@@ -331,3 +331,76 @@ func TestEnsureIngressServiceForDataPlane(t *testing.T) {
331331
})
332332
}
333333
}
334+
335+
func TestComparePorts(t *testing.T) {
336+
testCases := []struct {
337+
name string
338+
a []corev1.ServicePort
339+
b []corev1.ServicePort
340+
dataPlane *operatorv1beta1.DataPlane
341+
expected bool
342+
}{
343+
{
344+
name: "should return true when NodePort differs but not specified in DataPlane spec",
345+
a: []corev1.ServicePort{{Name: "port-80", Port: 80, NodePort: 30080}},
346+
b: []corev1.ServicePort{{Name: "port-80", Port: 80, NodePort: 30081}},
347+
dataPlane: builder.NewDataPlaneBuilder().
348+
WithIngressServicePorts([]operatorv1beta1.DataPlaneServicePort{
349+
{
350+
Name: "http",
351+
Port: 80,
352+
TargetPort: intstr.FromInt(8000),
353+
// NodePort not specified
354+
},
355+
}).Build(),
356+
expected: true,
357+
},
358+
{
359+
name: "should return false when NodePort differs and is specified in DataPlane spec",
360+
a: []corev1.ServicePort{{Name: "port-80", Port: 80, NodePort: 30080}},
361+
b: []corev1.ServicePort{{Name: "port-80", Port: 80, NodePort: 30081}},
362+
dataPlane: builder.NewDataPlaneBuilder().
363+
WithIngressServicePorts([]operatorv1beta1.DataPlaneServicePort{
364+
{
365+
Name: "http",
366+
Port: 80,
367+
TargetPort: intstr.FromInt(8000),
368+
NodePort: 30080,
369+
},
370+
}).Build(),
371+
expected: false,
372+
},
373+
{
374+
name: "should return true when multiple ports match except NodePort which is not specified",
375+
a: []corev1.ServicePort{
376+
{Name: "port-80", Port: 80, NodePort: 30080},
377+
{Name: "port-443", Port: 443, NodePort: 30443},
378+
},
379+
b: []corev1.ServicePort{
380+
{Name: "port-80", Port: 80, NodePort: 30081},
381+
{Name: "port-443", Port: 443, NodePort: 30444},
382+
},
383+
dataPlane: builder.NewDataPlaneBuilder().
384+
WithIngressServicePorts([]operatorv1beta1.DataPlaneServicePort{
385+
{
386+
Name: "http",
387+
Port: 80,
388+
TargetPort: intstr.FromInt(8000),
389+
},
390+
{
391+
Name: "https",
392+
Port: 443,
393+
TargetPort: intstr.FromInt(8443),
394+
},
395+
}).Build(),
396+
expected: true,
397+
},
398+
}
399+
400+
for _, tc := range testCases {
401+
t.Run(tc.name, func(t *testing.T) {
402+
actual := comparePorts(tc.a, tc.b, tc.dataPlane)
403+
require.Equal(t, tc.expected, actual)
404+
})
405+
}
406+
}

go.mod

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ require (
1919
github.com/google/go-containerregistry v0.20.3
2020
github.com/google/uuid v1.6.0
2121
github.com/gruntwork-io/terratest v0.48.2
22-
github.com/kong/kubernetes-configuration v1.3.2-0.20250416141332-1c6842bc66da
22+
github.com/kong/kubernetes-configuration v1.3.2-0.20250418121302-ae2932af9c0d
2323
github.com/kong/kubernetes-telemetry v0.1.9
2424
github.com/kong/kubernetes-testing-framework v0.47.2
2525
github.com/kong/semver/v4 v4.0.1

go.sum

+2-2
Original file line numberDiff line numberDiff line change
@@ -309,8 +309,8 @@ github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zt
309309
github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
310310
github.com/kong/go-kong v0.65.1 h1:CM+8NlF+VbJckTxP2hGmSPKhA1GMliitXjQ7vJiPkaE=
311311
github.com/kong/go-kong v0.65.1/go.mod h1:sqdysTKrXIJ6mpxHwTwjgZhLW7jR1/puczTXHLUwJaE=
312-
github.com/kong/kubernetes-configuration v1.3.2-0.20250416141332-1c6842bc66da h1:LLP1I+lIdU+hbasONUxnjpK2TUAr0juMqw+bqygwYd8=
313-
github.com/kong/kubernetes-configuration v1.3.2-0.20250416141332-1c6842bc66da/go.mod h1:+HRrz0eeoy7d5YJYiCkk736xaSq3y9fbV5SvucYo/tY=
312+
github.com/kong/kubernetes-configuration v1.3.2-0.20250418121302-ae2932af9c0d h1:0ArTLuANecKiI9/B5+Fxf80And1T1nb+pyob+l1LuVQ=
313+
github.com/kong/kubernetes-configuration v1.3.2-0.20250418121302-ae2932af9c0d/go.mod h1:3p31CROMO9LZmAB18Udn0luTPl/xu5XLls6DQj4IjB4=
314314
github.com/kong/kubernetes-telemetry v0.1.9 h1:XbDMZjZZclHO4oyJGW1mmZ6bzbTnANjcRAYsBg+jpno=
315315
github.com/kong/kubernetes-telemetry v0.1.9/go.mod h1:lBSbaQdJkoMMO0d+cJWopoJiJ+QHFBttbhCp5VRibJ8=
316316
github.com/kong/kubernetes-testing-framework v0.47.2 h1:+2Z9anTpbV/hwNeN+NFQz53BMU+g3QJydkweBp3tULo=

pkg/utils/kubernetes/resources/services.go

+1
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,7 @@ func ServicePortsFromDataPlaneIngressOpt(dataplane *operatorv1beta1.DataPlane) S
159159
Protocol: corev1.ProtocolTCP,
160160
Port: p.Port,
161161
TargetPort: targetPort,
162+
NodePort: p.NodePort,
162163
})
163164
alreadyUsedPorts[p.Port] = struct{}{}
164165
}

0 commit comments

Comments
 (0)