Skip to content

Commit 52da4cf

Browse files
authored
CP/DP Split: Support configuring NodePorts (#3343)
Problem: Now that the control plane provisions the NGINX Service, users can't set specific NodePorts values. Solution: Allow users to specify NodePorts in the helm chart (globally) and in the NginxProxy resource.
1 parent f9cad70 commit 52da4cf

18 files changed

+659
-57
lines changed

apis/v1alpha2/nginxproxy_types.go

+22
Original file line numberDiff line numberDiff line change
@@ -533,6 +533,13 @@ type ServiceSpec struct {
533533
//
534534
// +optional
535535
LoadBalancerSourceRanges []string `json:"loadBalancerSourceRanges,omitempty"`
536+
537+
// NodePorts are the list of NodePorts to expose on the NGINX data plane service.
538+
// Each NodePort MUST map to a Gateway listener port, otherwise it will be ignored.
539+
// The default NodePort range enforced by Kubernetes is 30000-32767.
540+
//
541+
// +optional
542+
NodePorts []NodePort `json:"nodePorts,omitempty"`
536543
}
537544

538545
// ServiceType describes ingress method for the Service.
@@ -569,3 +576,18 @@ const (
569576
// (dropping the traffic if there are no local endpoints).
570577
ExternalTrafficPolicyLocal ExternalTrafficPolicy = ExternalTrafficPolicy(corev1.ServiceExternalTrafficPolicyLocal)
571578
)
579+
580+
// NodePort creates a port on each node on which the NGINX data plane service is exposed. The NodePort MUST
581+
// map to a Gateway listener port, otherwise it will be ignored. If not specified, Kubernetes allocates a NodePort
582+
// automatically if required. The default NodePort range enforced by Kubernetes is 30000-32767.
583+
type NodePort struct {
584+
// Port is the NodePort to expose.
585+
// kubebuilder:validation:Minimum=1
586+
// kubebuilder:validation:Maximum=65535
587+
Port int32 `json:"port"`
588+
589+
// ListenerPort is the Gateway listener port that this NodePort maps to.
590+
// kubebuilder:validation:Minimum=1
591+
// kubebuilder:validation:Maximum=65535
592+
ListenerPort int32 `json:"listenerPort"`
593+
}

apis/v1alpha2/zz_generated.deepcopy.go

+20
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

charts/nginx-gateway-fabric/README.md

+10-5
Original file line numberDiff line numberDiff line change
@@ -258,19 +258,24 @@ The following table lists the configurable parameters of the NGINX Gateway Fabri
258258
| `certGenerator.overwrite` | Overwrite existing TLS Secrets on startup. | bool | `false` |
259259
| `certGenerator.serverTLSSecretName` | The name of the Secret containing TLS CA, certificate, and key for the NGINX Gateway Fabric control plane to securely communicate with the NGINX Agent. Must exist in the same namespace that the NGINX Gateway Fabric control plane is running in (default namespace: nginx-gateway). | string | `"server-tls"` |
260260
| `clusterDomain` | The DNS cluster domain of your Kubernetes cluster. | string | `"cluster.local"` |
261-
| `nginx` | The nginx section contains the configuration for all NGINX data plane deployments installed by the NGINX Gateway Fabric control plane. | object | `{"config":{},"container":{},"debug":false,"image":{"pullPolicy":"Always","repository":"ghcr.io/nginx/nginx-gateway-fabric/nginx","tag":"edge"},"imagePullSecret":"","imagePullSecrets":[],"kind":"deployment","plus":false,"pod":{},"replicas":1,"service":{"externalTrafficPolicy":"Local","type":"LoadBalancer"},"usage":{"caSecretName":"","clientSSLSecretName":"","endpoint":"","resolver":"","secretName":"nplus-license","skipVerify":false}}` |
262-
| `nginx.config` | The configuration for the data plane that is contained in the NginxProxy resource. | object | `{}` |
263-
| `nginx.container` | The container configuration for the NGINX container. | object | `{}` |
261+
| `nginx` | The nginx section contains the configuration for all NGINX data plane deployments installed by the NGINX Gateway Fabric control plane. | object | `{"config":{},"container":{},"debug":false,"image":{"pullPolicy":"Always","repository":"ghcr.io/nginx/nginx-gateway-fabric/nginx","tag":"edge"},"imagePullSecret":"","imagePullSecrets":[],"kind":"deployment","plus":false,"pod":{},"replicas":1,"service":{"annotations":{},"externalTrafficPolicy":"Local","loadBalancerClass":"","loadBalancerIP":"","loadBalancerSourceRanges":[],"nodePorts":[],"type":"LoadBalancer"},"usage":{"caSecretName":"","clientSSLSecretName":"","endpoint":"","resolver":"","secretName":"nplus-license","skipVerify":false}}` |
262+
| `nginx.config` | The configuration for the data plane that is contained in the NginxProxy resource. This is applied globally to all Gateways managed by this instance of NGINX Gateway Fabric. | object | `{}` |
263+
| `nginx.container` | The container configuration for the NGINX container. This is applied globally to all Gateways managed by this instance of NGINX Gateway Fabric. | object | `{}` |
264264
| `nginx.debug` | Enable debugging for NGINX. Uses the nginx-debug binary. The NGINX error log level should be set to debug in the NginxProxy resource. | bool | `false` |
265265
| `nginx.image.repository` | The NGINX image to use. | string | `"ghcr.io/nginx/nginx-gateway-fabric/nginx"` |
266266
| `nginx.imagePullSecret` | The name of the secret containing docker registry credentials. Secret must exist in the same namespace as the helm release. The control plane will copy this secret into any namespace where NGINX is deployed. | string | `""` |
267267
| `nginx.imagePullSecrets` | A list of secret names containing docker registry credentials. Secrets must exist in the same namespace as the helm release. The control plane will copy these secrets into any namespace where NGINX is deployed. | list | `[]` |
268268
| `nginx.kind` | The kind of NGINX deployment. | string | `"deployment"` |
269269
| `nginx.plus` | Is NGINX Plus image being used. | bool | `false` |
270-
| `nginx.pod` | The pod configuration for the NGINX data plane pod. | object | `{}` |
270+
| `nginx.pod` | The pod configuration for the NGINX data plane pod. This is applied globally to all Gateways managed by this instance of NGINX Gateway Fabric. | object | `{}` |
271271
| `nginx.replicas` | The number of replicas of the NGINX Deployment. | int | `1` |
272-
| `nginx.service` | The service configuration for the NGINX data plane. | object | `{"externalTrafficPolicy":"Local","type":"LoadBalancer"}` |
272+
| `nginx.service` | The service configuration for the NGINX data plane. This is applied globally to all Gateways managed by this instance of NGINX Gateway Fabric. | object | `{"annotations":{},"externalTrafficPolicy":"Local","loadBalancerClass":"","loadBalancerIP":"","loadBalancerSourceRanges":[],"nodePorts":[],"type":"LoadBalancer"}` |
273+
| `nginx.service.annotations` | The annotations of the NGINX data plane service. | object | `{}` |
273274
| `nginx.service.externalTrafficPolicy` | The externalTrafficPolicy of the service. The value Local preserves the client source IP. | string | `"Local"` |
275+
| `nginx.service.loadBalancerClass` | LoadBalancerClass is the class of the load balancer implementation this Service belongs to. Requires nginx.service.type set to LoadBalancer. | string | `""` |
276+
| `nginx.service.loadBalancerIP` | The static IP address for the load balancer. Requires nginx.service.type set to LoadBalancer. | string | `""` |
277+
| `nginx.service.loadBalancerSourceRanges` | The IP ranges (CIDR) that are allowed to access the load balancer. Requires nginx.service.type set to LoadBalancer. | list | `[]` |
278+
| `nginx.service.nodePorts` | A list of NodePorts to expose on the NGINX data plane service. Each NodePort MUST map to a Gateway listener port, otherwise it will be ignored. The default NodePort range enforced by Kubernetes is 30000-32767. | list | `[]` |
274279
| `nginx.service.type` | The type of service to create for the NGINX data plane. | string | `"LoadBalancer"` |
275280
| `nginx.usage.caSecretName` | The name of the Secret containing the NGINX Instance Manager CA certificate. Must exist in the same namespace that the NGINX Gateway Fabric control plane is running in (default namespace: nginx-gateway). | string | `""` |
276281
| `nginx.usage.clientSSLSecretName` | The name of the Secret containing the client certificate and key for authenticating with NGINX Instance Manager. Must exist in the same namespace that the NGINX Gateway Fabric control plane is running in (default namespace: nginx-gateway). | string | `""` |

charts/nginx-gateway-fabric/templates/_helpers.tpl

+13
Original file line numberDiff line numberDiff line change
@@ -91,3 +91,16 @@ Expand leader election lock name.
9191
{{- printf "%s-%s" (include "nginx-gateway.fullname" .) "leader-election" -}}
9292
{{- end -}}
9393
{{- end -}}
94+
95+
{{/*
96+
Filters out empty fields from a struct.
97+
*/}}
98+
{{- define "filterEmptyFields" -}}
99+
{{- $result := dict }}
100+
{{- range $key, $value := . }}
101+
{{- if and (not (empty $value)) (not (and (kindIs "slice" $value) (eq (len $value) 0))) }}
102+
{{- $result = merge $result (dict $key $value) }}
103+
{{- end }}
104+
{{- end }}
105+
{{- $result | toYaml }}
106+
{{- end }}

charts/nginx-gateway-fabric/templates/nginxproxy.yaml

+3-1
Original file line numberDiff line numberDiff line change
@@ -29,5 +29,7 @@ spec:
2929
{{- end }}
3030
{{- if .Values.nginx.service }}
3131
service:
32-
{{- toYaml .Values.nginx.service | nindent 6 }}
32+
{{- with .Values.nginx.service }}
33+
{{- include "filterEmptyFields" . | nindent 6 }}
34+
{{- end }}
3335
{{- end }}

charts/nginx-gateway-fabric/values.schema.json

+57-4
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@
5353
"description": "The nginx section contains the configuration for all NGINX data plane deployments\ninstalled by the NGINX Gateway Fabric control plane.",
5454
"properties": {
5555
"config": {
56-
"description": "The configuration for the data plane that is contained in the NginxProxy resource.",
56+
"description": "The configuration for the data plane that is contained in the NginxProxy resource. This is applied globally to all Gateways\nmanaged by this instance of NGINX Gateway Fabric.",
5757
"properties": {
5858
"disableHTTP2": {
5959
"description": "DisableHTTP2 defines if http2 should be disabled for all servers.",
@@ -266,7 +266,7 @@
266266
"type": "object"
267267
},
268268
"container": {
269-
"description": "The container configuration for the NGINX container.",
269+
"description": "The container configuration for the NGINX container. This is applied globally to all Gateways managed by this\ninstance of NGINX Gateway Fabric.",
270270
"required": [],
271271
"title": "container",
272272
"type": "object"
@@ -341,7 +341,7 @@
341341
"type": "boolean"
342342
},
343343
"pod": {
344-
"description": "The pod configuration for the NGINX data plane pod.",
344+
"description": "The pod configuration for the NGINX data plane pod. This is applied globally to all Gateways managed by this\ninstance of NGINX Gateway Fabric.",
345345
"required": [],
346346
"title": "pod",
347347
"type": "object"
@@ -354,8 +354,14 @@
354354
"type": "integer"
355355
},
356356
"service": {
357-
"description": "The service configuration for the NGINX data plane.",
357+
"description": "The service configuration for the NGINX data plane. This is applied globally to all Gateways managed by this\ninstance of NGINX Gateway Fabric.",
358358
"properties": {
359+
"annotations": {
360+
"description": "The annotations of the NGINX data plane service.",
361+
"required": [],
362+
"title": "annotations",
363+
"type": "object"
364+
},
359365
"externalTrafficPolicy": {
360366
"default": "Local",
361367
"description": "The externalTrafficPolicy of the service. The value Local preserves the client source IP.",
@@ -366,6 +372,53 @@
366372
"required": [],
367373
"title": "externalTrafficPolicy"
368374
},
375+
"loadBalancerClass": {
376+
"default": "",
377+
"description": "LoadBalancerClass is the class of the load balancer implementation this Service belongs to.\nRequires nginx.service.type set to LoadBalancer.",
378+
"required": [],
379+
"title": "loadBalancerClass",
380+
"type": "string"
381+
},
382+
"loadBalancerIP": {
383+
"default": "",
384+
"description": "The static IP address for the load balancer. Requires nginx.service.type set to LoadBalancer.",
385+
"required": [],
386+
"title": "loadBalancerIP",
387+
"type": "string"
388+
},
389+
"loadBalancerSourceRanges": {
390+
"description": "The IP ranges (CIDR) that are allowed to access the load balancer. Requires nginx.service.type set to LoadBalancer.",
391+
"items": {
392+
"required": []
393+
},
394+
"required": [],
395+
"title": "loadBalancerSourceRanges",
396+
"type": "array"
397+
},
398+
"nodePorts": {
399+
"description": "A list of NodePorts to expose on the NGINX data plane service. Each NodePort MUST map to a Gateway listener port,\notherwise it will be ignored. The default NodePort range enforced by Kubernetes is 30000-32767.",
400+
"items": {
401+
"properties": {
402+
"listenerPort": {
403+
"maximum": 65535,
404+
"minimum": 1,
405+
"required": [],
406+
"type": "integer"
407+
},
408+
"port": {
409+
"maximum": 65535,
410+
"minimum": 1,
411+
"required": [],
412+
"type": "integer"
413+
}
414+
},
415+
"required": [],
416+
"type": "object"
417+
},
418+
"required": [],
419+
"title": "nodePorts",
420+
"type": "array"
421+
},
369422
"type": {
370423
"default": "LoadBalancer",
371424
"description": "The type of service to create for the NGINX data plane.",

charts/nginx-gateway-fabric/values.yaml

+34-8
Original file line numberDiff line numberDiff line change
@@ -367,10 +367,12 @@ nginx:
367367
# value:
368368
# type: string
369369
# @schema
370-
# -- The configuration for the data plane that is contained in the NginxProxy resource.
370+
# -- The configuration for the data plane that is contained in the NginxProxy resource. This is applied globally to all Gateways
371+
# managed by this instance of NGINX Gateway Fabric.
371372
config: {}
372373

373-
# -- The pod configuration for the NGINX data plane pod.
374+
# -- The pod configuration for the NGINX data plane pod. This is applied globally to all Gateways managed by this
375+
# instance of NGINX Gateway Fabric.
374376
pod: {}
375377
# -- The termination grace period of the NGINX data plane pod.
376378
# terminationGracePeriodSeconds: 30
@@ -391,7 +393,8 @@ nginx:
391393
# nginx.container.extraVolumeMounts mount additional volumes to the container.
392394
# extraVolumes: []
393395

394-
# -- The container configuration for the NGINX container.
396+
# -- The container configuration for the NGINX container. This is applied globally to all Gateways managed by this
397+
# instance of NGINX Gateway Fabric.
395398
container: {}
396399
# -- The resource requirements of the NGINX container.
397400
# resources: {}
@@ -402,7 +405,8 @@ nginx:
402405
# -- extraVolumeMounts are the additional volume mounts for the NGINX container.
403406
# extraVolumeMounts: []
404407

405-
# -- The service configuration for the NGINX data plane.
408+
# -- The service configuration for the NGINX data plane. This is applied globally to all Gateways managed by this
409+
# instance of NGINX Gateway Fabric.
406410
service:
407411
# @schema
408412
# enum:
@@ -422,17 +426,39 @@ nginx:
422426
externalTrafficPolicy: Local
423427

424428
# -- The annotations of the NGINX data plane service.
425-
# annotations: {}
429+
annotations: {}
426430

427431
# -- The static IP address for the load balancer. Requires nginx.service.type set to LoadBalancer.
428-
# loadBalancerIP: ""
432+
loadBalancerIP: ""
429433

430434
# -- LoadBalancerClass is the class of the load balancer implementation this Service belongs to.
431435
# Requires nginx.service.type set to LoadBalancer.
432-
# loadBalancerClass: ""
436+
loadBalancerClass: ""
433437

434438
# -- The IP ranges (CIDR) that are allowed to access the load balancer. Requires nginx.service.type set to LoadBalancer.
435-
# loadBalancerSourceRanges: []
439+
loadBalancerSourceRanges: []
440+
441+
# @schema
442+
# type: array
443+
# items:
444+
# type: object
445+
# properties:
446+
# port:
447+
# type: integer
448+
# required: true
449+
# minimum: 1
450+
# maximum: 65535
451+
# listenerPort:
452+
# type: integer
453+
# required: true
454+
# minimum: 1
455+
# maximum: 65535
456+
# @schema
457+
# -- A list of NodePorts to expose on the NGINX data plane service. Each NodePort MUST map to a Gateway listener port,
458+
# otherwise it will be ignored. The default NodePort range enforced by Kubernetes is 30000-32767.
459+
nodePorts: []
460+
# - port: 30025
461+
# listenerPort: 80
436462

437463
# -- Enable debugging for NGINX. Uses the nginx-debug binary. The NGINX error log level should be set to debug in the NginxProxy resource.
438464
debug: false

config/crd/bases/gateway.nginx.org_nginxproxies.yaml

+30
Original file line numberDiff line numberDiff line change
@@ -3498,6 +3498,36 @@ spec:
34983498
items:
34993499
type: string
35003500
type: array
3501+
nodePorts:
3502+
description: |-
3503+
NodePorts are the list of NodePorts to expose on the NGINX data plane service.
3504+
Each NodePort MUST map to a Gateway listener port, otherwise it will be ignored.
3505+
The default NodePort range enforced by Kubernetes is 30000-32767.
3506+
items:
3507+
description: |-
3508+
NodePort creates a port on each node on which the NGINX data plane service is exposed. The NodePort MUST
3509+
map to a Gateway listener port, otherwise it will be ignored. If not specified, Kubernetes allocates a NodePort
3510+
automatically if required. The default NodePort range enforced by Kubernetes is 30000-32767.
3511+
properties:
3512+
listenerPort:
3513+
description: |-
3514+
ListenerPort is the Gateway listener port that this NodePort maps to.
3515+
kubebuilder:validation:Minimum=1
3516+
kubebuilder:validation:Maximum=65535
3517+
format: int32
3518+
type: integer
3519+
port:
3520+
description: |-
3521+
Port is the NodePort to expose.
3522+
kubebuilder:validation:Minimum=1
3523+
kubebuilder:validation:Maximum=65535
3524+
format: int32
3525+
type: integer
3526+
required:
3527+
- listenerPort
3528+
- port
3529+
type: object
3530+
type: array
35013531
type:
35023532
default: LoadBalancer
35033533
description: ServiceType describes ingress method for the

0 commit comments

Comments
 (0)