diff --git a/charts/nginx-ingress/templates/controller-daemonset.yaml b/charts/nginx-ingress/templates/controller-daemonset.yaml index 653ef4eb9e..17e8729cbc 100644 --- a/charts/nginx-ingress/templates/controller-daemonset.yaml +++ b/charts/nginx-ingress/templates/controller-daemonset.yaml @@ -86,6 +86,12 @@ spec: {{- if .Values.controller.readyStatus.enable }} - name: readiness-port containerPort: {{ .Values.controller.readyStatus.port }} +{{- end }} +{{- if .Values.controller.startupStatus.enable }} + - name: startup-port + containerPort: {{ .Values.controller.startupStatus.port }} +{{- end }} +{{- if .Values.controller.readyStatus.enable }} readinessProbe: httpGet: path: /nginx-ready @@ -93,6 +99,17 @@ spec: periodSeconds: 1 initialDelaySeconds: {{ .Values.controller.readyStatus.initialDelaySeconds }} {{- end }} +{{- if .Values.controller.startupStatus.enable }} + startupProbe: + httpGet: + path: {{ .Values.controller.startupStatus.path }} + port: startup-port + initialDelaySeconds: {{ .Values.controller.startupStatus.initialDelaySeconds }} + periodSeconds: {{ .Values.controller.startupStatus.periodSeconds }} + timeoutSeconds: {{ .Values.controller.startupStatus.timeoutSeconds }} + successThreshold: {{ .Values.controller.startupStatus.successThreshold }} + failureThreshold: {{ .Values.controller.startupStatus.failureThreshold }} +{{- end }} {{- if .Values.controller.securityContext }} securityContext: {{ toYaml .Values.controller.securityContext | indent 10 }} diff --git a/charts/nginx-ingress/templates/controller-deployment.yaml b/charts/nginx-ingress/templates/controller-deployment.yaml index 9f2c6bd1e3..8d60772271 100644 --- a/charts/nginx-ingress/templates/controller-deployment.yaml +++ b/charts/nginx-ingress/templates/controller-deployment.yaml @@ -93,12 +93,29 @@ spec: {{- if .Values.controller.readyStatus.enable }} - name: readiness-port containerPort: {{ .Values.controller.readyStatus.port }} +{{- end }} +{{- if .Values.controller.startupStatus.enable }} + - name: startup-port + containerPort: {{ .Values.controller.startupStatus.port }} +{{- end }} +{{- if .Values.controller.readyStatus.enable }} readinessProbe: httpGet: path: /nginx-ready port: readiness-port periodSeconds: 1 initialDelaySeconds: {{ .Values.controller.readyStatus.initialDelaySeconds }} +{{- end }} +{{- if .Values.controller.startupStatus.enable }} + startupProbe: + httpGet: + path: {{ .Values.controller.startupStatus.path }} + port: startup-port + initialDelaySeconds: {{ .Values.controller.startupStatus.initialDelaySeconds }} + periodSeconds: {{ .Values.controller.startupStatus.periodSeconds }} + timeoutSeconds: {{ .Values.controller.startupStatus.timeoutSeconds }} + successThreshold: {{ .Values.controller.startupStatus.successThreshold }} + failureThreshold: {{ .Values.controller.startupStatus.failureThreshold }} {{- end }} resources: {{ toYaml .Values.controller.resources | indent 10 }} diff --git a/charts/nginx-ingress/values.schema.json b/charts/nginx-ingress/values.schema.json index bbb6658e04..3cd6fe9765 100644 --- a/charts/nginx-ingress/values.schema.json +++ b/charts/nginx-ingress/values.schema.json @@ -1758,6 +1758,98 @@ } ] }, + "startupStatus": { + "type": "object", + "default": {}, + "title": "The startupStatus", + "required": [], + "properties": { + "enable": { + "type": "boolean", + "default": false, + "title": "Enable the startup probe", + "examples": [ + true + ] + }, + "port": { + "type": "integer", + "default": 0, + "title": "The port for the startup probe", + "examples": [ + 9999 + ] + }, + "path": { + "type": "string", + "default": "", + "title": "The path for the startup probe", + "examples": [ + "/" + ] + }, + "initialDelaySeconds": { + "type": "integer", + "default": 0, + "title": "Initial delay seconds for the startup probe", + "$ref": "https://raw.githubusercontent.com/nginxinc/kubernetes-json-schema/master/v1.33.1/_definitions.json#/definitions/io.k8s.api.core.v1.Probe/properties/initialDelaySeconds" + }, + "periodSeconds": { + "type": "integer", + "default": 0, + "title": "Period seconds for the startup probe", + "$ref": "https://raw.githubusercontent.com/nginxinc/kubernetes-json-schema/master/v1.33.1/_definitions.json#/definitions/io.k8s.api.core.v1.Probe/properties/periodSeconds" + }, + "timeoutSeconds": { + "type": "integer", + "default": 0, + "title": "Timeout seconds for the startup probe", + "$ref": "https://raw.githubusercontent.com/nginxinc/kubernetes-json-schema/master/v1.33.1/_definitions.json#/definitions/io.k8s.api.core.v1.Probe/properties/timeoutSeconds" + }, + "successThreshold": { + "type": "integer", + "default": 0, + "title": "Success threshold for the startup probe", + "$ref": "https://raw.githubusercontent.com/nginxinc/kubernetes-json-schema/master/v1.33.1/_definitions.json#/definitions/io.k8s.api.core.v1.Probe/properties/successThreshold" + }, + "failureThreshold": { + "type": "integer", + "default": 0, + "title": "Failure threshold for the startup probe", + "$ref": "https://raw.githubusercontent.com/nginxinc/kubernetes-json-schema/master/v1.33.1/_definitions.json#/definitions/io.k8s.api.core.v1.Probe/properties/failureThreshold" + } + }, + "allOf": [ + { + "if": { + "properties": { + "enable": { + "const": true + } + } + }, + "then": { + "required": [ + "enable", + "port", + "path" + ] + } + } + ], + "examples": [ + { + "enable": true, + "port": 9999, + "path": "/", + "initialDelaySeconds": 5, + "periodSeconds": 1, + "timeoutSeconds": 1, + "successThreshold": 1, + "failureThreshold": 30 + } + ] + }, "enableLatencyMetrics": { "type": "boolean", "default": false, diff --git a/charts/nginx-ingress/values.yaml b/charts/nginx-ingress/values.yaml index 5557e20b83..e62b5fa59c 100644 --- a/charts/nginx-ingress/values.yaml +++ b/charts/nginx-ingress/values.yaml @@ -566,6 +566,32 @@ controller: ## The number of seconds after the Ingress Controller pod has started before readiness probes are initiated. initialDelaySeconds: 0 + startupStatus: + + ## Enable the startup probe. + enable: false + + # ## Set the port where the startup endpoint is exposed. This is a required value if startupStatus.enable is true. + # port: 9999 + + # ## path to the startup endpoint. This is a required value if startupStatus.enable is true. + # path: / + + # ## The number of seconds after the Ingress Controller pod has started before startup probes are initiated. + # initialDelaySeconds: 5 + + # ## The number of seconds between each startup probe. + # periodSeconds: 1 + + # ## The number of seconds after which the startup probe times out. + # timeoutSeconds: 1 + + # ## The number of seconds after which the startup probe is considered successful. + # successThreshold: 1 + + # ## The number of seconds after which the startup probe is considered failed. + # failureThreshold: 30 + ## Enable collection of latency metrics for upstreams. Requires prometheus.create. enableLatencyMetrics: false diff --git a/charts/tests/__snapshots__/helmunit_test.snap b/charts/tests/__snapshots__/helmunit_test.snap index 979f247d68..b822b8e24c 100755 --- a/charts/tests/__snapshots__/helmunit_test.snap +++ b/charts/tests/__snapshots__/helmunit_test.snap @@ -9530,3 +9530,457 @@ metadata: app.kubernetes.io/version: "5.2.0" app.kubernetes.io/managed-by: Helm --- + +[TestHelmNICTemplate/startupStatusValid - 1] +/-/-/-/ +# Source: nginx-ingress/templates/controller-serviceaccount.yaml +apiVersion: v1 +kind: ServiceAccount +metadata: + name: startupstatus-nginx-ingress + namespace: default + labels: + helm.sh/chart: nginx-ingress-2.3.0 + app.kubernetes.io/name: nginx-ingress + app.kubernetes.io/instance: startupstatus + app.kubernetes.io/version: "5.2.0" + app.kubernetes.io/managed-by: Helm +/-/-/-/ +# Source: nginx-ingress/templates/controller-configmap.yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: startupstatus-nginx-ingress + namespace: default + labels: + helm.sh/chart: nginx-ingress-2.3.0 + app.kubernetes.io/name: nginx-ingress + app.kubernetes.io/instance: startupstatus + app.kubernetes.io/version: "5.2.0" + app.kubernetes.io/managed-by: Helm +data: + {} +/-/-/-/ +# Source: nginx-ingress/templates/controller-leader-election-configmap.yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: startupstatus-nginx-ingress-leader-election + namespace: default + labels: + helm.sh/chart: nginx-ingress-2.3.0 + app.kubernetes.io/name: nginx-ingress + app.kubernetes.io/instance: startupstatus + app.kubernetes.io/version: "5.2.0" + app.kubernetes.io/managed-by: Helm +/-/-/-/ +# Source: nginx-ingress/templates/clusterrole.yaml +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: startupstatus-nginx-ingress + labels: + helm.sh/chart: nginx-ingress-2.3.0 + app.kubernetes.io/name: nginx-ingress + app.kubernetes.io/instance: startupstatus + app.kubernetes.io/version: "5.2.0" + app.kubernetes.io/managed-by: Helm +rules: +- apiGroups: + - "" + resources: + - configmaps + - namespaces + - pods + - secrets + verbs: + - get + - list + - watch +- apiGroups: + - "" + resources: + - events + verbs: + - create + - patch + - list +- apiGroups: + - "" + resources: + - services + verbs: + - get + - list + - watch + - create + - update + - patch + - delete +- apiGroups: + - coordination.k8s.io + resources: + - leases + verbs: + - list + - watch +- apiGroups: + - discovery.k8s.io + resources: + - endpointslices + verbs: + - get + - list + - watch +- apiGroups: + - networking.k8s.io + resources: + - ingresses + verbs: + - get + - list + - watch +- apiGroups: + - "" + resources: + - nodes + verbs: + - list +- apiGroups: + - "apps" + resources: + - replicasets + - daemonsets + verbs: + - get +- apiGroups: + - networking.k8s.io + resources: + - ingressclasses + verbs: + - get + - list +- apiGroups: + - networking.k8s.io + resources: + - ingresses/status + verbs: + - update +- apiGroups: + - k8s.nginx.org + resources: + - virtualservers + - virtualserverroutes + - globalconfigurations + - transportservers + - policies + verbs: + - list + - watch + - get +- apiGroups: + - k8s.nginx.org + resources: + - virtualservers/status + - virtualserverroutes/status + - policies/status + - transportservers/status + verbs: + - update +/-/-/-/ +# Source: nginx-ingress/templates/clusterrolebinding.yaml +kind: ClusterRoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: startupstatus-nginx-ingress + labels: + helm.sh/chart: nginx-ingress-2.3.0 + app.kubernetes.io/name: nginx-ingress + app.kubernetes.io/instance: startupstatus + app.kubernetes.io/version: "5.2.0" + app.kubernetes.io/managed-by: Helm +subjects: +- kind: ServiceAccount + name: startupstatus-nginx-ingress + namespace: default +roleRef: + kind: ClusterRole + name: startupstatus-nginx-ingress + apiGroup: rbac.authorization.k8s.io +/-/-/-/ +# Source: nginx-ingress/templates/controller-role.yaml +kind: Role +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: startupstatus-nginx-ingress + labels: + helm.sh/chart: nginx-ingress-2.3.0 + app.kubernetes.io/name: nginx-ingress + app.kubernetes.io/instance: startupstatus + app.kubernetes.io/version: "5.2.0" + app.kubernetes.io/managed-by: Helm + namespace: default +rules: +- apiGroups: + - "" + resources: + - configmaps + - pods + - secrets + - services + verbs: + - get + - list + - watch +- apiGroups: + - "" + resources: + - namespaces + verbs: + - get +- apiGroups: + - "" + resources: + - pods + verbs: + - update +- apiGroups: + - "" + resources: + - events + verbs: + - create + - patch + - list +- apiGroups: + - coordination.k8s.io + resources: + - leases + resourceNames: + - startupstatus-nginx-ingress-leader-election + verbs: + - get + - update +- apiGroups: + - coordination.k8s.io + resources: + - leases + verbs: + - create +/-/-/-/ +# Source: nginx-ingress/templates/controller-rolebinding.yaml +kind: RoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: startupstatus-nginx-ingress + labels: + helm.sh/chart: nginx-ingress-2.3.0 + app.kubernetes.io/name: nginx-ingress + app.kubernetes.io/instance: startupstatus + app.kubernetes.io/version: "5.2.0" + app.kubernetes.io/managed-by: Helm + namespace: default +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: startupstatus-nginx-ingress +subjects: +- kind: ServiceAccount + name: startupstatus-nginx-ingress + namespace: default +/-/-/-/ +# Source: nginx-ingress/templates/controller-service.yaml +apiVersion: v1 +kind: Service +metadata: + name: startupstatus-nginx-ingress-controller + namespace: default + labels: + helm.sh/chart: nginx-ingress-2.3.0 + app.kubernetes.io/name: nginx-ingress + app.kubernetes.io/instance: startupstatus + app.kubernetes.io/version: "5.2.0" + app.kubernetes.io/managed-by: Helm +spec: + externalTrafficPolicy: Local + type: LoadBalancer + ports: + - port: 80 + targetPort: 80 + protocol: TCP + name: http + nodePort: + - port: 443 + targetPort: 443 + protocol: TCP + name: https + nodePort: + selector: + app.kubernetes.io/name: nginx-ingress + app.kubernetes.io/instance: startupstatus +/-/-/-/ +# Source: nginx-ingress/templates/controller-deployment.yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: startupstatus-nginx-ingress-controller + namespace: default + labels: + helm.sh/chart: nginx-ingress-2.3.0 + app.kubernetes.io/name: nginx-ingress + app.kubernetes.io/instance: startupstatus + app.kubernetes.io/version: "5.2.0" + app.kubernetes.io/managed-by: Helm +spec: + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/name: nginx-ingress + app.kubernetes.io/instance: startupstatus + template: + metadata: + labels: + app.kubernetes.io/name: nginx-ingress + app.kubernetes.io/instance: startupstatus + annotations: + prometheus.io/scrape: "true" + prometheus.io/port: "9113" + prometheus.io/scheme: "http" + spec: + volumes: [] + serviceAccountName: startupstatus-nginx-ingress + automountServiceAccountToken: true + securityContext: + seccompProfile: + type: RuntimeDefault + terminationGracePeriodSeconds: 30 + hostNetwork: false + dnsPolicy: ClusterFirst + containers: + - image: nginx/nginx-ingress:5.2.0 + name: nginx-ingress + imagePullPolicy: "IfNotPresent" + ports: + - name: http + containerPort: 80 + protocol: TCP + - name: https + containerPort: 443 + protocol: TCP + - name: prometheus + containerPort: 9113 + - name: readiness-port + containerPort: 8081 + - name: startup-port + containerPort: 9999 + readinessProbe: + httpGet: + path: /nginx-ready + port: readiness-port + periodSeconds: 1 + initialDelaySeconds: 0 + startupProbe: + httpGet: + path: / + port: startup-port + initialDelaySeconds: 7 + periodSeconds: 2 + timeoutSeconds: 3 + successThreshold: 1 + failureThreshold: 5 + resources: + requests: + cpu: 100m + memory: 128Mi + securityContext: + allowPrivilegeEscalation: false + readOnlyRootFilesystem: false + runAsUser: 101 #nginx + runAsNonRoot: true + capabilities: + drop: + - ALL + add: + - NET_BIND_SERVICE + volumeMounts: [] + env: + - name: POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + args: + + - -nginx-plus=false + - -nginx-reload-timeout=60000 + - -enable-app-protect=false + - -enable-app-protect-dos=false + - -nginx-configmaps=$(POD_NAMESPACE)/startupstatus-nginx-ingress + - -ingress-class=nginx + - -health-status=false + - -health-status-uri=/nginx-health + - -nginx-debug=false + - -log-level=info + - -log-format=glog + - -nginx-status=true + - -nginx-status-port=8080 + - -nginx-status-allow-cidrs=127.0.0.1 + - -report-ingress-status + - -external-service=startupstatus-nginx-ingress-controller + - -enable-leader-election=true + - -leader-election-lock-name=startupstatus-nginx-ingress-leader-election + - -enable-prometheus-metrics=true + - -prometheus-metrics-listen-port=9113 + - -prometheus-tls-secret= + - -enable-service-insight=false + - -service-insight-listen-port=9114 + - -service-insight-tls-secret= + - -enable-custom-resources=true + - -enable-snippets=false + - -disable-ipv6=false + - -enable-tls-passthrough=false + - -enable-cert-manager=false + - -enable-oidc=false + - -enable-external-dns=false + - -default-http-listener-port=80 + - -default-https-listener-port=443 + - -ready-status=true + - -ready-status-port=8081 + - -enable-latency-metrics=false + - -ssl-dynamic-reload=true + - -enable-telemetry-reporting=true + - -weight-changes-dynamic-reload=false +/-/-/-/ +# Source: nginx-ingress/templates/controller-ingress-class.yaml +apiVersion: networking.k8s.io/v1 +kind: IngressClass +metadata: + name: nginx + labels: + helm.sh/chart: nginx-ingress-2.3.0 + app.kubernetes.io/name: nginx-ingress + app.kubernetes.io/instance: startupstatus + app.kubernetes.io/version: "5.2.0" + app.kubernetes.io/managed-by: Helm +spec: + controller: nginx.org/ingress-controller +/-/-/-/ +# Source: nginx-ingress/templates/controller-configmap.yaml +/-/-/-/ +/-/-/-/ +# Source: nginx-ingress/templates/controller-lease.yaml +apiVersion: coordination.k8s.io/v1 +kind: Lease +metadata: + name: startupstatus-nginx-ingress-leader-election + namespace: default + labels: + helm.sh/chart: nginx-ingress-2.3.0 + app.kubernetes.io/name: nginx-ingress + app.kubernetes.io/instance: startupstatus + app.kubernetes.io/version: "5.2.0" + app.kubernetes.io/managed-by: Helm +--- diff --git a/charts/tests/helmunit_test.go b/charts/tests/helmunit_test.go index 208c7a6fea..94a8029982 100644 --- a/charts/tests/helmunit_test.go +++ b/charts/tests/helmunit_test.go @@ -5,6 +5,7 @@ package test import ( "os" "path/filepath" + "strings" "testing" "github.com/gkampitakis/go-snaps/snaps" @@ -130,6 +131,11 @@ func TestHelmNICTemplate(t *testing.T) { releaseName: "app-protect-waf-agentv2", namespace: "default", }, + "startupStatusValid": { + valuesFile: "testdata/startupstatus-valid.yaml", + releaseName: "startupstatus", + namespace: "default", + }, } // Path to the helm chart we will test @@ -155,3 +161,51 @@ func TestHelmNICTemplate(t *testing.T) { }) } } + +// Test for negative cases where helm template rendering should fail +func TestHelmNICTemplateNegative(t *testing.T) { + t.Parallel() + + negativeTests := map[string]struct { + valuesFile string + releaseName string + namespace string + expectedErrorMsg string + }{ + "startupStatusInvalid": { + valuesFile: "testdata/startupstatus-invalid.yaml", + releaseName: "startupstatus-invalid", + namespace: "default", + expectedErrorMsg: "port is required", + }, + } + + // Path to the helm chart we will test + helmChartPath, err := filepath.Abs("../nginx-ingress") + if err != nil { + t.Fatal("Failed to open helm chart path ../nginx-ingress") + } + + for testName, tc := range negativeTests { + t.Run(testName, func(t *testing.T) { + options := &helm.Options{ + KubectlOptions: k8s.NewKubectlOptions("", "", tc.namespace), + } + + if tc.valuesFile != "" { + options.ValuesFiles = []string{tc.valuesFile} + } + _, err := helm.RenderTemplateE(t, options, helmChartPath, tc.releaseName, make([]string, 0)) + + if err == nil { + t.Fatalf("Expected helm template to fail for invalid configuration, but it succeeded") + } + + if tc.expectedErrorMsg != "" && !strings.Contains(err.Error(), tc.expectedErrorMsg) { + t.Fatalf("Expected error to contain '%s', but got: %s", tc.expectedErrorMsg, err.Error()) + } + + t.Logf("Expected failure occurred: %s", err.Error()) + }) + } +} diff --git a/charts/tests/testdata/startupstatus-invalid.yaml b/charts/tests/testdata/startupstatus-invalid.yaml new file mode 100644 index 0000000000..d3902b4628 --- /dev/null +++ b/charts/tests/testdata/startupstatus-invalid.yaml @@ -0,0 +1,4 @@ +controller: + startupStatus: + enable: true + # All other required values missing diff --git a/charts/tests/testdata/startupstatus-valid.yaml b/charts/tests/testdata/startupstatus-valid.yaml new file mode 100644 index 0000000000..59c2a6dc26 --- /dev/null +++ b/charts/tests/testdata/startupstatus-valid.yaml @@ -0,0 +1,10 @@ +controller: + startupStatus: + enable: true + port: 9999 + path: "/" + initialDelaySeconds: 7 + periodSeconds: 2 + timeoutSeconds: 3 + successThreshold: 1 + failureThreshold: 5 diff --git a/examples/ingress-resources/startup-probe/README.md b/examples/ingress-resources/startup-probe/README.md new file mode 100644 index 0000000000..a747b4407e --- /dev/null +++ b/examples/ingress-resources/startup-probe/README.md @@ -0,0 +1,66 @@ +# Startup Probe Configuration for NGINX Ingress Controller + +This example demonstrates how to configure Kubernetes startup probes for the NGINX Ingress Controller using a dedicated endpoint that always returns HTTP 200. + +## Configuration + +### 1. Deploy the Always-200 Ingress + +Apply the startup probe Ingress resource that creates a dedicated endpoint: + +```shell +kubectl apply -f startup-probe-ingress.yaml +``` + +This Ingress uses `nginx.org/server-snippets` to: + +- Listen on port 9999 (dedicated startup probe port) +- Always return HTTP 200 with "ok" response + +### 2. Helm Chart Configuration + +Configure the startup probe in your Helm values: + +```yaml +controller: + enableSnippets: true # Enable custom NGINX configuration snippets + startupStatus: + enable: true + port: 9999 + path: / + initialDelaySeconds: 5 + periodSeconds: 1 + timeoutSeconds: 1 + successThreshold: 1 + failureThreshold: 30 +``` + +If enable is set to true then port and path are required. + +### 3. Install/Upgrade the Helm Chart + +Deploy or upgrade your NGINX Ingress Controller with startup probe enabled: + +```shell +helm upgrade --install nginx-ingress nginx-stable/nginx-ingress \ + --set controller.enableSnippets=true \ + --set controller.startupStatus.enable=true \ + --set controller.startupStatus.port=9999 \ + --set controller.startupStatus.path=/ +``` + +## Verification + +Check that the startup probe is working: + +```shell +# Check pod status +kubectl logs -n +>> "GET / HTTP/1.1" 200 2 "-" "kube-probe/1.33" "-" +``` + +```shell +# Check startup probe endpoint (from within the pod) +kubectl exec -it -n -- curl http://localhost:9999/ +>>ok% +``` diff --git a/examples/ingress-resources/startup-probe/startup-probe-ingress.yaml b/examples/ingress-resources/startup-probe/startup-probe-ingress.yaml new file mode 100644 index 0000000000..fbffb055b1 --- /dev/null +++ b/examples/ingress-resources/startup-probe/startup-probe-ingress.yaml @@ -0,0 +1,21 @@ +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: always-200-ingress + annotations: + nginx.org/server-snippets: | + listen 9999; + return 200 'ok'; +spec: + ingressClassName: nginx + rules: + - http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: dummy-service + port: + number: 80 + host: example.com