From 5d18c9441f00e47ffadfa5350dbbd3cc97034ccc Mon Sep 17 00:00:00 2001 From: salonichf5 <146118978+salonichf5@users.noreply.github.com> Date: Mon, 14 Jul 2025 14:05:19 -0600 Subject: [PATCH 1/5] add readiness probe for nginx on startup --- apis/v1alpha2/nginxproxy_types.go | 43 ++++ apis/v1alpha2/zz_generated.deepcopy.go | 40 ++++ charts/nginx-gateway-fabric/README.md | 2 +- .../templates/nginxproxy.yaml | 5 + .../nginx-gateway-fabric/values.schema.json | 6 + charts/nginx-gateway-fabric/values.yaml | 34 +++ .../bases/gateway.nginx.org_nginxproxies.yaml | 42 ++++ deploy/azure/deploy.yaml | 5 + deploy/crds.yaml | 42 ++++ deploy/default/deploy.yaml | 5 + deploy/experimental-nginx-plus/deploy.yaml | 5 + deploy/experimental/deploy.yaml | 5 + deploy/nginx-plus/deploy.yaml | 5 + deploy/nodeport/deploy.yaml | 5 + deploy/openshift/deploy.yaml | 5 + .../snippets-filters-nginx-plus/deploy.yaml | 5 + deploy/snippets-filters/deploy.yaml | 5 + .../nginx/config/base_http_config.go | 10 +- .../nginx/config/base_http_config_template.go | 9 + .../nginx/config/base_http_config_test.go | 56 +++++ internal/controller/provisioner/objects.go | 41 ++++ .../controller/provisioner/objects_test.go | 198 ++++++++++++++++++ .../state/dataplane/configuration.go | 49 +++-- .../state/dataplane/configuration_test.go | 90 +++++++- internal/controller/state/dataplane/types.go | 2 + 25 files changed, 687 insertions(+), 27 deletions(-) diff --git a/apis/v1alpha2/nginxproxy_types.go b/apis/v1alpha2/nginxproxy_types.go index d1845411ab..d05015ded3 100644 --- a/apis/v1alpha2/nginxproxy_types.go +++ b/apis/v1alpha2/nginxproxy_types.go @@ -386,6 +386,49 @@ type KubernetesSpec struct { // // +optional Service *ServiceSpec `json:"service,omitempty"` + + // ReadinessProbe is the configuration for the NGINX Readiness probe. + // + // +optional + ReadinessProbe *ReadinessProbeSpec `json:"readinessProbe,omitempty"` +} + +// ReadinessProbeSpec defines the configuration for the NGINX readiness probe. +type ReadinessProbeSpec struct { + // Port is the port on which the readiness endpoint is exposed. + // If not specified, the default port is 8081. + // + // +optional + // +kubebuilder:default:=8081 + // +kubebuilder:validation:Minimum=1 + // +kubebuilder:validation:Maximum=65535 + Port *int32 `json:"port,omitempty"` + + // InitialDelaySeconds is the number of seconds after the container has + // started before the readiness probe is initiated. + // If not specified, the default is 3 seconds. + // +optional + // +kubebuilder:default:=3 + // +kubebuilder:validation:Minimum=0 + // +kubebuilder:validation:Maximum=3600 + InitialDelaySeconds *int32 `json:"initialDelaySeconds,omitempty"` + + // PeriodSeconds is the number of seconds between consecutive readiness probes. + // If not specified, the default is 10 seconds. + // +optional + // +kubebuilder:default:=10 + // +kubebuilder:validation:Minimum=1 + // +kubebuilder:validation:Maximum=3600 + PeriodSeconds *int32 `json:"periodSeconds,omitempty"` + + // TimeoutSeconds is the number of seconds after which the readiness probe times out. + // If not specified, the default is 1 second. + // + // +optional + // +kubebuilder:default:=1 + // +kubebuilder:validation:Minimum=1 + // +kubebuilder:validation:Maximum=3600 + TimeoutSeconds *int32 `json:"timeoutSeconds,omitempty"` } // Deployment is the configuration for the NGINX Deployment. diff --git a/apis/v1alpha2/zz_generated.deepcopy.go b/apis/v1alpha2/zz_generated.deepcopy.go index 61eea4445a..8307ba17ab 100644 --- a/apis/v1alpha2/zz_generated.deepcopy.go +++ b/apis/v1alpha2/zz_generated.deepcopy.go @@ -160,6 +160,11 @@ func (in *KubernetesSpec) DeepCopyInto(out *KubernetesSpec) { *out = new(ServiceSpec) (*in).DeepCopyInto(*out) } + if in.ReadinessProbe != nil { + in, out := &in.ReadinessProbe, &out.ReadinessProbe + *out = new(ReadinessProbeSpec) + (*in).DeepCopyInto(*out) + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KubernetesSpec. @@ -529,6 +534,41 @@ func (in *PodSpec) DeepCopy() *PodSpec { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ReadinessProbeSpec) DeepCopyInto(out *ReadinessProbeSpec) { + *out = *in + if in.Port != nil { + in, out := &in.Port, &out.Port + *out = new(int32) + **out = **in + } + if in.InitialDelaySeconds != nil { + in, out := &in.InitialDelaySeconds, &out.InitialDelaySeconds + *out = new(int32) + **out = **in + } + if in.PeriodSeconds != nil { + in, out := &in.PeriodSeconds, &out.PeriodSeconds + *out = new(int32) + **out = **in + } + if in.TimeoutSeconds != nil { + in, out := &in.TimeoutSeconds, &out.TimeoutSeconds + *out = new(int32) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ReadinessProbeSpec. +func (in *ReadinessProbeSpec) DeepCopy() *ReadinessProbeSpec { + if in == nil { + return nil + } + out := new(ReadinessProbeSpec) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *RewriteClientIP) DeepCopyInto(out *RewriteClientIP) { *out = *in diff --git a/charts/nginx-gateway-fabric/README.md b/charts/nginx-gateway-fabric/README.md index 627335ec19..ee8a17c53e 100644 --- a/charts/nginx-gateway-fabric/README.md +++ b/charts/nginx-gateway-fabric/README.md @@ -264,7 +264,7 @@ The following table lists the configurable parameters of the NGINX Gateway Fabri | `certGenerator.ttlSecondsAfterFinished` | How long to wait after the cert generator job has finished before it is removed by the job controller. | int | `30` | | `clusterDomain` | The DNS cluster domain of your Kubernetes cluster. | string | `"cluster.local"` | | `gateways` | A list of Gateway objects. View https://gateway-api.sigs.k8s.io/reference/spec/#gateway for full Gateway reference. | list | `[]` | -| `nginx` | The nginx section contains the configuration for all NGINX data plane deployments installed by the NGINX Gateway Fabric control plane. | object | `{"config":{},"container":{"hostPorts":[],"lifecycle":{},"resources":{},"volumeMounts":[]},"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","loadBalancerClass":"","loadBalancerIP":"","loadBalancerSourceRanges":[],"nodePorts":[],"type":"LoadBalancer"},"usage":{"caSecretName":"","clientSSLSecretName":"","endpoint":"","resolver":"","secretName":"nplus-license","skipVerify":false}}` | +| `nginx` | The nginx section contains the configuration for all NGINX data plane deployments installed by the NGINX Gateway Fabric control plane. | object | `{"config":{},"container":{"hostPorts":[],"lifecycle":{},"resources":{},"volumeMounts":[]},"debug":false,"image":{"pullPolicy":"Always","repository":"ghcr.io/nginx/nginx-gateway-fabric/nginx","tag":"edge"},"imagePullSecret":"","imagePullSecrets":[],"kind":"deployment","plus":false,"pod":{},"readinessProbe":{},"replicas":1,"service":{"externalTrafficPolicy":"Local","loadBalancerClass":"","loadBalancerIP":"","loadBalancerSourceRanges":[],"nodePorts":[],"type":"LoadBalancer"},"usage":{"caSecretName":"","clientSSLSecretName":"","endpoint":"","resolver":"","secretName":"nplus-license","skipVerify":false}}` | | `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 | `{}` | | `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 | `{"hostPorts":[],"lifecycle":{},"resources":{},"volumeMounts":[]}` | | `nginx.container.hostPorts` | A list of HostPorts to expose on the host. This configuration allows containers to bind to a specific port on the host node, enabling external network traffic to reach the container directly through the host's IP address and port. Use this option when you need to expose container ports on the host for direct access, such as for debugging, legacy integrations, or when NodePort/LoadBalancer services are not suitable. Note: Using hostPort may have security and scheduling implications, as it ties pods to specific nodes and ports. | list | `[]` | diff --git a/charts/nginx-gateway-fabric/templates/nginxproxy.yaml b/charts/nginx-gateway-fabric/templates/nginxproxy.yaml index 0c4640c5b9..8e2c253204 100644 --- a/charts/nginx-gateway-fabric/templates/nginxproxy.yaml +++ b/charts/nginx-gateway-fabric/templates/nginxproxy.yaml @@ -58,3 +58,8 @@ spec: {{- end }} {{- end }} {{- end }} + readinessProbe: + port: {{ .Values.nginx.readinessProbe.port | default 8081 }} + initialDelaySeconds: {{ .Values.nginx.readinessProbe.initialDelaySeconds | default 3 }} + periodSeconds: {{ .Values.nginx.readinessProbe.periodSeconds | default 10 }} + timeoutSeconds: {{ .Values.nginx.readinessProbe.timeoutSeconds | default 1 }} diff --git a/charts/nginx-gateway-fabric/values.schema.json b/charts/nginx-gateway-fabric/values.schema.json index 9748af66b0..8310cd1f34 100644 --- a/charts/nginx-gateway-fabric/values.schema.json +++ b/charts/nginx-gateway-fabric/values.schema.json @@ -447,6 +447,12 @@ "title": "pod", "type": "object" }, + "readinessProbe": { + "description": "# Defines the settings for the data plane readiness probe. This probe returns Ready when the NGINX data plane is ready to serve traffic.", + "required": [], + "title": "readinessProbe", + "type": "object" + }, "replicas": { "default": 1, "description": "The number of replicas of the NGINX Deployment.", diff --git a/charts/nginx-gateway-fabric/values.yaml b/charts/nginx-gateway-fabric/values.yaml index cd55ef6eda..1a30d7bd03 100644 --- a/charts/nginx-gateway-fabric/values.yaml +++ b/charts/nginx-gateway-fabric/values.yaml @@ -493,6 +493,40 @@ nginx: # - port: 30025 # listenerPort: 80 + ## Defines the settings for the data plane readiness probe. This probe returns Ready when the NGINX data plane is ready to serve traffic. + readinessProbe: {} + # @schema + # type: integer + # minimum: 1 + # maximum: 65535 + # @schema + # -- Port in which the readiness endpoint is exposed. + # port: 8081 + + # @schema + # type: integer + # minimum: 0 + # maximum: 3600 + # @schema + # -- The number of seconds after the Pod has started before the readiness probes are initiated. + # initialDelaySeconds: 3 + + # @schema + # type: integer + # minimum: 1 + # maximum: 3600 + # @schema + # -- The number of seconds between consecutive readiness probes. + # periodSeconds: 10 + + # @schema + # type: integer + # minimum: 1 + # maximum: 3600 + # @schema + # -- The number of seconds after which the readiness probe times out. + # timeoutSeconds: 1 + # -- Enable debugging for NGINX. Uses the nginx-debug binary. The NGINX error log level should be set to debug in the NginxProxy resource. debug: false diff --git a/config/crd/bases/gateway.nginx.org_nginxproxies.yaml b/config/crd/bases/gateway.nginx.org_nginxproxies.yaml index 8afed8b803..56aca54dbf 100644 --- a/config/crd/bases/gateway.nginx.org_nginxproxies.yaml +++ b/config/crd/bases/gateway.nginx.org_nginxproxies.yaml @@ -6894,6 +6894,48 @@ spec: format: int32 type: integer type: object + readinessProbe: + description: ReadinessProbe is the configuration for the NGINX + Readiness probe. + properties: + initialDelaySeconds: + default: 3 + description: |- + InitialDelaySeconds is the number of seconds after the container has + started before the readiness probe is initiated. + If not specified, the default is 3 seconds. + format: int32 + maximum: 3600 + minimum: 0 + type: integer + periodSeconds: + default: 10 + description: |- + PeriodSeconds is the number of seconds between consecutive readiness probes. + If not specified, the default is 10 seconds. + format: int32 + maximum: 3600 + minimum: 1 + type: integer + port: + default: 8081 + description: |- + Port is the port on which the readiness endpoint is exposed. + If not specified, the default port is 8081. + format: int32 + maximum: 65535 + minimum: 1 + type: integer + timeoutSeconds: + default: 1 + description: |- + TimeoutSeconds is the number of seconds after which the readiness probe times out. + If not specified, the default is 1 second. + format: int32 + maximum: 3600 + minimum: 1 + type: integer + type: object service: description: Service is the configuration for the NGINX Service. properties: diff --git a/deploy/azure/deploy.yaml b/deploy/azure/deploy.yaml index 0a7e457685..e4ec417633 100644 --- a/deploy/azure/deploy.yaml +++ b/deploy/azure/deploy.yaml @@ -421,6 +421,11 @@ spec: nodeSelector: kubernetes.io/os: linux replicas: 1 + readinessProbe: + initialDelaySeconds: 3 + periodSeconds: 10 + port: 8081 + timeoutSeconds: 1 service: externalTrafficPolicy: Local type: LoadBalancer diff --git a/deploy/crds.yaml b/deploy/crds.yaml index 016c3074d3..78d8c8306b 100644 --- a/deploy/crds.yaml +++ b/deploy/crds.yaml @@ -7479,6 +7479,48 @@ spec: format: int32 type: integer type: object + readinessProbe: + description: ReadinessProbe is the configuration for the NGINX + Readiness probe. + properties: + initialDelaySeconds: + default: 3 + description: |- + InitialDelaySeconds is the number of seconds after the container has + started before the readiness probe is initiated. + If not specified, the default is 3 seconds. + format: int32 + maximum: 3600 + minimum: 0 + type: integer + periodSeconds: + default: 10 + description: |- + PeriodSeconds is the number of seconds between consecutive readiness probes. + If not specified, the default is 10 seconds. + format: int32 + maximum: 3600 + minimum: 1 + type: integer + port: + default: 8081 + description: |- + Port is the port on which the readiness endpoint is exposed. + If not specified, the default port is 8081. + format: int32 + maximum: 65535 + minimum: 1 + type: integer + timeoutSeconds: + default: 1 + description: |- + TimeoutSeconds is the number of seconds after which the readiness probe times out. + If not specified, the default is 1 second. + format: int32 + maximum: 3600 + minimum: 1 + type: integer + type: object service: description: Service is the configuration for the NGINX Service. properties: diff --git a/deploy/default/deploy.yaml b/deploy/default/deploy.yaml index 4324fc92f7..31b584fdca 100644 --- a/deploy/default/deploy.yaml +++ b/deploy/default/deploy.yaml @@ -416,6 +416,11 @@ spec: repository: ghcr.io/nginx/nginx-gateway-fabric/nginx tag: edge replicas: 1 + readinessProbe: + initialDelaySeconds: 3 + periodSeconds: 10 + port: 8081 + timeoutSeconds: 1 service: externalTrafficPolicy: Local type: LoadBalancer diff --git a/deploy/experimental-nginx-plus/deploy.yaml b/deploy/experimental-nginx-plus/deploy.yaml index f0ac53ba0d..1a1a900be4 100644 --- a/deploy/experimental-nginx-plus/deploy.yaml +++ b/deploy/experimental-nginx-plus/deploy.yaml @@ -424,6 +424,11 @@ spec: repository: private-registry.nginx.com/nginx-gateway-fabric/nginx-plus tag: edge replicas: 1 + readinessProbe: + initialDelaySeconds: 3 + periodSeconds: 10 + port: 8081 + timeoutSeconds: 1 service: externalTrafficPolicy: Local type: LoadBalancer diff --git a/deploy/experimental/deploy.yaml b/deploy/experimental/deploy.yaml index ad3cf361a6..0cdd91240a 100644 --- a/deploy/experimental/deploy.yaml +++ b/deploy/experimental/deploy.yaml @@ -421,6 +421,11 @@ spec: repository: ghcr.io/nginx/nginx-gateway-fabric/nginx tag: edge replicas: 1 + readinessProbe: + initialDelaySeconds: 3 + periodSeconds: 10 + port: 8081 + timeoutSeconds: 1 service: externalTrafficPolicy: Local type: LoadBalancer diff --git a/deploy/nginx-plus/deploy.yaml b/deploy/nginx-plus/deploy.yaml index a966b9e325..bfbc11ba52 100644 --- a/deploy/nginx-plus/deploy.yaml +++ b/deploy/nginx-plus/deploy.yaml @@ -419,6 +419,11 @@ spec: repository: private-registry.nginx.com/nginx-gateway-fabric/nginx-plus tag: edge replicas: 1 + readinessProbe: + initialDelaySeconds: 3 + periodSeconds: 10 + port: 8081 + timeoutSeconds: 1 service: externalTrafficPolicy: Local type: LoadBalancer diff --git a/deploy/nodeport/deploy.yaml b/deploy/nodeport/deploy.yaml index d151c82319..f357d56c50 100644 --- a/deploy/nodeport/deploy.yaml +++ b/deploy/nodeport/deploy.yaml @@ -416,6 +416,11 @@ spec: repository: ghcr.io/nginx/nginx-gateway-fabric/nginx tag: edge replicas: 1 + readinessProbe: + initialDelaySeconds: 3 + periodSeconds: 10 + port: 8081 + timeoutSeconds: 1 service: externalTrafficPolicy: Local type: NodePort diff --git a/deploy/openshift/deploy.yaml b/deploy/openshift/deploy.yaml index e6ecf6b3e0..09786bcba9 100644 --- a/deploy/openshift/deploy.yaml +++ b/deploy/openshift/deploy.yaml @@ -438,6 +438,11 @@ spec: repository: ghcr.io/nginx/nginx-gateway-fabric/nginx tag: edge replicas: 1 + readinessProbe: + initialDelaySeconds: 3 + periodSeconds: 10 + port: 8081 + timeoutSeconds: 1 service: externalTrafficPolicy: Local type: LoadBalancer diff --git a/deploy/snippets-filters-nginx-plus/deploy.yaml b/deploy/snippets-filters-nginx-plus/deploy.yaml index 7461912539..2ff50ce6b9 100644 --- a/deploy/snippets-filters-nginx-plus/deploy.yaml +++ b/deploy/snippets-filters-nginx-plus/deploy.yaml @@ -422,6 +422,11 @@ spec: repository: private-registry.nginx.com/nginx-gateway-fabric/nginx-plus tag: edge replicas: 1 + readinessProbe: + initialDelaySeconds: 3 + periodSeconds: 10 + port: 8081 + timeoutSeconds: 1 service: externalTrafficPolicy: Local type: LoadBalancer diff --git a/deploy/snippets-filters/deploy.yaml b/deploy/snippets-filters/deploy.yaml index d23d775600..35148ead13 100644 --- a/deploy/snippets-filters/deploy.yaml +++ b/deploy/snippets-filters/deploy.yaml @@ -419,6 +419,11 @@ spec: repository: ghcr.io/nginx/nginx-gateway-fabric/nginx tag: edge replicas: 1 + readinessProbe: + initialDelaySeconds: 3 + periodSeconds: 10 + port: 8081 + timeoutSeconds: 1 service: externalTrafficPolicy: Local type: LoadBalancer diff --git a/internal/controller/nginx/config/base_http_config.go b/internal/controller/nginx/config/base_http_config.go index f808e86b3e..e4722c1b55 100644 --- a/internal/controller/nginx/config/base_http_config.go +++ b/internal/controller/nginx/config/base_http_config.go @@ -11,16 +11,18 @@ import ( var baseHTTPTemplate = gotemplate.Must(gotemplate.New("baseHttp").Parse(baseHTTPTemplateText)) type httpConfig struct { - Includes []shared.Include - HTTP2 bool + Includes []shared.Include + HTTP2 bool + NginxReadinessProbePort int32 } func executeBaseHTTPConfig(conf dataplane.Configuration) []executeResult { includes := createIncludesFromSnippets(conf.BaseHTTPConfig.Snippets) hc := httpConfig{ - HTTP2: conf.BaseHTTPConfig.HTTP2, - Includes: includes, + HTTP2: conf.BaseHTTPConfig.HTTP2, + Includes: includes, + NginxReadinessProbePort: conf.BaseHTTPConfig.NginxReadinessProbePort, } results := make([]executeResult, 0, len(includes)+1) diff --git a/internal/controller/nginx/config/base_http_config_template.go b/internal/controller/nginx/config/base_http_config_template.go index 5163904e26..a46f62796d 100644 --- a/internal/controller/nginx/config/base_http_config_template.go +++ b/internal/controller/nginx/config/base_http_config_template.go @@ -24,6 +24,15 @@ map $request_uri $request_uri_path { "~^(?P[^?]*)(\?.*)?$" $path; } +# NGINX health check server block. +server { + listen {{ .NginxReadinessProbePort }}; + + location = /readyz { + return 200; + } +} + {{ range $i := .Includes -}} include {{ $i.Name }}; {{ end -}} diff --git a/internal/controller/nginx/config/base_http_config_test.go b/internal/controller/nginx/config/base_http_config_test.go index 31cc7aff52..32115e44b6 100644 --- a/internal/controller/nginx/config/base_http_config_test.go +++ b/internal/controller/nginx/config/base_http_config_test.go @@ -107,3 +107,59 @@ func TestExecuteBaseHttp_Snippets(t *testing.T) { snippet2IncludeRes := string(res[2].data) g.Expect(snippet2IncludeRes).To(ContainSubstring("contents2")) } + +func TestExecuteBaseHttp_NginxReadinessProbePort(t *testing.T) { + t.Parallel() + + defaultConfig := dataplane.Configuration{ + BaseHTTPConfig: dataplane.BaseHTTPConfig{ + NginxReadinessProbePort: dataplane.DefaultNginxReadinessProbePort, + }, + } + + customConfig := dataplane.Configuration{ + BaseHTTPConfig: dataplane.BaseHTTPConfig{ + NginxReadinessProbePort: 9090, + }, + } + + tests := []struct { + name string + expectedPort string + expectedListen string + conf dataplane.Configuration + }{ + { + name: "default nginx readiness probe port", + conf: defaultConfig, + expectedPort: "8081", + expectedListen: "listen 8081;", + }, + { + name: "custom nginx readiness probe 9090", + conf: customConfig, + expectedPort: "9090", + expectedListen: "listen 9090;", + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + t.Parallel() + g := NewWithT(t) + + res := executeBaseHTTPConfig(test.conf) + g.Expect(res).To(HaveLen(1)) + + httpConfig := string(res[0].data) + + // check that the listen directive contains the expected port + g.Expect(httpConfig).To(ContainSubstring(test.expectedListen)) + + // check that the health check server block is present + g.Expect(httpConfig).To(ContainSubstring("server {")) + g.Expect(httpConfig).To(ContainSubstring("location = /readyz {")) + g.Expect(httpConfig).To(ContainSubstring("return 200;")) + }) + } +} diff --git a/internal/controller/provisioner/objects.go b/internal/controller/provisioner/objects.go index 84cdefa02f..4bc7374887 100644 --- a/internal/controller/provisioner/objects.go +++ b/internal/controller/provisioner/objects.go @@ -37,6 +37,10 @@ const ( defaultNginxImagePath = "ghcr.io/nginx/nginx-gateway-fabric/nginx" defaultNginxPlusImagePath = "private-registry.nginx.com/nginx-gateway-fabric/nginx-plus" defaultImagePullPolicy = corev1.PullIfNotPresent + + defaultInitialDelaySeconds = int32(3) + defaultPeriodSeconds = int32(10) + defaultTimeoutSeconds = int32(1) ) var emptyDirVolumeSource = corev1.VolumeSource{EmptyDir: &corev1.EmptyDirVolumeSource{}} @@ -623,6 +627,7 @@ func (p *NginxProvisioner) buildNginxPodTemplateSpec( Image: image, ImagePullPolicy: pullPolicy, Ports: containerPorts, + ReadinessProbe: p.buildReadinessProbe(nProxyCfg), SecurityContext: &corev1.SecurityContext{ AllowPrivilegeEscalation: helpers.GetPointer(false), Capabilities: &corev1.Capabilities{ @@ -1037,3 +1042,39 @@ func (p *NginxProvisioner) buildNginxResourceObjectsForDeletion(deploymentNSName return objects } + +// buildReadinessProbe creates a readiness probe configuration for the NGINX container. +func (p *NginxProvisioner) buildReadinessProbe(nProxyCfg *graph.EffectiveNginxProxy) *corev1.Probe { + port := dataplane.DefaultNginxReadinessProbePort + initialDelaySeconds := defaultInitialDelaySeconds + timeoutSeconds := defaultTimeoutSeconds + periodSeconds := defaultPeriodSeconds + + if nProxyCfg != nil && nProxyCfg.Kubernetes != nil && nProxyCfg.Kubernetes.ReadinessProbe != nil { + readinessProbeSpec := nProxyCfg.Kubernetes.ReadinessProbe + if readinessProbeSpec.Port != nil { + port = *readinessProbeSpec.Port + } + if readinessProbeSpec.InitialDelaySeconds != nil { + initialDelaySeconds = *readinessProbeSpec.InitialDelaySeconds + } + if readinessProbeSpec.PeriodSeconds != nil { + periodSeconds = *readinessProbeSpec.PeriodSeconds + } + if readinessProbeSpec.TimeoutSeconds != nil { + timeoutSeconds = *readinessProbeSpec.TimeoutSeconds + } + } + + return &corev1.Probe{ + ProbeHandler: corev1.ProbeHandler{ + HTTPGet: &corev1.HTTPGetAction{ + Path: "/readyz", + Port: intstr.FromInt32(port), + }, + }, + InitialDelaySeconds: initialDelaySeconds, + TimeoutSeconds: timeoutSeconds, + PeriodSeconds: periodSeconds, + } +} diff --git a/internal/controller/provisioner/objects_test.go b/internal/controller/provisioner/objects_test.go index 608edf8b4d..5939052137 100644 --- a/internal/controller/provisioner/objects_test.go +++ b/internal/controller/provisioner/objects_test.go @@ -301,6 +301,12 @@ func TestBuildNginxResourceObjects_NginxProxyConfig(t *testing.T) { HostPorts: []ngfAPIv1alpha2.HostPort{{ContainerPort: int32(8443), Port: int32(8443)}}, }, }, + ReadinessProbe: &ngfAPIv1alpha2.ReadinessProbeSpec{ + Port: helpers.GetPointer[int32](9091), + InitialDelaySeconds: helpers.GetPointer[int32](5), + PeriodSeconds: helpers.GetPointer[int32](10), + TimeoutSeconds: helpers.GetPointer[int32](2), + }, }, } @@ -356,6 +362,13 @@ func TestBuildNginxResourceObjects_NginxProxyConfig(t *testing.T) { Name: "port-8443", HostPort: 8443, })) + + g.Expect(container.ReadinessProbe).ToNot(BeNil()) + g.Expect(container.ReadinessProbe.HTTPGet.Path).To(Equal("/readyz")) + g.Expect(container.ReadinessProbe.HTTPGet.Port).To(Equal(intstr.FromInt(9091))) + g.Expect(container.ReadinessProbe.InitialDelaySeconds).To(Equal(int32(5))) + g.Expect(container.ReadinessProbe.PeriodSeconds).To(Equal(int32(10))) + g.Expect(container.ReadinessProbe.TimeoutSeconds).To(Equal(int32(2))) } func TestBuildNginxResourceObjects_Plus(t *testing.T) { @@ -1058,3 +1071,188 @@ func TestBuildNginxConfigMaps_WorkerConnections(t *testing.T) { g.Expect(ok).To(BeTrue()) g.Expect(bootstrapCM.Data["main.conf"]).To(ContainSubstring("worker_connections 2048;")) } + +func TestBuildReadinessProbe(t *testing.T) { + t.Parallel() + + provisioner := &NginxProvisioner{} + + defaultProbe := &corev1.Probe{ + ProbeHandler: corev1.ProbeHandler{ + HTTPGet: &corev1.HTTPGetAction{ + Path: "/readyz", + Port: intstr.FromInt32(8081), + }, + }, + InitialDelaySeconds: 3, + TimeoutSeconds: 1, + PeriodSeconds: 10, + } + + tests := []struct { + nProxyCfg *graph.EffectiveNginxProxy + expectedProbe *corev1.Probe + name string + }{ + { + name: "nil nginx proxy config returns default probe", + nProxyCfg: nil, + expectedProbe: defaultProbe, + }, + { + name: "empty nginx proxy config returns default probe", + nProxyCfg: &graph.EffectiveNginxProxy{}, + expectedProbe: defaultProbe, + }, + { + name: "nginx proxy config with nil kubernetes returns default probe", + nProxyCfg: &graph.EffectiveNginxProxy{ + Kubernetes: nil, + }, + expectedProbe: defaultProbe, + }, + { + name: "nginx proxy config with empty kubernetes returns default probe", + nProxyCfg: &graph.EffectiveNginxProxy{ + Kubernetes: &ngfAPIv1alpha2.KubernetesSpec{}, + }, + expectedProbe: defaultProbe, + }, + { + name: "nginx proxy config with nil readiness probe returns default probe", + nProxyCfg: &graph.EffectiveNginxProxy{ + Kubernetes: &ngfAPIv1alpha2.KubernetesSpec{ + ReadinessProbe: nil, + }, + }, + expectedProbe: defaultProbe, + }, + { + name: "nginx proxy config with empty readiness probe returns default probe", + nProxyCfg: &graph.EffectiveNginxProxy{ + Kubernetes: &ngfAPIv1alpha2.KubernetesSpec{ + ReadinessProbe: &ngfAPIv1alpha2.ReadinessProbeSpec{}, + }, + }, + expectedProbe: defaultProbe, + }, + { + name: "nginx proxy config with custom port", + nProxyCfg: &graph.EffectiveNginxProxy{ + Kubernetes: &ngfAPIv1alpha2.KubernetesSpec{ + ReadinessProbe: &ngfAPIv1alpha2.ReadinessProbeSpec{ + Port: helpers.GetPointer(int32(9090)), + }, + }, + }, + expectedProbe: &corev1.Probe{ + ProbeHandler: corev1.ProbeHandler{ + HTTPGet: &corev1.HTTPGetAction{ + Path: "/readyz", + Port: intstr.FromInt32(9090), + }, + }, + InitialDelaySeconds: 3, + TimeoutSeconds: 1, + PeriodSeconds: 10, + }, + }, + { + name: "nginx proxy config with custom initialDelaySeconds", + nProxyCfg: &graph.EffectiveNginxProxy{ + Kubernetes: &ngfAPIv1alpha2.KubernetesSpec{ + ReadinessProbe: &ngfAPIv1alpha2.ReadinessProbeSpec{ + InitialDelaySeconds: helpers.GetPointer(int32(5)), + }, + }, + }, + expectedProbe: &corev1.Probe{ + ProbeHandler: corev1.ProbeHandler{ + HTTPGet: &corev1.HTTPGetAction{ + Path: "/readyz", + Port: intstr.FromInt32(8081), + }, + }, + InitialDelaySeconds: 5, + TimeoutSeconds: 1, + PeriodSeconds: 10, + }, + }, + { + name: "nginx proxy config with custom timeoutSeconds", + nProxyCfg: &graph.EffectiveNginxProxy{ + Kubernetes: &ngfAPIv1alpha2.KubernetesSpec{ + ReadinessProbe: &ngfAPIv1alpha2.ReadinessProbeSpec{ + TimeoutSeconds: helpers.GetPointer(int32(2)), + }, + }, + }, + expectedProbe: &corev1.Probe{ + ProbeHandler: corev1.ProbeHandler{ + HTTPGet: &corev1.HTTPGetAction{ + Path: "/readyz", + Port: intstr.FromInt32(8081), + }, + }, + InitialDelaySeconds: 3, + TimeoutSeconds: 2, + PeriodSeconds: 10, + }, + }, + { + name: "nginx proxy config with custom periodSeconds", + nProxyCfg: &graph.EffectiveNginxProxy{ + Kubernetes: &ngfAPIv1alpha2.KubernetesSpec{ + ReadinessProbe: &ngfAPIv1alpha2.ReadinessProbeSpec{ + PeriodSeconds: helpers.GetPointer(int32(15)), + }, + }, + }, + expectedProbe: &corev1.Probe{ + ProbeHandler: corev1.ProbeHandler{ + HTTPGet: &corev1.HTTPGetAction{ + Path: "/readyz", + Port: intstr.FromInt32(8081), + }, + }, + InitialDelaySeconds: 3, + TimeoutSeconds: 1, + PeriodSeconds: 15, + }, + }, + { + name: "nginx proxy config with all custom values", + nProxyCfg: &graph.EffectiveNginxProxy{ + Kubernetes: &ngfAPIv1alpha2.KubernetesSpec{ + ReadinessProbe: &ngfAPIv1alpha2.ReadinessProbeSpec{ + Port: helpers.GetPointer(int32(9000)), + InitialDelaySeconds: helpers.GetPointer(int32(7)), + TimeoutSeconds: helpers.GetPointer(int32(3)), + PeriodSeconds: helpers.GetPointer(int32(20)), + }, + }, + }, + expectedProbe: &corev1.Probe{ + ProbeHandler: corev1.ProbeHandler{ + HTTPGet: &corev1.HTTPGetAction{ + Path: "/readyz", + Port: intstr.FromInt32(9000), + }, + }, + InitialDelaySeconds: 7, + TimeoutSeconds: 3, + PeriodSeconds: 20, + }, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + t.Parallel() + g := NewWithT(t) + + result := provisioner.buildReadinessProbe(test.nProxyCfg) + g.Expect(result).To(Equal(test.expectedProbe)) + }) + } +} diff --git a/internal/controller/state/dataplane/configuration.go b/internal/controller/state/dataplane/configuration.go index ecdba8d3e8..72d7b194bc 100644 --- a/internal/controller/state/dataplane/configuration.go +++ b/internal/controller/state/dataplane/configuration.go @@ -22,10 +22,11 @@ import ( ) const ( - wildcardHostname = "~^" - alpineSSLRootCAPath = "/etc/ssl/cert.pem" - defaultErrorLogLevel = "info" - DefaultWorkerConnections = int32(1024) + wildcardHostname = "~^" + alpineSSLRootCAPath = "/etc/ssl/cert.pem" + defaultErrorLogLevel = "info" + DefaultWorkerConnections = int32(1024) + DefaultNginxReadinessProbePort = int32(8081) ) // BuildConfiguration builds the Configuration from the Graph. @@ -974,9 +975,10 @@ func buildBaseHTTPConfig( ) BaseHTTPConfig { baseConfig := BaseHTTPConfig{ // HTTP2 should be enabled by default - HTTP2: true, - IPFamily: Dual, - Snippets: buildSnippetsForContext(gatewaySnippetsFilters, ngfAPIv1alpha1.NginxContextHTTP), + HTTP2: true, + IPFamily: Dual, + Snippets: buildSnippetsForContext(gatewaySnippetsFilters, ngfAPIv1alpha1.NginxContextHTTP), + NginxReadinessProbePort: DefaultNginxReadinessProbePort, } // safe to access EffectiveNginxProxy since we only call this function when the Gateway is not nil. @@ -998,28 +1000,39 @@ func buildBaseHTTPConfig( } } - if np.RewriteClientIP != nil { - if np.RewriteClientIP.Mode != nil { - switch *np.RewriteClientIP.Mode { + baseConfig.RewriteClientIPSettings = buildRewriteClientIPConfig(np.RewriteClientIP) + + if np.Kubernetes != nil && np.Kubernetes.ReadinessProbe != nil && np.Kubernetes.ReadinessProbe.Port != nil { + baseConfig.NginxReadinessProbePort = *np.Kubernetes.ReadinessProbe.Port + } + + return baseConfig +} + +func buildRewriteClientIPConfig(rewriteClientIPConfig *ngfAPIv1alpha2.RewriteClientIP) RewriteClientIPSettings { + var rewriteClientIPSettings RewriteClientIPSettings + if rewriteClientIPConfig != nil { + if rewriteClientIPConfig.Mode != nil { + switch *rewriteClientIPConfig.Mode { case ngfAPIv1alpha2.RewriteClientIPModeProxyProtocol: - baseConfig.RewriteClientIPSettings.Mode = RewriteIPModeProxyProtocol + rewriteClientIPSettings.Mode = RewriteIPModeProxyProtocol case ngfAPIv1alpha2.RewriteClientIPModeXForwardedFor: - baseConfig.RewriteClientIPSettings.Mode = RewriteIPModeXForwardedFor + rewriteClientIPSettings.Mode = RewriteIPModeXForwardedFor } } - if len(np.RewriteClientIP.TrustedAddresses) > 0 { - baseConfig.RewriteClientIPSettings.TrustedAddresses = convertAddresses( - np.RewriteClientIP.TrustedAddresses, + if len(rewriteClientIPConfig.TrustedAddresses) > 0 { + rewriteClientIPSettings.TrustedAddresses = convertAddresses( + rewriteClientIPConfig.TrustedAddresses, ) } - if np.RewriteClientIP.SetIPRecursively != nil { - baseConfig.RewriteClientIPSettings.IPRecursive = *np.RewriteClientIP.SetIPRecursively + if rewriteClientIPConfig.SetIPRecursively != nil { + rewriteClientIPSettings.IPRecursive = *rewriteClientIPConfig.SetIPRecursively } } - return baseConfig + return rewriteClientIPSettings } func createSnippetName(nc ngfAPIv1alpha1.NginxContext, nsname types.NamespacedName) string { diff --git a/internal/controller/state/dataplane/configuration_test.go b/internal/controller/state/dataplane/configuration_test.go index 07b7874937..1461319da3 100644 --- a/internal/controller/state/dataplane/configuration_test.go +++ b/internal/controller/state/dataplane/configuration_test.go @@ -31,6 +31,12 @@ import ( "github.com/nginx/nginx-gateway-fabric/internal/framework/kinds" ) +var defaultBaseHTTPConfig = BaseHTTPConfig{ + NginxReadinessProbePort: DefaultNginxReadinessProbePort, + HTTP2: true, + IPFamily: Dual, +} + func getNormalBackendRef() graph.BackendRef { return graph.BackendRef{ SvcNsName: types.NamespacedName{Name: "foo", Namespace: "test"}, @@ -42,7 +48,7 @@ func getNormalBackendRef() graph.BackendRef { func getExpectedConfiguration() Configuration { return Configuration{ - BaseHTTPConfig: BaseHTTPConfig{HTTP2: true, IPFamily: Dual}, + BaseHTTPConfig: defaultBaseHTTPConfig, HTTPServers: []VirtualServer{ { IsDefault: true, @@ -2227,7 +2233,11 @@ func TestBuildConfiguration(t *testing.T) { Ratios: []Ratio{}, SpanAttributes: []SpanAttribute{}, } - conf.BaseHTTPConfig = BaseHTTPConfig{HTTP2: false, IPFamily: Dual} + conf.BaseHTTPConfig = BaseHTTPConfig{ + HTTP2: false, + IPFamily: Dual, + NginxReadinessProbePort: DefaultNginxReadinessProbePort, + } return conf }), msg: "EffectiveNginxProxy with tracing config and http2 disabled", @@ -2350,7 +2360,11 @@ func TestBuildConfiguration(t *testing.T) { expConf: getModifiedExpectedConfiguration(func(conf Configuration) Configuration { conf.SSLServers = []VirtualServer{} conf.SSLKeyPairs = map[SSLKeyPairID]SSLKeyPair{} - conf.BaseHTTPConfig = BaseHTTPConfig{HTTP2: true, IPFamily: IPv4} + conf.BaseHTTPConfig = BaseHTTPConfig{ + HTTP2: true, + IPFamily: IPv4, + NginxReadinessProbePort: DefaultNginxReadinessProbePort, + } return conf }), msg: "GatewayClass has NginxProxy with IPv4 IPFamily and no routes", @@ -2375,7 +2389,11 @@ func TestBuildConfiguration(t *testing.T) { expConf: getModifiedExpectedConfiguration(func(conf Configuration) Configuration { conf.SSLServers = []VirtualServer{} conf.SSLKeyPairs = map[SSLKeyPairID]SSLKeyPair{} - conf.BaseHTTPConfig = BaseHTTPConfig{HTTP2: true, IPFamily: IPv6} + conf.BaseHTTPConfig = BaseHTTPConfig{ + HTTP2: true, + IPFamily: IPv6, + NginxReadinessProbePort: DefaultNginxReadinessProbePort, + } return conf }), msg: "GatewayClass has NginxProxy with IPv6 IPFamily and no routes", @@ -2419,6 +2437,7 @@ func TestBuildConfiguration(t *testing.T) { TrustedAddresses: []string{"1.1.1.1/32"}, Mode: RewriteIPModeProxyProtocol, }, + NginxReadinessProbePort: DefaultNginxReadinessProbePort, } return conf }), @@ -4941,3 +4960,66 @@ func TestBuildWorkerConnections(t *testing.T) { }) } } + +func TestBuildBaseHTTPConfig_ReadinessProbe(t *testing.T) { + t.Parallel() + test := []struct { + msg string + gateway *graph.Gateway + expected BaseHTTPConfig + }{ + { + msg: "nginx proxy config is nil", + gateway: &graph.Gateway{ + EffectiveNginxProxy: &graph.EffectiveNginxProxy{}, + }, + expected: defaultBaseHTTPConfig, + }, + { + msg: "kubernetes spec is nil", + gateway: &graph.Gateway{ + EffectiveNginxProxy: &graph.EffectiveNginxProxy{ + Kubernetes: &ngfAPIv1alpha2.KubernetesSpec{}, + }, + }, + expected: defaultBaseHTTPConfig, + }, + { + msg: "readiness probe spec is nil", + gateway: &graph.Gateway{ + EffectiveNginxProxy: &graph.EffectiveNginxProxy{ + Kubernetes: &ngfAPIv1alpha2.KubernetesSpec{ + ReadinessProbe: nil, + }, + }, + }, + expected: defaultBaseHTTPConfig, + }, + { + msg: "readiness probe is configured", + gateway: &graph.Gateway{ + EffectiveNginxProxy: &graph.EffectiveNginxProxy{ + Kubernetes: &ngfAPIv1alpha2.KubernetesSpec{ + ReadinessProbe: &ngfAPIv1alpha2.ReadinessProbeSpec{ + Port: helpers.GetPointer(int32(7020)), + }, + }, + }, + }, + expected: BaseHTTPConfig{ + NginxReadinessProbePort: int32(7020), + IPFamily: Dual, + HTTP2: true, + }, + }, + } + + for _, tc := range test { + t.Run(tc.msg, func(t *testing.T) { + t.Parallel() + g := NewWithT(t) + + g.Expect(buildBaseHTTPConfig(tc.gateway, nil)).To(Equal(tc.expected)) + }) + } +} diff --git a/internal/controller/state/dataplane/types.go b/internal/controller/state/dataplane/types.go index 0cfe48beb0..646eaa924c 100644 --- a/internal/controller/state/dataplane/types.go +++ b/internal/controller/state/dataplane/types.go @@ -374,6 +374,8 @@ type BaseHTTPConfig struct { RewriteClientIPSettings RewriteClientIPSettings // HTTP2 specifies whether http2 should be enabled for all servers. HTTP2 bool + // NginxReadinessProbePort is the port on which the health check endpoint for NGINX is exposed. + NginxReadinessProbePort int32 } // Snippet is a snippet of configuration. From a48078346c3fd21517fda20e37277c54bae7eb18 Mon Sep 17 00:00:00 2001 From: salonichf5 <146118978+salonichf5@users.noreply.github.com> Date: Wed, 16 Jul 2025 13:28:11 -0600 Subject: [PATCH 2/5] update schema structure based on reviews --- apis/v1alpha2/nginxproxy_types.go | 110 +---- apis/v1alpha2/zz_generated.deepcopy.go | 32 +- .../templates/nginxproxy.yaml | 7 +- charts/nginx-gateway-fabric/values.yaml | 24 +- .../bases/gateway.nginx.org_nginxproxies.yaml | 409 +++++++++++++++--- deploy/azure/deploy.yaml | 5 - deploy/crds.yaml | 409 +++++++++++++++--- deploy/default/deploy.yaml | 5 - deploy/experimental-nginx-plus/deploy.yaml | 5 - deploy/experimental/deploy.yaml | 5 - deploy/nginx-plus/deploy.yaml | 5 - deploy/nodeport/deploy.yaml | 5 - deploy/openshift/deploy.yaml | 5 - .../snippets-filters-nginx-plus/deploy.yaml | 5 - deploy/snippets-filters/deploy.yaml | 5 - .../nginx/config/base_http_config_template.go | 1 + .../nginx/config/base_http_config_test.go | 1 + internal/controller/provisioner/objects.go | 61 +-- .../controller/provisioner/objects_test.go | 194 ++++----- .../state/dataplane/configuration.go | 12 +- .../state/dataplane/configuration_test.go | 29 +- 21 files changed, 869 insertions(+), 465 deletions(-) diff --git a/apis/v1alpha2/nginxproxy_types.go b/apis/v1alpha2/nginxproxy_types.go index d05015ded3..8f79314191 100644 --- a/apis/v1alpha2/nginxproxy_types.go +++ b/apis/v1alpha2/nginxproxy_types.go @@ -386,80 +386,19 @@ type KubernetesSpec struct { // // +optional Service *ServiceSpec `json:"service,omitempty"` - - // ReadinessProbe is the configuration for the NGINX Readiness probe. - // - // +optional - ReadinessProbe *ReadinessProbeSpec `json:"readinessProbe,omitempty"` -} - -// ReadinessProbeSpec defines the configuration for the NGINX readiness probe. -type ReadinessProbeSpec struct { - // Port is the port on which the readiness endpoint is exposed. - // If not specified, the default port is 8081. - // - // +optional - // +kubebuilder:default:=8081 - // +kubebuilder:validation:Minimum=1 - // +kubebuilder:validation:Maximum=65535 - Port *int32 `json:"port,omitempty"` - - // InitialDelaySeconds is the number of seconds after the container has - // started before the readiness probe is initiated. - // If not specified, the default is 3 seconds. - // +optional - // +kubebuilder:default:=3 - // +kubebuilder:validation:Minimum=0 - // +kubebuilder:validation:Maximum=3600 - InitialDelaySeconds *int32 `json:"initialDelaySeconds,omitempty"` - - // PeriodSeconds is the number of seconds between consecutive readiness probes. - // If not specified, the default is 10 seconds. - // +optional - // +kubebuilder:default:=10 - // +kubebuilder:validation:Minimum=1 - // +kubebuilder:validation:Maximum=3600 - PeriodSeconds *int32 `json:"periodSeconds,omitempty"` - - // TimeoutSeconds is the number of seconds after which the readiness probe times out. - // If not specified, the default is 1 second. - // - // +optional - // +kubebuilder:default:=1 - // +kubebuilder:validation:Minimum=1 - // +kubebuilder:validation:Maximum=3600 - TimeoutSeconds *int32 `json:"timeoutSeconds,omitempty"` } // Deployment is the configuration for the NGINX Deployment. type DeploymentSpec struct { - // Number of desired Pods. - // - // +optional - Replicas *int32 `json:"replicas,omitempty"` - - // Pod defines Pod-specific fields. - // - // +optional - Pod PodSpec `json:"pod"` - - // Container defines container fields for the NGINX container. - // - // +optional Container ContainerSpec `json:"container"` + Replicas *int32 `json:"replicas,omitempty"` + Pod PodSpec `json:"pod"` } // DaemonSet is the configuration for the NGINX DaemonSet. type DaemonSetSpec struct { - // Pod defines Pod-specific fields. - // - // +optional - Pod PodSpec `json:"pod"` - - // Container defines container fields for the NGINX container. - // - // +optional Container ContainerSpec `json:"container"` + Pod PodSpec `json:"pod"` } // PodSpec defines Pod-specific fields. @@ -507,37 +446,30 @@ type PodSpec struct { // ContainerSpec defines container fields for the NGINX container. type ContainerSpec struct { - // Debug enables debugging for NGINX by using the nginx-debug binary. - // - // +optional - Debug *bool `json:"debug,omitempty"` - - // Image is the NGINX image to use. - // - // +optional - Image *Image `json:"image,omitempty"` - - // Resources describes the compute resource requirements. - // - // +optional - Resources *corev1.ResourceRequirements `json:"resources,omitempty"` - - // Lifecycle describes actions that the management system should take in response to container lifecycle - // events. For the PostStart and PreStop lifecycle handlers, management of the container blocks - // until the action is complete, unless the container process fails, in which case the handler is aborted. - // - // +optional - Lifecycle *corev1.Lifecycle `json:"lifecycle,omitempty"` + Debug *bool `json:"debug,omitempty"` + Image *Image `json:"image,omitempty"` + Resources *corev1.ResourceRequirements `json:"resources,omitempty"` + Lifecycle *corev1.Lifecycle `json:"lifecycle,omitempty"` + ReadinessProbe *ReadinessProbeSpec `json:"readinessProbe,omitempty"` + HostPorts []HostPort `json:"hostPorts,omitempty"` + VolumeMounts []corev1.VolumeMount `json:"volumeMounts,omitempty"` +} - // HostPorts are the list of ports to expose on the host. +// ReadinessProbeSpec defines the configuration for the NGINX readiness probe. +type ReadinessProbeSpec struct { + // Port is the port on which the readiness endpoint is exposed. + // If not specified, the default port is 8081. // // +optional - HostPorts []HostPort `json:"hostPorts,omitempty"` + // +kubebuilder:default:=8081 + // +kubebuilder:validation:Minimum=1 + // +kubebuilder:validation:Maximum=65535 + Port *int32 `json:"port,omitempty"` - // VolumeMounts describe the mounting of Volumes within a container. + // Probe describes the Kubernetes Probe configuration. // // +optional - VolumeMounts []corev1.VolumeMount `json:"volumeMounts,omitempty"` + *corev1.Probe `json:",inline"` } // Image is the NGINX image to use. diff --git a/apis/v1alpha2/zz_generated.deepcopy.go b/apis/v1alpha2/zz_generated.deepcopy.go index 8307ba17ab..a218a71f0c 100644 --- a/apis/v1alpha2/zz_generated.deepcopy.go +++ b/apis/v1alpha2/zz_generated.deepcopy.go @@ -34,6 +34,11 @@ func (in *ContainerSpec) DeepCopyInto(out *ContainerSpec) { *out = new(v1.Lifecycle) (*in).DeepCopyInto(*out) } + if in.ReadinessProbe != nil { + in, out := &in.ReadinessProbe, &out.ReadinessProbe + *out = new(ReadinessProbeSpec) + (*in).DeepCopyInto(*out) + } if in.HostPorts != nil { in, out := &in.HostPorts, &out.HostPorts *out = make([]HostPort, len(*in)) @@ -61,8 +66,8 @@ func (in *ContainerSpec) DeepCopy() *ContainerSpec { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *DaemonSetSpec) DeepCopyInto(out *DaemonSetSpec) { *out = *in - in.Pod.DeepCopyInto(&out.Pod) in.Container.DeepCopyInto(&out.Container) + in.Pod.DeepCopyInto(&out.Pod) } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DaemonSetSpec. @@ -78,13 +83,13 @@ func (in *DaemonSetSpec) DeepCopy() *DaemonSetSpec { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *DeploymentSpec) DeepCopyInto(out *DeploymentSpec) { *out = *in + in.Container.DeepCopyInto(&out.Container) if in.Replicas != nil { in, out := &in.Replicas, &out.Replicas *out = new(int32) **out = **in } in.Pod.DeepCopyInto(&out.Pod) - in.Container.DeepCopyInto(&out.Container) } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DeploymentSpec. @@ -160,11 +165,6 @@ func (in *KubernetesSpec) DeepCopyInto(out *KubernetesSpec) { *out = new(ServiceSpec) (*in).DeepCopyInto(*out) } - if in.ReadinessProbe != nil { - in, out := &in.ReadinessProbe, &out.ReadinessProbe - *out = new(ReadinessProbeSpec) - (*in).DeepCopyInto(*out) - } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KubernetesSpec. @@ -542,20 +542,10 @@ func (in *ReadinessProbeSpec) DeepCopyInto(out *ReadinessProbeSpec) { *out = new(int32) **out = **in } - if in.InitialDelaySeconds != nil { - in, out := &in.InitialDelaySeconds, &out.InitialDelaySeconds - *out = new(int32) - **out = **in - } - if in.PeriodSeconds != nil { - in, out := &in.PeriodSeconds, &out.PeriodSeconds - *out = new(int32) - **out = **in - } - if in.TimeoutSeconds != nil { - in, out := &in.TimeoutSeconds, &out.TimeoutSeconds - *out = new(int32) - **out = **in + if in.Probe != nil { + in, out := &in.Probe, &out.Probe + *out = new(v1.Probe) + (*in).DeepCopyInto(*out) } } diff --git a/charts/nginx-gateway-fabric/templates/nginxproxy.yaml b/charts/nginx-gateway-fabric/templates/nginxproxy.yaml index 8e2c253204..7f0f2b1af0 100644 --- a/charts/nginx-gateway-fabric/templates/nginxproxy.yaml +++ b/charts/nginx-gateway-fabric/templates/nginxproxy.yaml @@ -48,6 +48,8 @@ spec: {{- if .Values.nginx.debug }} debug: {{ .Values.nginx.debug }} {{- end }} + readinessProbe: + port: {{ .Values.nginx.readinessProbe.port | default 8081 }} {{- end }} {{- if .Values.nginx.service }} service: @@ -58,8 +60,3 @@ spec: {{- end }} {{- end }} {{- end }} - readinessProbe: - port: {{ .Values.nginx.readinessProbe.port | default 8081 }} - initialDelaySeconds: {{ .Values.nginx.readinessProbe.initialDelaySeconds | default 3 }} - periodSeconds: {{ .Values.nginx.readinessProbe.periodSeconds | default 10 }} - timeoutSeconds: {{ .Values.nginx.readinessProbe.timeoutSeconds | default 1 }} diff --git a/charts/nginx-gateway-fabric/values.yaml b/charts/nginx-gateway-fabric/values.yaml index 1a30d7bd03..3ace0a2a33 100644 --- a/charts/nginx-gateway-fabric/values.yaml +++ b/charts/nginx-gateway-fabric/values.yaml @@ -503,29 +503,7 @@ nginx: # -- Port in which the readiness endpoint is exposed. # port: 8081 - # @schema - # type: integer - # minimum: 0 - # maximum: 3600 - # @schema - # -- The number of seconds after the Pod has started before the readiness probes are initiated. - # initialDelaySeconds: 3 - - # @schema - # type: integer - # minimum: 1 - # maximum: 3600 - # @schema - # -- The number of seconds between consecutive readiness probes. - # periodSeconds: 10 - - # @schema - # type: integer - # minimum: 1 - # maximum: 3600 - # @schema - # -- The number of seconds after which the readiness probe times out. - # timeoutSeconds: 1 + # The Kubernetes probe can also be configured by modifying the NginxProxy resource. # -- Enable debugging for NGINX. Uses the nginx-debug binary. The NGINX error log level should be set to debug in the NginxProxy resource. debug: false diff --git a/config/crd/bases/gateway.nginx.org_nginxproxies.yaml b/config/crd/bases/gateway.nginx.org_nginxproxies.yaml index 56aca54dbf..6c8e16c639 100644 --- a/config/crd/bases/gateway.nginx.org_nginxproxies.yaml +++ b/config/crd/bases/gateway.nginx.org_nginxproxies.yaml @@ -74,16 +74,12 @@ spec: description: DaemonSet is the configuration for the NGINX DaemonSet. properties: container: - description: Container defines container fields for the NGINX - container. + description: ContainerSpec defines container fields for the + NGINX container. properties: debug: - description: Debug enables debugging for NGINX by using - the nginx-debug binary. type: boolean hostPorts: - description: HostPorts are the list of ports to expose - on the host. items: description: HostPort exposes an nginx container port on the host. @@ -362,9 +358,173 @@ spec: StopSignal can only be set for Pods with a non-empty .spec.os.name type: string type: object + readinessProbe: + description: ReadinessProbeSpec defines the configuration + for the NGINX readiness probe. + properties: + exec: + description: Exec specifies a command to execute in + the container. + properties: + command: + description: |- + Command is the command line to execute inside the container, the working directory for the + command is root ('/') in the container's filesystem. The command is simply exec'd, it is + not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use + a shell, you need to explicitly call out to that shell. + Exit status of 0 is treated as live/healthy and non-zero is unhealthy. + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + description: |- + Minimum consecutive failures for the probe to be considered failed after having succeeded. + Defaults to 3. Minimum value is 1. + format: int32 + type: integer + grpc: + description: GRPC specifies a GRPC HealthCheckRequest. + properties: + port: + description: Port number of the gRPC service. + Number must be in the range 1 to 65535. + format: int32 + type: integer + service: + default: "" + description: |- + Service is the name of the service to place in the gRPC HealthCheckRequest + (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). + + If this is not specified, the default behavior is defined by gRPC. + type: string + required: + - port + type: object + httpGet: + description: HTTPGet specifies an HTTP GET request + to perform. + properties: + host: + description: |- + Host name to connect to, defaults to the pod IP. You probably want to set + "Host" in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in the request. + HTTP allows repeated headers. + items: + description: HTTPHeader describes a custom header + to be used in HTTP probes + properties: + name: + description: |- + The header field name. + This will be canonicalized upon output, so case-variant names will be understood as the same header. + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + description: Path to access on the HTTP server. + type: string + port: + anyOf: + - type: integer + - type: string + description: |- + Name or number of the port to access on the container. + Number must be in the range 1 to 65535. + Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: |- + Scheme to use for connecting to the host. + Defaults to HTTP. + type: string + required: + - port + type: object + initialDelaySeconds: + description: |- + Number of seconds after the container has started before liveness probes are initiated. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes + format: int32 + type: integer + periodSeconds: + description: |- + How often (in seconds) to perform the probe. + Default to 10 seconds. Minimum value is 1. + format: int32 + type: integer + port: + default: 8081 + description: |- + Port is the port on which the readiness endpoint is exposed. + If not specified, the default port is 8081. + format: int32 + maximum: 65535 + minimum: 1 + type: integer + successThreshold: + description: |- + Minimum consecutive successes for the probe to be considered successful after having failed. + Defaults to 1. Must be 1 for liveness and startup. Minimum value is 1. + format: int32 + type: integer + tcpSocket: + description: TCPSocket specifies a connection to a + TCP port. + properties: + host: + description: 'Optional: Host name to connect to, + defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: |- + Number or name of the port to access on the container. + Number must be in the range 1 to 65535. + Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + description: |- + Optional duration in seconds the pod needs to terminate gracefully upon probe failure. + The grace period is the duration in seconds after the processes running in the pod are sent + a termination signal and the time when the processes are forcibly halted with a kill signal. + Set this value longer than the expected cleanup time for your process. + If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this + value overrides the value provided by the pod spec. + Value must be non-negative integer. The value zero indicates stop immediately via + the kill signal (no opportunity to shut down). + This is a beta field and requires enabling ProbeTerminationGracePeriod feature gate. + Minimum value is 1. spec.terminationGracePeriodSeconds is used if unset. + format: int64 + type: integer + timeoutSeconds: + description: |- + Number of seconds after which the probe times out. + Defaults to 1 second. Minimum value is 1. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes + format: int32 + type: integer + type: object resources: - description: Resources describes the compute resource - requirements. + description: ResourceRequirements describes the compute + resource requirements. properties: claims: description: |- @@ -424,8 +584,6 @@ spec: type: object type: object volumeMounts: - description: VolumeMounts describe the mounting of Volumes - within a container. items: description: VolumeMount describes a mounting of a Volume within a container. @@ -490,7 +648,7 @@ spec: type: array type: object pod: - description: Pod defines Pod-specific fields. + description: PodSpec defines Pod-specific fields. properties: affinity: description: Affinity is the pod's scheduling constraints. @@ -3478,6 +3636,9 @@ spec: type: object type: array type: object + required: + - container + - pod type: object deployment: description: |- @@ -3485,16 +3646,12 @@ spec: This is the default deployment option. properties: container: - description: Container defines container fields for the NGINX - container. + description: ContainerSpec defines container fields for the + NGINX container. properties: debug: - description: Debug enables debugging for NGINX by using - the nginx-debug binary. type: boolean hostPorts: - description: HostPorts are the list of ports to expose - on the host. items: description: HostPort exposes an nginx container port on the host. @@ -3773,9 +3930,173 @@ spec: StopSignal can only be set for Pods with a non-empty .spec.os.name type: string type: object + readinessProbe: + description: ReadinessProbeSpec defines the configuration + for the NGINX readiness probe. + properties: + exec: + description: Exec specifies a command to execute in + the container. + properties: + command: + description: |- + Command is the command line to execute inside the container, the working directory for the + command is root ('/') in the container's filesystem. The command is simply exec'd, it is + not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use + a shell, you need to explicitly call out to that shell. + Exit status of 0 is treated as live/healthy and non-zero is unhealthy. + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + description: |- + Minimum consecutive failures for the probe to be considered failed after having succeeded. + Defaults to 3. Minimum value is 1. + format: int32 + type: integer + grpc: + description: GRPC specifies a GRPC HealthCheckRequest. + properties: + port: + description: Port number of the gRPC service. + Number must be in the range 1 to 65535. + format: int32 + type: integer + service: + default: "" + description: |- + Service is the name of the service to place in the gRPC HealthCheckRequest + (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). + + If this is not specified, the default behavior is defined by gRPC. + type: string + required: + - port + type: object + httpGet: + description: HTTPGet specifies an HTTP GET request + to perform. + properties: + host: + description: |- + Host name to connect to, defaults to the pod IP. You probably want to set + "Host" in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in the request. + HTTP allows repeated headers. + items: + description: HTTPHeader describes a custom header + to be used in HTTP probes + properties: + name: + description: |- + The header field name. + This will be canonicalized upon output, so case-variant names will be understood as the same header. + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + description: Path to access on the HTTP server. + type: string + port: + anyOf: + - type: integer + - type: string + description: |- + Name or number of the port to access on the container. + Number must be in the range 1 to 65535. + Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: |- + Scheme to use for connecting to the host. + Defaults to HTTP. + type: string + required: + - port + type: object + initialDelaySeconds: + description: |- + Number of seconds after the container has started before liveness probes are initiated. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes + format: int32 + type: integer + periodSeconds: + description: |- + How often (in seconds) to perform the probe. + Default to 10 seconds. Minimum value is 1. + format: int32 + type: integer + port: + default: 8081 + description: |- + Port is the port on which the readiness endpoint is exposed. + If not specified, the default port is 8081. + format: int32 + maximum: 65535 + minimum: 1 + type: integer + successThreshold: + description: |- + Minimum consecutive successes for the probe to be considered successful after having failed. + Defaults to 1. Must be 1 for liveness and startup. Minimum value is 1. + format: int32 + type: integer + tcpSocket: + description: TCPSocket specifies a connection to a + TCP port. + properties: + host: + description: 'Optional: Host name to connect to, + defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: |- + Number or name of the port to access on the container. + Number must be in the range 1 to 65535. + Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + description: |- + Optional duration in seconds the pod needs to terminate gracefully upon probe failure. + The grace period is the duration in seconds after the processes running in the pod are sent + a termination signal and the time when the processes are forcibly halted with a kill signal. + Set this value longer than the expected cleanup time for your process. + If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this + value overrides the value provided by the pod spec. + Value must be non-negative integer. The value zero indicates stop immediately via + the kill signal (no opportunity to shut down). + This is a beta field and requires enabling ProbeTerminationGracePeriod feature gate. + Minimum value is 1. spec.terminationGracePeriodSeconds is used if unset. + format: int64 + type: integer + timeoutSeconds: + description: |- + Number of seconds after which the probe times out. + Defaults to 1 second. Minimum value is 1. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes + format: int32 + type: integer + type: object resources: - description: Resources describes the compute resource - requirements. + description: ResourceRequirements describes the compute + resource requirements. properties: claims: description: |- @@ -3835,8 +4156,6 @@ spec: type: object type: object volumeMounts: - description: VolumeMounts describe the mounting of Volumes - within a container. items: description: VolumeMount describes a mounting of a Volume within a container. @@ -3901,7 +4220,7 @@ spec: type: array type: object pod: - description: Pod defines Pod-specific fields. + description: PodSpec defines Pod-specific fields. properties: affinity: description: Affinity is the pod's scheduling constraints. @@ -6890,51 +7209,11 @@ spec: type: array type: object replicas: - description: Number of desired Pods. - format: int32 - type: integer - type: object - readinessProbe: - description: ReadinessProbe is the configuration for the NGINX - Readiness probe. - properties: - initialDelaySeconds: - default: 3 - description: |- - InitialDelaySeconds is the number of seconds after the container has - started before the readiness probe is initiated. - If not specified, the default is 3 seconds. - format: int32 - maximum: 3600 - minimum: 0 - type: integer - periodSeconds: - default: 10 - description: |- - PeriodSeconds is the number of seconds between consecutive readiness probes. - If not specified, the default is 10 seconds. - format: int32 - maximum: 3600 - minimum: 1 - type: integer - port: - default: 8081 - description: |- - Port is the port on which the readiness endpoint is exposed. - If not specified, the default port is 8081. - format: int32 - maximum: 65535 - minimum: 1 - type: integer - timeoutSeconds: - default: 1 - description: |- - TimeoutSeconds is the number of seconds after which the readiness probe times out. - If not specified, the default is 1 second. format: int32 - maximum: 3600 - minimum: 1 type: integer + required: + - container + - pod type: object service: description: Service is the configuration for the NGINX Service. diff --git a/deploy/azure/deploy.yaml b/deploy/azure/deploy.yaml index e4ec417633..0a7e457685 100644 --- a/deploy/azure/deploy.yaml +++ b/deploy/azure/deploy.yaml @@ -421,11 +421,6 @@ spec: nodeSelector: kubernetes.io/os: linux replicas: 1 - readinessProbe: - initialDelaySeconds: 3 - periodSeconds: 10 - port: 8081 - timeoutSeconds: 1 service: externalTrafficPolicy: Local type: LoadBalancer diff --git a/deploy/crds.yaml b/deploy/crds.yaml index 78d8c8306b..60a9309de5 100644 --- a/deploy/crds.yaml +++ b/deploy/crds.yaml @@ -659,16 +659,12 @@ spec: description: DaemonSet is the configuration for the NGINX DaemonSet. properties: container: - description: Container defines container fields for the NGINX - container. + description: ContainerSpec defines container fields for the + NGINX container. properties: debug: - description: Debug enables debugging for NGINX by using - the nginx-debug binary. type: boolean hostPorts: - description: HostPorts are the list of ports to expose - on the host. items: description: HostPort exposes an nginx container port on the host. @@ -947,9 +943,173 @@ spec: StopSignal can only be set for Pods with a non-empty .spec.os.name type: string type: object + readinessProbe: + description: ReadinessProbeSpec defines the configuration + for the NGINX readiness probe. + properties: + exec: + description: Exec specifies a command to execute in + the container. + properties: + command: + description: |- + Command is the command line to execute inside the container, the working directory for the + command is root ('/') in the container's filesystem. The command is simply exec'd, it is + not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use + a shell, you need to explicitly call out to that shell. + Exit status of 0 is treated as live/healthy and non-zero is unhealthy. + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + description: |- + Minimum consecutive failures for the probe to be considered failed after having succeeded. + Defaults to 3. Minimum value is 1. + format: int32 + type: integer + grpc: + description: GRPC specifies a GRPC HealthCheckRequest. + properties: + port: + description: Port number of the gRPC service. + Number must be in the range 1 to 65535. + format: int32 + type: integer + service: + default: "" + description: |- + Service is the name of the service to place in the gRPC HealthCheckRequest + (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). + + If this is not specified, the default behavior is defined by gRPC. + type: string + required: + - port + type: object + httpGet: + description: HTTPGet specifies an HTTP GET request + to perform. + properties: + host: + description: |- + Host name to connect to, defaults to the pod IP. You probably want to set + "Host" in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in the request. + HTTP allows repeated headers. + items: + description: HTTPHeader describes a custom header + to be used in HTTP probes + properties: + name: + description: |- + The header field name. + This will be canonicalized upon output, so case-variant names will be understood as the same header. + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + description: Path to access on the HTTP server. + type: string + port: + anyOf: + - type: integer + - type: string + description: |- + Name or number of the port to access on the container. + Number must be in the range 1 to 65535. + Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: |- + Scheme to use for connecting to the host. + Defaults to HTTP. + type: string + required: + - port + type: object + initialDelaySeconds: + description: |- + Number of seconds after the container has started before liveness probes are initiated. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes + format: int32 + type: integer + periodSeconds: + description: |- + How often (in seconds) to perform the probe. + Default to 10 seconds. Minimum value is 1. + format: int32 + type: integer + port: + default: 8081 + description: |- + Port is the port on which the readiness endpoint is exposed. + If not specified, the default port is 8081. + format: int32 + maximum: 65535 + minimum: 1 + type: integer + successThreshold: + description: |- + Minimum consecutive successes for the probe to be considered successful after having failed. + Defaults to 1. Must be 1 for liveness and startup. Minimum value is 1. + format: int32 + type: integer + tcpSocket: + description: TCPSocket specifies a connection to a + TCP port. + properties: + host: + description: 'Optional: Host name to connect to, + defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: |- + Number or name of the port to access on the container. + Number must be in the range 1 to 65535. + Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + description: |- + Optional duration in seconds the pod needs to terminate gracefully upon probe failure. + The grace period is the duration in seconds after the processes running in the pod are sent + a termination signal and the time when the processes are forcibly halted with a kill signal. + Set this value longer than the expected cleanup time for your process. + If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this + value overrides the value provided by the pod spec. + Value must be non-negative integer. The value zero indicates stop immediately via + the kill signal (no opportunity to shut down). + This is a beta field and requires enabling ProbeTerminationGracePeriod feature gate. + Minimum value is 1. spec.terminationGracePeriodSeconds is used if unset. + format: int64 + type: integer + timeoutSeconds: + description: |- + Number of seconds after which the probe times out. + Defaults to 1 second. Minimum value is 1. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes + format: int32 + type: integer + type: object resources: - description: Resources describes the compute resource - requirements. + description: ResourceRequirements describes the compute + resource requirements. properties: claims: description: |- @@ -1009,8 +1169,6 @@ spec: type: object type: object volumeMounts: - description: VolumeMounts describe the mounting of Volumes - within a container. items: description: VolumeMount describes a mounting of a Volume within a container. @@ -1075,7 +1233,7 @@ spec: type: array type: object pod: - description: Pod defines Pod-specific fields. + description: PodSpec defines Pod-specific fields. properties: affinity: description: Affinity is the pod's scheduling constraints. @@ -4063,6 +4221,9 @@ spec: type: object type: array type: object + required: + - container + - pod type: object deployment: description: |- @@ -4070,16 +4231,12 @@ spec: This is the default deployment option. properties: container: - description: Container defines container fields for the NGINX - container. + description: ContainerSpec defines container fields for the + NGINX container. properties: debug: - description: Debug enables debugging for NGINX by using - the nginx-debug binary. type: boolean hostPorts: - description: HostPorts are the list of ports to expose - on the host. items: description: HostPort exposes an nginx container port on the host. @@ -4358,9 +4515,173 @@ spec: StopSignal can only be set for Pods with a non-empty .spec.os.name type: string type: object + readinessProbe: + description: ReadinessProbeSpec defines the configuration + for the NGINX readiness probe. + properties: + exec: + description: Exec specifies a command to execute in + the container. + properties: + command: + description: |- + Command is the command line to execute inside the container, the working directory for the + command is root ('/') in the container's filesystem. The command is simply exec'd, it is + not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use + a shell, you need to explicitly call out to that shell. + Exit status of 0 is treated as live/healthy and non-zero is unhealthy. + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + description: |- + Minimum consecutive failures for the probe to be considered failed after having succeeded. + Defaults to 3. Minimum value is 1. + format: int32 + type: integer + grpc: + description: GRPC specifies a GRPC HealthCheckRequest. + properties: + port: + description: Port number of the gRPC service. + Number must be in the range 1 to 65535. + format: int32 + type: integer + service: + default: "" + description: |- + Service is the name of the service to place in the gRPC HealthCheckRequest + (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). + + If this is not specified, the default behavior is defined by gRPC. + type: string + required: + - port + type: object + httpGet: + description: HTTPGet specifies an HTTP GET request + to perform. + properties: + host: + description: |- + Host name to connect to, defaults to the pod IP. You probably want to set + "Host" in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in the request. + HTTP allows repeated headers. + items: + description: HTTPHeader describes a custom header + to be used in HTTP probes + properties: + name: + description: |- + The header field name. + This will be canonicalized upon output, so case-variant names will be understood as the same header. + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + description: Path to access on the HTTP server. + type: string + port: + anyOf: + - type: integer + - type: string + description: |- + Name or number of the port to access on the container. + Number must be in the range 1 to 65535. + Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: |- + Scheme to use for connecting to the host. + Defaults to HTTP. + type: string + required: + - port + type: object + initialDelaySeconds: + description: |- + Number of seconds after the container has started before liveness probes are initiated. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes + format: int32 + type: integer + periodSeconds: + description: |- + How often (in seconds) to perform the probe. + Default to 10 seconds. Minimum value is 1. + format: int32 + type: integer + port: + default: 8081 + description: |- + Port is the port on which the readiness endpoint is exposed. + If not specified, the default port is 8081. + format: int32 + maximum: 65535 + minimum: 1 + type: integer + successThreshold: + description: |- + Minimum consecutive successes for the probe to be considered successful after having failed. + Defaults to 1. Must be 1 for liveness and startup. Minimum value is 1. + format: int32 + type: integer + tcpSocket: + description: TCPSocket specifies a connection to a + TCP port. + properties: + host: + description: 'Optional: Host name to connect to, + defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: |- + Number or name of the port to access on the container. + Number must be in the range 1 to 65535. + Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + description: |- + Optional duration in seconds the pod needs to terminate gracefully upon probe failure. + The grace period is the duration in seconds after the processes running in the pod are sent + a termination signal and the time when the processes are forcibly halted with a kill signal. + Set this value longer than the expected cleanup time for your process. + If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this + value overrides the value provided by the pod spec. + Value must be non-negative integer. The value zero indicates stop immediately via + the kill signal (no opportunity to shut down). + This is a beta field and requires enabling ProbeTerminationGracePeriod feature gate. + Minimum value is 1. spec.terminationGracePeriodSeconds is used if unset. + format: int64 + type: integer + timeoutSeconds: + description: |- + Number of seconds after which the probe times out. + Defaults to 1 second. Minimum value is 1. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes + format: int32 + type: integer + type: object resources: - description: Resources describes the compute resource - requirements. + description: ResourceRequirements describes the compute + resource requirements. properties: claims: description: |- @@ -4420,8 +4741,6 @@ spec: type: object type: object volumeMounts: - description: VolumeMounts describe the mounting of Volumes - within a container. items: description: VolumeMount describes a mounting of a Volume within a container. @@ -4486,7 +4805,7 @@ spec: type: array type: object pod: - description: Pod defines Pod-specific fields. + description: PodSpec defines Pod-specific fields. properties: affinity: description: Affinity is the pod's scheduling constraints. @@ -7475,51 +7794,11 @@ spec: type: array type: object replicas: - description: Number of desired Pods. - format: int32 - type: integer - type: object - readinessProbe: - description: ReadinessProbe is the configuration for the NGINX - Readiness probe. - properties: - initialDelaySeconds: - default: 3 - description: |- - InitialDelaySeconds is the number of seconds after the container has - started before the readiness probe is initiated. - If not specified, the default is 3 seconds. - format: int32 - maximum: 3600 - minimum: 0 - type: integer - periodSeconds: - default: 10 - description: |- - PeriodSeconds is the number of seconds between consecutive readiness probes. - If not specified, the default is 10 seconds. - format: int32 - maximum: 3600 - minimum: 1 - type: integer - port: - default: 8081 - description: |- - Port is the port on which the readiness endpoint is exposed. - If not specified, the default port is 8081. - format: int32 - maximum: 65535 - minimum: 1 - type: integer - timeoutSeconds: - default: 1 - description: |- - TimeoutSeconds is the number of seconds after which the readiness probe times out. - If not specified, the default is 1 second. format: int32 - maximum: 3600 - minimum: 1 type: integer + required: + - container + - pod type: object service: description: Service is the configuration for the NGINX Service. diff --git a/deploy/default/deploy.yaml b/deploy/default/deploy.yaml index 31b584fdca..4324fc92f7 100644 --- a/deploy/default/deploy.yaml +++ b/deploy/default/deploy.yaml @@ -416,11 +416,6 @@ spec: repository: ghcr.io/nginx/nginx-gateway-fabric/nginx tag: edge replicas: 1 - readinessProbe: - initialDelaySeconds: 3 - periodSeconds: 10 - port: 8081 - timeoutSeconds: 1 service: externalTrafficPolicy: Local type: LoadBalancer diff --git a/deploy/experimental-nginx-plus/deploy.yaml b/deploy/experimental-nginx-plus/deploy.yaml index 1a1a900be4..f0ac53ba0d 100644 --- a/deploy/experimental-nginx-plus/deploy.yaml +++ b/deploy/experimental-nginx-plus/deploy.yaml @@ -424,11 +424,6 @@ spec: repository: private-registry.nginx.com/nginx-gateway-fabric/nginx-plus tag: edge replicas: 1 - readinessProbe: - initialDelaySeconds: 3 - periodSeconds: 10 - port: 8081 - timeoutSeconds: 1 service: externalTrafficPolicy: Local type: LoadBalancer diff --git a/deploy/experimental/deploy.yaml b/deploy/experimental/deploy.yaml index 0cdd91240a..ad3cf361a6 100644 --- a/deploy/experimental/deploy.yaml +++ b/deploy/experimental/deploy.yaml @@ -421,11 +421,6 @@ spec: repository: ghcr.io/nginx/nginx-gateway-fabric/nginx tag: edge replicas: 1 - readinessProbe: - initialDelaySeconds: 3 - periodSeconds: 10 - port: 8081 - timeoutSeconds: 1 service: externalTrafficPolicy: Local type: LoadBalancer diff --git a/deploy/nginx-plus/deploy.yaml b/deploy/nginx-plus/deploy.yaml index bfbc11ba52..a966b9e325 100644 --- a/deploy/nginx-plus/deploy.yaml +++ b/deploy/nginx-plus/deploy.yaml @@ -419,11 +419,6 @@ spec: repository: private-registry.nginx.com/nginx-gateway-fabric/nginx-plus tag: edge replicas: 1 - readinessProbe: - initialDelaySeconds: 3 - periodSeconds: 10 - port: 8081 - timeoutSeconds: 1 service: externalTrafficPolicy: Local type: LoadBalancer diff --git a/deploy/nodeport/deploy.yaml b/deploy/nodeport/deploy.yaml index f357d56c50..d151c82319 100644 --- a/deploy/nodeport/deploy.yaml +++ b/deploy/nodeport/deploy.yaml @@ -416,11 +416,6 @@ spec: repository: ghcr.io/nginx/nginx-gateway-fabric/nginx tag: edge replicas: 1 - readinessProbe: - initialDelaySeconds: 3 - periodSeconds: 10 - port: 8081 - timeoutSeconds: 1 service: externalTrafficPolicy: Local type: NodePort diff --git a/deploy/openshift/deploy.yaml b/deploy/openshift/deploy.yaml index 09786bcba9..e6ecf6b3e0 100644 --- a/deploy/openshift/deploy.yaml +++ b/deploy/openshift/deploy.yaml @@ -438,11 +438,6 @@ spec: repository: ghcr.io/nginx/nginx-gateway-fabric/nginx tag: edge replicas: 1 - readinessProbe: - initialDelaySeconds: 3 - periodSeconds: 10 - port: 8081 - timeoutSeconds: 1 service: externalTrafficPolicy: Local type: LoadBalancer diff --git a/deploy/snippets-filters-nginx-plus/deploy.yaml b/deploy/snippets-filters-nginx-plus/deploy.yaml index 2ff50ce6b9..7461912539 100644 --- a/deploy/snippets-filters-nginx-plus/deploy.yaml +++ b/deploy/snippets-filters-nginx-plus/deploy.yaml @@ -422,11 +422,6 @@ spec: repository: private-registry.nginx.com/nginx-gateway-fabric/nginx-plus tag: edge replicas: 1 - readinessProbe: - initialDelaySeconds: 3 - periodSeconds: 10 - port: 8081 - timeoutSeconds: 1 service: externalTrafficPolicy: Local type: LoadBalancer diff --git a/deploy/snippets-filters/deploy.yaml b/deploy/snippets-filters/deploy.yaml index 35148ead13..d23d775600 100644 --- a/deploy/snippets-filters/deploy.yaml +++ b/deploy/snippets-filters/deploy.yaml @@ -419,11 +419,6 @@ spec: repository: ghcr.io/nginx/nginx-gateway-fabric/nginx tag: edge replicas: 1 - readinessProbe: - initialDelaySeconds: 3 - periodSeconds: 10 - port: 8081 - timeoutSeconds: 1 service: externalTrafficPolicy: Local type: LoadBalancer diff --git a/internal/controller/nginx/config/base_http_config_template.go b/internal/controller/nginx/config/base_http_config_template.go index a46f62796d..169b876a30 100644 --- a/internal/controller/nginx/config/base_http_config_template.go +++ b/internal/controller/nginx/config/base_http_config_template.go @@ -29,6 +29,7 @@ server { listen {{ .NginxReadinessProbePort }}; location = /readyz { + access_log off; return 200; } } diff --git a/internal/controller/nginx/config/base_http_config_test.go b/internal/controller/nginx/config/base_http_config_test.go index 32115e44b6..4932fdad89 100644 --- a/internal/controller/nginx/config/base_http_config_test.go +++ b/internal/controller/nginx/config/base_http_config_test.go @@ -158,6 +158,7 @@ func TestExecuteBaseHttp_NginxReadinessProbePort(t *testing.T) { // check that the health check server block is present g.Expect(httpConfig).To(ContainSubstring("server {")) + g.Expect(httpConfig).To(ContainSubstring("access_log off;")) g.Expect(httpConfig).To(ContainSubstring("location = /readyz {")) g.Expect(httpConfig).To(ContainSubstring("return 200;")) }) diff --git a/internal/controller/provisioner/objects.go b/internal/controller/provisioner/objects.go index 4bc7374887..69469fde2b 100644 --- a/internal/controller/provisioner/objects.go +++ b/internal/controller/provisioner/objects.go @@ -37,10 +37,6 @@ const ( defaultNginxImagePath = "ghcr.io/nginx/nginx-gateway-fabric/nginx" defaultNginxPlusImagePath = "private-registry.nginx.com/nginx-gateway-fabric/nginx-plus" defaultImagePullPolicy = corev1.PullIfNotPresent - - defaultInitialDelaySeconds = int32(3) - defaultPeriodSeconds = int32(10) - defaultTimeoutSeconds = int32(1) ) var emptyDirVolumeSource = corev1.VolumeSource{EmptyDir: &corev1.EmptyDirVolumeSource{}} @@ -1045,36 +1041,41 @@ func (p *NginxProvisioner) buildNginxResourceObjectsForDeletion(deploymentNSName // buildReadinessProbe creates a readiness probe configuration for the NGINX container. func (p *NginxProvisioner) buildReadinessProbe(nProxyCfg *graph.EffectiveNginxProxy) *corev1.Probe { - port := dataplane.DefaultNginxReadinessProbePort - initialDelaySeconds := defaultInitialDelaySeconds - timeoutSeconds := defaultTimeoutSeconds - periodSeconds := defaultPeriodSeconds - - if nProxyCfg != nil && nProxyCfg.Kubernetes != nil && nProxyCfg.Kubernetes.ReadinessProbe != nil { - readinessProbeSpec := nProxyCfg.Kubernetes.ReadinessProbe - if readinessProbeSpec.Port != nil { - port = *readinessProbeSpec.Port - } - if readinessProbeSpec.InitialDelaySeconds != nil { - initialDelaySeconds = *readinessProbeSpec.InitialDelaySeconds - } - if readinessProbeSpec.PeriodSeconds != nil { - periodSeconds = *readinessProbeSpec.PeriodSeconds - } - if readinessProbeSpec.TimeoutSeconds != nil { - timeoutSeconds = *readinessProbeSpec.TimeoutSeconds - } - } - - return &corev1.Probe{ + probe := &corev1.Probe{ ProbeHandler: corev1.ProbeHandler{ HTTPGet: &corev1.HTTPGetAction{ Path: "/readyz", - Port: intstr.FromInt32(port), + Port: intstr.FromInt32(dataplane.DefaultNginxReadinessProbePort), }, }, - InitialDelaySeconds: initialDelaySeconds, - TimeoutSeconds: timeoutSeconds, - PeriodSeconds: periodSeconds, } + + var containerSpec *ngfAPIv1alpha2.ContainerSpec + if nProxyCfg != nil && nProxyCfg.Kubernetes != nil { + if nProxyCfg.Kubernetes.Deployment != nil { + containerSpec = &nProxyCfg.Kubernetes.Deployment.Container + } else if nProxyCfg.Kubernetes.DaemonSet != nil { + containerSpec = &nProxyCfg.Kubernetes.DaemonSet.Container + } + } + + if containerSpec == nil || containerSpec.ReadinessProbe == nil { + return probe + } + + if containerSpec.ReadinessProbe.Port != nil { + probe.HTTPGet.Port = intstr.FromInt32(*containerSpec.ReadinessProbe.Port) + } + + probeSpec := containerSpec.ReadinessProbe.Probe + if probeSpec != nil { + probe.InitialDelaySeconds = probeSpec.InitialDelaySeconds + probe.TimeoutSeconds = probeSpec.TimeoutSeconds + probe.PeriodSeconds = probeSpec.PeriodSeconds + probe.SuccessThreshold = probeSpec.SuccessThreshold + probe.FailureThreshold = probeSpec.FailureThreshold + probe.TerminationGracePeriodSeconds = probeSpec.TerminationGracePeriodSeconds + } + + return probe } diff --git a/internal/controller/provisioner/objects_test.go b/internal/controller/provisioner/objects_test.go index 5939052137..aff50123ee 100644 --- a/internal/controller/provisioner/objects_test.go +++ b/internal/controller/provisioner/objects_test.go @@ -18,6 +18,7 @@ import ( ngfAPIv1alpha2 "github.com/nginx/nginx-gateway-fabric/apis/v1alpha2" "github.com/nginx/nginx-gateway-fabric/internal/controller/config" + "github.com/nginx/nginx-gateway-fabric/internal/controller/state/dataplane" "github.com/nginx/nginx-gateway-fabric/internal/controller/state/graph" "github.com/nginx/nginx-gateway-fabric/internal/framework/controller" "github.com/nginx/nginx-gateway-fabric/internal/framework/helpers" @@ -298,15 +299,20 @@ func TestBuildNginxResourceObjects_NginxProxyConfig(t *testing.T) { corev1.ResourceCPU: resource.Quantity{Format: "100m"}, }, }, + ReadinessProbe: &ngfAPIv1alpha2.ReadinessProbeSpec{ + Port: helpers.GetPointer[int32](9091), + Probe: &corev1.Probe{ + InitialDelaySeconds: 5, + PeriodSeconds: 10, + TimeoutSeconds: 2, + SuccessThreshold: 1, + FailureThreshold: 3, + TerminationGracePeriodSeconds: helpers.GetPointer[int64](25), + }, + }, HostPorts: []ngfAPIv1alpha2.HostPort{{ContainerPort: int32(8443), Port: int32(8443)}}, }, }, - ReadinessProbe: &ngfAPIv1alpha2.ReadinessProbeSpec{ - Port: helpers.GetPointer[int32](9091), - InitialDelaySeconds: helpers.GetPointer[int32](5), - PeriodSeconds: helpers.GetPointer[int32](10), - TimeoutSeconds: helpers.GetPointer[int32](2), - }, }, } @@ -369,6 +375,9 @@ func TestBuildNginxResourceObjects_NginxProxyConfig(t *testing.T) { g.Expect(container.ReadinessProbe.InitialDelaySeconds).To(Equal(int32(5))) g.Expect(container.ReadinessProbe.PeriodSeconds).To(Equal(int32(10))) g.Expect(container.ReadinessProbe.TimeoutSeconds).To(Equal(int32(2))) + g.Expect(container.ReadinessProbe.SuccessThreshold).To(Equal(int32(1))) + g.Expect(container.ReadinessProbe.FailureThreshold).To(Equal(int32(3))) + g.Expect(container.ReadinessProbe.TerminationGracePeriodSeconds).To(Equal(helpers.GetPointer[int64](25))) } func TestBuildNginxResourceObjects_Plus(t *testing.T) { @@ -1074,185 +1083,136 @@ func TestBuildNginxConfigMaps_WorkerConnections(t *testing.T) { func TestBuildReadinessProbe(t *testing.T) { t.Parallel() - - provisioner := &NginxProvisioner{} + g := NewWithT(t) defaultProbe := &corev1.Probe{ ProbeHandler: corev1.ProbeHandler{ HTTPGet: &corev1.HTTPGetAction{ Path: "/readyz", - Port: intstr.FromInt32(8081), + Port: intstr.FromInt32(dataplane.DefaultNginxReadinessProbePort), }, }, - InitialDelaySeconds: 3, - TimeoutSeconds: 1, - PeriodSeconds: 10, } + provisioner := &NginxProvisioner{} + tests := []struct { - nProxyCfg *graph.EffectiveNginxProxy - expectedProbe *corev1.Probe - name string + nProxyCfg *graph.EffectiveNginxProxy + expected *corev1.Probe + name string }{ { - name: "nil nginx proxy config returns default probe", - nProxyCfg: nil, - expectedProbe: defaultProbe, - }, - { - name: "empty nginx proxy config returns default probe", - nProxyCfg: &graph.EffectiveNginxProxy{}, - expectedProbe: defaultProbe, + name: "nginx proxy config is nil, default probe is returned", + nProxyCfg: nil, + expected: defaultProbe, }, { - name: "nginx proxy config with nil kubernetes returns default probe", - nProxyCfg: &graph.EffectiveNginxProxy{ - Kubernetes: nil, - }, - expectedProbe: defaultProbe, - }, - { - name: "nginx proxy config with empty kubernetes returns default probe", - nProxyCfg: &graph.EffectiveNginxProxy{ - Kubernetes: &ngfAPIv1alpha2.KubernetesSpec{}, - }, - expectedProbe: defaultProbe, - }, - { - name: "nginx proxy config with nil readiness probe returns default probe", + name: "deployment is nil, default probe is returned", nProxyCfg: &graph.EffectiveNginxProxy{ Kubernetes: &ngfAPIv1alpha2.KubernetesSpec{ - ReadinessProbe: nil, + Deployment: nil, }, }, - expectedProbe: defaultProbe, + expected: defaultProbe, }, { - name: "nginx proxy config with empty readiness probe returns default probe", + name: "daemonSet is nil, default probe is returned", nProxyCfg: &graph.EffectiveNginxProxy{ Kubernetes: &ngfAPIv1alpha2.KubernetesSpec{ - ReadinessProbe: &ngfAPIv1alpha2.ReadinessProbeSpec{}, + DaemonSet: nil, }, }, - expectedProbe: defaultProbe, + expected: defaultProbe, }, { - name: "nginx proxy config with custom port", + name: "container is nil, default probe is returned", nProxyCfg: &graph.EffectiveNginxProxy{ Kubernetes: &ngfAPIv1alpha2.KubernetesSpec{ - ReadinessProbe: &ngfAPIv1alpha2.ReadinessProbeSpec{ - Port: helpers.GetPointer(int32(9090)), + Deployment: &ngfAPIv1alpha2.DeploymentSpec{ + Container: ngfAPIv1alpha2.ContainerSpec{}, }, }, }, - expectedProbe: &corev1.Probe{ - ProbeHandler: corev1.ProbeHandler{ - HTTPGet: &corev1.HTTPGetAction{ - Path: "/readyz", - Port: intstr.FromInt32(9090), - }, - }, - InitialDelaySeconds: 3, - TimeoutSeconds: 1, - PeriodSeconds: 10, - }, + expected: defaultProbe, }, { - name: "nginx proxy config with custom initialDelaySeconds", + name: "readinessProbe is nil, default probe is returned", nProxyCfg: &graph.EffectiveNginxProxy{ Kubernetes: &ngfAPIv1alpha2.KubernetesSpec{ - ReadinessProbe: &ngfAPIv1alpha2.ReadinessProbeSpec{ - InitialDelaySeconds: helpers.GetPointer(int32(5)), - }, - }, - }, - expectedProbe: &corev1.Probe{ - ProbeHandler: corev1.ProbeHandler{ - HTTPGet: &corev1.HTTPGetAction{ - Path: "/readyz", - Port: intstr.FromInt32(8081), - }, - }, - InitialDelaySeconds: 5, - TimeoutSeconds: 1, - PeriodSeconds: 10, - }, - }, - { - name: "nginx proxy config with custom timeoutSeconds", - nProxyCfg: &graph.EffectiveNginxProxy{ - Kubernetes: &ngfAPIv1alpha2.KubernetesSpec{ - ReadinessProbe: &ngfAPIv1alpha2.ReadinessProbeSpec{ - TimeoutSeconds: helpers.GetPointer(int32(2)), - }, - }, - }, - expectedProbe: &corev1.Probe{ - ProbeHandler: corev1.ProbeHandler{ - HTTPGet: &corev1.HTTPGetAction{ - Path: "/readyz", - Port: intstr.FromInt32(8081), + Deployment: &ngfAPIv1alpha2.DeploymentSpec{ + Container: ngfAPIv1alpha2.ContainerSpec{ + ReadinessProbe: nil, + }, }, }, - InitialDelaySeconds: 3, - TimeoutSeconds: 2, - PeriodSeconds: 10, }, + expected: defaultProbe, }, { - name: "nginx proxy config with custom periodSeconds", + name: "port is set in readinessProbe, custom probe is returned", nProxyCfg: &graph.EffectiveNginxProxy{ Kubernetes: &ngfAPIv1alpha2.KubernetesSpec{ - ReadinessProbe: &ngfAPIv1alpha2.ReadinessProbeSpec{ - PeriodSeconds: helpers.GetPointer(int32(15)), + Deployment: &ngfAPIv1alpha2.DeploymentSpec{ + Container: ngfAPIv1alpha2.ContainerSpec{ + ReadinessProbe: &ngfAPIv1alpha2.ReadinessProbeSpec{ + Port: helpers.GetPointer[int32](9091), + }, + }, }, }, }, - expectedProbe: &corev1.Probe{ + expected: &corev1.Probe{ ProbeHandler: corev1.ProbeHandler{ HTTPGet: &corev1.HTTPGetAction{ Path: "/readyz", - Port: intstr.FromInt32(8081), + Port: intstr.FromInt32(9091), }, }, - InitialDelaySeconds: 3, - TimeoutSeconds: 1, - PeriodSeconds: 15, }, }, { - name: "nginx proxy config with all custom values", + name: "port and probe fields are set in readinessProbe, custom probe is returned", nProxyCfg: &graph.EffectiveNginxProxy{ Kubernetes: &ngfAPIv1alpha2.KubernetesSpec{ - ReadinessProbe: &ngfAPIv1alpha2.ReadinessProbeSpec{ - Port: helpers.GetPointer(int32(9000)), - InitialDelaySeconds: helpers.GetPointer(int32(7)), - TimeoutSeconds: helpers.GetPointer(int32(3)), - PeriodSeconds: helpers.GetPointer(int32(20)), + Deployment: &ngfAPIv1alpha2.DeploymentSpec{ + Container: ngfAPIv1alpha2.ContainerSpec{ + ReadinessProbe: &ngfAPIv1alpha2.ReadinessProbeSpec{ + Port: helpers.GetPointer[int32](7033), + Probe: &corev1.Probe{ + InitialDelaySeconds: 5, + PeriodSeconds: 10, + TimeoutSeconds: 2, + SuccessThreshold: 5, + FailureThreshold: 7, + TerminationGracePeriodSeconds: helpers.GetPointer[int64](25), + }, + }, + }, }, }, }, - expectedProbe: &corev1.Probe{ + expected: &corev1.Probe{ ProbeHandler: corev1.ProbeHandler{ HTTPGet: &corev1.HTTPGetAction{ Path: "/readyz", - Port: intstr.FromInt32(9000), + Port: intstr.FromInt32(7033), }, }, - InitialDelaySeconds: 7, - TimeoutSeconds: 3, - PeriodSeconds: 20, + InitialDelaySeconds: 5, + PeriodSeconds: 10, + TimeoutSeconds: 2, + SuccessThreshold: 5, + FailureThreshold: 7, + TerminationGracePeriodSeconds: helpers.GetPointer[int64](25), }, }, } - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { t.Parallel() - g := NewWithT(t) - - result := provisioner.buildReadinessProbe(test.nProxyCfg) - g.Expect(result).To(Equal(test.expectedProbe)) + probe := provisioner.buildReadinessProbe(tt.nProxyCfg) + g.Expect(probe).To(Equal(tt.expected)) }) } } diff --git a/internal/controller/state/dataplane/configuration.go b/internal/controller/state/dataplane/configuration.go index 72d7b194bc..24ff197e55 100644 --- a/internal/controller/state/dataplane/configuration.go +++ b/internal/controller/state/dataplane/configuration.go @@ -1002,8 +1002,16 @@ func buildBaseHTTPConfig( baseConfig.RewriteClientIPSettings = buildRewriteClientIPConfig(np.RewriteClientIP) - if np.Kubernetes != nil && np.Kubernetes.ReadinessProbe != nil && np.Kubernetes.ReadinessProbe.Port != nil { - baseConfig.NginxReadinessProbePort = *np.Kubernetes.ReadinessProbe.Port + if np.Kubernetes != nil { + var containerSpec *ngfAPIv1alpha2.ContainerSpec + if np.Kubernetes.Deployment != nil { + containerSpec = &np.Kubernetes.Deployment.Container + } else if np.Kubernetes.DaemonSet != nil { + containerSpec = &np.Kubernetes.DaemonSet.Container + } + if containerSpec != nil && containerSpec.ReadinessProbe != nil && containerSpec.ReadinessProbe.Port != nil { + baseConfig.NginxReadinessProbePort = *containerSpec.ReadinessProbe.Port + } } return baseConfig diff --git a/internal/controller/state/dataplane/configuration_test.go b/internal/controller/state/dataplane/configuration_test.go index 1461319da3..9d3a0ff5dd 100644 --- a/internal/controller/state/dataplane/configuration_test.go +++ b/internal/controller/state/dataplane/configuration_test.go @@ -4989,7 +4989,26 @@ func TestBuildBaseHTTPConfig_ReadinessProbe(t *testing.T) { gateway: &graph.Gateway{ EffectiveNginxProxy: &graph.EffectiveNginxProxy{ Kubernetes: &ngfAPIv1alpha2.KubernetesSpec{ - ReadinessProbe: nil, + Deployment: &ngfAPIv1alpha2.DeploymentSpec{ + Container: ngfAPIv1alpha2.ContainerSpec{ + ReadinessProbe: nil, + }, + }, + }, + }, + }, + expected: defaultBaseHTTPConfig, + }, + { + msg: "readiness probe spec is empty", + gateway: &graph.Gateway{ + EffectiveNginxProxy: &graph.EffectiveNginxProxy{ + Kubernetes: &ngfAPIv1alpha2.KubernetesSpec{ + Deployment: &ngfAPIv1alpha2.DeploymentSpec{ + Container: ngfAPIv1alpha2.ContainerSpec{ + ReadinessProbe: &ngfAPIv1alpha2.ReadinessProbeSpec{}, + }, + }, }, }, }, @@ -5000,8 +5019,12 @@ func TestBuildBaseHTTPConfig_ReadinessProbe(t *testing.T) { gateway: &graph.Gateway{ EffectiveNginxProxy: &graph.EffectiveNginxProxy{ Kubernetes: &ngfAPIv1alpha2.KubernetesSpec{ - ReadinessProbe: &ngfAPIv1alpha2.ReadinessProbeSpec{ - Port: helpers.GetPointer(int32(7020)), + Deployment: &ngfAPIv1alpha2.DeploymentSpec{ + Container: ngfAPIv1alpha2.ContainerSpec{ + ReadinessProbe: &ngfAPIv1alpha2.ReadinessProbeSpec{ + Port: helpers.GetPointer(int32(7020)), + }, + }, }, }, }, From 6bb36af546ec2d1afe39a18737762f6b395a885e Mon Sep 17 00:00:00 2001 From: salonichf5 <146118978+salonichf5@users.noreply.github.com> Date: Wed, 16 Jul 2025 15:10:03 -0600 Subject: [PATCH 3/5] fix chart rendering --- apis/v1alpha2/nginxproxy_types.go | 67 ++++++++++++++++--- apis/v1alpha2/zz_generated.deepcopy.go | 14 ++-- .../templates/nginxproxy.yaml | 4 +- .../bases/gateway.nginx.org_nginxproxies.yaml | 47 +++++++------ deploy/azure/deploy.yaml | 1 + deploy/crds.yaml | 47 +++++++------ deploy/default/deploy.yaml | 1 + deploy/experimental-nginx-plus/deploy.yaml | 1 + deploy/experimental/deploy.yaml | 1 + deploy/nginx-plus/deploy.yaml | 1 + deploy/nodeport/deploy.yaml | 1 + deploy/openshift/deploy.yaml | 1 + .../snippets-filters-nginx-plus/deploy.yaml | 1 + deploy/snippets-filters/deploy.yaml | 1 + .../state/dataplane/configuration_test.go | 23 ++++++- 15 files changed, 152 insertions(+), 59 deletions(-) diff --git a/apis/v1alpha2/nginxproxy_types.go b/apis/v1alpha2/nginxproxy_types.go index 8f79314191..2b8f9062cd 100644 --- a/apis/v1alpha2/nginxproxy_types.go +++ b/apis/v1alpha2/nginxproxy_types.go @@ -390,15 +390,33 @@ type KubernetesSpec struct { // Deployment is the configuration for the NGINX Deployment. type DeploymentSpec struct { + // Container defines container fields for the NGINX container. + // + // +optional Container ContainerSpec `json:"container"` - Replicas *int32 `json:"replicas,omitempty"` - Pod PodSpec `json:"pod"` + + // Number of desired Pods. + // + // +optional + Replicas *int32 `json:"replicas,omitempty"` + + // Pod defines Pod-specific fields. + // + // +optional + Pod PodSpec `json:"pod"` } // DaemonSet is the configuration for the NGINX DaemonSet. type DaemonSetSpec struct { + // Container defines container fields for the NGINX container. + // + // +optional Container ContainerSpec `json:"container"` - Pod PodSpec `json:"pod"` + + // Pod defines Pod-specific fields. + // + // +optional + Pod PodSpec `json:"pod"` } // PodSpec defines Pod-specific fields. @@ -446,13 +464,42 @@ type PodSpec struct { // ContainerSpec defines container fields for the NGINX container. type ContainerSpec struct { - Debug *bool `json:"debug,omitempty"` - Image *Image `json:"image,omitempty"` - Resources *corev1.ResourceRequirements `json:"resources,omitempty"` - Lifecycle *corev1.Lifecycle `json:"lifecycle,omitempty"` - ReadinessProbe *ReadinessProbeSpec `json:"readinessProbe,omitempty"` - HostPorts []HostPort `json:"hostPorts,omitempty"` - VolumeMounts []corev1.VolumeMount `json:"volumeMounts,omitempty"` + // Debug enables debugging for NGINX by using the nginx-debug binary. + // + // +optional + Debug *bool `json:"debug,omitempty"` + + // Image is the NGINX image to use. + // + // +optional + Image *Image `json:"image,omitempty"` + + // Resources describes the compute resource requirements. + // + // +optional + Resources *corev1.ResourceRequirements `json:"resources,omitempty"` + + // Lifecycle describes actions that the management system should take in response to container lifecycle + // events. For the PostStart and PreStop lifecycle handlers, management of the container blocks + // until the action is complete, unless the container process fails, in which case the handler is aborted. + // + // +optional + Lifecycle *corev1.Lifecycle `json:"lifecycle,omitempty"` + + // ReadinessProbe defines the readiness probe for the NGINX container. + // + // +optional + ReadinessProbe *ReadinessProbeSpec `json:"readinessProbe,omitempty"` + + // HostPorts are the list of ports to expose on the host. + // + // +optional + HostPorts []HostPort `json:"hostPorts,omitempty"` + + // VolumeMounts describe the mounting of Volumes within a container. + // + // +optional + VolumeMounts []corev1.VolumeMount `json:"volumeMounts,omitempty"` } // ReadinessProbeSpec defines the configuration for the NGINX readiness probe. diff --git a/apis/v1alpha2/zz_generated.deepcopy.go b/apis/v1alpha2/zz_generated.deepcopy.go index a218a71f0c..e092280ed9 100644 --- a/apis/v1alpha2/zz_generated.deepcopy.go +++ b/apis/v1alpha2/zz_generated.deepcopy.go @@ -34,11 +34,6 @@ func (in *ContainerSpec) DeepCopyInto(out *ContainerSpec) { *out = new(v1.Lifecycle) (*in).DeepCopyInto(*out) } - if in.ReadinessProbe != nil { - in, out := &in.ReadinessProbe, &out.ReadinessProbe - *out = new(ReadinessProbeSpec) - (*in).DeepCopyInto(*out) - } if in.HostPorts != nil { in, out := &in.HostPorts, &out.HostPorts *out = make([]HostPort, len(*in)) @@ -51,6 +46,11 @@ func (in *ContainerSpec) DeepCopyInto(out *ContainerSpec) { (*in)[i].DeepCopyInto(&(*out)[i]) } } + if in.ReadinessProbe != nil { + in, out := &in.ReadinessProbe, &out.ReadinessProbe + *out = new(ReadinessProbeSpec) + (*in).DeepCopyInto(*out) + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ContainerSpec. @@ -66,8 +66,8 @@ func (in *ContainerSpec) DeepCopy() *ContainerSpec { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *DaemonSetSpec) DeepCopyInto(out *DaemonSetSpec) { *out = *in - in.Container.DeepCopyInto(&out.Container) in.Pod.DeepCopyInto(&out.Pod) + in.Container.DeepCopyInto(&out.Container) } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DaemonSetSpec. @@ -83,13 +83,13 @@ func (in *DaemonSetSpec) DeepCopy() *DaemonSetSpec { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *DeploymentSpec) DeepCopyInto(out *DeploymentSpec) { *out = *in - in.Container.DeepCopyInto(&out.Container) if in.Replicas != nil { in, out := &in.Replicas, &out.Replicas *out = new(int32) **out = **in } in.Pod.DeepCopyInto(&out.Pod) + in.Container.DeepCopyInto(&out.Container) } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DeploymentSpec. diff --git a/charts/nginx-gateway-fabric/templates/nginxproxy.yaml b/charts/nginx-gateway-fabric/templates/nginxproxy.yaml index 7f0f2b1af0..0bd79a7a00 100644 --- a/charts/nginx-gateway-fabric/templates/nginxproxy.yaml +++ b/charts/nginx-gateway-fabric/templates/nginxproxy.yaml @@ -26,6 +26,8 @@ spec: {{- end }} image: {{- toYaml .Values.nginx.image | nindent 10 }} + readinessProbe: + {{- toYaml .Values.nginx.readinessProbe | nindent 10 }} {{- if .Values.nginx.debug }} debug: {{ .Values.nginx.debug }} {{- end }} @@ -49,7 +51,7 @@ spec: debug: {{ .Values.nginx.debug }} {{- end }} readinessProbe: - port: {{ .Values.nginx.readinessProbe.port | default 8081 }} + {{- toYaml .Values.nginx.readinessProbe | nindent 10 }} {{- end }} {{- if .Values.nginx.service }} service: diff --git a/config/crd/bases/gateway.nginx.org_nginxproxies.yaml b/config/crd/bases/gateway.nginx.org_nginxproxies.yaml index 6c8e16c639..ec77547ee1 100644 --- a/config/crd/bases/gateway.nginx.org_nginxproxies.yaml +++ b/config/crd/bases/gateway.nginx.org_nginxproxies.yaml @@ -74,12 +74,16 @@ spec: description: DaemonSet is the configuration for the NGINX DaemonSet. properties: container: - description: ContainerSpec defines container fields for the - NGINX container. + description: Container defines container fields for the NGINX + container. properties: debug: + description: Debug enables debugging for NGINX by using + the nginx-debug binary. type: boolean hostPorts: + description: HostPorts are the list of ports to expose + on the host. items: description: HostPort exposes an nginx container port on the host. @@ -359,8 +363,8 @@ spec: type: string type: object readinessProbe: - description: ReadinessProbeSpec defines the configuration - for the NGINX readiness probe. + description: ReadinessProbe defines the readiness probe + for the NGINX container. properties: exec: description: Exec specifies a command to execute in @@ -523,8 +527,8 @@ spec: type: integer type: object resources: - description: ResourceRequirements describes the compute - resource requirements. + description: Resources describes the compute resource + requirements. properties: claims: description: |- @@ -584,6 +588,8 @@ spec: type: object type: object volumeMounts: + description: VolumeMounts describe the mounting of Volumes + within a container. items: description: VolumeMount describes a mounting of a Volume within a container. @@ -648,7 +654,7 @@ spec: type: array type: object pod: - description: PodSpec defines Pod-specific fields. + description: Pod defines Pod-specific fields. properties: affinity: description: Affinity is the pod's scheduling constraints. @@ -3636,9 +3642,6 @@ spec: type: object type: array type: object - required: - - container - - pod type: object deployment: description: |- @@ -3646,12 +3649,16 @@ spec: This is the default deployment option. properties: container: - description: ContainerSpec defines container fields for the - NGINX container. + description: Container defines container fields for the NGINX + container. properties: debug: + description: Debug enables debugging for NGINX by using + the nginx-debug binary. type: boolean hostPorts: + description: HostPorts are the list of ports to expose + on the host. items: description: HostPort exposes an nginx container port on the host. @@ -3931,8 +3938,8 @@ spec: type: string type: object readinessProbe: - description: ReadinessProbeSpec defines the configuration - for the NGINX readiness probe. + description: ReadinessProbe defines the readiness probe + for the NGINX container. properties: exec: description: Exec specifies a command to execute in @@ -4095,8 +4102,8 @@ spec: type: integer type: object resources: - description: ResourceRequirements describes the compute - resource requirements. + description: Resources describes the compute resource + requirements. properties: claims: description: |- @@ -4156,6 +4163,8 @@ spec: type: object type: object volumeMounts: + description: VolumeMounts describe the mounting of Volumes + within a container. items: description: VolumeMount describes a mounting of a Volume within a container. @@ -4220,7 +4229,7 @@ spec: type: array type: object pod: - description: PodSpec defines Pod-specific fields. + description: Pod defines Pod-specific fields. properties: affinity: description: Affinity is the pod's scheduling constraints. @@ -7209,11 +7218,9 @@ spec: type: array type: object replicas: + description: Number of desired Pods. format: int32 type: integer - required: - - container - - pod type: object service: description: Service is the configuration for the NGINX Service. diff --git a/deploy/azure/deploy.yaml b/deploy/azure/deploy.yaml index 0a7e457685..8aefb97431 100644 --- a/deploy/azure/deploy.yaml +++ b/deploy/azure/deploy.yaml @@ -417,6 +417,7 @@ spec: pullPolicy: Always repository: ghcr.io/nginx/nginx-gateway-fabric/nginx tag: edge + readinessProbe: {} pod: nodeSelector: kubernetes.io/os: linux diff --git a/deploy/crds.yaml b/deploy/crds.yaml index 60a9309de5..b786243fe4 100644 --- a/deploy/crds.yaml +++ b/deploy/crds.yaml @@ -659,12 +659,16 @@ spec: description: DaemonSet is the configuration for the NGINX DaemonSet. properties: container: - description: ContainerSpec defines container fields for the - NGINX container. + description: Container defines container fields for the NGINX + container. properties: debug: + description: Debug enables debugging for NGINX by using + the nginx-debug binary. type: boolean hostPorts: + description: HostPorts are the list of ports to expose + on the host. items: description: HostPort exposes an nginx container port on the host. @@ -944,8 +948,8 @@ spec: type: string type: object readinessProbe: - description: ReadinessProbeSpec defines the configuration - for the NGINX readiness probe. + description: ReadinessProbe defines the readiness probe + for the NGINX container. properties: exec: description: Exec specifies a command to execute in @@ -1108,8 +1112,8 @@ spec: type: integer type: object resources: - description: ResourceRequirements describes the compute - resource requirements. + description: Resources describes the compute resource + requirements. properties: claims: description: |- @@ -1169,6 +1173,8 @@ spec: type: object type: object volumeMounts: + description: VolumeMounts describe the mounting of Volumes + within a container. items: description: VolumeMount describes a mounting of a Volume within a container. @@ -1233,7 +1239,7 @@ spec: type: array type: object pod: - description: PodSpec defines Pod-specific fields. + description: Pod defines Pod-specific fields. properties: affinity: description: Affinity is the pod's scheduling constraints. @@ -4221,9 +4227,6 @@ spec: type: object type: array type: object - required: - - container - - pod type: object deployment: description: |- @@ -4231,12 +4234,16 @@ spec: This is the default deployment option. properties: container: - description: ContainerSpec defines container fields for the - NGINX container. + description: Container defines container fields for the NGINX + container. properties: debug: + description: Debug enables debugging for NGINX by using + the nginx-debug binary. type: boolean hostPorts: + description: HostPorts are the list of ports to expose + on the host. items: description: HostPort exposes an nginx container port on the host. @@ -4516,8 +4523,8 @@ spec: type: string type: object readinessProbe: - description: ReadinessProbeSpec defines the configuration - for the NGINX readiness probe. + description: ReadinessProbe defines the readiness probe + for the NGINX container. properties: exec: description: Exec specifies a command to execute in @@ -4680,8 +4687,8 @@ spec: type: integer type: object resources: - description: ResourceRequirements describes the compute - resource requirements. + description: Resources describes the compute resource + requirements. properties: claims: description: |- @@ -4741,6 +4748,8 @@ spec: type: object type: object volumeMounts: + description: VolumeMounts describe the mounting of Volumes + within a container. items: description: VolumeMount describes a mounting of a Volume within a container. @@ -4805,7 +4814,7 @@ spec: type: array type: object pod: - description: PodSpec defines Pod-specific fields. + description: Pod defines Pod-specific fields. properties: affinity: description: Affinity is the pod's scheduling constraints. @@ -7794,11 +7803,9 @@ spec: type: array type: object replicas: + description: Number of desired Pods. format: int32 type: integer - required: - - container - - pod type: object service: description: Service is the configuration for the NGINX Service. diff --git a/deploy/default/deploy.yaml b/deploy/default/deploy.yaml index 4324fc92f7..511555b3d0 100644 --- a/deploy/default/deploy.yaml +++ b/deploy/default/deploy.yaml @@ -415,6 +415,7 @@ spec: pullPolicy: Always repository: ghcr.io/nginx/nginx-gateway-fabric/nginx tag: edge + readinessProbe: {} replicas: 1 service: externalTrafficPolicy: Local diff --git a/deploy/experimental-nginx-plus/deploy.yaml b/deploy/experimental-nginx-plus/deploy.yaml index f0ac53ba0d..d96767fc61 100644 --- a/deploy/experimental-nginx-plus/deploy.yaml +++ b/deploy/experimental-nginx-plus/deploy.yaml @@ -423,6 +423,7 @@ spec: pullPolicy: Always repository: private-registry.nginx.com/nginx-gateway-fabric/nginx-plus tag: edge + readinessProbe: {} replicas: 1 service: externalTrafficPolicy: Local diff --git a/deploy/experimental/deploy.yaml b/deploy/experimental/deploy.yaml index ad3cf361a6..e5d20fcd51 100644 --- a/deploy/experimental/deploy.yaml +++ b/deploy/experimental/deploy.yaml @@ -420,6 +420,7 @@ spec: pullPolicy: Always repository: ghcr.io/nginx/nginx-gateway-fabric/nginx tag: edge + readinessProbe: {} replicas: 1 service: externalTrafficPolicy: Local diff --git a/deploy/nginx-plus/deploy.yaml b/deploy/nginx-plus/deploy.yaml index a966b9e325..f1190d4a7e 100644 --- a/deploy/nginx-plus/deploy.yaml +++ b/deploy/nginx-plus/deploy.yaml @@ -418,6 +418,7 @@ spec: pullPolicy: Always repository: private-registry.nginx.com/nginx-gateway-fabric/nginx-plus tag: edge + readinessProbe: {} replicas: 1 service: externalTrafficPolicy: Local diff --git a/deploy/nodeport/deploy.yaml b/deploy/nodeport/deploy.yaml index d151c82319..35804abe0a 100644 --- a/deploy/nodeport/deploy.yaml +++ b/deploy/nodeport/deploy.yaml @@ -415,6 +415,7 @@ spec: pullPolicy: Always repository: ghcr.io/nginx/nginx-gateway-fabric/nginx tag: edge + readinessProbe: {} replicas: 1 service: externalTrafficPolicy: Local diff --git a/deploy/openshift/deploy.yaml b/deploy/openshift/deploy.yaml index e6ecf6b3e0..6454a600c2 100644 --- a/deploy/openshift/deploy.yaml +++ b/deploy/openshift/deploy.yaml @@ -437,6 +437,7 @@ spec: pullPolicy: Always repository: ghcr.io/nginx/nginx-gateway-fabric/nginx tag: edge + readinessProbe: {} replicas: 1 service: externalTrafficPolicy: Local diff --git a/deploy/snippets-filters-nginx-plus/deploy.yaml b/deploy/snippets-filters-nginx-plus/deploy.yaml index 7461912539..581819d79e 100644 --- a/deploy/snippets-filters-nginx-plus/deploy.yaml +++ b/deploy/snippets-filters-nginx-plus/deploy.yaml @@ -421,6 +421,7 @@ spec: pullPolicy: Always repository: private-registry.nginx.com/nginx-gateway-fabric/nginx-plus tag: edge + readinessProbe: {} replicas: 1 service: externalTrafficPolicy: Local diff --git a/deploy/snippets-filters/deploy.yaml b/deploy/snippets-filters/deploy.yaml index d23d775600..6977699e1d 100644 --- a/deploy/snippets-filters/deploy.yaml +++ b/deploy/snippets-filters/deploy.yaml @@ -418,6 +418,7 @@ spec: pullPolicy: Always repository: ghcr.io/nginx/nginx-gateway-fabric/nginx tag: edge + readinessProbe: {} replicas: 1 service: externalTrafficPolicy: Local diff --git a/internal/controller/state/dataplane/configuration_test.go b/internal/controller/state/dataplane/configuration_test.go index 9d3a0ff5dd..b374493710 100644 --- a/internal/controller/state/dataplane/configuration_test.go +++ b/internal/controller/state/dataplane/configuration_test.go @@ -5015,7 +5015,7 @@ func TestBuildBaseHTTPConfig_ReadinessProbe(t *testing.T) { expected: defaultBaseHTTPConfig, }, { - msg: "readiness probe is configured", + msg: "readiness probe is configured for deployment kind", gateway: &graph.Gateway{ EffectiveNginxProxy: &graph.EffectiveNginxProxy{ Kubernetes: &ngfAPIv1alpha2.KubernetesSpec{ @@ -5035,6 +5035,27 @@ func TestBuildBaseHTTPConfig_ReadinessProbe(t *testing.T) { HTTP2: true, }, }, + { + msg: "readiness probe is configured for daemonset kind", + gateway: &graph.Gateway{ + EffectiveNginxProxy: &graph.EffectiveNginxProxy{ + Kubernetes: &ngfAPIv1alpha2.KubernetesSpec{ + DaemonSet: &ngfAPIv1alpha2.DaemonSetSpec{ + Container: ngfAPIv1alpha2.ContainerSpec{ + ReadinessProbe: &ngfAPIv1alpha2.ReadinessProbeSpec{ + Port: helpers.GetPointer(int32(8881)), + }, + }, + }, + }, + }, + }, + expected: BaseHTTPConfig{ + NginxReadinessProbePort: int32(8881), + IPFamily: Dual, + HTTP2: true, + }, + }, } for _, tc := range test { From 19bb3ecef6959c1c1a5536a9c05ff7a124ed6b8b Mon Sep 17 00:00:00 2001 From: salonichf5 <146118978+salonichf5@users.noreply.github.com> Date: Thu, 17 Jul 2025 11:26:47 -0600 Subject: [PATCH 4/5] remove probe struct and honor only port and initialDelaySeconds --- apis/v1alpha2/nginxproxy_types.go | 9 +- apis/v1alpha2/zz_generated.deepcopy.go | 22 +- charts/nginx-gateway-fabric/README.md | 4 +- .../templates/nginxproxy.yaml | 4 - .../nginx-gateway-fabric/values.schema.json | 12 +- charts/nginx-gateway-fabric/values.yaml | 25 +- .../bases/gateway.nginx.org_nginxproxies.yaml | 304 +----------------- deploy/azure/deploy.yaml | 1 - deploy/crds.yaml | 304 +----------------- deploy/default/deploy.yaml | 1 - deploy/experimental-nginx-plus/deploy.yaml | 1 - deploy/experimental/deploy.yaml | 1 - deploy/nginx-plus/deploy.yaml | 1 - deploy/nodeport/deploy.yaml | 1 - deploy/openshift/deploy.yaml | 1 - .../snippets-filters-nginx-plus/deploy.yaml | 1 - deploy/snippets-filters/deploy.yaml | 1 - internal/controller/provisioner/objects.go | 18 +- .../controller/provisioner/objects_test.go | 59 +--- 19 files changed, 72 insertions(+), 698 deletions(-) diff --git a/apis/v1alpha2/nginxproxy_types.go b/apis/v1alpha2/nginxproxy_types.go index 2b8f9062cd..c27b9a7e2f 100644 --- a/apis/v1alpha2/nginxproxy_types.go +++ b/apis/v1alpha2/nginxproxy_types.go @@ -508,15 +508,18 @@ type ReadinessProbeSpec struct { // If not specified, the default port is 8081. // // +optional - // +kubebuilder:default:=8081 // +kubebuilder:validation:Minimum=1 // +kubebuilder:validation:Maximum=65535 Port *int32 `json:"port,omitempty"` - // Probe describes the Kubernetes Probe configuration. + // InitialDelaySeconds is the number of seconds after the container has + // started before the readiness probe is initiated. + // If not specified, the default is 3 seconds. // // +optional - *corev1.Probe `json:",inline"` + // +kubebuilder:validation:Minimum=0 + // +kubebuilder:validation:Maximum=3600 + InitialDelaySeconds *int32 `json:"initialDelaySeconds,omitempty"` } // Image is the NGINX image to use. diff --git a/apis/v1alpha2/zz_generated.deepcopy.go b/apis/v1alpha2/zz_generated.deepcopy.go index e092280ed9..cd5239296b 100644 --- a/apis/v1alpha2/zz_generated.deepcopy.go +++ b/apis/v1alpha2/zz_generated.deepcopy.go @@ -34,6 +34,11 @@ func (in *ContainerSpec) DeepCopyInto(out *ContainerSpec) { *out = new(v1.Lifecycle) (*in).DeepCopyInto(*out) } + if in.ReadinessProbe != nil { + in, out := &in.ReadinessProbe, &out.ReadinessProbe + *out = new(ReadinessProbeSpec) + (*in).DeepCopyInto(*out) + } if in.HostPorts != nil { in, out := &in.HostPorts, &out.HostPorts *out = make([]HostPort, len(*in)) @@ -46,11 +51,6 @@ func (in *ContainerSpec) DeepCopyInto(out *ContainerSpec) { (*in)[i].DeepCopyInto(&(*out)[i]) } } - if in.ReadinessProbe != nil { - in, out := &in.ReadinessProbe, &out.ReadinessProbe - *out = new(ReadinessProbeSpec) - (*in).DeepCopyInto(*out) - } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ContainerSpec. @@ -66,8 +66,8 @@ func (in *ContainerSpec) DeepCopy() *ContainerSpec { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *DaemonSetSpec) DeepCopyInto(out *DaemonSetSpec) { *out = *in - in.Pod.DeepCopyInto(&out.Pod) in.Container.DeepCopyInto(&out.Container) + in.Pod.DeepCopyInto(&out.Pod) } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DaemonSetSpec. @@ -83,13 +83,13 @@ func (in *DaemonSetSpec) DeepCopy() *DaemonSetSpec { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *DeploymentSpec) DeepCopyInto(out *DeploymentSpec) { *out = *in + in.Container.DeepCopyInto(&out.Container) if in.Replicas != nil { in, out := &in.Replicas, &out.Replicas *out = new(int32) **out = **in } in.Pod.DeepCopyInto(&out.Pod) - in.Container.DeepCopyInto(&out.Container) } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DeploymentSpec. @@ -542,10 +542,10 @@ func (in *ReadinessProbeSpec) DeepCopyInto(out *ReadinessProbeSpec) { *out = new(int32) **out = **in } - if in.Probe != nil { - in, out := &in.Probe, &out.Probe - *out = new(v1.Probe) - (*in).DeepCopyInto(*out) + if in.InitialDelaySeconds != nil { + in, out := &in.InitialDelaySeconds, &out.InitialDelaySeconds + *out = new(int32) + **out = **in } } diff --git a/charts/nginx-gateway-fabric/README.md b/charts/nginx-gateway-fabric/README.md index ee8a17c53e..3bcafee80e 100644 --- a/charts/nginx-gateway-fabric/README.md +++ b/charts/nginx-gateway-fabric/README.md @@ -264,9 +264,9 @@ The following table lists the configurable parameters of the NGINX Gateway Fabri | `certGenerator.ttlSecondsAfterFinished` | How long to wait after the cert generator job has finished before it is removed by the job controller. | int | `30` | | `clusterDomain` | The DNS cluster domain of your Kubernetes cluster. | string | `"cluster.local"` | | `gateways` | A list of Gateway objects. View https://gateway-api.sigs.k8s.io/reference/spec/#gateway for full Gateway reference. | list | `[]` | -| `nginx` | The nginx section contains the configuration for all NGINX data plane deployments installed by the NGINX Gateway Fabric control plane. | object | `{"config":{},"container":{"hostPorts":[],"lifecycle":{},"resources":{},"volumeMounts":[]},"debug":false,"image":{"pullPolicy":"Always","repository":"ghcr.io/nginx/nginx-gateway-fabric/nginx","tag":"edge"},"imagePullSecret":"","imagePullSecrets":[],"kind":"deployment","plus":false,"pod":{},"readinessProbe":{},"replicas":1,"service":{"externalTrafficPolicy":"Local","loadBalancerClass":"","loadBalancerIP":"","loadBalancerSourceRanges":[],"nodePorts":[],"type":"LoadBalancer"},"usage":{"caSecretName":"","clientSSLSecretName":"","endpoint":"","resolver":"","secretName":"nplus-license","skipVerify":false}}` | +| `nginx` | The nginx section contains the configuration for all NGINX data plane deployments installed by the NGINX Gateway Fabric control plane. | object | `{"config":{},"container":{"hostPorts":[],"lifecycle":{},"readinessProbe":{},"resources":{},"volumeMounts":[]},"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","loadBalancerClass":"","loadBalancerIP":"","loadBalancerSourceRanges":[],"nodePorts":[],"type":"LoadBalancer"},"usage":{"caSecretName":"","clientSSLSecretName":"","endpoint":"","resolver":"","secretName":"nplus-license","skipVerify":false}}` | | `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 | `{}` | -| `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 | `{"hostPorts":[],"lifecycle":{},"resources":{},"volumeMounts":[]}` | +| `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 | `{"hostPorts":[],"lifecycle":{},"readinessProbe":{},"resources":{},"volumeMounts":[]}` | | `nginx.container.hostPorts` | A list of HostPorts to expose on the host. This configuration allows containers to bind to a specific port on the host node, enabling external network traffic to reach the container directly through the host's IP address and port. Use this option when you need to expose container ports on the host for direct access, such as for debugging, legacy integrations, or when NodePort/LoadBalancer services are not suitable. Note: Using hostPort may have security and scheduling implications, as it ties pods to specific nodes and ports. | list | `[]` | | `nginx.container.lifecycle` | The lifecycle of the NGINX container. | object | `{}` | | `nginx.container.resources` | The resource requirements of the NGINX container. | object | `{}` | diff --git a/charts/nginx-gateway-fabric/templates/nginxproxy.yaml b/charts/nginx-gateway-fabric/templates/nginxproxy.yaml index 0bd79a7a00..0c4640c5b9 100644 --- a/charts/nginx-gateway-fabric/templates/nginxproxy.yaml +++ b/charts/nginx-gateway-fabric/templates/nginxproxy.yaml @@ -26,8 +26,6 @@ spec: {{- end }} image: {{- toYaml .Values.nginx.image | nindent 10 }} - readinessProbe: - {{- toYaml .Values.nginx.readinessProbe | nindent 10 }} {{- if .Values.nginx.debug }} debug: {{ .Values.nginx.debug }} {{- end }} @@ -50,8 +48,6 @@ spec: {{- if .Values.nginx.debug }} debug: {{ .Values.nginx.debug }} {{- end }} - readinessProbe: - {{- toYaml .Values.nginx.readinessProbe | nindent 10 }} {{- end }} {{- if .Values.nginx.service }} service: diff --git a/charts/nginx-gateway-fabric/values.schema.json b/charts/nginx-gateway-fabric/values.schema.json index 8310cd1f34..e272a75491 100644 --- a/charts/nginx-gateway-fabric/values.schema.json +++ b/charts/nginx-gateway-fabric/values.schema.json @@ -351,6 +351,12 @@ "title": "lifecycle", "type": "object" }, + "readinessProbe": { + "description": "# Defines the settings for the data plane readiness probe. This probe returns Ready when the NGINX data plane is ready to serve traffic.", + "required": [], + "title": "readinessProbe", + "type": "object" + }, "resources": { "description": "The resource requirements of the NGINX container.", "required": [], @@ -447,12 +453,6 @@ "title": "pod", "type": "object" }, - "readinessProbe": { - "description": "# Defines the settings for the data plane readiness probe. This probe returns Ready when the NGINX data plane is ready to serve traffic.", - "required": [], - "title": "readinessProbe", - "type": "object" - }, "replicas": { "default": 1, "description": "The number of replicas of the NGINX Deployment.", diff --git a/charts/nginx-gateway-fabric/values.yaml b/charts/nginx-gateway-fabric/values.yaml index 3ace0a2a33..406cfff2d2 100644 --- a/charts/nginx-gateway-fabric/values.yaml +++ b/charts/nginx-gateway-fabric/values.yaml @@ -441,6 +441,19 @@ nginx: # -- volumeMounts are the additional volume mounts for the NGINX container. volumeMounts: [] + ## Defines the settings for the data plane readiness probe. This probe returns Ready when the NGINX data plane is ready to serve traffic. + readinessProbe: {} + # @schema + # type: integer + # minimum: 1 + # maximum: 65535 + # @schema + # -- Port in which the readiness endpoint is exposed. + # port: 8081 + + # -- The number of seconds after the Pod has started before the readiness probes are initiated. + # initialDelaySeconds: 3 + # -- The service configuration for the NGINX data plane. This is applied globally to all Gateways managed by this # instance of NGINX Gateway Fabric. service: @@ -493,18 +506,6 @@ nginx: # - port: 30025 # listenerPort: 80 - ## Defines the settings for the data plane readiness probe. This probe returns Ready when the NGINX data plane is ready to serve traffic. - readinessProbe: {} - # @schema - # type: integer - # minimum: 1 - # maximum: 65535 - # @schema - # -- Port in which the readiness endpoint is exposed. - # port: 8081 - - # The Kubernetes probe can also be configured by modifying the NginxProxy resource. - # -- Enable debugging for NGINX. Uses the nginx-debug binary. The NGINX error log level should be set to debug in the NginxProxy resource. debug: false diff --git a/config/crd/bases/gateway.nginx.org_nginxproxies.yaml b/config/crd/bases/gateway.nginx.org_nginxproxies.yaml index ec77547ee1..3bcaf309db 100644 --- a/config/crd/bases/gateway.nginx.org_nginxproxies.yaml +++ b/config/crd/bases/gateway.nginx.org_nginxproxies.yaml @@ -366,111 +366,16 @@ spec: description: ReadinessProbe defines the readiness probe for the NGINX container. properties: - exec: - description: Exec specifies a command to execute in - the container. - properties: - command: - description: |- - Command is the command line to execute inside the container, the working directory for the - command is root ('/') in the container's filesystem. The command is simply exec'd, it is - not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use - a shell, you need to explicitly call out to that shell. - Exit status of 0 is treated as live/healthy and non-zero is unhealthy. - items: - type: string - type: array - x-kubernetes-list-type: atomic - type: object - failureThreshold: - description: |- - Minimum consecutive failures for the probe to be considered failed after having succeeded. - Defaults to 3. Minimum value is 1. - format: int32 - type: integer - grpc: - description: GRPC specifies a GRPC HealthCheckRequest. - properties: - port: - description: Port number of the gRPC service. - Number must be in the range 1 to 65535. - format: int32 - type: integer - service: - default: "" - description: |- - Service is the name of the service to place in the gRPC HealthCheckRequest - (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). - - If this is not specified, the default behavior is defined by gRPC. - type: string - required: - - port - type: object - httpGet: - description: HTTPGet specifies an HTTP GET request - to perform. - properties: - host: - description: |- - Host name to connect to, defaults to the pod IP. You probably want to set - "Host" in httpHeaders instead. - type: string - httpHeaders: - description: Custom headers to set in the request. - HTTP allows repeated headers. - items: - description: HTTPHeader describes a custom header - to be used in HTTP probes - properties: - name: - description: |- - The header field name. - This will be canonicalized upon output, so case-variant names will be understood as the same header. - type: string - value: - description: The header field value - type: string - required: - - name - - value - type: object - type: array - x-kubernetes-list-type: atomic - path: - description: Path to access on the HTTP server. - type: string - port: - anyOf: - - type: integer - - type: string - description: |- - Name or number of the port to access on the container. - Number must be in the range 1 to 65535. - Name must be an IANA_SVC_NAME. - x-kubernetes-int-or-string: true - scheme: - description: |- - Scheme to use for connecting to the host. - Defaults to HTTP. - type: string - required: - - port - type: object initialDelaySeconds: description: |- - Number of seconds after the container has started before liveness probes are initiated. - More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes - format: int32 - type: integer - periodSeconds: - description: |- - How often (in seconds) to perform the probe. - Default to 10 seconds. Minimum value is 1. + InitialDelaySeconds is the number of seconds after the container has + started before the readiness probe is initiated. + If not specified, the default is 3 seconds. format: int32 + maximum: 3600 + minimum: 0 type: integer port: - default: 8081 description: |- Port is the port on which the readiness endpoint is exposed. If not specified, the default port is 8081. @@ -478,53 +383,6 @@ spec: maximum: 65535 minimum: 1 type: integer - successThreshold: - description: |- - Minimum consecutive successes for the probe to be considered successful after having failed. - Defaults to 1. Must be 1 for liveness and startup. Minimum value is 1. - format: int32 - type: integer - tcpSocket: - description: TCPSocket specifies a connection to a - TCP port. - properties: - host: - description: 'Optional: Host name to connect to, - defaults to the pod IP.' - type: string - port: - anyOf: - - type: integer - - type: string - description: |- - Number or name of the port to access on the container. - Number must be in the range 1 to 65535. - Name must be an IANA_SVC_NAME. - x-kubernetes-int-or-string: true - required: - - port - type: object - terminationGracePeriodSeconds: - description: |- - Optional duration in seconds the pod needs to terminate gracefully upon probe failure. - The grace period is the duration in seconds after the processes running in the pod are sent - a termination signal and the time when the processes are forcibly halted with a kill signal. - Set this value longer than the expected cleanup time for your process. - If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this - value overrides the value provided by the pod spec. - Value must be non-negative integer. The value zero indicates stop immediately via - the kill signal (no opportunity to shut down). - This is a beta field and requires enabling ProbeTerminationGracePeriod feature gate. - Minimum value is 1. spec.terminationGracePeriodSeconds is used if unset. - format: int64 - type: integer - timeoutSeconds: - description: |- - Number of seconds after which the probe times out. - Defaults to 1 second. Minimum value is 1. - More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes - format: int32 - type: integer type: object resources: description: Resources describes the compute resource @@ -3941,111 +3799,16 @@ spec: description: ReadinessProbe defines the readiness probe for the NGINX container. properties: - exec: - description: Exec specifies a command to execute in - the container. - properties: - command: - description: |- - Command is the command line to execute inside the container, the working directory for the - command is root ('/') in the container's filesystem. The command is simply exec'd, it is - not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use - a shell, you need to explicitly call out to that shell. - Exit status of 0 is treated as live/healthy and non-zero is unhealthy. - items: - type: string - type: array - x-kubernetes-list-type: atomic - type: object - failureThreshold: - description: |- - Minimum consecutive failures for the probe to be considered failed after having succeeded. - Defaults to 3. Minimum value is 1. - format: int32 - type: integer - grpc: - description: GRPC specifies a GRPC HealthCheckRequest. - properties: - port: - description: Port number of the gRPC service. - Number must be in the range 1 to 65535. - format: int32 - type: integer - service: - default: "" - description: |- - Service is the name of the service to place in the gRPC HealthCheckRequest - (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). - - If this is not specified, the default behavior is defined by gRPC. - type: string - required: - - port - type: object - httpGet: - description: HTTPGet specifies an HTTP GET request - to perform. - properties: - host: - description: |- - Host name to connect to, defaults to the pod IP. You probably want to set - "Host" in httpHeaders instead. - type: string - httpHeaders: - description: Custom headers to set in the request. - HTTP allows repeated headers. - items: - description: HTTPHeader describes a custom header - to be used in HTTP probes - properties: - name: - description: |- - The header field name. - This will be canonicalized upon output, so case-variant names will be understood as the same header. - type: string - value: - description: The header field value - type: string - required: - - name - - value - type: object - type: array - x-kubernetes-list-type: atomic - path: - description: Path to access on the HTTP server. - type: string - port: - anyOf: - - type: integer - - type: string - description: |- - Name or number of the port to access on the container. - Number must be in the range 1 to 65535. - Name must be an IANA_SVC_NAME. - x-kubernetes-int-or-string: true - scheme: - description: |- - Scheme to use for connecting to the host. - Defaults to HTTP. - type: string - required: - - port - type: object initialDelaySeconds: description: |- - Number of seconds after the container has started before liveness probes are initiated. - More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes - format: int32 - type: integer - periodSeconds: - description: |- - How often (in seconds) to perform the probe. - Default to 10 seconds. Minimum value is 1. + InitialDelaySeconds is the number of seconds after the container has + started before the readiness probe is initiated. + If not specified, the default is 3 seconds. format: int32 + maximum: 3600 + minimum: 0 type: integer port: - default: 8081 description: |- Port is the port on which the readiness endpoint is exposed. If not specified, the default port is 8081. @@ -4053,53 +3816,6 @@ spec: maximum: 65535 minimum: 1 type: integer - successThreshold: - description: |- - Minimum consecutive successes for the probe to be considered successful after having failed. - Defaults to 1. Must be 1 for liveness and startup. Minimum value is 1. - format: int32 - type: integer - tcpSocket: - description: TCPSocket specifies a connection to a - TCP port. - properties: - host: - description: 'Optional: Host name to connect to, - defaults to the pod IP.' - type: string - port: - anyOf: - - type: integer - - type: string - description: |- - Number or name of the port to access on the container. - Number must be in the range 1 to 65535. - Name must be an IANA_SVC_NAME. - x-kubernetes-int-or-string: true - required: - - port - type: object - terminationGracePeriodSeconds: - description: |- - Optional duration in seconds the pod needs to terminate gracefully upon probe failure. - The grace period is the duration in seconds after the processes running in the pod are sent - a termination signal and the time when the processes are forcibly halted with a kill signal. - Set this value longer than the expected cleanup time for your process. - If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this - value overrides the value provided by the pod spec. - Value must be non-negative integer. The value zero indicates stop immediately via - the kill signal (no opportunity to shut down). - This is a beta field and requires enabling ProbeTerminationGracePeriod feature gate. - Minimum value is 1. spec.terminationGracePeriodSeconds is used if unset. - format: int64 - type: integer - timeoutSeconds: - description: |- - Number of seconds after which the probe times out. - Defaults to 1 second. Minimum value is 1. - More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes - format: int32 - type: integer type: object resources: description: Resources describes the compute resource diff --git a/deploy/azure/deploy.yaml b/deploy/azure/deploy.yaml index 8aefb97431..0a7e457685 100644 --- a/deploy/azure/deploy.yaml +++ b/deploy/azure/deploy.yaml @@ -417,7 +417,6 @@ spec: pullPolicy: Always repository: ghcr.io/nginx/nginx-gateway-fabric/nginx tag: edge - readinessProbe: {} pod: nodeSelector: kubernetes.io/os: linux diff --git a/deploy/crds.yaml b/deploy/crds.yaml index b786243fe4..555934b682 100644 --- a/deploy/crds.yaml +++ b/deploy/crds.yaml @@ -951,111 +951,16 @@ spec: description: ReadinessProbe defines the readiness probe for the NGINX container. properties: - exec: - description: Exec specifies a command to execute in - the container. - properties: - command: - description: |- - Command is the command line to execute inside the container, the working directory for the - command is root ('/') in the container's filesystem. The command is simply exec'd, it is - not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use - a shell, you need to explicitly call out to that shell. - Exit status of 0 is treated as live/healthy and non-zero is unhealthy. - items: - type: string - type: array - x-kubernetes-list-type: atomic - type: object - failureThreshold: - description: |- - Minimum consecutive failures for the probe to be considered failed after having succeeded. - Defaults to 3. Minimum value is 1. - format: int32 - type: integer - grpc: - description: GRPC specifies a GRPC HealthCheckRequest. - properties: - port: - description: Port number of the gRPC service. - Number must be in the range 1 to 65535. - format: int32 - type: integer - service: - default: "" - description: |- - Service is the name of the service to place in the gRPC HealthCheckRequest - (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). - - If this is not specified, the default behavior is defined by gRPC. - type: string - required: - - port - type: object - httpGet: - description: HTTPGet specifies an HTTP GET request - to perform. - properties: - host: - description: |- - Host name to connect to, defaults to the pod IP. You probably want to set - "Host" in httpHeaders instead. - type: string - httpHeaders: - description: Custom headers to set in the request. - HTTP allows repeated headers. - items: - description: HTTPHeader describes a custom header - to be used in HTTP probes - properties: - name: - description: |- - The header field name. - This will be canonicalized upon output, so case-variant names will be understood as the same header. - type: string - value: - description: The header field value - type: string - required: - - name - - value - type: object - type: array - x-kubernetes-list-type: atomic - path: - description: Path to access on the HTTP server. - type: string - port: - anyOf: - - type: integer - - type: string - description: |- - Name or number of the port to access on the container. - Number must be in the range 1 to 65535. - Name must be an IANA_SVC_NAME. - x-kubernetes-int-or-string: true - scheme: - description: |- - Scheme to use for connecting to the host. - Defaults to HTTP. - type: string - required: - - port - type: object initialDelaySeconds: description: |- - Number of seconds after the container has started before liveness probes are initiated. - More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes - format: int32 - type: integer - periodSeconds: - description: |- - How often (in seconds) to perform the probe. - Default to 10 seconds. Minimum value is 1. + InitialDelaySeconds is the number of seconds after the container has + started before the readiness probe is initiated. + If not specified, the default is 3 seconds. format: int32 + maximum: 3600 + minimum: 0 type: integer port: - default: 8081 description: |- Port is the port on which the readiness endpoint is exposed. If not specified, the default port is 8081. @@ -1063,53 +968,6 @@ spec: maximum: 65535 minimum: 1 type: integer - successThreshold: - description: |- - Minimum consecutive successes for the probe to be considered successful after having failed. - Defaults to 1. Must be 1 for liveness and startup. Minimum value is 1. - format: int32 - type: integer - tcpSocket: - description: TCPSocket specifies a connection to a - TCP port. - properties: - host: - description: 'Optional: Host name to connect to, - defaults to the pod IP.' - type: string - port: - anyOf: - - type: integer - - type: string - description: |- - Number or name of the port to access on the container. - Number must be in the range 1 to 65535. - Name must be an IANA_SVC_NAME. - x-kubernetes-int-or-string: true - required: - - port - type: object - terminationGracePeriodSeconds: - description: |- - Optional duration in seconds the pod needs to terminate gracefully upon probe failure. - The grace period is the duration in seconds after the processes running in the pod are sent - a termination signal and the time when the processes are forcibly halted with a kill signal. - Set this value longer than the expected cleanup time for your process. - If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this - value overrides the value provided by the pod spec. - Value must be non-negative integer. The value zero indicates stop immediately via - the kill signal (no opportunity to shut down). - This is a beta field and requires enabling ProbeTerminationGracePeriod feature gate. - Minimum value is 1. spec.terminationGracePeriodSeconds is used if unset. - format: int64 - type: integer - timeoutSeconds: - description: |- - Number of seconds after which the probe times out. - Defaults to 1 second. Minimum value is 1. - More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes - format: int32 - type: integer type: object resources: description: Resources describes the compute resource @@ -4526,111 +4384,16 @@ spec: description: ReadinessProbe defines the readiness probe for the NGINX container. properties: - exec: - description: Exec specifies a command to execute in - the container. - properties: - command: - description: |- - Command is the command line to execute inside the container, the working directory for the - command is root ('/') in the container's filesystem. The command is simply exec'd, it is - not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use - a shell, you need to explicitly call out to that shell. - Exit status of 0 is treated as live/healthy and non-zero is unhealthy. - items: - type: string - type: array - x-kubernetes-list-type: atomic - type: object - failureThreshold: - description: |- - Minimum consecutive failures for the probe to be considered failed after having succeeded. - Defaults to 3. Minimum value is 1. - format: int32 - type: integer - grpc: - description: GRPC specifies a GRPC HealthCheckRequest. - properties: - port: - description: Port number of the gRPC service. - Number must be in the range 1 to 65535. - format: int32 - type: integer - service: - default: "" - description: |- - Service is the name of the service to place in the gRPC HealthCheckRequest - (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). - - If this is not specified, the default behavior is defined by gRPC. - type: string - required: - - port - type: object - httpGet: - description: HTTPGet specifies an HTTP GET request - to perform. - properties: - host: - description: |- - Host name to connect to, defaults to the pod IP. You probably want to set - "Host" in httpHeaders instead. - type: string - httpHeaders: - description: Custom headers to set in the request. - HTTP allows repeated headers. - items: - description: HTTPHeader describes a custom header - to be used in HTTP probes - properties: - name: - description: |- - The header field name. - This will be canonicalized upon output, so case-variant names will be understood as the same header. - type: string - value: - description: The header field value - type: string - required: - - name - - value - type: object - type: array - x-kubernetes-list-type: atomic - path: - description: Path to access on the HTTP server. - type: string - port: - anyOf: - - type: integer - - type: string - description: |- - Name or number of the port to access on the container. - Number must be in the range 1 to 65535. - Name must be an IANA_SVC_NAME. - x-kubernetes-int-or-string: true - scheme: - description: |- - Scheme to use for connecting to the host. - Defaults to HTTP. - type: string - required: - - port - type: object initialDelaySeconds: description: |- - Number of seconds after the container has started before liveness probes are initiated. - More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes - format: int32 - type: integer - periodSeconds: - description: |- - How often (in seconds) to perform the probe. - Default to 10 seconds. Minimum value is 1. + InitialDelaySeconds is the number of seconds after the container has + started before the readiness probe is initiated. + If not specified, the default is 3 seconds. format: int32 + maximum: 3600 + minimum: 0 type: integer port: - default: 8081 description: |- Port is the port on which the readiness endpoint is exposed. If not specified, the default port is 8081. @@ -4638,53 +4401,6 @@ spec: maximum: 65535 minimum: 1 type: integer - successThreshold: - description: |- - Minimum consecutive successes for the probe to be considered successful after having failed. - Defaults to 1. Must be 1 for liveness and startup. Minimum value is 1. - format: int32 - type: integer - tcpSocket: - description: TCPSocket specifies a connection to a - TCP port. - properties: - host: - description: 'Optional: Host name to connect to, - defaults to the pod IP.' - type: string - port: - anyOf: - - type: integer - - type: string - description: |- - Number or name of the port to access on the container. - Number must be in the range 1 to 65535. - Name must be an IANA_SVC_NAME. - x-kubernetes-int-or-string: true - required: - - port - type: object - terminationGracePeriodSeconds: - description: |- - Optional duration in seconds the pod needs to terminate gracefully upon probe failure. - The grace period is the duration in seconds after the processes running in the pod are sent - a termination signal and the time when the processes are forcibly halted with a kill signal. - Set this value longer than the expected cleanup time for your process. - If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this - value overrides the value provided by the pod spec. - Value must be non-negative integer. The value zero indicates stop immediately via - the kill signal (no opportunity to shut down). - This is a beta field and requires enabling ProbeTerminationGracePeriod feature gate. - Minimum value is 1. spec.terminationGracePeriodSeconds is used if unset. - format: int64 - type: integer - timeoutSeconds: - description: |- - Number of seconds after which the probe times out. - Defaults to 1 second. Minimum value is 1. - More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes - format: int32 - type: integer type: object resources: description: Resources describes the compute resource diff --git a/deploy/default/deploy.yaml b/deploy/default/deploy.yaml index 511555b3d0..4324fc92f7 100644 --- a/deploy/default/deploy.yaml +++ b/deploy/default/deploy.yaml @@ -415,7 +415,6 @@ spec: pullPolicy: Always repository: ghcr.io/nginx/nginx-gateway-fabric/nginx tag: edge - readinessProbe: {} replicas: 1 service: externalTrafficPolicy: Local diff --git a/deploy/experimental-nginx-plus/deploy.yaml b/deploy/experimental-nginx-plus/deploy.yaml index d96767fc61..f0ac53ba0d 100644 --- a/deploy/experimental-nginx-plus/deploy.yaml +++ b/deploy/experimental-nginx-plus/deploy.yaml @@ -423,7 +423,6 @@ spec: pullPolicy: Always repository: private-registry.nginx.com/nginx-gateway-fabric/nginx-plus tag: edge - readinessProbe: {} replicas: 1 service: externalTrafficPolicy: Local diff --git a/deploy/experimental/deploy.yaml b/deploy/experimental/deploy.yaml index e5d20fcd51..ad3cf361a6 100644 --- a/deploy/experimental/deploy.yaml +++ b/deploy/experimental/deploy.yaml @@ -420,7 +420,6 @@ spec: pullPolicy: Always repository: ghcr.io/nginx/nginx-gateway-fabric/nginx tag: edge - readinessProbe: {} replicas: 1 service: externalTrafficPolicy: Local diff --git a/deploy/nginx-plus/deploy.yaml b/deploy/nginx-plus/deploy.yaml index f1190d4a7e..a966b9e325 100644 --- a/deploy/nginx-plus/deploy.yaml +++ b/deploy/nginx-plus/deploy.yaml @@ -418,7 +418,6 @@ spec: pullPolicy: Always repository: private-registry.nginx.com/nginx-gateway-fabric/nginx-plus tag: edge - readinessProbe: {} replicas: 1 service: externalTrafficPolicy: Local diff --git a/deploy/nodeport/deploy.yaml b/deploy/nodeport/deploy.yaml index 35804abe0a..d151c82319 100644 --- a/deploy/nodeport/deploy.yaml +++ b/deploy/nodeport/deploy.yaml @@ -415,7 +415,6 @@ spec: pullPolicy: Always repository: ghcr.io/nginx/nginx-gateway-fabric/nginx tag: edge - readinessProbe: {} replicas: 1 service: externalTrafficPolicy: Local diff --git a/deploy/openshift/deploy.yaml b/deploy/openshift/deploy.yaml index 6454a600c2..e6ecf6b3e0 100644 --- a/deploy/openshift/deploy.yaml +++ b/deploy/openshift/deploy.yaml @@ -437,7 +437,6 @@ spec: pullPolicy: Always repository: ghcr.io/nginx/nginx-gateway-fabric/nginx tag: edge - readinessProbe: {} replicas: 1 service: externalTrafficPolicy: Local diff --git a/deploy/snippets-filters-nginx-plus/deploy.yaml b/deploy/snippets-filters-nginx-plus/deploy.yaml index 581819d79e..7461912539 100644 --- a/deploy/snippets-filters-nginx-plus/deploy.yaml +++ b/deploy/snippets-filters-nginx-plus/deploy.yaml @@ -421,7 +421,6 @@ spec: pullPolicy: Always repository: private-registry.nginx.com/nginx-gateway-fabric/nginx-plus tag: edge - readinessProbe: {} replicas: 1 service: externalTrafficPolicy: Local diff --git a/deploy/snippets-filters/deploy.yaml b/deploy/snippets-filters/deploy.yaml index 6977699e1d..d23d775600 100644 --- a/deploy/snippets-filters/deploy.yaml +++ b/deploy/snippets-filters/deploy.yaml @@ -418,7 +418,6 @@ spec: pullPolicy: Always repository: ghcr.io/nginx/nginx-gateway-fabric/nginx tag: edge - readinessProbe: {} replicas: 1 service: externalTrafficPolicy: Local diff --git a/internal/controller/provisioner/objects.go b/internal/controller/provisioner/objects.go index 69469fde2b..d24a8971b8 100644 --- a/internal/controller/provisioner/objects.go +++ b/internal/controller/provisioner/objects.go @@ -34,9 +34,10 @@ const ( defaultServiceType = corev1.ServiceTypeLoadBalancer defaultServicePolicy = corev1.ServiceExternalTrafficPolicyLocal - defaultNginxImagePath = "ghcr.io/nginx/nginx-gateway-fabric/nginx" - defaultNginxPlusImagePath = "private-registry.nginx.com/nginx-gateway-fabric/nginx-plus" - defaultImagePullPolicy = corev1.PullIfNotPresent + defaultNginxImagePath = "ghcr.io/nginx/nginx-gateway-fabric/nginx" + defaultNginxPlusImagePath = "private-registry.nginx.com/nginx-gateway-fabric/nginx-plus" + defaultImagePullPolicy = corev1.PullIfNotPresent + defaultInitialDelaySeconds = int32(3) ) var emptyDirVolumeSource = corev1.VolumeSource{EmptyDir: &corev1.EmptyDirVolumeSource{}} @@ -1048,6 +1049,7 @@ func (p *NginxProvisioner) buildReadinessProbe(nProxyCfg *graph.EffectiveNginxPr Port: intstr.FromInt32(dataplane.DefaultNginxReadinessProbePort), }, }, + InitialDelaySeconds: defaultInitialDelaySeconds, } var containerSpec *ngfAPIv1alpha2.ContainerSpec @@ -1067,14 +1069,8 @@ func (p *NginxProvisioner) buildReadinessProbe(nProxyCfg *graph.EffectiveNginxPr probe.HTTPGet.Port = intstr.FromInt32(*containerSpec.ReadinessProbe.Port) } - probeSpec := containerSpec.ReadinessProbe.Probe - if probeSpec != nil { - probe.InitialDelaySeconds = probeSpec.InitialDelaySeconds - probe.TimeoutSeconds = probeSpec.TimeoutSeconds - probe.PeriodSeconds = probeSpec.PeriodSeconds - probe.SuccessThreshold = probeSpec.SuccessThreshold - probe.FailureThreshold = probeSpec.FailureThreshold - probe.TerminationGracePeriodSeconds = probeSpec.TerminationGracePeriodSeconds + if containerSpec.ReadinessProbe.InitialDelaySeconds != nil { + probe.InitialDelaySeconds = *containerSpec.ReadinessProbe.InitialDelaySeconds } return probe diff --git a/internal/controller/provisioner/objects_test.go b/internal/controller/provisioner/objects_test.go index aff50123ee..da1e750ec6 100644 --- a/internal/controller/provisioner/objects_test.go +++ b/internal/controller/provisioner/objects_test.go @@ -300,15 +300,8 @@ func TestBuildNginxResourceObjects_NginxProxyConfig(t *testing.T) { }, }, ReadinessProbe: &ngfAPIv1alpha2.ReadinessProbeSpec{ - Port: helpers.GetPointer[int32](9091), - Probe: &corev1.Probe{ - InitialDelaySeconds: 5, - PeriodSeconds: 10, - TimeoutSeconds: 2, - SuccessThreshold: 1, - FailureThreshold: 3, - TerminationGracePeriodSeconds: helpers.GetPointer[int64](25), - }, + Port: helpers.GetPointer[int32](9091), + InitialDelaySeconds: helpers.GetPointer[int32](5), }, HostPorts: []ngfAPIv1alpha2.HostPort{{ContainerPort: int32(8443), Port: int32(8443)}}, }, @@ -373,11 +366,6 @@ func TestBuildNginxResourceObjects_NginxProxyConfig(t *testing.T) { g.Expect(container.ReadinessProbe.HTTPGet.Path).To(Equal("/readyz")) g.Expect(container.ReadinessProbe.HTTPGet.Port).To(Equal(intstr.FromInt(9091))) g.Expect(container.ReadinessProbe.InitialDelaySeconds).To(Equal(int32(5))) - g.Expect(container.ReadinessProbe.PeriodSeconds).To(Equal(int32(10))) - g.Expect(container.ReadinessProbe.TimeoutSeconds).To(Equal(int32(2))) - g.Expect(container.ReadinessProbe.SuccessThreshold).To(Equal(int32(1))) - g.Expect(container.ReadinessProbe.FailureThreshold).To(Equal(int32(3))) - g.Expect(container.ReadinessProbe.TerminationGracePeriodSeconds).To(Equal(helpers.GetPointer[int64](25))) } func TestBuildNginxResourceObjects_Plus(t *testing.T) { @@ -1092,6 +1080,7 @@ func TestBuildReadinessProbe(t *testing.T) { Port: intstr.FromInt32(dataplane.DefaultNginxReadinessProbePort), }, }, + InitialDelaySeconds: 3, } provisioner := &NginxProvisioner{} @@ -1149,13 +1138,14 @@ func TestBuildReadinessProbe(t *testing.T) { expected: defaultProbe, }, { - name: "port is set in readinessProbe, custom probe is returned", + name: "port & initialDelaySeconds is set in readinessProbe, custom probe is returned", nProxyCfg: &graph.EffectiveNginxProxy{ Kubernetes: &ngfAPIv1alpha2.KubernetesSpec{ Deployment: &ngfAPIv1alpha2.DeploymentSpec{ Container: ngfAPIv1alpha2.ContainerSpec{ ReadinessProbe: &ngfAPIv1alpha2.ReadinessProbeSpec{ - Port: helpers.GetPointer[int32](9091), + Port: helpers.GetPointer[int32](9091), + InitialDelaySeconds: helpers.GetPointer[int32](10), }, }, }, @@ -1168,42 +1158,7 @@ func TestBuildReadinessProbe(t *testing.T) { Port: intstr.FromInt32(9091), }, }, - }, - }, - { - name: "port and probe fields are set in readinessProbe, custom probe is returned", - nProxyCfg: &graph.EffectiveNginxProxy{ - Kubernetes: &ngfAPIv1alpha2.KubernetesSpec{ - Deployment: &ngfAPIv1alpha2.DeploymentSpec{ - Container: ngfAPIv1alpha2.ContainerSpec{ - ReadinessProbe: &ngfAPIv1alpha2.ReadinessProbeSpec{ - Port: helpers.GetPointer[int32](7033), - Probe: &corev1.Probe{ - InitialDelaySeconds: 5, - PeriodSeconds: 10, - TimeoutSeconds: 2, - SuccessThreshold: 5, - FailureThreshold: 7, - TerminationGracePeriodSeconds: helpers.GetPointer[int64](25), - }, - }, - }, - }, - }, - }, - expected: &corev1.Probe{ - ProbeHandler: corev1.ProbeHandler{ - HTTPGet: &corev1.HTTPGetAction{ - Path: "/readyz", - Port: intstr.FromInt32(7033), - }, - }, - InitialDelaySeconds: 5, - PeriodSeconds: 10, - TimeoutSeconds: 2, - SuccessThreshold: 5, - FailureThreshold: 7, - TerminationGracePeriodSeconds: helpers.GetPointer[int64](25), + InitialDelaySeconds: 10, }, }, } From 87a298a76c007ecac59bc041b5782cf9c8a5bfc9 Mon Sep 17 00:00:00 2001 From: salonichf5 <146118978+salonichf5@users.noreply.github.com> Date: Fri, 18 Jul 2025 13:03:11 -0600 Subject: [PATCH 5/5] update unit tests and schema --- charts/nginx-gateway-fabric/values.schema.json | 2 +- charts/nginx-gateway-fabric/values.yaml | 2 +- internal/controller/provisioner/objects_test.go | 11 +---------- 3 files changed, 3 insertions(+), 12 deletions(-) diff --git a/charts/nginx-gateway-fabric/values.schema.json b/charts/nginx-gateway-fabric/values.schema.json index e272a75491..d750c0a42a 100644 --- a/charts/nginx-gateway-fabric/values.schema.json +++ b/charts/nginx-gateway-fabric/values.schema.json @@ -352,7 +352,7 @@ "type": "object" }, "readinessProbe": { - "description": "# Defines the settings for the data plane readiness probe. This probe returns Ready when the NGINX data plane is ready to serve traffic.", + "description": "# -- Defines the settings for the data plane readiness probe. This probe returns Ready when the NGINX data plane is ready to serve traffic.", "required": [], "title": "readinessProbe", "type": "object" diff --git a/charts/nginx-gateway-fabric/values.yaml b/charts/nginx-gateway-fabric/values.yaml index 406cfff2d2..e9765ea511 100644 --- a/charts/nginx-gateway-fabric/values.yaml +++ b/charts/nginx-gateway-fabric/values.yaml @@ -441,7 +441,7 @@ nginx: # -- volumeMounts are the additional volume mounts for the NGINX container. volumeMounts: [] - ## Defines the settings for the data plane readiness probe. This probe returns Ready when the NGINX data plane is ready to serve traffic. + ## -- Defines the settings for the data plane readiness probe. This probe returns Ready when the NGINX data plane is ready to serve traffic. readinessProbe: {} # @schema # type: integer diff --git a/internal/controller/provisioner/objects_test.go b/internal/controller/provisioner/objects_test.go index da1e750ec6..6486e61bac 100644 --- a/internal/controller/provisioner/objects_test.go +++ b/internal/controller/provisioner/objects_test.go @@ -1071,7 +1071,6 @@ func TestBuildNginxConfigMaps_WorkerConnections(t *testing.T) { func TestBuildReadinessProbe(t *testing.T) { t.Parallel() - g := NewWithT(t) defaultProbe := &corev1.Probe{ ProbeHandler: corev1.ProbeHandler{ @@ -1104,15 +1103,6 @@ func TestBuildReadinessProbe(t *testing.T) { }, expected: defaultProbe, }, - { - name: "daemonSet is nil, default probe is returned", - nProxyCfg: &graph.EffectiveNginxProxy{ - Kubernetes: &ngfAPIv1alpha2.KubernetesSpec{ - DaemonSet: nil, - }, - }, - expected: defaultProbe, - }, { name: "container is nil, default probe is returned", nProxyCfg: &graph.EffectiveNginxProxy{ @@ -1166,6 +1156,7 @@ func TestBuildReadinessProbe(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() + g := NewWithT(t) probe := provisioner.buildReadinessProbe(tt.nProxyCfg) g.Expect(probe).To(Equal(tt.expected)) })