From 5cf6b44dd7abf4b652ee4f6dec2048a9dae0e11a Mon Sep 17 00:00:00 2001 From: bjee19 <139261241+bjee19@users.noreply.github.com> Date: Fri, 21 Feb 2025 10:18:23 -0800 Subject: [PATCH 01/22] Add documentation on running NGINX in debug mode (#215) Problem: Added support for running NGINX in debug mode in NGF's CP-DP split which changes the old way to run NGINX in debug mode. Solution: Update docs to show new way to run NGINX in debug mode. --- .../ngf/how-to/data-plane-configuration.md | 31 +++++++++++++------ 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/content/ngf/how-to/data-plane-configuration.md b/content/ngf/how-to/data-plane-configuration.md index fbd75d681..1ea88a8e2 100644 --- a/content/ngf/how-to/data-plane-configuration.md +++ b/content/ngf/how-to/data-plane-configuration.md @@ -317,19 +317,30 @@ To run NGINX Gateway Fabric with NGINX in debug mode, follow the [installation d Using Helm: Set `nginx.debug` to true. -Using Kubernetes Manifests: Under the `nginx` container of the deployment manifest, add `-c` and `rm -rf /var/run/nginx/*.sock && nginx-debug -g 'daemon off;'` -as arguments and add `/bin/sh` as the command. The deployment manifest should look something like this: +Using Kubernetes Manifests: In the deployment manifest, set the `spec.kubernetes.deployment.container.debug` field in the `NginxProxy` resource to true. -```text -... -- args: - - -c - - rm -rf /var/run/nginx/*.sock && nginx-debug -g 'daemon off;' - command: - - /bin/sh -... +If you want to change the NGINX mode after deploying NGINX Gateway Fabric, you can do so through the `NginxProxy` `spec.kubernetes.deployment.container.debug` field. + +The following command creates a basic `NginxProxy` configuration that both sets the NGINX log level to `debug` and runs NGINX in `debug` mode. + +```yaml +kubectl apply -f - <}} When modifying any `deployment` field in the `NginxProxy` resource, any corresponding NGINX instances will be restarted. {{< /note >}} + --- ## Configure PROXY protocol and RewriteClientIP settings From bca3f0c000f686e4cacb9e77d7aa7bdd04315e3f Mon Sep 17 00:00:00 2001 From: Saylor Berman Date: Mon, 3 Mar 2025 08:08:18 -0700 Subject: [PATCH 02/22] Update NGINX Plus secrets docs for NGF split (#235) Problem: With the new NGF architecture incoming, the process for setting up NGINX Plus is slightly different than before. Solution: Update the docs to remove unnecessary steps and add extra context around creating NGINX Plus Secrets. --- content/ngf/installation/nginx-plus-jwt.md | 63 ++++------------------ 1 file changed, 9 insertions(+), 54 deletions(-) diff --git a/content/ngf/installation/nginx-plus-jwt.md b/content/ngf/installation/nginx-plus-jwt.md index fc3241052..b94457b44 100644 --- a/content/ngf/installation/nginx-plus-jwt.md +++ b/content/ngf/installation/nginx-plus-jwt.md @@ -15,6 +15,8 @@ This requirement is part of F5’s broader licensing program and aligns with ind The JWT is required for validating your subscription and reporting telemetry data. For environments connected to the internet, telemetry is automatically sent to F5’s licensing endpoint. In offline environments, telemetry is routed through [NGINX Instance Manager](https://docs.nginx.com/nginx-instance-manager/). Usage is reported every hour and on startup whenever NGINX is reloaded. +{{< note >}} The following Secrets should be created in the same namespace as the NGINX Gateway Fabric control plane (default: nginx-gateway). The control plane will copy these Secrets into any namespaces where NGINX gets deployed. {{< /note >}} + --- ## Set up the JWT @@ -41,13 +43,13 @@ Provide the name of this Secret when installing NGINX Gateway Fabric: {{%tab name="Helm"%}} -Specify the Secret name using the `serviceAccount.imagePullSecret` or `serviceAccount.imagePullSecrets` helm value. +Specify the Secret name using the `nginx.imagePullSecret` or `nginx.imagePullSecrets` helm value. {{% /tab %}} {{%tab name="Manifests"%}} -Specify the Secret name in the `imagePullSecrets` field of the `nginx-gateway` ServiceAccount. +Specify the Secret name in the `nginx-docker-secret` command-line argument of the `nginx-gateway` container. {{% /tab %}} @@ -73,22 +75,6 @@ Specify the Secret name using the `nginx.usage.secretName` helm value. Specify the Secret name in the `--usage-report-secret` command-line flag on the `nginx-gateway` container. -You also need to define the proper volume mount to mount the Secret to the nginx container. If it doesn't already exist, add the following volume to the Deployment: - -```yaml -- name: nginx-plus-license - secret: - secretName: nplus-license -``` - -and the following volume mount to the `nginx` container: - -```yaml -- mountPath: /etc/nginx/license.jwt - name: nginx-plus-license - subPath: license.jwt -``` - {{% /tab %}} {{}} @@ -113,11 +99,7 @@ Specify the endpoint using the `nginx.usage.endpoint` helm value. {{%tab name="Manifests"%}} -Specify the endpoint in the `--usage-report-endpoint` command-line flag on the `nginx-gateway` container. You also need to add the following line to the `mgmt` block of the `nginx-includes-bootstrap` ConfigMap: - -```text -usage_report endpoint=; -``` +Specify the endpoint in the `--usage-report-endpoint` command-line flag on the `nginx-gateway` container. {{% /tab %}} @@ -153,33 +135,6 @@ Specify the CA Secret name using the `nginx.usage.caSecretName` helm value. Spec Specify the CA Secret name in the `--usage-report-ca-secret` command-line flag on the `nginx-gateway` container. Specify the client Secret name in the `--usage-report-client-ssl-secret` command-line flag on the `nginx-gateway` container. -You also need to define the proper volume mount to mount the Secrets to the nginx container. Add the following volume to the Deployment: - -```yaml -- name: nginx-plus-usage-certs - projected: - sources: - - secret: - name: nim-ca - - secret: - name: nim-client -``` - -and the following volume mounts to the `nginx` container: - -```yaml -- mountPath: /etc/nginx/certs-bootstrap/ - name: nginx-plus-usage-certs -``` - -Finally, in the `nginx-includes-bootstrap` ConfigMap, add the following lines to the `mgmt` block: - -```text -ssl_trusted_certificate /etc/nginx/certs-bootstrap/ca.crt; -ssl_certificate /etc/nginx/certs-bootstrap/tls.crt; -ssl_certificate_key /etc/nginx/certs-bootstrap/tls.key; -``` - {{% /tab %}} {{}} @@ -205,12 +160,12 @@ If using Helm, the `nginx.usage` values should be set as necessary: If using manifests, the following command-line options should be set as necessary on the `nginx-gateway` container: -- `--usage-report-secret` should be the name of the JWT Secret you created. Must exist in the same namespace that the NGINX Gateway Fabric control plane is running in (default namespace: nginx-gateway). By default this field is set to `nplus-license`. A [volume mount](#nginx-plus-secret) for this Secret is required for installation. -- `--usage-report-endpoint` is the endpoint to send the telemetry data to. This is optional, and by default is `product.connect.nginx.com`. Requires [extra configuration](#nim) if specified. +- `--usage-report-secret` should be the name of the JWT Secret you created. Must exist in the same namespace that the NGINX Gateway Fabric control plane is running in (default namespace: nginx-gateway). By default this field is set to `nplus-license`. +- `--usage-report-endpoint` is the endpoint to send the telemetry data to. This is optional, and by default is `product.connect.nginx.com`. - `--usage-report-resolver` is the nameserver used to resolve the NGINX Plus usage reporting endpoint. This is optional and used with NGINX Instance Manager. - `--usage-report-skip-verify` disables client verification of the NGINX Plus usage reporting server certificate. -- `--usage-report-ca-secret` is the name of the Secret containing the NGINX Instance Manager CA certificate. Must exist in the same namespace that the NGINX Gateway Fabric control plane is running in (default namespace: nginx-gateway). Requires [extra configuration](#nim-cert) if specified. -- `--usage-report-client-ssl-secret` is the name of the Secret containing the client certificate and key for authenticating with NGINX Instance Manager. Must exist in the same namespace that the NGINX Gateway Fabric control plane is running in (default namespace: nginx-gateway). Requires [extra configuration](#nim-cert) if specified. +- `--usage-report-ca-secret` is the name of the Secret containing the NGINX Instance Manager CA certificate. Must exist in the same namespace that the NGINX Gateway Fabric control plane is running in (default namespace: nginx-gateway). +- `--usage-report-client-ssl-secret` is the name of the Secret containing the client certificate and key for authenticating with NGINX Instance Manager. Must exist in the same namespace that the NGINX Gateway Fabric control plane is running in (default namespace: nginx-gateway). --- From 17cc6c68b6e573f02aacdb8223719be27a170539 Mon Sep 17 00:00:00 2001 From: Saylor Berman Date: Mon, 3 Mar 2025 17:04:24 -0700 Subject: [PATCH 03/22] Update NGF CLI doc for new feature (#246) Add new CLI field and update CLI name for the changes in the split feature. --- content/ngf/reference/cli-help.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/content/ngf/reference/cli-help.md b/content/ngf/reference/cli-help.md index be11a41b5..815676e2e 100644 --- a/content/ngf/reference/cli-help.md +++ b/content/ngf/reference/cli-help.md @@ -13,14 +13,14 @@ Learn about the commands available for the executable file of the NGINX Gateway --- -## Static mode +## Controller -This command configures NGINX for a single NGINX Gateway Fabric resource. +This command runs the NGINX Gateway Fabric control plane. *Usage*: ```shell - gateway static-mode [flags] + gateway controller [flags] ``` --- @@ -47,6 +47,7 @@ This command configures NGINX for a single NGINX Gateway Fabric resource. | _leader-election-disable_ | _bool_ | Disable leader election, which is used to avoid multiple replicas of the NGINX Gateway Fabric reporting the status of the Gateway API resources. If disabled, all replicas of NGINX Gateway Fabric will update the statuses of the Gateway API resources (Default: `false`). | | _leader-election-lock-name_ | _string_ | The name of the leader election lock. A lease object with this name will be created in the same namespace as the controller (Default: `"nginx-gateway-leader-election-lock"`). | | _product-telemetry-disable_ | _bool_ | Disable the collection of product telemetry (Default: `false`). | +| _nginx-docker-secret_ | _list_ | The name of the NGINX docker registry Secret(s). Must exist in the same namespace that the NGINX Gateway Fabric control plane is running in (default namespace: nginx-gateway). | | _usage-report-secret_ | _string_ | The name of the Secret containing the JWT for NGINX Plus usage reporting. Must exist in the same namespace that the NGINX Gateway Fabric control plane is running in (default namespace: nginx-gateway) | | _usage-report-endpoint_ | _string_ | The endpoint of the NGINX Plus usage reporting server. | | _usage-report-resolver_ | _string_ | The nameserver used to resolve the NGINX Plus usage reporting endpoint. Used with NGINX Instance Manager. | From 4548256243d14c23b710817b6c6a4087478bc2fc Mon Sep 17 00:00:00 2001 From: bjee19 <139261241+bjee19@users.noreply.github.com> Date: Wed, 5 Mar 2025 11:00:59 -0800 Subject: [PATCH 04/22] Update NGF documentation on prometheus metrics (#249) Update documentation on prometheus metrics. Problem: Because NGF now uses NGINX Agent to export NGINX metrics, we need to update our documentation on metrics available and the example grafana dashboard. Solution: Update the metrics. * Add feedback --- content/ngf/how-to/monitoring/prometheus.md | 47 +- ...hboard.json => ngf-grafana-dashboard.json} | 518 +++++++----------- 2 files changed, 244 insertions(+), 321 deletions(-) rename static/ngf/{grafana-dashboard.json => ngf-grafana-dashboard.json} (65%) diff --git a/content/ngf/how-to/monitoring/prometheus.md b/content/ngf/how-to/monitoring/prometheus.md index 37253b3d5..1580e3789 100644 --- a/content/ngf/how-to/monitoring/prometheus.md +++ b/content/ngf/how-to/monitoring/prometheus.md @@ -83,9 +83,44 @@ NGINX Gateway Fabric provides a variety of metrics for monitoring and analyzing ### NGINX/NGINX Plus metrics -NGINX metrics cover specific NGINX operations such as the total number of accepted client connections. For a complete list of available NGINX/NGINX Plus metrics, refer to the [NGINX Prometheus Exporter developer docs](https://github.com/nginx/nginx-prometheus-exporter#exported-metrics). - -These metrics use the `nginx_gateway_fabric` namespace and include the `class` label, indicating the NGINX Gateway class. For example, `nginx_gateway_fabric_connections_accepted{class="nginx"}`. +NGINX metrics include NGINX-specific data such as the total number of accepted client connections. These metrics are +collected through NGINX Agent and are reported by each NGINX Pod. + +NGINX Gateway Fabric currently supports a subset of all metrics available through NGINX OSS and Plus. Listed below are +the supported metrics along with a small accompanying description. + +Metrics provided by NGINX Open Source include: +- `nginx_http_connections`: NGINX-wide statistics describing HTTP connections. +- `nginx_http_requests`: The total number of client requests received from clients. + +In addition to the previous metrics provided by NGINX Open Source, NGINX Plus includes: +- `nginx_config_reloads`: The total number of NGINX config reloads. +- `nginx_http_response_status_responses_total`: The number of responses, grouped by status code range. +- `nginx_http_request_discarded_requests_total`: The total number of requests completed without sending a response. +- `nginx_http_request_processing_count_requests`: The number of client requests that are currently being processed. +- `nginx_http_request_byte_io_bytes_total`: The total number of HTTP byte IO. +- `nginx_http_upstream_keepalive_count_connections`: The current number of idle keepalive connections per HTTP upstream. +- `nginx_http_upstream_peer_byte_io_bytes_total`: The total number of byte IO per HTTP upstream peer. +- `nginx_http_upstream_peer_count_peers`: The current count of peers on the HTTP upstream grouped by state. +- `nginx_http_upstream_peer_fails_attempts`: The total number of unsuccessful attempts to communicate with the HTTP upstream peer. +- `nginx_http_upstream_peer_header_time_milliseconds`: The average time to get the response header from the HTTP upstream peer. +- `nginx_http_upstream_peer_health_checks_requests_total`: The total number of health check requests made to a HTTP upstream peer. +- `nginx_http_upstream_peer_requests_total`: The total number of client requests forwarded to the HTTP upstream peer. +- `nginx_http_upstream_peer_response_time_milliseconds`: The average time to get the full response from the HTTP upstream peer. +- `nginx_http_upstream_peer_responses_total`: The total number of responses obtained from the HTTP upstream peer grouped by status range. +- `nginx_http_upstream_peer_state_is_deployed`: Current state of an upstream peer in deployment. +- `nginx_http_upstream_peer_unavailables_requests_total`: Number of times the server became unavailable for client requests (“unavail”). +- `nginx_http_upstream_queue_limit_requests`: The maximum number of requests that can be in the queue at the same time. +- `nginx_http_upstream_queue_overflows_responses_total`: The total number of requests rejected due to the queue overflow. +- `nginx_http_upstream_queue_usage_requests`: The current number of requests in the queue. +- `nginx_http_upstream_zombie_count_is_deployed`: The current number of upstream peers removed from the group but still processing active client requests. +- `nginx_slab_page_free_pages`: The current number of free memory pages. +- `nginx_slab_page_usage_pages`: The current number of used memory pages. +- `nginx_slab_slot_allocations_total`: The number of attempts to allocate memory of specified size. +- `nginx_slab_slot_free_slots`: The current number of free memory slots. +- `nginx_slab_slot_usage_slots`: The current number of used memory slots. +- `nginx_ssl_certificate_verify_failures_certificates_total`: The total number of SSL certificate verification failures. +- `nginx_ssl_handshakes_total`: The total number of SSL handshakes. --- @@ -93,13 +128,9 @@ These metrics use the `nginx_gateway_fabric` namespace and include the `class` l Metrics specific to NGINX Gateway Fabric include: -- `nginx_reloads_total`: Counts successful NGINX reloads. -- `nginx_reload_errors_total`: Counts NGINX reload failures. -- `nginx_stale_config`: Indicates if NGINX Gateway Fabric couldn't update NGINX with the latest configuration, resulting in a stale version. -- `nginx_reloads_milliseconds`: Time in milliseconds for NGINX reloads. - `event_batch_processing_milliseconds`: Time in milliseconds to process batches of Kubernetes events. -All these metrics are under the `nginx_gateway_fabric` namespace and include a `class` label set to the Gateway class of NGINX Gateway Fabric. For example, `nginx_gateway_fabric_nginx_reloads_total{class="nginx"}`. +All these metrics are under the `nginx_gateway_fabric` namespace and include a `class` label set to the GatewayClass of NGINX Gateway Fabric. For example, `nginx_gateway_fabric_event_batch_processing_milliseconds_sum{class="nginx"}`. --- diff --git a/static/ngf/grafana-dashboard.json b/static/ngf/ngf-grafana-dashboard.json similarity index 65% rename from static/ngf/grafana-dashboard.json rename to static/ngf/ngf-grafana-dashboard.json index 0c3c40392..9af953ce1 100644 --- a/static/ngf/grafana-dashboard.json +++ b/static/ngf/ngf-grafana-dashboard.json @@ -21,7 +21,6 @@ "graphTooltip": 0, "id": 1, "links": [], - "liveNow": false, "panels": [ { "collapsed": false, @@ -31,7 +30,7 @@ "x": 0, "y": 0 }, - "id": 5, + "id": 13, "panels": [], "title": "Status", "type": "row" @@ -44,69 +43,79 @@ "fieldConfig": { "defaults": { "color": { - "mode": "thresholds" + "mode": "palette-classic" }, - "mappings": [ - { - "options": { - "0": { - "index": 0, - "text": "Down" - }, - "1": { - "index": 1, - "text": "Up" - } - }, - "type": "value" + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" } - ], + }, + "mappings": [], "thresholds": { "mode": "absolute", "steps": [ { - "color": "semi-dark-red", + "color": "green", "value": null }, { - "color": "#EAB839", - "value": 1 - }, - { - "color": "semi-dark-green", - "value": 1 + "color": "red", + "value": 80 } ] - }, - "unit": "none", - "unitScale": true + } }, "overrides": [] }, "gridPos": { - "h": 4, - "w": 6, + "h": 8, + "w": 12, "x": 0, "y": 1 }, - "id": 3, + "id": 12, "options": { - "colorMode": "background", - "graphMode": "none", - "justifyMode": "auto", - "orientation": "horizontal", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true }, - "showPercentChange": false, - "textMode": "auto", - "wideLayout": true + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } }, - "pluginVersion": "10.3.3", + "pluginVersion": "11.5.2", "targets": [ { "datasource": { @@ -115,38 +124,23 @@ }, "disableTextWrap": false, "editorMode": "builder", - "expr": "nginx_gateway_fabric_up{instance=~\"$instance\"}", + "expr": "up{instance=~\"$ngf_instance\"}", "fullMetaSearch": false, "includeNullMetadata": true, - "instant": false, "legendFormat": "", "range": true, "refId": "A", "useBackend": false } ], - "title": "NGINX Status for $instance", - "type": "stat" - }, - { - "collapsed": false, - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 5 - }, - "id": 6, - "panels": [], - "title": "Metrics", - "type": "row" + "title": "NGF Status", + "type": "timeseries" }, { "datasource": { "type": "prometheus", "uid": "${DS_PROMETHEUS}" }, - "description": "", "fieldConfig": { "defaults": { "color": { @@ -156,11 +150,12 @@ "axisBorderShow": false, "axisCenteredZero": false, "axisColorMode": "text", - "axisLabel": "Connections (rate)", + "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "line", - "fillOpacity": 10, + "fillOpacity": 0, "gradientMode": "none", "hideFrom": { "legend": false, @@ -170,7 +165,7 @@ "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, - "pointSize": 1, + "pointSize": 5, "scaleDistribution": { "type": "linear" }, @@ -191,21 +186,23 @@ { "color": "green", "value": null + }, + { + "color": "red", + "value": 80 } ] - }, - "unit": "reqps", - "unitScale": true + } }, "overrides": [] }, "gridPos": { - "h": 10, + "h": 8, "w": 12, - "x": 0, - "y": 6 + "x": 12, + "y": 1 }, - "id": 1, + "id": 14, "options": { "legend": { "calcs": [], @@ -214,10 +211,12 @@ "showLegend": true }, "tooltip": { + "hideZeros": false, "mode": "single", "sort": "none" } }, + "pluginVersion": "11.5.2", "targets": [ { "datasource": { @@ -225,34 +224,33 @@ "uid": "${DS_PROMETHEUS}" }, "disableTextWrap": false, - "editorMode": "code", - "expr": "irate(nginx_gateway_fabric_connections_accepted{instance=~\"$instance\"}[1m])", + "editorMode": "builder", + "expr": "up{instance=~\"$nginx_instance\"}", + "format": "time_series", "fullMetaSearch": false, - "includeNullMetadata": false, - "instant": false, - "interval": "", - "legendFormat": "{{instance}} accepted", + "includeNullMetadata": true, + "legendFormat": "", "range": true, "refId": "A", "useBackend": false - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "irate(nginx_gateway_fabric_connections_handled{instance=~\"$instance\"}[1m])", - "hide": false, - "instant": false, - "legendFormat": "{{instance}} handled", - "range": true, - "refId": "B" } ], - "title": "Processed Connections", + "title": "NGINX Status for All", "type": "timeseries" }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 9 + }, + "id": 6, + "panels": [], + "title": "Metrics", + "type": "row" + }, { "datasource": { "type": "prometheus", @@ -271,6 +269,7 @@ "axisLabel": "Connections", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "line", "fillOpacity": 10, "gradientMode": "none", @@ -306,16 +305,15 @@ } ] }, - "unit": "short", - "unitScale": true + "unit": "short" }, "overrides": [] }, "gridPos": { "h": 10, "w": 12, - "x": 12, - "y": 6 + "x": 0, + "y": 10 }, "id": 4, "options": { @@ -326,64 +324,83 @@ "showLegend": true }, "tooltip": { + "hideZeros": false, "mode": "single", "sort": "none" } }, + "pluginVersion": "11.5.2", "targets": [ { "datasource": { "type": "prometheus", "uid": "${DS_PROMETHEUS}" }, - "editorMode": "code", - "expr": "nginx_gateway_fabric_connections_active{instance=~\"$instance\"}", + "disableTextWrap": false, + "editorMode": "builder", + "exemplar": false, + "expr": "irate(nginx_http_connections_count{instance=~\"$nginx_instance\", nginx_connections_outcome=\"ACTIVE\"}[1m])", + "fullMetaSearch": false, + "includeNullMetadata": true, "instant": false, "legendFormat": "{{instance}} active", "range": true, - "refId": "A" + "refId": "A", + "useBackend": false }, { "datasource": { "type": "prometheus", "uid": "${DS_PROMETHEUS}" }, - "editorMode": "code", - "expr": "nginx_gateway_fabric_connections_reading{instance=~\"$instance\"}", + "disableTextWrap": false, + "editorMode": "builder", + "expr": "irate(nginx_http_connections_count{instance=~\"$nginx_instance\", nginx_connections_outcome=\"READING\"}[1m])", + "fullMetaSearch": false, "hide": false, + "includeNullMetadata": true, "instant": false, "legendFormat": "{{instance}} reading", "range": true, - "refId": "B" + "refId": "B", + "useBackend": false }, { "datasource": { "type": "prometheus", "uid": "${DS_PROMETHEUS}" }, - "editorMode": "code", - "expr": "nginx_gateway_fabric_connections_waiting{instance=~\"$instance\"}", + "disableTextWrap": false, + "editorMode": "builder", + "expr": "irate(nginx_http_connections_count{instance=~\"$nginx_instance\", nginx_connections_outcome=\"WAITING\"}[1m])", + "fullMetaSearch": false, "hide": false, + "includeNullMetadata": true, "instant": false, "legendFormat": "{{instance}} waiting", "range": true, - "refId": "C" + "refId": "C", + "useBackend": false }, { "datasource": { "type": "prometheus", "uid": "${DS_PROMETHEUS}" }, - "editorMode": "code", - "expr": "nginx_gateway_fabric_connections_writing{instance=~\"$instance\"}", + "disableTextWrap": false, + "editorMode": "builder", + "expr": "irate(nginx_http_connections_count{instance=~\"$nginx_instance\", nginx_connections_outcome=\"WRITING\"}[1m])", + "fullMetaSearch": false, "hide": false, + "includeNullMetadata": true, "instant": false, "legendFormat": "{{instance}} writing", "range": true, - "refId": "D" + "refId": "D", + "useBackend": false } ], - "title": "Active Connections", + "title": "NGINX Active Connections", "type": "timeseries" }, { @@ -403,8 +420,9 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "line", - "fillOpacity": 10, + "fillOpacity": 0, "gradientMode": "none", "hideFrom": { "legend": false, @@ -414,7 +432,7 @@ "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, - "pointSize": 1, + "pointSize": 5, "scaleDistribution": { "type": "linear" }, @@ -435,21 +453,23 @@ { "color": "green", "value": null + }, + { + "color": "red", + "value": 80 } ] - }, - "unit": "reqps", - "unitScale": true + } }, "overrides": [] }, "gridPos": { - "h": 8, - "w": 24, - "x": 0, - "y": 16 + "h": 10, + "w": 12, + "x": 12, + "y": 10 }, - "id": 2, + "id": 11, "options": { "legend": { "calcs": [], @@ -458,10 +478,12 @@ "showLegend": true }, "tooltip": { + "hideZeros": false, "mode": "single", "sort": "none" } }, + "pluginVersion": "11.5.2", "targets": [ { "datasource": { @@ -470,17 +492,29 @@ }, "disableTextWrap": false, "editorMode": "code", - "expr": "irate(nginx_gateway_fabric_http_requests_total{instance=~\"$instance\"}[1m])", + "expr": "irate(nginx_http_connections_total{instance=~\"$nginx_instance\", nginx_connections_outcome=\"ACCEPTED\"}[1m])", "fullMetaSearch": false, - "includeNullMetadata": false, - "instant": false, - "legendFormat": "{{instance}} total requests", + "includeNullMetadata": true, + "legendFormat": "{{instance}} accepted", "range": true, "refId": "A", "useBackend": false + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "expr": "irate(nginx_http_connections_total{instance=~\"$nginx_instance\", nginx_connections_outcome=\"HANDLED\"}[1m])", + "hide": false, + "instant": false, + "legendFormat": "{{instance}} handled", + "range": true, + "refId": "B" } ], - "title": "Total Requests", + "title": "NGINX Processed Connections", "type": "timeseries" }, { @@ -500,6 +534,7 @@ "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, + "barWidthFactor": 0.6, "drawStyle": "line", "fillOpacity": 10, "gradientMode": "none", @@ -535,17 +570,17 @@ } ] }, - "unitScale": true + "unit": "reqps" }, "overrides": [] }, "gridPos": { "h": 8, - "w": 12, + "w": 24, "x": 0, - "y": 24 + "y": 20 }, - "id": 8, + "id": 2, "options": { "legend": { "calcs": [], @@ -554,11 +589,12 @@ "showLegend": true }, "tooltip": { + "hideZeros": false, "mode": "single", "sort": "none" } }, - "pluginVersion": "10.3.3", + "pluginVersion": "11.5.2", "targets": [ { "datasource": { @@ -566,185 +602,24 @@ "uid": "${DS_PROMETHEUS}" }, "disableTextWrap": false, - "editorMode": "code", - "expr": "irate(nginx_gateway_fabric_nginx_reloads_total{instance=~\"$instance\"}[1m])", + "editorMode": "builder", + "expr": "irate(nginx_http_requests_total{instance=~\"$nginx_instance\"}[1m])", "fullMetaSearch": false, "includeNullMetadata": false, "instant": false, - "legendFormat": "{{instance}}", + "legendFormat": "{{instance}} total requests", "range": true, "refId": "A", "useBackend": false } ], - "title": "Total NGINX Reloads Rate", + "title": "Total Requests", "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "red", - "value": 1 - } - ] - }, - "unitScale": true - }, - "overrides": [] - }, - "gridPos": { - "h": 8, - "w": 6, - "x": 12, - "y": 24 - }, - "id": 9, - "options": { - "colorMode": "value", - "graphMode": "area", - "justifyMode": "auto", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "showPercentChange": false, - "textMode": "auto", - "wideLayout": true - }, - "pluginVersion": "10.3.3", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "disableTextWrap": false, - "editorMode": "builder", - "expr": "nginx_gateway_fabric_nginx_reload_errors_total{instance=~\"$instance\"}", - "fullMetaSearch": false, - "includeNullMetadata": true, - "instant": false, - "legendFormat": "{{instance}}", - "range": true, - "refId": "A", - "useBackend": false - } - ], - "title": "Total NGINX Reload Errors", - "type": "stat" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [ - { - "options": { - "0": { - "color": "semi-dark-green", - "index": 0, - "text": "Up to date" - }, - "1": { - "color": "semi-dark-red", - "index": 1, - "text": "Stale" - } - }, - "type": "value" - } - ], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "semi-dark-red", - "value": 1 - } - ] - }, - "unitScale": true - }, - "overrides": [] - }, - "gridPos": { - "h": 8, - "w": 6, - "x": 18, - "y": 24 - }, - "id": 10, - "options": { - "colorMode": "value", - "graphMode": "area", - "justifyMode": "auto", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "showPercentChange": false, - "textMode": "auto", - "wideLayout": true - }, - "pluginVersion": "10.3.3", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "disableTextWrap": false, - "editorMode": "builder", - "expr": "nginx_gateway_fabric_nginx_stale_config{instance=~\"$instance\"}", - "fullMetaSearch": false, - "includeNullMetadata": true, - "instant": false, - "legendFormat": "__auto", - "range": true, - "refId": "A", - "useBackend": false - } - ], - "title": "NGINX Config State", - "type": "stat" } ], + "preload": false, "refresh": "5s", - "schemaVersion": 39, + "schemaVersion": 40, "tags": [ "nginx-gateway-fabric" ], @@ -752,26 +627,45 @@ "list": [ { "current": { - "selected": false, - "text": "default", - "value": "default" + "text": "prometheus", + "value": "aeeumt3huyhogd" }, - "hide": 0, "includeAll": false, "label": "datasource", - "multi": false, "name": "DS_PROMETHEUS", "options": [], "query": "prometheus", - "queryValue": "", "refresh": 1, "regex": "", - "skipUrlSync": false, "type": "datasource" }, { "current": { - "selected": true, + "text": "All", + "value": [ + "$__all" + ] + }, + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "definition": "label_values(nginx_http_connections_total,instance)", + "includeAll": true, + "multi": true, + "name": "nginx_instance", + "options": [], + "query": { + "qryType": 1, + "query": "label_values(nginx_http_connections_total,instance)", + "refId": "PrometheusVariableQueryEditor-VariableQuery" + }, + "refresh": 1, + "regex": "", + "type": "query" + }, + { + "current": { "text": [ "All" ], @@ -783,33 +677,31 @@ "type": "prometheus", "uid": "${DS_PROMETHEUS}" }, - "definition": "label_values(nginx_gateway_fabric_up,instance)", - "hide": 0, + "definition": "label_values(nginx_gateway_fabric_event_batch_processing_milliseconds_sum,instance)", "includeAll": true, + "label": "ngf_instance", "multi": true, - "name": "instance", + "name": "ngf_instance", "options": [], "query": { "qryType": 1, - "query": "label_values(nginx_gateway_fabric_up,instance)", + "query": "label_values(nginx_gateway_fabric_event_batch_processing_milliseconds_sum,instance)", "refId": "PrometheusVariableQueryEditor-VariableQuery" }, "refresh": 1, "regex": "", - "skipUrlSync": false, - "sort": 0, "type": "query" } ] }, "time": { - "from": "now-15m", + "from": "now-5m", "to": "now" }, "timepicker": {}, "timezone": "", "title": "NGINX Gateway Fabric", "uid": "cdb1c6f6-7c77-4cee-a177-593f41364dbe", - "version": 1, + "version": 5, "weekStart": "" -} +} \ No newline at end of file From 658af5f8d2ff4b1d5c91b39fae0226fdcbb44a71 Mon Sep 17 00:00:00 2001 From: Saylor Berman Date: Tue, 11 Mar 2025 07:43:10 -0600 Subject: [PATCH 05/22] docs: NGF - add more context to Secret duplication (#262) Mention that users can update the original Secrets to propagate changes to duplicate Secrets. --- content/ngf/installation/nginx-plus-jwt.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/ngf/installation/nginx-plus-jwt.md b/content/ngf/installation/nginx-plus-jwt.md index b94457b44..b1422fd3c 100644 --- a/content/ngf/installation/nginx-plus-jwt.md +++ b/content/ngf/installation/nginx-plus-jwt.md @@ -15,7 +15,7 @@ This requirement is part of F5’s broader licensing program and aligns with ind The JWT is required for validating your subscription and reporting telemetry data. For environments connected to the internet, telemetry is automatically sent to F5’s licensing endpoint. In offline environments, telemetry is routed through [NGINX Instance Manager](https://docs.nginx.com/nginx-instance-manager/). Usage is reported every hour and on startup whenever NGINX is reloaded. -{{< note >}} The following Secrets should be created in the same namespace as the NGINX Gateway Fabric control plane (default: nginx-gateway). The control plane will copy these Secrets into any namespaces where NGINX gets deployed. {{< /note >}} +{{< note >}} The following Secrets should be created in the same namespace as the NGINX Gateway Fabric control plane (default: nginx-gateway). The control plane will copy these Secrets into any namespaces where NGINX gets deployed. If you need to update the Secrets, update the originals that you created in the control plane namespace, and the control plane will propagate those updates to all duplicated Secrets. {{< /note >}} --- From e95d5f28c654418cba8db516eb35e9d159281ed8 Mon Sep 17 00:00:00 2001 From: Saylor Berman Date: Tue, 22 Apr 2025 15:54:45 -0600 Subject: [PATCH 06/22] Update NGF cli doc for control/data plane split (#438) A few flags have been removed, and one new one has been added. --- content/ngf/reference/cli-help.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/content/ngf/reference/cli-help.md b/content/ngf/reference/cli-help.md index 815676e2e..a526ce149 100644 --- a/content/ngf/reference/cli-help.md +++ b/content/ngf/reference/cli-help.md @@ -33,7 +33,6 @@ This command runs the NGINX Gateway Fabric control plane. |-------------------------------------|----------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | _gateway-ctlr-name_ | _string_ | The name of the Gateway controller. The controller name must be in the form: `DOMAIN/PATH`. The controller's domain is `gateway.nginx.org`. | | _gatewayclass_ | _string_ | The name of the GatewayClass resource. Every NGINX Gateway Fabric must have a unique corresponding GatewayClass resource. | -| _gateway_ | _string_ | The namespaced name of the Gateway resource to use. Must be of the form: `NAMESPACE/NAME`. If not specified, the control plane will process all Gateways for the configured GatewayClass. Among them, it will choose the oldest resource by creation timestamp. If the timestamps are equal, it will choose the resource that appears first in alphabetical order by {namespace}/{name}. | | _nginx-plus_ | _bool_ | Enable support for NGINX Plus. | | _gateway-api-experimental-features_ | _bool_ | Enable the experimental features of Gateway API which are supported by NGINX Gateway Fabric. Requires the Gateway APIs installed from the experimental channel. | | _config_ | _string_ | The name of the NginxGateway resource to be used for this controller's dynamic configuration. Lives in the same namespace as the controller. | @@ -41,7 +40,6 @@ This command runs the NGINX Gateway Fabric control plane. | _metrics-disable_ | _bool_ | Disable exposing metrics in the Prometheus format (Default: `false`). | | _metrics-listen-port_ | _int_ | Sets the port where the Prometheus metrics are exposed. An integer between 1024 - 65535 (Default: `9113`) | | _metrics-secure-serving_ | _bool_ | Configures if the metrics endpoint should be secured using https. Note that this endpoint will be secured with a self-signed certificate (Default `false`). | -| _update-gatewayclass-status_ | _bool_ | Update the status of the GatewayClass resource (Default: `true`). | | _health-disable_ | _bool_ | Disable running the health probe server (Default: `false`). | | _health-port_ | _int_ | Set the port where the health probe server is exposed. An integer between 1024 - 65535 (Default: `8081`). | | _leader-election-disable_ | _bool_ | Disable leader election, which is used to avoid multiple replicas of the NGINX Gateway Fabric reporting the status of the Gateway API resources. If disabled, all replicas of NGINX Gateway Fabric will update the statuses of the Gateway API resources (Default: `false`). | @@ -55,6 +53,7 @@ This command runs the NGINX Gateway Fabric control plane. | _usage-report-ca-secret_ | _string_ | The name of the Secret containing the NGINX Instance Manager CA certificate. Must exist in the same namespace that the NGINX Gateway Fabric control plane is running in (default namespace: nginx-gateway) | | _usage-report-client-ssl-secret_ | _string_ | TThe name of the Secret containing the client certificate and key for authenticating with NGINX Instance Manager. Must exist in the same namespace that the NGINX Gateway Fabric control plane is running in (default namespace: nginx-gateway) | | _snippets-filters_ | _bool_ | Enable SnippetsFilters feature. SnippetsFilters allow inserting NGINX configuration into the generated NGINX config for HTTPRoute and GRPCRoute resources. | +| _nginx-scc_ | _string_ | The name of the SecurityContextConstraints to be used with the NGINX data plane Pods. Only applicable in OpenShift. | {{% /bootstrap-table %}} From 59dbd52a54b82e00b6906da9d69f27d36a150085 Mon Sep 17 00:00:00 2001 From: bjee19 <139261241+bjee19@users.noreply.github.com> Date: Tue, 29 Apr 2025 11:26:50 -0700 Subject: [PATCH 07/22] NGF: Update documentation on accessing nginx container (#453) Update documentation on accessing nginx container Problem: With our incoming changes to our control data plane split, the nginx container will no longer be in the NGF Pod. Thus all documentation on accessing the nginx container (logs, sending traffic, config...) need to be updated. Solution: Updated the documentation. Mainly, when sending traffic in the examples, the host and IP of the NGINX Service are recorded after the Gateway is deployed. Also updated a link in the NGINX Plus feature document to point away from the NGINX Prometheus exporter and to the internal document showing metrics. --- content/ngf/how-to/monitoring/dashboard.md | 4 +- content/ngf/how-to/monitoring/tracing.md | 16 ++- .../ngf/how-to/monitoring/troubleshooting.md | 122 ++++++++++++------ .../traffic-management/advanced-routing.md | 24 ++-- .../traffic-management/client-settings.md | 21 +-- .../traffic-management/https-termination.md | 29 ++--- .../ngf/how-to/traffic-management/mirror.md | 19 +-- .../redirects-and-rewrites.md | 24 ++-- .../request-response-headers.md | 20 +-- .../routing-traffic-to-your-app.md | 43 +++--- .../ngf/how-to/traffic-management/snippets.md | 25 ++-- .../traffic-management/tls-passthrough.md | 25 ++-- .../traffic-management/upstream-settings.md | 39 +++--- .../integrating-cert-manager.md | 2 +- .../securing-backend-traffic.md | 21 +-- .../installation/installing-ngf/manifests.md | 2 +- content/ngf/overview/nginx-plus.md | 2 +- 17 files changed, 260 insertions(+), 178 deletions(-) diff --git a/content/ngf/how-to/monitoring/dashboard.md b/content/ngf/how-to/monitoring/dashboard.md index fd16d9911..8019aa8a8 100644 --- a/content/ngf/how-to/monitoring/dashboard.md +++ b/content/ngf/how-to/monitoring/dashboard.md @@ -17,10 +17,10 @@ The NGINX Plus dashboard offers a real-time live activity monitoring interface t To access the dashboard: -1. Use port-forwarding to forward connections to port 8765 on your local machine to port 8765 on the NGINX Gateway Fabric pod (replace `` with the actual name of the pod). +1. Use port-forwarding to forward connections to port 8765 on your local machine to port 8765 on the NGINX Plus pod (replace `` with the actual name of the pod). ```shell - kubectl port-forward 8765:8765 -n nginx-gateway + kubectl port-forward 8765:8765 -n ``` 1. Open your browser to [http://127.0.0.1:8765/dashboard.html](http://127.0.0.1:8765/dashboard.html) to access the dashboard. diff --git a/content/ngf/how-to/monitoring/tracing.md b/content/ngf/how-to/monitoring/tracing.md index 34a0dfc60..db711b128 100644 --- a/content/ngf/how-to/monitoring/tracing.md +++ b/content/ngf/how-to/monitoring/tracing.md @@ -170,13 +170,6 @@ If you already have NGINX Gateway Fabric installed, then you can create the `Ngi kubectl edit gatewayclasses.gateway.networking.k8s.io nginx ``` -Save the public IP address and port of NGINX Gateway Fabric into shell variables: - -```text -GW_IP=XXX.YYY.ZZZ.III -GW_PORT= -``` - You can now create the application, route, and tracing policy. --- @@ -257,6 +250,15 @@ spec: EOF ``` +After creating the Gateway resource, NGINX Gateway Fabric will provision an NGINX Pod and Service fronting it to route traffic. + +Save the public IP address and port of the NGINX Service into shell variables: + +```text +GW_IP=XXX.YYY.ZZZ.III +GW_PORT= +``` + Check that traffic can flow to the application. {{< note >}} If you have a DNS record allocated for `cafe.example.com`, you can send the request directly to that hostname, without needing to resolve. {{< /note >}} diff --git a/content/ngf/how-to/monitoring/troubleshooting.md b/content/ngf/how-to/monitoring/troubleshooting.md index 4f8cf1e4f..009e64abc 100644 --- a/content/ngf/how-to/monitoring/troubleshooting.md +++ b/content/ngf/how-to/monitoring/troubleshooting.md @@ -80,7 +80,7 @@ LAST SEEN TYPE REASON OBJECT Getting shell access to containers allows developers and operators to view the environment of a running container, see its logs or diagnose any problems. To get shell access to the NGINX container, use `kubectl exec`: ```shell -kubectl exec -it -n nginx-gateway -c nginx -- /bin/sh +kubectl exec -it -n -- /bin/sh ``` --- @@ -104,7 +104,7 @@ You can see logs for a crashed or killed container by adding the `-p` flag to th To see logs for the data plane container: ```shell - kubectl -n nginx-gateway logs -c nginx + kubectl -n logs -c nginx ``` 1. Error Logs @@ -118,13 +118,13 @@ You can see logs for a crashed or killed container by adding the `-p` flag to th For the _nginx_ container you can `grep` for various [error](https://nginx.org/en/docs/ngx_core_module.html#error_log) logs. For example, to search for all logs logged at the `emerg` level: ```shell - kubectl -n nginx-gateway logs -c nginx | grep emerg + kubectl -n logs -c nginx | grep emerg ``` For example, if a variable is too long, NGINX may display such an error message: ```text - kubectl logs -n nginx-gateway ngf-nginx-gateway-fabric-bb8598998-jwk2m -c nginx | grep emerg + kubectl logs -n dev-env gateway-nginx-bb8598998-jwk2m -c nginx | grep emerg 2024/06/13 20:04:17 [emerg] 27#27: too long parameter, probably missing terminating """ character in /etc/nginx/conf.d/http.conf:78 ``` @@ -158,7 +158,7 @@ server { } ``` -Once a HTTPRoute with path matches and rules are defined, nginx.conf is updated accordingly to determine which location block will manage incoming requests. To demonstrate how `nginx.conf` is changed, create some resources: +Once an HTTPRoute with path matches and rules are defined, nginx.conf is updated accordingly to determine which location block will manage incoming requests. To demonstrate how `nginx.conf` is changed, create some resources: 1. A Gateway with single listener with the hostname `*.example.com` on port 80. 2. A simple `coffee` application. @@ -290,10 +290,6 @@ The configuration may change in future releases. This configuration is valid for Metrics can be useful to identify performance bottlenecks and pinpoint areas of high resource consumption within NGINX Gateway Fabric. To set up metrics collection, refer to the [Prometheus Metrics guide]({{< ref "prometheus.md" >}}). The metrics dashboard will help you understand problems with the way NGINX Gateway Fabric is set up or potential issues that could show up with time. -For example, metrics `nginx_reloads_total` and `nginx_reload_errors_total` offer valuable insights into the system's stability and reliability. A high `nginx_reloads_total` value indicates frequent updates or configuration changes, while a high `nginx_reload_errors_total` value suggests issues with the configuration or other problems preventing successful reloads. Monitoring these metrics helps identify and resolve configuration errors, ensuring consistent service reliability. - -In such situations, it's advisable to review the logs of both NGINX and NGINX Gateway containers for any potential error messages. Additionally, verify the configured resources to ensure they are in a valid state. - --- #### Access the NGINX Plus Dashboard @@ -336,46 +332,100 @@ To understand why the NGINX Gateway Fabric Pod has not started running or is not kubectl describe pod -n nginx-gateway ``` -The Pod description includes details about the image name, tags, current status, and environment variables. Verify that these details match your setup and cross-check with the events to ensure everything is functioning as expected. For example, the Pod below has two containers that are running and the events reflect the same. +The Pod description includes details about the image name, tags, current status, and environment variables. Verify that these details match your setup and cross-check with the events to ensure everything is functioning as expected. For example, the Pod below has the nginx-gateway container that is running and the events reflect the same. ```text Containers: nginx-gateway: - Container ID: containerd://06c97a9de938b35049b7c63e251418395aef65dd1ff996119362212708b79cab - Image: nginx-gateway-fabric - Image ID: docker.io/library/import-2024-06-13@sha256:1460d63bd8a352a6e455884d7ebf51ce9c92c512cb43b13e44a1c3e3e6a08918 - Ports: 9113/TCP, 8081/TCP - Host Ports: 0/TCP, 0/TCP + Container ID: containerd://492f380d5919ae2cdca0e009e7a7d5bf4092f8e1910f52d8951d58b73f125646 + Image: nginx-gateway-fabric:latest + Image ID: sha256:c034f1e5bde0490b1f2441e0e9b0bcfce5f2e259bb6210c55d4d67f808a74ecb + Ports: 8443/TCP, 9113/TCP, 8081/TCP + Host Ports: 0/TCP, 0/TCP, 0/TCP + SeccompProfile: RuntimeDefault + Args: + controller + --gateway-ctlr-name=gateway.nginx.org/nginx-gateway-controller + --gatewayclass=nginx + --config=my-release-config + --service=my-release-nginx-gateway-fabric + --agent-tls-secret=agent-tls + --metrics-port=9113 + --health-port=8081 + --leader-election-lock-name=my-release-nginx-gateway-fabric-leader-election State: Running - Started: Thu, 13 Jun 2024 11:47:46 -0600 + Started: Thu, 24 Apr 2025 10:57:16 -0700 Ready: True Restart Count: 0 Readiness: http-get http://:health/readyz delay=3s timeout=1s period=1s #success=1 #failure=3 Environment: - POD_IP: (v1:status.podIP) POD_NAMESPACE: nginx-gateway (v1:metadata.namespace) - POD_NAME: ngf-nginx-gateway-fabric-66dd665756-zh7d7 (v1:metadata.name) - nginx: - Container ID: containerd://c2f3684fd8922e4fac7d5707ab4eb5f49b1f76a48893852c9a812cd6dbaa2f55 - Image: nginx-gateway-fabric/nginx - Image ID: docker.io/library/import-2024-06-13@sha256:c9a02cb5665c6218373f8f65fc2c730f018d0ca652ae827cc913a7c6e9db6f45 - Ports: 80/TCP, 443/TCP - Host Ports: 0/TCP, 0/TCP - State: Running - Started: Thu, 13 Jun 2024 11:47:46 -0600 - Ready: True - Restart Count: 0 - Environment: + POD_NAME: my-release-nginx-gateway-fabric-b99bd5cdd-qzp5q (v1:metadata.name) + POD_UID: (v1:metadata.uid) + INSTANCE_NAME: (v1:metadata.labels['app.kubernetes.io/instance']) + IMAGE_NAME: nginx-gateway-fabric:latest + Mounts: + /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-5dg45 (ro) + /var/run/secrets/ngf from nginx-agent-tls (rw) Events: Type Reason Age From Message ---- ------ ---- ---- ------- - Normal Scheduled 40s default-scheduler Successfully assigned nginx-gateway/ngf-nginx-gateway-fabric-66dd665756-zh7d7 to kind-control-plane - Normal Pulled 40s kubelet Container image "nginx-gateway-fabric" already present on machine - Normal Created 40s kubelet Created container nginx-gateway - Normal Started 39s kubelet Started container nginx-gateway - Normal Pulled 39s kubelet Container image "nginx-gateway-fabric/nginx" already present on machine - Normal Created 39s kubelet Created container nginx - Normal Started 39s kubelet Started container nginx + Normal Scheduled 22s default-scheduler Successfully assigned nginx-gateway/my-release-nginx-gateway-fabric-b99bd5cdd-qzp5q to kind-control-plane + Normal Pulled 20s kubelet Container image "nginx-gateway-fabric:latest" already present on machine + Normal Created 20s kubelet Created container: nginx-gateway + Normal Started 20s kubelet Started container nginx-gateway +``` + +--- + +##### NGINX Pod is not running or ready + +To understand why the NGINX Pod has not started running or is not ready, check the state of the Pod to get detailed information about the current status and events happening in the Pod. To do this, use `kubectl describe`: + +```shell +kubectl describe pod -n +``` + +The Pod description includes details about the image name, tags, current status, and environment variables. Verify that these details match your setup and cross-check with the events to ensure everything is functioning as expected. For example, the Pod below has the nginx container that is running and the events reflect the same. + +```text +Containers: + nginx: + Container ID: containerd://0dd33fd358ba3b369de315be15b197e369342aba7aa8d3ea12e4455823fa90ce + Image: nginx-gateway-fabric/nginx:latest + Image ID: sha256:e5cb19bab49cbde6222df607a0946e1e00c1af767263b79ae36e4c69f8547f20 + Ports: 80/TCP, 9113/TCP + Host Ports: 0/TCP, 0/TCP + SeccompProfile: RuntimeDefault + State: Running + Started: Thu, 24 Apr 2025 10:57:36 -0700 + Ready: True + Restart Count: 0 + Environment: + Mounts: + /etc/nginx-agent from nginx-agent (rw) + /etc/nginx/conf.d from nginx-conf (rw) + /etc/nginx/includes from nginx-includes (rw) + /etc/nginx/main-includes from nginx-main-includes (rw) + /etc/nginx/secrets from nginx-secrets (rw) + /etc/nginx/stream-conf.d from nginx-stream-conf (rw) + /var/cache/nginx from nginx-cache (rw) + /var/lib/nginx-agent from nginx-agent-lib (rw) + /var/log/nginx-agent from nginx-agent-log (rw) + /var/run/nginx from nginx-run (rw) + /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-f9kph (ro) + /var/run/secrets/ngf from nginx-agent-tls (rw) + /var/run/secrets/ngf/serviceaccount from token (rw) +Events: + Type Reason Age From Message + ---- ------ ---- ---- ------- + Normal Scheduled 2m57s default-scheduler Successfully assigned default/gateway-nginx-85f7f6d7d-fx7q2 to kind-control-plane + Normal Pulled 2m54s kubelet Container image "nginx-gateway-fabric:latest" already present on machine + Normal Created 2m54s kubelet Created container: init + Normal Started 2m54s kubelet Started container init + Normal Pulled 2m53s kubelet Container image "nginx-gateway-fabric/nginx:latest" already present on machine + Normal Created 2m53s kubelet Created container: nginx + Normal Started 2m53s kubelet Started container nginx ``` --- diff --git a/content/ngf/how-to/traffic-management/advanced-routing.md b/content/ngf/how-to/traffic-management/advanced-routing.md index 1ca8e61ce..2709961e0 100644 --- a/content/ngf/how-to/traffic-management/advanced-routing.md +++ b/content/ngf/how-to/traffic-management/advanced-routing.md @@ -26,14 +26,6 @@ The goal is to create a set of rules that will result in client requests being s ## Before you begin - [Install]({{< ref "/ngf/installation/" >}}) NGINX Gateway Fabric. -- Save the public IP address and port of NGINX Gateway Fabric into shell variables: - - ```text - GW_IP=XXX.YYY.ZZZ.III - GW_PORT= - ``` - -{{< note >}} In a production environment, you should have a DNS record for the external IP address that is exposed, and it should refer to the hostname that the gateway will forward for. {{< /note >}} --- @@ -69,6 +61,16 @@ EOF ``` This gateway defines a single listener on port 80. Since no hostname is specified, this listener matches on all hostnames. +After creating the Gateway resource, NGINX Gateway Fabric will provision an NGINX Pod and Service fronting it to route traffic. + +Save the public IP address and port of the NGINX Service into shell variables: + + ```text + GW_IP=XXX.YYY.ZZZ.III + GW_PORT= + ``` + +{{< note >}}In a production environment, you should have a DNS record for the external IP address that is exposed, and it should refer to the hostname that the gateway will forward for.{{< /note >}} The [HTTPRoute](https://gateway-api.sigs.k8s.io/api-types/httproute/) is typically deployed by the [application developer](https://gateway-api.sigs.k8s.io/concepts/roles-and-personas/#roles-and-personas_1). To deploy the `coffee` HTTPRoute: @@ -154,7 +156,7 @@ This HTTPRoute has a few important properties: ### Send traffic to Coffee -Using the external IP address and port for NGINX Gateway Fabric, we can send traffic to our coffee applications. +Using the external IP address and port for the NGINX Service, we can send traffic to our coffee applications. {{< note >}} If you have a DNS record allocated for `cafe.example.com`, you can send the request directly to that hostname, without needing to resolve. {{< /note >}} @@ -269,7 +271,7 @@ The properties of this HTTPRoute include: ### Send traffic to Tea -Using the external IP address and port for NGINX Gateway Fabric, we can send traffic to our tea applications. +Using the external IP address and port for the NGINX Service, we can send traffic to our tea applications. {{< note >}} If you have a DNS record allocated for `cafe.example.com`, you can send the request directly to that hostname, without needing to resolve. {{< /note >}} @@ -303,7 +305,7 @@ This request should receive a response from the `tea-post` pod. Any other type o If you have any issues while sending traffic, try the following to debug your configuration and setup: -- Make sure you set the shell variables $GW_IP and $GW_PORT to the public IP and port of the NGINX Gateway Fabric service. Refer to the [Installation]({{< ref "/ngf/installation/" >}}) guides for more information. +- Make sure you set the shell variables $GW_IP and $GW_PORT to the public IP and port of the NGINX Service. Refer to the [Installation]({{< ref "/ngf/installation/" >}}) guides for more information. - Check the status of the Gateway: diff --git a/content/ngf/how-to/traffic-management/client-settings.md b/content/ngf/how-to/traffic-management/client-settings.md index 5ccc454cd..518f01bcc 100644 --- a/content/ngf/how-to/traffic-management/client-settings.md +++ b/content/ngf/how-to/traffic-management/client-settings.md @@ -39,14 +39,6 @@ For all the possible configuration options for `ClientSettingsPolicy`, see the [ ## Before you begin - [Install]({{< ref "/ngf/installation/" >}}) NGINX Gateway Fabric. -- Save the public IP address and port of NGINX Gateway Fabric into shell variables: - - ```text - GW_IP=XXX.YYY.ZZZ.III - GW_PORT= - ``` - - {{< note >}}In a production environment, you should have a DNS record for the external IP address that is exposed, and it should refer to the hostname that the gateway will forward for.{{< /note >}} - Create the coffee and tea example applications: @@ -59,6 +51,7 @@ For all the possible configuration options for `ClientSettingsPolicy`, see the [ ```yaml kubectl apply -f https://raw.githubusercontent.com/nginx/nginx-gateway-fabric/v{{< version-ngf >}}/examples/client-settings-policy/gateway.yaml ``` +After creating the Gateway resource, NGINX Gateway Fabric will provision an NGINX Pod and Service fronting it to route traffic. - Create HTTPRoutes for the coffee and tea applications: @@ -66,9 +59,19 @@ For all the possible configuration options for `ClientSettingsPolicy`, see the [ kubectl apply -f https://raw.githubusercontent.com/nginx/nginx-gateway-fabric/v{{< version-ngf >}}/examples/client-settings-policy/httproutes.yaml ``` +- Save the public IP address and port of the NGINX Service into shell variables: + + ```text + GW_IP=XXX.YYY.ZZZ.III + GW_PORT= + ``` + + {{< note >}}In a production environment, you should have a DNS record for the external IP address that is exposed, and it should refer to the hostname that the gateway will forward for.{{< /note >}} + + - Test the configuration: - You can send traffic to the coffee and tea applications using the external IP address and port for NGINX Gateway Fabric. + You can send traffic to the coffee and tea applications using the external IP address and port for the NGINX Service. Send a request to coffee: diff --git a/content/ngf/how-to/traffic-management/https-termination.md b/content/ngf/how-to/traffic-management/https-termination.md index bc4253098..7d6e4da62 100644 --- a/content/ngf/how-to/traffic-management/https-termination.md +++ b/content/ngf/how-to/traffic-management/https-termination.md @@ -20,21 +20,6 @@ In this guide, we will show how to configure HTTPS termination for your applicat ## Before you begin - [Install]({{< ref "/ngf/installation/" >}}) NGINX Gateway Fabric. -- Save the public IP address and port of NGINX Gateway Fabric into shell variables: - - ```text - GW_IP=XXX.YYY.ZZZ.III - GW_PORT= - ``` - - Save the ports of NGINX Gateway Fabric: - - ```text - GW_HTTP_PORT= - GW_HTTPS_PORT= - ``` - -{{< note >}}In a production environment, you should have a DNS record for the external IP address that is exposed, and it should refer to the hostname that the gateway will forward for.{{< /note >}} --- @@ -175,6 +160,18 @@ This gateway configures: - `http` listener for HTTP traffic - `https` listener for HTTPS traffic. It terminates TLS connections using the `cafe-secret` we created. +After creating the Gateway resource, NGINX Gateway Fabric will provision an NGINX Pod and Service fronting it to route traffic. + +Save the public IP address and ports of the NGINX Service into shell variables: + + ```text + GW_IP=XXX.YYY.ZZZ.III + GW_HTTP_PORT= + GW_HTTPS_PORT= + ``` + +{{< note >}}In a production environment, you should have a DNS record for the external IP address that is exposed, and it should refer to the hostname that the gateway will forward for.{{< /note >}} + To create the httproute resources, copy and paste the following into your terminal: ```yaml @@ -223,7 +220,7 @@ The first route issues a `requestRedirect` from the `http` listener on port 80 t ## Send traffic -Using the external IP address and port for NGINX Gateway Fabric, we can send traffic to our coffee application. +Using the external IP address and ports for the NGINX Service, we can send traffic to our coffee application. {{< note >}}If you have a DNS record allocated for `cafe.example.com`, you can send the request directly to that hostname, without needing to resolve.{{< /note >}} diff --git a/content/ngf/how-to/traffic-management/mirror.md b/content/ngf/how-to/traffic-management/mirror.md index 8ca7a5c2e..e6a5c0bd0 100644 --- a/content/ngf/how-to/traffic-management/mirror.md +++ b/content/ngf/how-to/traffic-management/mirror.md @@ -23,14 +23,6 @@ sent to the **coffee** application will also be sent to the **tea** application ## Before you begin - [Install]({{< ref "/ngf/installation/" >}}) NGINX Gateway Fabric. -- Save the public IP address and port of NGINX Gateway Fabric into shell variables: - - ```text - GW_IP=XXX.YYY.ZZZ.III - GW_PORT= - ``` - -{{< note >}}In a production environment, you should have a DNS record for the external IP address that is exposed, and it should refer to the hostname that the gateway will forward for.{{< /note >}} --- @@ -147,6 +139,17 @@ spec: EOF ``` +After creating the Gateway resource, NGINX Gateway Fabric will provision an NGINX Pod and Service fronting it to route traffic. + +Save the public IP address and port of the NGINX Service into shell variables: + + ```text + GW_IP=XXX.YYY.ZZZ.III + GW_PORT= + ``` + +{{< note >}}In a production environment, you should have a DNS record for the external IP address that is exposed, and it should refer to the hostname that the gateway will forward for.{{< /note >}} + Now create an HTTPRoute that defines a RequestMirror filter that copies all requests sent to `/coffee` to be sent to the **coffee** backend and mirrored to the **tea** backend. Use the following command: ```yaml diff --git a/content/ngf/how-to/traffic-management/redirects-and-rewrites.md b/content/ngf/how-to/traffic-management/redirects-and-rewrites.md index 9552d88f3..60df195f8 100644 --- a/content/ngf/how-to/traffic-management/redirects-and-rewrites.md +++ b/content/ngf/how-to/traffic-management/redirects-and-rewrites.md @@ -24,14 +24,6 @@ To see an example of a redirect using scheme and port, see the [HTTPS Terminatio ## Before you begin - [Install]({{< ref "/ngf/installation/" >}}) NGINX Gateway Fabric. -- Save the public IP address and port of NGINX Gateway Fabric into shell variables: - - ```text - GW_IP=XXX.YYY.ZZZ.III - GW_PORT= - ``` - -{{< note >}}In a production environment, you should have a DNS record for the external IP address that is exposed, and it should refer to the hostname that the gateway will forward for.{{< /note >}} --- @@ -60,6 +52,18 @@ spec: EOF ``` +After creating the Gateway resource, NGINX Gateway Fabric will provision an NGINX Pod and Service fronting it to route traffic. + +Save the public IP address and port of the NGINX Service into shell variables: + +```text +GW_IP=XXX.YYY.ZZZ.III +GW_PORT= +``` + +{{< note >}}In a production environment, you should have a DNS record for the external IP address that is exposed, and it should refer to the hostname that the gateway will forward for.{{< /note >}} + + --- ## URLRewrite example @@ -184,7 +188,7 @@ EOF ### Send traffic -Using the external IP address and port for NGINX Gateway Fabric, we can send traffic to our coffee application. +Using the external IP address and port for the NGINX Service, we can send traffic to our coffee application. {{< note >}}If you have a DNS record allocated for `cafe.example.com`, you can send the request directly to that hostname, without needing to resolve.{{< /note >}} @@ -431,7 +435,7 @@ EOF ### Send traffic -Using the external IP address and port for NGINX Gateway Fabric, we can send traffic to our tea and soda applications to verify the redirect is successful. We will use curl's `--include` option to print the response headers (we are interested in the `Location` header). +Using the external IP address and port for the NGINX Service, we can send traffic to our tea and soda applications to verify the redirect is successful. We will use curl's `--include` option to print the response headers (we are interested in the `Location` header). {{< note >}}If you have a DNS record allocated for `cafe.example.com`, you can send the request directly to that hostname, without needing to resolve.{{< /note >}} diff --git a/content/ngf/how-to/traffic-management/request-response-headers.md b/content/ngf/how-to/traffic-management/request-response-headers.md index c4820a46c..6d41a07d2 100644 --- a/content/ngf/how-to/traffic-management/request-response-headers.md +++ b/content/ngf/how-to/traffic-management/request-response-headers.md @@ -20,14 +20,6 @@ This guide describes how to configure the headers application to modify the head ## Before you begin - [Install]({{< ref "/ngf/installation/" >}}) NGINX Gateway Fabric. -- Save the public IP address and port of NGINX Gateway Fabric into shell variables: - - ```text - GW_IP=XXX.YYY.ZZZ.III - GW_PORT= - ``` - -{{< note >}} In a production environment, you should have a DNS record for the external IP address that is exposed, and it should refer to the hostname that the gateway will forward for .{{< /note >}} --- @@ -56,6 +48,18 @@ spec: EOF ``` +After creating the Gateway resource, NGINX Gateway Fabric will provision an NGINX Pod and Service fronting it to route traffic. + +Save the public IP address and port of the NGINX Service into shell variables: + +```text +GW_IP=XXX.YYY.ZZZ.III +GW_PORT= +``` + +{{< note >}} In a production environment, you should have a DNS record for the external IP address that is exposed, and it should refer to the hostname that the gateway will forward for .{{< /note >}} + + --- ## RequestHeaderModifier example diff --git a/content/ngf/how-to/traffic-management/routing-traffic-to-your-app.md b/content/ngf/how-to/traffic-management/routing-traffic-to-your-app.md index 8d405485d..904b21650 100644 --- a/content/ngf/how-to/traffic-management/routing-traffic-to-your-app.md +++ b/content/ngf/how-to/traffic-management/routing-traffic-to-your-app.md @@ -20,12 +20,6 @@ You can route traffic to your Kubernetes applications using the Gateway API and ## Before you begin - [Install]({{< ref "/ngf/installation/" >}}) NGINX Gateway Fabric. -- Save the public IP address and port of NGINX Gateway Fabric into shell variables: - - ```text - GW_IP=XXX.YYY.ZZZ.III - GW_PORT= - ``` --- @@ -106,19 +100,19 @@ service/coffee ClusterIP 198.51.100.1 80/TCP 77s ## Application architecture with NGINX Gateway Fabric -To route traffic to the **coffee** application, we will create a gateway and HTTPRoute. The following diagram shows the configuration we are creating in the next step: +To route traffic to the **coffee** application, we will create a Gateway and HTTPRoute. The following diagram shows the configuration we are creating in the next step: {{}} -We need a gateway to create an entry point for HTTP traffic coming into the cluster. The **cafe** gateway we are going to create will open an entry point to the cluster on port 80 for HTTP traffic. +We need a Gateway to create an entry point for HTTP traffic coming into the cluster. The **cafe** Gateway we are going to create will open an entry point to the cluster on port 80 for HTTP traffic. -To route HTTP traffic from the gateway to the **coffee** service, we need to create an HTTPRoute named **coffee** and attach it to the gateway. This HTTPRoute will have a single routing rule that routes all traffic to the hostname "cafe.example.com" from the gateway to the **coffee** service. +To route HTTP traffic from the Gateway to the **coffee** service, we need to create an HTTPRoute named **coffee** and attach it to the Gateway. This HTTPRoute will have a single routing rule that routes all traffic to the hostname "cafe.example.com" from the Gateway to the **coffee** service. -Once NGINX Gateway Fabric processes the **cafe** gateway and **coffee** HTTPRoute, it will configure its data plane (NGINX) to route all HTTP requests sent to "cafe.example.com" to the pods that the **coffee** service targets: +Once NGINX Gateway Fabric processes the **cafe** Gateway and **coffee** HTTPRoute, it will configure a data plane (NGINX) to route all HTTP requests sent to "cafe.example.com" to the pods that the **coffee** service targets: {{Traffic Flow}} -The **coffee** service is omitted from the diagram above because the NGINX Gateway Fabric routes directly to the pods that the **coffee** service targets. +The **coffee** service is omitted from the diagram above because the NGINX Pod routes directly to the pods that the **coffee** service targets. {{< note >}}In the diagrams above, all resources that are the responsibility of the cluster operator are shown in blue. The orange resources are the responsibility of the application developers. @@ -145,11 +139,22 @@ spec: EOF ``` -This gateway is associated with the NGINX Gateway Fabric through the **gatewayClassName** field. The default installation of NGINX Gateway Fabric creates a GatewayClass with the name **nginx**. NGINX Gateway Fabric will only configure gateways with a **gatewayClassName** of **nginx** unless you change the name via the `--gatewayclass` [command-line flag]({{< ref "/ngf/reference/cli-help.md#static-mode" >}}). +After creating the Gateway resource, NGINX Gateway Fabric will provision an NGINX Pod and Service fronting it to route traffic. + +Save the public IP address and port of the NGINX Service into shell variables: + + ```text + GW_IP=XXX.YYY.ZZZ.III + GW_PORT= + ``` + +{{< note >}}In a production environment, you should have a DNS record for the external IP address that is exposed, and it should refer to the hostname that the gateway will forward for.{{< /note >}} + +This Gateway is associated with NGINX Gateway Fabric through the **gatewayClassName** field. The default installation of NGINX Gateway Fabric creates a GatewayClass with the name **nginx**. NGINX Gateway Fabric will only configure Gateways with a **gatewayClassName** of **nginx** unless you change the name via the `--gatewayclass` [command-line flag]({{< ref "/ngf/reference/cli-help.md#static-mode" >}}). -We specify a [listener](https://gateway-api.sigs.k8s.io/references/spec/#gateway.networking.k8s.io/v1.Listener) on the gateway to open an entry point on the cluster. In this case, since the coffee application accepts HTTP requests, we create an HTTP listener, named **http**, that listens on port 80. +We specify a [listener](https://gateway-api.sigs.k8s.io/references/spec/#gateway.networking.k8s.io/v1.Listener) on the Gateway to open an entry point on the cluster. In this case, since the coffee application accepts HTTP requests, we create an HTTP listener, named **http**, that listens on port 80. -By default, gateways only allow routes (such as HTTPRoutes) to attach if they are in the same namespace as the gateway. If you want to change this behavior, you can set +By default, Gateways only allow routes (such as HTTPRoutes) to attach if they are in the same namespace as the Gateway. If you want to change this behavior, you can set the [**allowedRoutes**](https://gateway-api.sigs.k8s.io/references/spec/#gateway.networking.k8s.io/v1.AllowedRoutes) field. Next you will create the HTTPRoute by copying and pasting the following into your terminal: @@ -176,7 +181,7 @@ spec: EOF ``` -To attach the **coffee** HTTPRoute to the **cafe** gateway, we specify the gateway name in the [**parentRefs**](https://gateway-api.sigs.k8s.io/references/spec/#gateway.networking.k8s.io/v1.CommonRouteSpec) field. The attachment will succeed if the hostnames and protocol in the HTTPRoute are allowed by at least one of the gateway's listeners. +To attach the **coffee** HTTPRoute to the **cafe** Gateway, we specify the Gateway name in the [**parentRefs**](https://gateway-api.sigs.k8s.io/references/spec/#gateway.networking.k8s.io/v1.CommonRouteSpec) field. The attachment will succeed if the hostnames and protocol in the HTTPRoute are allowed by at least one of the Gateway's listeners. The [**hostnames**](https://gateway-api.sigs.k8s.io/references/spec/#gateway.networking.k8s.io/v1.HTTPRouteSpec) field allows you to list the hostnames that the HTTPRoute matches. In this case, incoming requests handled by the **http** listener with the HTTP host header "cafe.example.com" will match this HTTPRoute and will be routed according to the rules in the spec. @@ -186,9 +191,9 @@ The [**rules**](https://gateway-api.sigs.k8s.io/references/spec/#gateway.network ## Test the configuration -To test the configuration, we will send a request to the public IP and port of NGINX Gateway Fabric that you saved in the [Before you begin](#before-you-begin) section and verify that the response comes from one of the **coffee** pods. +To test the configuration, we will send a request to the public IP and port of the NGINX Service that you saved earlier after creating the Gateway resource and verify that the response comes from one of the **coffee** pods. -{{< note >}}Your clients should be able to resolve the domain name "cafe.example.com" to the public IP of the NGINX Gateway Fabric. In this guide we will simulate that using curl's `--resolve` option. {{< /note >}} +{{< note >}}Your clients should be able to resolve the domain name "cafe.example.com" to the public IP of the NGINX Service. In this guide we will simulate that using curl's `--resolve` option. {{< /note >}} First, let's send a request to the path "/": @@ -248,7 +253,7 @@ You should receive a 404 Not Found error: If you have any issues while testing the configuration, try the following to debug your configuration and setup: -- Make sure you set the shell variables $GW_IP and $GW_PORT to the public IP and port of the NGINX Gateway Fabric Service. Refer to the [Installation]({{< ref "/ngf/installation/" >}}) guides for more information. +- Make sure you set the shell variables $GW_IP and $GW_PORT to the public IP and port of the NGINX Service. Refer to the [Installation]({{< ref "/ngf/installation/" >}}) guides for more information. - Check the status of the gateway: @@ -345,7 +350,7 @@ If you have any issues while testing the configuration, try the following to deb - Check the generated nginx config: ```shell - kubectl exec -it -n nginx-gateway -c nginx -- nginx -T + kubectl exec -it -n -- nginx -T ``` The config should contain a server block with the server name "cafe.example.com" that listens on port 80. This server block should have a single location `/` that proxy passes to the coffee upstream: diff --git a/content/ngf/how-to/traffic-management/snippets.md b/content/ngf/how-to/traffic-management/snippets.md index 543c2b917..2c91deb93 100644 --- a/content/ngf/how-to/traffic-management/snippets.md +++ b/content/ngf/how-to/traffic-management/snippets.md @@ -64,15 +64,6 @@ We have outlined a few best practices to keep in mind when using `SnippetsFilter - Using Kubernetes manifests: set the `--snippets-filters` flag in the nginx-gateway container argument, add `snippetsfilters` to the RBAC rules with verbs `list` and `watch`, and add `snippetsfilters/status` to the RBAC rules with verb `update`. See this [example manifest](https://raw.githubusercontent.com/nginx/nginx-gateway-fabric/main/deploy/snippets-filters/deploy.yaml) for clarification. -- Save the public IP address and port of NGINX Gateway Fabric into shell variables: - - ```text - GW_IP= - GW_PORT= - ``` - - {{< note >}} In a production environment, you should have a DNS record for the external IP address that is exposed, and it should refer to the hostname that the gateway will forward for. {{< /note >}} - - Create the coffee and tea example applications: ```yaml @@ -85,6 +76,18 @@ We have outlined a few best practices to keep in mind when using `SnippetsFilter kubectl apply -f https://raw.githubusercontent.com/nginx/nginx-gateway-fabric/v{{< version-ngf >}}/examples/snippets-filter/gateway.yaml ``` +After creating the Gateway resource, NGINX Gateway Fabric will provision an NGINX Pod and Service fronting it to route traffic. + +- Save the public IP address and port of the NGINX Service into shell variables: + + ```text + GW_IP= + GW_PORT= + ``` + + {{< note >}} In a production environment, you should have a DNS record for the external IP address that is exposed, and it should refer to the hostname that the gateway will forward for. {{< /note >}} + + - Create HTTPRoutes for the coffee and tea applications: ```yaml @@ -93,7 +96,7 @@ We have outlined a few best practices to keep in mind when using `SnippetsFilter - Test the configuration: - You can send traffic to the coffee and tea applications using the external IP address and port for NGINX Gateway Fabric. + You can send traffic to the coffee and tea applications using the external IP address and port for the NGINX Service. Send a request to coffee: @@ -427,7 +430,7 @@ An example of an error from the NGINX Gateway Fabric `nginx-gateway` container l {"level":"error","ts":"2024-10-29T22:19:41Z","logger":"eventLoop.eventHandler","msg":"Failed to update NGINX configuration","batchID":156,"error":"failed to reload NGINX: reload unsuccessful: no new NGINX worker processes started for config version 141. Please check the NGINX container logs for possible configuration issues: context deadline exceeded","stacktrace":"github.com/nginx/nginx-gateway-fabric/internal/mode/static.(*eventHandlerImpl).HandleEventBatch\n\tgithub.com/nginx/nginx-gateway-fabric/internal/mode/static/handler.go:219\ngithub.com/nginx/nginx-gateway-fabric/internal/framework/events.(*EventLoop).Start.func1.1\n\tgithub.com/nginx/nginx-gateway-fabric/internal/framework/events/loop.go:74"} ``` -An example of an error from the NGINX Gateway Fabric `nginx` container logs: +An example of an error from the NGINX Pod's `nginx` container logs: ```text 2024/10/29 22:18:41 [emerg] 40#40: invalid number of arguments in "limit_req_zone" directive in /etc/nginx/includes/SnippetsFilter_http_default_rate-limiting-sf.conf:1 diff --git a/content/ngf/how-to/traffic-management/tls-passthrough.md b/content/ngf/how-to/traffic-management/tls-passthrough.md index 92f1c5385..52cf11f58 100644 --- a/content/ngf/how-to/traffic-management/tls-passthrough.md +++ b/content/ngf/how-to/traffic-management/tls-passthrough.md @@ -7,7 +7,7 @@ product: NGF docs: DOCS-000 --- -Learn how to use TLSRoutes to configure TLS Passthrough load-balancing with NGINX Gateway Fabric. +Learn how to use TLSRoutes to configure TLS passthrough load-balancing with NGINX Gateway Fabric. --- @@ -27,15 +27,7 @@ In this guide, we will show how to configure TLS passthrough for your applicatio ## Before you begin -- [Install]({{< ref "/ngf/installation/" >}}) NGINX Gateway Fabric with experimental features enabled. -- Save the public IP address and port of NGINX Gateway Fabric into shell variables: - - ```text - GW_IP=XXX.YYY.ZZZ.III - GW_TLS_PORT= - ``` - -{{< note >}} In a production environment, you should have a DNS record for the external IP address that is exposed, and it should refer to the hostname that the Gateway will forward for. {{< /note >}} +- [Install]({{< relref "/ngf/installation/" >}}) NGINX Gateway Fabric with experimental features enabled. --- @@ -171,6 +163,17 @@ This Gateway will configure NGINX Gateway Fabric to accept TLS connections on po {{< note >}}It is possible to add an HTTPS listener on the same port that terminates TLS connections so long as the hostname does not overlap with the TLS listener hostname.{{< /note >}} +After creating the Gateway resource, NGINX Gateway Fabric will provision an NGINX Pod and Service fronting it to route traffic. + +Save the public IP address and port of the NGINX Service into shell variables: + +```text +GW_IP=XXX.YYY.ZZZ.III +GW_TLS_PORT= +``` + +{{< note >}} In a production environment, you should have a DNS record for the external IP address that is exposed, and it should refer to the hostname that the Gateway will forward for. {{< /note >}} + Create a TLSRoute that attaches to the Gateway and routes requests to `app.example.com` to the `secure-app` Service: ```yaml @@ -199,7 +202,7 @@ EOF ## Send traffic -Using the external IP address and port for NGINX Gateway Fabric, send traffic to the `secure-app` application. +Using the external IP address and port for the NGINX Service, send traffic to the `secure-app` application. {{< note >}}If you have a DNS record allocated for `app.example.com`, you can send the request directly to that hostname, without needing to resolve.{{< /note >}} diff --git a/content/ngf/how-to/traffic-management/upstream-settings.md b/content/ngf/how-to/traffic-management/upstream-settings.md index 6fd92b620..8f99f3d2d 100644 --- a/content/ngf/how-to/traffic-management/upstream-settings.md +++ b/content/ngf/how-to/traffic-management/upstream-settings.md @@ -34,21 +34,7 @@ For all the possible configuration options for `UpstreamSettingsPolicy`, see the ## Before you begin -- [Install]({{< ref "/ngf/installation/" >}}) NGINX Gateway Fabric. -- Save the public IP address and port of NGINX Gateway Fabric into shell variables: - - ```text - GW_IP=XXX.YYY.ZZZ.III - GW_PORT= - ``` - -- Lookup the name of the NGINX Gateway Fabric pod and save into shell variable: - - ```text - NGF_POD_NAME= - ``` - - {{< note >}}In a production environment, you should have a DNS record for the external IP address that is exposed, and it should refer to the hostname that the gateway will forward for.{{< /note >}} +- [Install]({{< relref "/ngf/installation/" >}}) NGINX Gateway Fabric. --- @@ -160,6 +146,23 @@ spec: EOF ``` +After creating the Gateway resource, NGINX Gateway Fabric will provision an NGINX Pod and Service fronting it to route traffic. + +Save the public IP address and port of the NGINX Service into shell variables: + +```text +GW_IP=XXX.YYY.ZZZ.III +GW_PORT= +``` + +Lookup the name of the NGINX pod and save into shell variable: + +```text +NGINX_POD_NAME= +``` + +{{< note >}}In a production environment, you should have a DNS record for the external IP address that is exposed, and it should refer to the hostname that the gateway will forward for.{{< /note >}} + Create HTTPRoutes for the `coffee` and `tea` applications: ```yaml @@ -206,7 +209,7 @@ EOF Test the configuration: -You can send traffic to the `coffee` and `tea` applications using the external IP address and port for NGINX Gateway Fabric. +You can send traffic to the `coffee` and `tea` applications using the external IP address and port for the NGINX Service. Send a request to `coffee`: @@ -290,7 +293,7 @@ Events: Next, verify that the policy has been applied to the `coffee` and `tea` upstreams by inspecting the NGINX configuration: ```shell -kubectl exec -it -n nginx-gateway $NGF_POD_NAME -c nginx -- nginx -T +kubectl exec -it -n $NGINX_POD_NAME -- nginx -T ``` You should see the `zone` directive in the `coffee` and `tea` upstreams both specify the size `1m`: @@ -363,7 +366,7 @@ Events: Next, verify that the policy has been applied to the `coffee` upstreams, by inspecting the NGINX configuration: ```shell -kubectl exec -it -n nginx-gateway $NGF_POD_NAME -c nginx -- nginx -T +kubectl exec -it -n $NGINX_POD_NAME -- nginx -T ``` You should see that the `coffee` upstream has the `keepalive` directive set to 32: diff --git a/content/ngf/how-to/traffic-security/integrating-cert-manager.md b/content/ngf/how-to/traffic-security/integrating-cert-manager.md index 751e06329..ec46560e9 100644 --- a/content/ngf/how-to/traffic-security/integrating-cert-manager.md +++ b/content/ngf/how-to/traffic-security/integrating-cert-manager.md @@ -288,7 +288,7 @@ Request ID: e64c54a2ac253375ac085d48980f000a - The temporary HTTPRoute created by cert-manager routes the traffic between cert-manager and the Let's Encrypt server through NGINX Gateway Fabric. If the challenge is not successful, it may be useful to inspect the NGINX logs to see the ACME challenge requests. You should see something like the following: ```shell - kubectl logs -n nginx-gateway -c nginx + kubectl logs -n <...> 52.208.162.19 - - [15/Aug/2023:13:18:12 +0000] "GET /.well-known/acme-challenge/bXQn27Lenax2AJKmOOS523T-MWOKeFhL0bvrouNkUc4 HTTP/1.1" 200 87 "-" "cert-manager-challenges/v1.12.0 (linux/amd64) cert-manager/bd192c4f76dd883f9ee908035b894ffb49002384" 52.208.162.19 - - [15/Aug/2023:13:18:14 +0000] "GET /.well-known/acme-challenge/bXQn27Lenax2AJKmOOS523T-MWOKeFhL0bvrouNkUc4 HTTP/1.1" 200 87 "-" "cert-manager-challenges/v1.12.0 (linux/amd64) cert-manager/bd192c4f76dd883f9ee908035b894ffb49002384" diff --git a/content/ngf/how-to/traffic-security/securing-backend-traffic.md b/content/ngf/how-to/traffic-security/securing-backend-traffic.md index 212861e65..e8ce86ec8 100644 --- a/content/ngf/how-to/traffic-security/securing-backend-traffic.md +++ b/content/ngf/how-to/traffic-security/securing-backend-traffic.md @@ -28,14 +28,6 @@ In this guide, we will show how to specify the TLS configuration of the connecti ## Before you begin - [Install]({{< ref "/ngf/installation/" >}}) NGINX Gateway Fabric with experimental features enabled. -- Save the public IP address and port of NGINX Gateway Fabric into shell variables: - - ```text - GW_IP=XXX.YYY.ZZZ.III - GW_PORT= - ``` - -{{< note >}}In a production environment, you should have a DNS record for the external IP address that is exposed, and it should refer to the hostname that the gateway will forward for.{{< /note >}} --- @@ -187,11 +179,22 @@ spec: EOF ``` +After creating the Gateway resource, NGINX Gateway Fabric will provision an NGINX Pod and Service fronting it to route traffic. + +Save the public IP address and port of the NGINX Service into shell variables: + +```text +GW_IP=XXX.YYY.ZZZ.III +GW_PORT= +``` + +{{< note >}}In a production environment, you should have a DNS record for the external IP address that is exposed, and it should refer to the hostname that the gateway will forward for.{{< /note >}} + --- ## Send Traffic without backend TLS configuration -Using the external IP address and port for NGINX Gateway Fabric, we can send traffic to our secure-app application. To show what happens if we send plain HTTP traffic from NGF to our `secure-app`, let's try sending a request before we create the backend TLS configuration. +Using the external IP address and port for the NGINX Service, we can send traffic to our secure-app application. To show what happens if we send plain HTTP traffic from NGINX to our `secure-app`, let's try sending a request before we create the backend TLS configuration. {{< note >}}If you have a DNS record allocated for `secure-app.example.com`, you can send the request directly to that hostname, without needing to resolve.{{< /note >}} diff --git a/content/ngf/installation/installing-ngf/manifests.md b/content/ngf/installation/installing-ngf/manifests.md index 50384c205..a42ea9bd0 100644 --- a/content/ngf/installation/installing-ngf/manifests.md +++ b/content/ngf/installation/installing-ngf/manifests.md @@ -182,7 +182,7 @@ The output should look similar to this (note that the pod name will include a un ```text NAME READY STATUS RESTARTS AGE -nginx-gateway-5d4f4c7db7-xk2kq 2/2 Running 0 112s +nginx-gateway-5d4f4c7db7-xk2kq 1/1 Running 0 112s ``` --- diff --git a/content/ngf/overview/nginx-plus.md b/content/ngf/overview/nginx-plus.md index ae4de3643..47aa8d8cc 100644 --- a/content/ngf/overview/nginx-plus.md +++ b/content/ngf/overview/nginx-plus.md @@ -10,7 +10,7 @@ NGINX Gateway Fabric can use NGINX Open Source or NGINX Plus as its data plane. ## Benefits of NGINX Plus -- **Robust metrics**: A plethora of [additional Prometheus metrics](https://github.com/nginx/nginx-prometheus-exporter#metrics-for-nginx-plus) are available. +- **Robust metrics**: A plethora of [additional Prometheus metrics]({{< ref "/ngf/how-to/monitoring/prometheus.md#nginxnginx-plus-metrics" >}}) are available. - **Live activity monitoring**: The [NGINX Plus dashboard]({{< ref "/ngf/how-to/monitoring/dashboard.md" >}}) shows real-time metrics and information about your server infrastructure. - **Dynamic upstream configuration**: NGINX Plus can dynamically reconfigure upstream servers when applications in Kubernetes scale up and down, preventing the need for an NGINX reload. - **Support**: With an NGINX Plus license, you can take advantage of full [support](https://my.f5.com/manage/s/article/K000140156/) from NGINX, Inc. From 2c9d18828e03a9b7ee391dd9b613db9f1f8b0883 Mon Sep 17 00:00:00 2001 From: Ciara Stacke <18287516+ciarams87@users.noreply.github.com> Date: Tue, 29 Apr 2025 20:16:34 +0100 Subject: [PATCH 08/22] NGF: Update architecture overview (#450) * NGF: Update architecture overview * Apply suggestions from code review Co-authored-by: Saylor Berman * Review feedback * Improve diagrams * Final feedback --------- Co-authored-by: Saylor Berman --- content/ngf/overview/gateway-architecture.md | 354 ++++++++++++++++--- static/ngf/img/ngf-high-level.png | Bin 138656 -> 0 bytes static/ngf/img/ngf-pod.png | Bin 131533 -> 0 bytes 3 files changed, 305 insertions(+), 49 deletions(-) delete mode 100644 static/ngf/img/ngf-high-level.png delete mode 100644 static/ngf/img/ngf-pod.png diff --git a/content/ngf/overview/gateway-architecture.md b/content/ngf/overview/gateway-architecture.md index 7426c67c1..613fafa03 100644 --- a/content/ngf/overview/gateway-architecture.md +++ b/content/ngf/overview/gateway-architecture.md @@ -24,87 +24,345 @@ NGINX Gateway Fabric is an open source project that provides an implementation o For a list of supported Gateway API resources and features, see the [Gateway API Compatibility]({{< ref "/ngf/overview/gateway-api-compatibility.md" >}}) documentation. -We have more information regarding our [design principles](https://github.com/nginx/nginx-gateway-fabric/blob/v{{< version-ngf >}}/docs/developer/design-principles.md) in the project's GitHub repository. +NGINX Gateway Fabric separates the control plane and data plane into distinct deployments. This architectural separation enhances scalability, security, and operational isolation between the two components. + +The control plane interacts with the Kubernetes API, watching for Gateway API resources. When a new Gateway resource is provisioned, it dynamically creates and manages a corresponding NGINX data plane Deployment and Service. This ensures that the system can adapt to changes in the cluster state seamlessly. + +Each NGINX data plane pod consists of an NGINX container integrated with the [NGINX agent](https://github.com/nginx/agent). The agent securely communicates with the control plane using gRPC. The control plane translates Gateway API resources into NGINX configurations and sends these configurations to the agent to ensure consistent traffic management. + +This design enables centralized management of multiple Gateways while ensuring that each NGINX instance stays aligned with the cluster's current configuration. Labels, annotations, and infrastructure settings such as service type or replica count can be specified globally via the Helm chart or customized per Gateway using the enhanced NginxProxy CRD and the Gateway's `infrastructure` section. + +We have more information regarding our [design principles](https://github.com/nginx/nginx-gateway-fabric/blob/v1.6.1/docs/developer/design-principles.md) in the project's GitHub repository. --- -## NGINX Gateway Fabric at a high level +## NGINX Gateway Fabric Deployment Model and Architectural Overview -This figure depicts an example of NGINX Gateway Fabric exposing two web applications within a Kubernetes cluster to clients on the internet: +The NGINX Gateway Fabric architecture separates the control plane and data plane into distinct and independent Deployments, ensuring enhanced security, flexibility, and resilience. -{{< img src="/ngf/img/ngf-high-level.png" alt="" >}} +### Control Plane: Centralized Management -{{< note >}} The figure does not show many of the necessary Kubernetes resources the Cluster Operators and Application Developers need to create, like deployment and services. {{< /note >}} +The control plane operates as a Deployment, serving as a [Kubernetes controller](https://kubernetes.io/docs/concepts/architecture/controller/) built with the [controller-runtime](https://github.com/kubernetes-sigs/controller-runtime) library. It manages all aspects of resource provisioning and configuration for the NGINX data planes by watching Gateway API resources and other Kubernetes objects such as Services, Endpoints, and Secrets. -The figure shows: +Key functionalities include: -- A _Kubernetes cluster_. -- Users _Cluster Operator_, _Application Developer A_ and _Application Developer B_. These users interact with the cluster through the Kubernetes API by creating Kubernetes objects. -- _Clients A_ and _Clients B_ connect to _Applications A_ and _B_, respectively, which they have deployed. -- The _NGF Pod_, [deployed by _Cluster Operator_]({{< ref "/ngf/installation">}}) in the namespace _nginx-gateway_. For scalability and availability, you can have multiple replicas. This pod consists of two containers: `NGINX` and `NGF`. The _NGF_ container interacts with the Kubernetes API to retrieve the most up-to-date Gateway API resources created within the cluster. It then dynamically configures the _NGINX_ container based on these resources, ensuring proper alignment between the cluster state and the NGINX configuration. -- _Gateway AB_, created by _Cluster Operator_, requests a point where traffic can be translated to Services within the cluster. This Gateway includes a listener with a hostname `*.example.com`. Application Developers have the ability to attach their application's routes to this Gateway if their application's hostname matches `*.example.com`. -- _Application A_ with two pods deployed in the _applications_ namespace by _Application Developer A_. To expose the application to its clients (_Clients A_) via the host `a.example.com`, _Application Developer A_ creates _HTTPRoute A_ and attaches it to `Gateway AB`. -- _Application B_ with one pod deployed in the _applications_ namespace by _Application Developer B_. To expose the application to its clients (_Clients B_) via the host `b.example.com`, _Application Developer B_ creates _HTTPRoute B_ and attaches it to `Gateway AB`. -- _Public Endpoint_, which fronts the _NGF_ pod. This is typically a TCP load balancer (cloud, software, or hardware) or a combination of such load balancer with a NodePort service. _Clients A_ and _B_ connect to their applications via the _Public Endpoint_. +- Dynamic provisioning: When a new Gateway resource is created, the control plane automatically provisions a dedicated NGINX Deployment and exposes it using a Service. +- Configuration management: Kubernetes and Gateway API resources are translated into NGINX configurations, which are securely delivered to the data plane pods via a gRPC connection to the NGINX Agent. +- Secure communication: By default, the gRPC connection uses self-signed certificates generated during installation. Integration with [cert-manager](https://cert-manager.io/) is also supported for optional certificate management. -The yellow and purple arrows represent connections related to the client traffic, and the black arrows represent access to the Kubernetes API. The resources within the cluster are color-coded based on the user responsible for their creation. +### Data Plane: Autonomous Traffic Management -For example, the Cluster Operator is denoted by the color green, indicating they create and manage all the green resources. +Each NGINX data plane pod is provisioned as an independent Deployment containing an `nginx` container. This container runs both the `nginx` process and the [NGINX agent](https://github.com/nginx/agent), which is responsible for: ---- +- Applying configurations: The agent receives updates from the control plane and applies them to the NGINX instance. +- Handling reloads: NGINX Agent handles configuration reconciliation and reloading NGINX, eliminating the need for shared volumes or Unix signals between the control plane and data plane pods. + +With this design, multiple NGINX data planes can be managed by a single control plane, enabling fine-grained, Gateway-specific control and isolation. + +### Gateway Resource Management -## The NGINX Gateway Fabric pod +The architecture supports flexible operation and isolation across multiple Gateways: -NGINX Gateway Fabric consists of two containers: +- Concurrent Gateways: Multiple Gateway objects can run simultaneously within a single installation. +- 1:1 resource mapping: Each Gateway resource corresponds uniquely to a dedicated data plane deployment, ensuring clear delineation of ownership and operational segregation. -1. `nginx`: the data plane. Consists of an NGINX master process and NGINX worker processes. The master process controls the worker processes. The worker processes handle the client traffic and load balance traffic to the backend applications. -1. `nginx-gateway`: the control plane. Watches Kubernetes objects and configures NGINX. +### Resilience and Fault Isolation -These containers are deployed in a single pod as a Kubernetes Deployment. +One of the primary advantages of this architecture is enhanced operational resilience and fault isolation: -The `nginx-gateway`, or the control plane, is a [Kubernetes controller](https://kubernetes.io/docs/concepts/architecture/controller/), written with the [controller-runtime](https://github.com/kubernetes-sigs/controller-runtime) library. It watches Kubernetes objects (services, endpoints, secrets, and Gateway API CRDs), translates them to NGINX configuration, and configures NGINX. +#### Control Plane Resilience -This configuration happens in two stages: +In the event of a control plane failure or downtime: +- Existing data plane pods continue serving traffic using their last-valid cached configurations. +- Updates to routes or Gateways are temporarily paused, but stable traffic delivery continues without degradation. +- Recovery restores functionality, resynchronizing configuration updates seamlessly. -1. NGINX configuration files are written to the NGINX configuration volume shared by the `nginx-gateway` and `nginx` containers. -1. The control plane reloads the NGINX process. +#### Data Plane Resilience -This is possible because the two containers [share a process namespace](https://kubernetes.io/docs/tasks/configure-pod-container/share-process-namespace/), allowing the NGINX Gateway Fabric process to send signals to the NGINX main process. +If a data plane pod encounters an outage or restarts: +- Only routes tied to the specific linked Gateway object experience brief disruptions. +- Configurations automatically resynchronize with the data plane upon pod restart, minimizing the scope of impact. +- Other data plane pods remain unaffected and continue serving traffic normally. -The following diagram represents the connections, relationships and interactions between process with the `nginx` and `nginx-gateway` containers, as well as external processes/entities. +This split architecture ensures operational boundaries between the control plane and data plane, delivering improved scalability, security, and robustness while minimizing risks associated with failures in either component. -{{< img src="/ngf/img/ngf-pod.png" alt="" >}} +--- + +## High-Level Example of NGINX Gateway Fabric in Action + +This figure depicts an example of NGINX Gateway Fabric exposing three web applications within a Kubernetes cluster to clients on the internet: + +```mermaid +graph LR + %% Nodes and Relationships + subgraph KubernetesCluster[Kubernetes Cluster] + + subgraph applications2[Namespace: applications2] + + subgraph DataplaneComponentsC[Dataplane Components] + GatewayC[Gateway C
Listener: *.other-example.com] + + subgraph NGINXPodC[NGINX Pod] + subgraph NGINXContainerC[NGINX Container] + NGINXProcessC(NGINX) + NGINXAgentC(NGINX Agent) + end + end + end + + subgraph HTTPRouteCAndApplicationC[HTTPRoute C and Application C] + HTTPRouteC[HTTPRoute C
Host: c.other-example.com] + ApplicationC[Application C
Pods: 1] + end + + end + + subgraph nginx-gateway[Namespace: nginx-gateway] + NGFPod[NGF Pod] + end + + subgraph applications1[Namespace: applications] + + subgraph DataplaneComponentsAB[Dataplane Components] + GatewayAB[Gateway AB
Listener: *.example.com] + + subgraph NGINXPodAB[NGINX Pod] + subgraph NGINXContainerAB[NGINX Container] + NGINXProcessAB(NGINX) + NGINXAgentAB(NGINX Agent) + end + end + end + + subgraph HTTPRouteBAndApplicationB[HTTPRoute B and Application B] + HTTPRouteB[HTTPRoute B
Host: b.example.com] + ApplicationB[Application B
Pods: 1] + end + + subgraph HTTPRouteAAndApplicationA[HTTPRoute A and Application A] + HTTPRouteA[HTTPRoute A
Host: a.example.com] + ApplicationA[Application AB
Pods: 2] + end + end + + KubernetesAPI[Kubernetes API] + end + + subgraph Users[Users] + ClusterOperator[Cluster Operator] + AppDevA[Application Developer A] + AppDevB[Application Developer B] + AppDevC[Application Developer C] + end + + subgraph Clients[Clients] + ClientsA[Clients A] + ClientsB[Clients B] + ClientsC[Clients C] + end + + subgraph "Public Endpoints" + PublicEndpointAB[Public Endpoint AB
TCP Load Balancer/NodePort] + PublicEndpointC[Public Endpoint C
TCP Load Balancer/NodePort] + end + + %% Updated Traffic Flow + ClientsA == a.example.com ==> PublicEndpointAB + ClientsB == b.example.com ==> PublicEndpointAB + ClientsC == c.other-example.com ==> PublicEndpointC + + PublicEndpointAB ==> NGINXProcessAB + PublicEndpointC ==> NGINXProcessC + NGINXProcessAB ==> ApplicationA + NGINXProcessAB ==> ApplicationB + NGINXProcessC ==> ApplicationC + + %% Kubernetes Configuration Flow + HTTPRouteA --> GatewayAB + HTTPRouteB --> GatewayAB + HTTPRouteC --> GatewayC + + NGFPod --> KubernetesAPI + NGFPod --gRPC--> NGINXAgentAB + NGINXAgentAB --> NGINXProcessAB + NGFPod --gRPC--> NGINXAgentC + NGINXAgentC --> NGINXProcessC + + ClusterOperator --> KubernetesAPI + AppDevA --> KubernetesAPI + AppDevB --> KubernetesAPI + AppDevC --> KubernetesAPI + + %% Styling + style ClusterOperator fill:#66CDAA,stroke:#333,stroke-width:2px + style GatewayAB fill:#66CDAA,stroke:#333,stroke-width:2px + style GatewayC fill:#66CDAA,stroke:#333,stroke-width:2px + style NGFPod fill:#66CDAA,stroke:#333,stroke-width:2px + + style NGINXProcessAB fill:#66CDAA,stroke:#333,stroke-width:2px + style NGINXProcessC fill:#66CDAA,stroke:#333,stroke-width:2px + + style KubernetesAPI fill:#9370DB,stroke:#333,stroke-width:2px + + style HTTPRouteAAndApplicationA fill:#E0FFFF,stroke:#333,stroke-width:2px + style HTTPRouteBAndApplicationB fill:#E0FFFF,stroke:#333,stroke-width:2px + + style AppDevA fill:#FFA07A,stroke:#333,stroke-width:2px + style HTTPRouteA fill:#FFA07A,stroke:#333,stroke-width:2px + style ApplicationA fill:#FFA07A,stroke:#333,stroke-width:2px + style ClientsA fill:#FFA07A,stroke:#333,stroke-width:2px + + style AppDevB fill:#87CEEB,stroke:#333,stroke-width:2px + style HTTPRouteB fill:#87CEEB,stroke:#333,stroke-width:2px + style ApplicationB fill:#87CEEB,stroke:#333,stroke-width:2px + style ClientsB fill:#87CEEB,stroke:#333,stroke-width:2px + + style AppDevC fill:#FFC0CB,stroke:#333,stroke-width:2px + style HTTPRouteC fill:#FFC0CB,stroke:#333,stroke-width:2px + style ApplicationC fill:#FFC0CB,stroke:#333,stroke-width:2px + style ClientsC fill:#FFC0CB,stroke:#333,stroke-width:2px + + style PublicEndpointAB fill:#FFD700,stroke:#333,stroke-width:2px + style PublicEndpointC fill:#FFD700,stroke:#333,stroke-width:2px + + %% Styling + classDef dashedSubgraph stroke-dasharray: 5, 5; + + %% Assign Custom Style Classes + class DataplaneComponentsAB dashedSubgraph; + class DataplaneComponentsC dashedSubgraph; +``` + +{{< note >}} The figure does not show many of the necessary Kubernetes resources the Cluster Operators and Application Developers need to create, like deployment and services. {{< /note >}} + +The figure shows: + +- A _Kubernetes cluster_. +- Users _Cluster Operator_, _Application Developer A_, _B_ and _C_. These users interact with the cluster through the Kubernetes API by creating Kubernetes objects. +- _Clients A_, _B_, and _C_ connect to _Applications A_, _B_, and _C_ respectively, which the developers have deployed. +- The _NGF Pod_, [deployed by _Cluster Operator_]({{< ref "/ngf/installation">}}) in the namespace _nginx-gateway_. For scalability and availability, you can have multiple replicas. The _NGF_ container interacts with the Kubernetes API to retrieve the most up-to-date Gateway API resources created within the cluster. When a new Gateway resource is provisioned, the control plane dynamically creates and manages a corresponding NGINX data plane Deployment and Service. It watches the Kubernetes API and dynamically configures these _NGINX_ deployments based on the Gateway API resources, ensuring proper alignment between the cluster state and the NGINX configuration. +- The _NGINX Pod_ consists of an NGINX container and the integrated NGINX agent, which securely communicates with the control plane over gRPC. The control plane translates Gateway API resources into NGINX configuration, and sends the configuration to the agent. +- Gateways _Gateway AB_ and _Gateway C_, created by _Cluster Operator_, request points where traffic can be translated to Services within the cluster. _Gateway AB_, includes a listener with a hostname `*.example.com`. _Gateway C_, includes a listener with a hostname `*.other-example.com`. Application Developers have the ability to attach their application's routes to the _Gateway AB_ if their application's hostname matches `*.example.com`, or to _Gateway C_ if their application's hostname matches `*.other-example.com` +- _Application A_ with two pods deployed in the _applications_ namespace by _Application Developer A_. To expose the application to its clients (_Clients A_) via the host `a.example.com`, _Application Developer A_ creates _HTTPRoute A_ and attaches it to `Gateway AB`. +- _Application B_ with one pod deployed in the _applications_ namespace by _Application Developer B_. To expose the application to its clients (_Clients B_) via the host `b.example.com`, _Application Developer B_ creates _HTTPRoute B_ and attaches it to `Gateway AB`. +- _Application C_ with one pod deployed in the _applications2_ namespace by _Application Developer C_. To expose the application to its clients (_Clients C_) via the host `c.other-example.com`, _Application Developer C_ creates _HTTPRoute C_ and attaches it to `Gateway C`. +- _Public Endpoint AB_, and _Public Endpoint C_ and which fronts the _NGINX AB_, and _NGINX C_ pods respectively. A public endpoint is typically a TCP load balancer (cloud, software, or hardware) or a combination of such load balancer with a NodePort service. _Clients A_ and _B_ connect to their applications via the _Public Endpoint AB_, and _Clients C_ connect to their applications via the _Public Endpoint C_. +- The bold arrows represent connections related to the client traffic. Note that the traffic from _Clients C_ to _Application C_ is completely isolated from the traffic between _Clients A_ and _B_ and _Application A_ and _B_ respectively. + +The resources within the cluster are color-coded based on the user responsible for their creation. +For example, the Cluster Operator is denoted by the color green, indicating they create and manage all the green resources. + +--- + +## NGINX Gateway Fabric: Component Communication Workflow + +```mermaid +graph LR + %% Main Components + KubernetesAPI[Kubernetes API] + PrometheusMonitor[Prometheus] + F5Telemetry[F5 Telemetry Service] + NGFPod[NGF Pod] + NGINXPod[NGINX Pod] + Client[Client] + Backend[Backend] + + %% NGINX Pod Grouping + subgraph NGINXPod[NGINX Pod] + NGINXAgent[NGINX Agent] + NGINXMaster[NGINX Master] + NGINXWorker[NGINX Worker] + ConfigFiles[Config Files] + ContainerRuntimeNGINX[stdout/stderr] + end + + subgraph NGFPod[NGF Pod] + NGFProcess[NGF Process] + ContainerRuntimeNGF[stdout/stderr] + end + + %% External Components Grouping + subgraph ExternalComponents[.] + KubernetesAPI[Kubernetes API] + PrometheusMonitor[Prometheus] + F5Telemetry[F5 Telemetry Service] + end + + %% HTTPS: Communication with Kubernetes API + NGFProcess -- "(1) Reads Updates" --> KubernetesAPI + NGFProcess -- "(1) Writes Statuses" --> KubernetesAPI + + %% Prometheus: Metrics Collection + PrometheusMonitor -- "(2) Fetches controller-runtime metrics" --> NGFPod + PrometheusMonitor -- "(5) Fetches NGINX metrics" --> NGINXWorker + + %% Telemetry: Product telemetry data + NGFProcess -- "(3) Sends telemetry data" --> F5Telemetry + + %% File I/O: Logging + NGFProcess -- "(4) Write logs" --> ContainerRuntimeNGF + NGINXMaster -- "(11) Write logs" --> ContainerRuntimeNGINX + NGINXWorker -- "(12) Write logs" --> ContainerRuntimeNGINX + + %% gRPC: Configuration Updates + NGFProcess -- "(6) Sends Config to Agent" --> NGINXAgent + NGINXAgent -- "(7) Validates & Writes Config & TLS Certs" --> ConfigFiles + NGINXAgent -- "(8) Reloads NGINX" --> NGINXMaster + NGINXAgent -- "(9) Sends DataPlaneResponse" --> NGFProcess + + %% File I/O: Configuration and Secrets + NGINXMaster -- "(10) Reads TLS Secrets" --> ConfigFiles + NGINXMaster -- "(11) Reads nginx.conf & NJS Modules" --> ConfigFiles + + %% Signals: Worker Lifecycle Management + NGINXMaster -- "(14) Manages Workers (Update/Shutdown)" --> NGINXWorker + + %% Traffic Flow + Client -- "(15) Sends Traffic" --> NGINXWorker + NGINXWorker -- "(16) Routes Traffic" --> Backend + + %% Styling + classDef important fill:#66CDAA,stroke:#333,stroke-width:2px; + classDef metrics fill:#FFC0CB,stroke:#333,stroke-width:2px; + classDef io fill:#FFD700,stroke:#333,stroke-width:2px; + classDef signal fill:#87CEEB,stroke:#333,stroke-width:2px; + style ExternalComponents fill:transparent,stroke-width:0px + + %% Class Assignments for Node Colors + class NGFPod,KubernetesAPI important; + class PrometheusMonitor,F5Telemetry metrics; + class ConfigFiles,NGINXMaster,NGINXWorker,NGINXAgent io; + class Client,Backend signal; +``` The following list describes the connections, preceeded by their types in parentheses. For brevity, the suffix "process" has been omitted from the process descriptions. 1. (HTTPS) - Read: _NGF_ reads the _Kubernetes API_ to get the latest versions of the resources in the cluster. - - Write: _NGF_ writes to the _Kubernetes API_ to update the handled resources' statuses and emit events. If there's more than one replica of _NGF_ and [leader election](https://github.com/nginx/nginx-gateway-fabric/tree/v{{< version-ngf >}}/charts/nginx-gateway-fabric#configuration) is enabled, only the _NGF_ pod that is leading will write statuses to the _Kubernetes API_. -1. (HTTP, HTTPS) _Prometheus_ fetches the `controller-runtime` and NGINX metrics via an HTTP endpoint that _NGF_ exposes (`:9113/metrics` by default). Prometheus is **not** required by NGINX Gateway Fabric, and its endpoint can be turned off. -1. (File I/O) - - Write: _NGF_ generates NGINX _configuration_ based on the cluster resources and writes them as `.conf` files to the mounted `nginx-conf` volume, located at `/etc/nginx/conf.d`. It also writes _TLS certificates_ and _keys_ from [TLS secrets](https://kubernetes.io/docs/concepts/configuration/secret/#tls-secrets) referenced in the accepted Gateway resource to the `nginx-secrets` volume at the path `/etc/nginx/secrets`. - - Read: _NGF_ reads the PID file `nginx.pid` from the `nginx-run` volume, located at `/var/run/nginx`. _NGF_ extracts the PID of the nginx process from this file in order to send reload signals to _NGINX master_. + - Write: _NGF_ writes to the _Kubernetes API_ to update the handled resources' statuses and emit events. If there's more than one replica of _NGF_ and [leader election](https://github.com/nginx/nginx-gateway-fabric/tree/v1.6.1/charts/nginx-gateway-fabric#configuration) is enabled, only the _NGF_ pod that is leading will write statuses to the _Kubernetes API_. +1. (HTTP, HTTPS) _Prometheus_ fetches the `controller-runtime` metrics via an HTTP endpoint that _NGF_ exposes (`:9113/metrics` by default). +Prometheus is **not** required by NGINX Gateway Fabric, and its endpoint can be turned off. +1. (HTTPS) NGF sends [product telemetry data]({{< ref "/ngf/overview/product-telemetry.md" >}}) to the F5 telemetry service. 1. (File I/O) _NGF_ writes logs to its _stdout_ and _stderr_, which are collected by the container runtime. -1. (HTTP) _NGF_ fetches the NGINX metrics via the unix:/var/run/nginx/nginx-status.sock UNIX socket and converts it to _Prometheus_ format used in #2. -1. (Signal) To reload NGINX, _NGF_ sends the [reload signal](https://nginx.org/en/docs/control.html) to the **NGINX master**. +1. (HTTP, HTTPS) _Prometheus_ fetches the NGINX metrics via an HTTP endpoint that _NGINX_ exposes (`:9113/metrics` by default). Prometheus is **not** required by NGINX, and its endpoint can be turned off. +1. (gRPC) _NGF_ generates NGINX _configuration_ based on the cluster resources and sends them to _NGINX Agent_ over a secure gRPC connection. + - NGF sends a message containing file metadata to all pods (subscriptions) for the deployment. + - Agent receives a ConfigApplyRequest with the list of file metadata. + - Agent calls GetFile for each file in the list, which NGF sends back to the agent. 1. (File I/O) - - Write: The _NGINX master_ writes its PID to the `nginx.pid` file stored in the `nginx-run` volume. - - Read: The _NGINX master_ reads _configuration files_ and the _TLS cert and keys_ referenced in the configuration when it starts or during a reload. These files, certificates, and keys are stored in the `nginx-conf` and `nginx-secrets` volumes that are mounted to both the `nginx-gateway` and `nginx` containers. + - Write: __NGINX Agent_ validates the received configuration, and then writes and applies the config if valid. It also writes _TLS certificates_ and _keys_ from [TLS secrets](https://kubernetes.io/docs/concepts/configuration/secret/#tls-secrets) referenced in the accepted Gateway resource. +1. (Signal) To reload NGINX, Agent sends the reload signal to the NGINX master. +1. (gRPC) Agent responds to NGF with a DataPlaneResponse. 1. (File I/O) - - Write: The _NGINX master_ writes to the auxiliary Unix sockets folder, which is located in the `/var/run/nginx` - directory. - - Read: The _NGINX master_ reads the `nginx.conf` file from the `/etc/nginx` directory. This [file](https://github.com/nginx/nginx-gateway-fabric/blob/v{{< version-ngf >}}/internal/mode/static/nginx/conf/nginx.conf) contains the global and http configuration settings for NGINX. In addition, _NGINX master_ reads the NJS modules referenced in the configuration when it starts or during a reload. NJS modules are stored in the `/usr/lib/nginx/modules` directory. + - Read: The _NGINX master_ reads _configuration files_ and the _TLS cert and keys_ referenced in the configuration when it starts or during a reload. +1. (File I/O) + - Read: The _NGINX master_ reads the `nginx.conf` file from the `/etc/nginx` directory. This [file](https://github.com/nginx/nginx-gateway-fabric/blob/v1.6.1/internal/mode/static/nginx/conf/nginx.conf) contains the global and http configuration settings for NGINX. In addition, _NGINX master_ reads the NJS modules referenced in the configuration when it starts or during a reload. NJS modules are stored in the `/usr/lib/nginx/modules` directory. 1. (File I/O) The _NGINX master_ sends logs to its _stdout_ and _stderr_, which are collected by the container runtime. 1. (File I/O) An _NGINX worker_ writes logs to its _stdout_ and _stderr_, which are collected by the container runtime. 1. (Signal) The _NGINX master_ controls the [lifecycle of _NGINX workers_](https://nginx.org/en/docs/control.html#reconfiguration) it creates workers with the new configuration and shutdowns workers with the old configuration. -1. (HTTP) To consider a configuration reload a success, _NGF_ ensures that at least one NGINX worker has the new configuration. To do that, _NGF_ checks a particular endpoint via the unix:/var/run/nginx/nginx-config-version.sock UNIX socket. 1. (HTTP, HTTPS) A _client_ sends traffic to and receives traffic from any of the _NGINX workers_ on ports 80 and 443. 1. (HTTP, HTTPS) An _NGINX worker_ sends traffic to and receives traffic from the _backends_. -Below are additional connections not depcited on the diagram: - -- (HTTPS) NGF sends [product telemetry data]({{< ref "/ngf/overview/product-telemetry.md" >}}) to the F5 telemetry service. - --- ### Differences with NGINX Plus @@ -123,6 +381,4 @@ The normal process to update any changes to NGINX is to write the configuration ## Pod readiness -The `nginx-gateway` container includes a readiness endpoint available through the path `/readyz`. A [readiness probe](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/#define-readiness-probes) periodically checks the endpoint on startup, returning a `200 OK` response when the pod can accept traffic for the data plane. Once the control plane successfully starts, the pod becomes ready. - -If there are relevant Gateway API resources in the cluster, the control plane will generate the first NGINX configuration and successfully reload NGINX before the pod is considered ready. +The `nginx-gateway` container exposes a readiness endpoint at `/readyz`. During startup, a [readiness probe](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/#define-readiness-probes) periodically checks this endpoint. The probe returns a `200 OK` response once the control plane initializes successfully and is ready to begin configuring NGINX. At that point, the pod is marked as ready. diff --git a/static/ngf/img/ngf-high-level.png b/static/ngf/img/ngf-high-level.png deleted file mode 100644 index 6f2bef6f055d5c908d7d3834519376ad2a9972e7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 138656 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

MSTL;|Gj^dh-5j+R7QX%z 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�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

ExGgIZh2KyhNhbtMBw(q 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%0A`8Qw~fwBtrRGC@kRdvCwW!%_bIr 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

a9z}u}L29^~#$+cqK{$ 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 From b15d47ef2a39c8c12628b84966971a56062ebc6c Mon Sep 17 00:00:00 2001 From: Saylor Berman Date: Wed, 30 Apr 2025 14:20:30 -0600 Subject: [PATCH 09/22] NGF: update Get started guide (#479) The getting started guide needs to change with the new NGF architecture, specifically regarding the NodePorts. The user no longer needs to create the Service, and instead specifies configuration at installation time. --- content/ngf/get-started.md | 163 ++++++++++++++----------------------- 1 file changed, 61 insertions(+), 102 deletions(-) diff --git a/content/ngf/get-started.md b/content/ngf/get-started.md index 334e99175..202d9ebe2 100644 --- a/content/ngf/get-started.md +++ b/content/ngf/get-started.md @@ -47,13 +47,10 @@ nodes: - containerPort: 31437 hostPort: 8080 protocol: TCP - - containerPort: 31438 - hostPort: 8443 - protocol: TCP ``` {{< note >}} -The two _containerPort_ values are used to later configure a _NodePort_. +The _containerPort_ value is used to later configure a _NodePort_. {{< /note >}} Run the following command: @@ -111,17 +108,20 @@ customresourcedefinition.apiextensions.k8s.io/referencegrants.gateway.networking ### Install the Helm chart -Use `helm` to install NGINX Gateway Fabric with the following command: +Use `helm` to install NGINX Gateway Fabric, specifying the NodePort configuration that will be set on the +NGINX Service when it is provisioned: ```shell -helm install ngf oci://ghcr.io/nginx/charts/nginx-gateway-fabric --create-namespace -n nginx-gateway --set service.create=false +helm install ngf oci://ghcr.io/nginx/charts/nginx-gateway-fabric --create-namespace -n nginx-gateway --set nginx.service.type=NodePort --set-json 'nginx.service.nodePorts=[{"port":31437,"listenerPort":80}]' ``` +{{< note >}} +The port value should equal the _containerPort_ value from _cluster-config.yaml_ [when you created the kind cluster](#set-up-a-kind-cluster). The _listenerPort_ value will match the port that we expose in the Gateway listener. +{{< /note >}} + ```text -Pulled: ghcr.io/nginx/charts/nginx-gateway-fabric:{{< version-ngf >}} -Digest: sha256:9bbd1a2fcbfd5407ad6be39f796f582e6263512f1f3a8969b427d39063cc6fee NAME: ngf -LAST DEPLOYED: Mon Oct 21 14:45:14 2024 +LAST DEPLOYED: Tue Apr 29 14:45:14 2025 NAMESPACE: nginx-gateway STATUS: deployed REVISION: 1 @@ -130,59 +130,6 @@ TEST SUITE: None --- -### Set up a NodePort - -Create the file _nodeport-config.yaml_ with the following contents: - -```yaml {linenos=true, hl_lines=[20, 25]} -apiVersion: v1 -kind: Service -metadata: - name: nginx-gateway - namespace: nginx-gateway - labels: - app.kubernetes.io/name: nginx-gateway-fabric - app.kubernetes.io/instance: ngf - app.kubernetes.io/version: "{{< version-ngf >}}" -spec: - type: NodePort - selector: - app.kubernetes.io/name: nginx-gateway-fabric - app.kubernetes.io/instance: ngf - ports: - - name: http - port: 80 - protocol: TCP - targetPort: 80 - nodePort: 31437 - - name: https - port: 443 - protocol: TCP - targetPort: 443 - nodePort: 31438 -``` - -{{< note >}} -The highlighted _nodePort_ values should equal the _containerPort_ values from _cluster-config.yaml_ [when you created the kind cluster](#set-up-a-kind-cluster). -{{< /note >}} - -Apply it using `kubectl`: - -```shell -kubectl apply -f nodeport-config.yaml -``` -```text -service/nginx-gateway created -``` - -{{< warning >}} -The NodePort resource must be deployed in the same namespace as NGINX Gateway Fabric. - -If you are making customizations, ensure your `labels:` and `selectors:` also match the labels of the NGINX Gateway Fabric deployment. -{{< /warning >}} - ---- - ## Create an example application In the previous section, you deployed NGINX Gateway Fabric to a local cluster. This section shows you how to deploy a simple web application to test that NGINX Gateway Fabric works. @@ -220,8 +167,8 @@ kubectl -n default get pods ```text NAME READY STATUS RESTARTS AGE -coffee-6db967495b-wk2mm 1/1 Running 0 10s -tea-7b7d6c947d-d4qcf 1/1 Running 0 10s +coffee-676c9f8944-k2bmd 1/1 Running 0 9s +tea-6fbfdcb95d-9lhbj 1/1 Running 0 9s ``` --- @@ -242,6 +189,19 @@ kubectl apply -f gateway.yaml gateway.gateway.networking.k8s.io/gateway created ``` +Verify that the NGINX deployment has been provisioned: + +```shell +kubectl -n default get pods +``` + +```text +NAME READY STATUS RESTARTS AGE +coffee-676c9f8944-k2bmd 1/1 Running 0 31s +gateway-nginx-66b5d78f8f-4fmtb 1/1 Running 0 13s +tea-6fbfdcb95d-9lhbj 1/1 Running 0 31s +``` + Create the file _cafe-routes.yaml_ with the following contents: {{< ghcode `https://raw.githubusercontent.com/nginx/nginx-gateway-fabric/refs/heads/main/examples/cafe-example/cafe-routes.yaml`>}} @@ -264,22 +224,21 @@ httproute.gateway.networking.k8s.io/tea created You can check that all of the expected services are available using `kubectl get`: ```shell -kubectl get service --all-namespaces +kubectl -n default get services ``` ```text -NAMESPACE NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE -default coffee ClusterIP 10.96.18.163 80/TCP 2m51s -default kubernetes ClusterIP 10.96.0.1 443/TCP 4m41s -default tea ClusterIP 10.96.169.132 80/TCP 2m51s -kube-system kube-dns ClusterIP 10.96.0.10 53/UDP,53/TCP,9153/TCP 4m40s -nginx-gateway nginx-gateway NodePort 10.96.186.45 80:31437/TCP,443:31438/TCP 3m6s +NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE +coffee ClusterIP 10.96.206.93 80/TCP 2m2s +gateway-nginx NodePort 10.96.157.168 80:31437/TCP 104s +kubernetes ClusterIP 10.96.0.1 443/TCP 142m +tea ClusterIP 10.96.43.183 80/TCP 2m2s ``` You can also use `kubectl describe` on the new resources to check their status: ```shell -kubectl describe httproutes +kubectl -n default describe httproutes ``` ```text @@ -290,10 +249,10 @@ Annotations: API Version: gateway.networking.k8s.io/v1 Kind: HTTPRoute Metadata: - Creation Timestamp: 2024-10-21T13:46:51Z + Creation Timestamp: 2025-04-29T19:06:31Z Generation: 1 - Resource Version: 821 - UID: cc591089-d3aa-44d3-a851-e2bbfa285029 + Resource Version: 12285 + UID: c8055a74-b4c6-442f-b3fb-350fb88b2a7c Spec: Hostnames: cafe.example.com @@ -316,13 +275,13 @@ Spec: Status: Parents: Conditions: - Last Transition Time: 2024-10-21T13:46:51Z + Last Transition Time: 2025-04-29T19:06:31Z Message: The route is accepted Observed Generation: 1 Reason: Accepted Status: True Type: Accepted - Last Transition Time: 2024-10-21T13:46:51Z + Last Transition Time: 2025-04-29T19:06:31Z Message: All references are resolved Observed Generation: 1 Reason: ResolvedRefs @@ -345,10 +304,10 @@ Annotations: API Version: gateway.networking.k8s.io/v1 Kind: HTTPRoute Metadata: - Creation Timestamp: 2024-10-21T13:46:51Z + Creation Timestamp: 2025-04-29T19:06:31Z Generation: 1 - Resource Version: 823 - UID: d72d2a19-1c4d-48c4-9808-5678cff6c331 + Resource Version: 12284 + UID: 55aa0ab5-9b1c-4028-9bb5-4903f05bb998 Spec: Hostnames: cafe.example.com @@ -371,13 +330,13 @@ Spec: Status: Parents: Conditions: - Last Transition Time: 2024-10-21T13:46:51Z + Last Transition Time: 2025-04-29T19:06:31Z Message: The route is accepted Observed Generation: 1 Reason: Accepted Status: True Type: Accepted - Last Transition Time: 2024-10-21T13:46:51Z + Last Transition Time: 2025-04-29T19:06:31Z Message: All references are resolved Observed Generation: 1 Reason: ResolvedRefs @@ -394,7 +353,7 @@ Events: ``` ```shell -kubectl describe gateways +kubectl -n default describe gateways ``` ```text @@ -405,10 +364,10 @@ Annotations: API Version: gateway.networking.k8s.io/v1 Kind: Gateway Metadata: - Creation Timestamp: 2024-10-21T13:46:36Z + Creation Timestamp: 2025-04-29T19:05:01Z Generation: 1 - Resource Version: 824 - UID: 2ae8ec42-70eb-41a4-b249-3e47177aea48 + Resource Version: 12286 + UID: 0baa6e15-55e0-405a-9e7c-de22472fc3ad Spec: Gateway Class Name: nginx Listeners: @@ -422,15 +381,15 @@ Spec: Status: Addresses: Type: IPAddress - Value: 10.244.0.5 + Value: 10.96.157.168 Conditions: - Last Transition Time: 2024-10-21T13:46:51Z + Last Transition Time: 2025-04-29T19:06:31Z Message: Gateway is accepted Observed Generation: 1 Reason: Accepted Status: True Type: Accepted - Last Transition Time: 2024-10-21T13:46:51Z + Last Transition Time: 2025-04-29T19:06:31Z Message: Gateway is programmed Observed Generation: 1 Reason: Programmed @@ -439,25 +398,25 @@ Status: Listeners: Attached Routes: 2 Conditions: - Last Transition Time: 2024-10-21T13:46:51Z + Last Transition Time: 2025-04-29T19:06:31Z Message: Listener is accepted Observed Generation: 1 Reason: Accepted Status: True Type: Accepted - Last Transition Time: 2024-10-21T13:46:51Z + Last Transition Time: 2025-04-29T19:06:31Z Message: Listener is programmed Observed Generation: 1 Reason: Programmed Status: True Type: Programmed - Last Transition Time: 2024-10-21T13:46:51Z + Last Transition Time: 2025-04-29T19:06:31Z Message: All references are resolved Observed Generation: 1 Reason: ResolvedRefs Status: True Type: ResolvedRefs - Last Transition Time: 2024-10-21T13:46:51Z + Last Transition Time: 2025-04-29T19:06:31Z Message: No conflicts Observed Generation: 1 Reason: NoConflicts @@ -476,7 +435,7 @@ Events: ## Test NGINX Gateway Fabric -By configuring the cluster with the ports `31437` and `31438`, there is implicit port forwarding from your local machine to NodePort, allowing for direct communication to the NGINX Gateway Fabric service. +By configuring the cluster with the port `31437`, there is implicit port forwarding from your local machine to NodePort, allowing for direct communication to the NGINX Gateway Fabric service. You can use `curl` to test the new services by targeting the hostname (_cafe.example.com_) with the _/coffee_ and _/tea_ paths: @@ -485,11 +444,11 @@ curl --resolve cafe.example.com:8080:127.0.0.1 http://cafe.example.com:8080/coff ``` ```text -Server address: 10.244.0.6:8080 -Server name: coffee-6db967495b-wk2mm -Date: 21/Oct/2024:13:52:13 +0000 +Server address: 10.244.0.16:8080 +Server name: coffee-676c9f8944-k2bmd +Date: 29/Apr/2025:19:08:21 +0000 URI: /coffee -Request ID: fb226a54fd94f927b484dd31fb30e747 +Request ID: f34e138922171977a79b1b0d0395b97e ``` ```shell @@ -497,11 +456,11 @@ curl --resolve cafe.example.com:8080:127.0.0.1 http://cafe.example.com:8080/tea ``` ```text -Server address: 10.244.0.7:8080 -Server name: tea-7b7d6c947d-d4qcf -Date: 21/Oct/2024:13:52:17 +0000 +Server address: 10.244.0.17:8080 +Server name: tea-6fbfdcb95d-9lhbj +Date: 29/Apr/2025:19:08:31 +0000 URI: /tea -Request ID: 43882f2f5794a1ee05d2ea017a035ce3 +Request ID: 1b5c8f3a4532ea7d7510cf14ffeb27af ``` --- From 707e7df5243f956045050a2c8ad33fd675985875 Mon Sep 17 00:00:00 2001 From: bjee19 <139261241+bjee19@users.noreply.github.com> Date: Thu, 1 May 2025 16:12:01 -0700 Subject: [PATCH 10/22] NGF: Update control data plane split telemetry (#485) Update docs for CP/DP split telemetry changes. Problem: Some small docs changes are needed for the new telemetry metrics/changes introduced with the control data plane split. Solution: Add the new metrics. Also updated the data plane configuration document small error of including the namespace field in the gateway.infrastructure.parametersRef field since that does not exist. --- content/ngf/how-to/data-plane-configuration.md | 1 - content/ngf/overview/product-telemetry.md | 3 ++- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/content/ngf/how-to/data-plane-configuration.md b/content/ngf/how-to/data-plane-configuration.md index 1ea88a8e2..61a1bc57d 100644 --- a/content/ngf/how-to/data-plane-configuration.md +++ b/content/ngf/how-to/data-plane-configuration.md @@ -260,7 +260,6 @@ infrastructure: group: gateway.nginx.org kind: NginxProxy name: ngf-proxy-config - namespace: default ``` After updating, you can check the status of the Gateway to see if the configuration is valid: diff --git a/content/ngf/overview/product-telemetry.md b/content/ngf/overview/product-telemetry.md index cd9f7a20f..ae0858c37 100644 --- a/content/ngf/overview/product-telemetry.md +++ b/content/ngf/overview/product-telemetry.md @@ -28,11 +28,12 @@ Telemetry data is collected once every 24 hours and sent to a service managed by - **Cluster Node Count:** the number of Nodes in the cluster. - **Version:** the version of the NGINX Gateway Fabric Deployment. - **Deployment UID:** the UID of the NGINX Gateway Fabric Deployment. -- **Deployment Replica Count:** the count of NGINX Gateway Fabric Pods. - **Image Build Source:** whether the image was built by GitHub or locally (values are `gha`, `local`, or `unknown`). The source repository of the images is **not** collected. - **Deployment Flags:** a list of NGINX Gateway Fabric Deployment flags that are specified by a user. The actual values of non-boolean flags are **not** collected; we only record that they are either `true` or `false` for boolean flags and `default` or `user-defined` for the rest. - **Count of Resources:** the total count of resources related to NGINX Gateway Fabric. This includes `GatewayClasses`, `Gateways`, `HTTPRoutes`,`GRPCRoutes`, `TLSRoutes`, `Secrets`, `Services`, `BackendTLSPolicies`, `ClientSettingsPolicies`, `NginxProxies`, `ObservabilityPolicies`, `UpstreamSettingsPolicies`, `SnippetsFilters`, and `Endpoints`. The data within these resources is **not** collected. - **SnippetsFilters Info**a list of directive-context strings from applied SnippetFilters and a total count per strings. The actual value of any NGINX directive is **not** collected. +- **Control Plane Pod Count** the count of NGINX Gateway Fabric Pods. +- **Data Plane Pod Count** the count of NGINX data plane Pods. This data is used to identify the following information: - The flavors of Kubernetes environments that are most popular among our users. From 27babac6892938db8040fc5429a22d07e8126997 Mon Sep 17 00:00:00 2001 From: Saylor Berman Date: Wed, 7 May 2025 08:16:28 -0600 Subject: [PATCH 11/22] NGF: add control plane/data plane TLS doc (#488) With the control plane and data plane split in NGF, a secure connection is necessary for communication between the two entities. We secure this by default, but for production environments, users should use an official solution to secure this communication channel. This doc describes how to do that. --- .../integrating-cert-manager.md | 2 + .../installing-ngf/control-plane-certs.md | 193 ++++++++++++++++++ .../ngf/installation/installing-ngf/helm.md | 1 + .../installation/installing-ngf/manifests.md | 1 + 4 files changed, 197 insertions(+) create mode 100644 content/ngf/installation/installing-ngf/control-plane-certs.md diff --git a/content/ngf/how-to/traffic-security/integrating-cert-manager.md b/content/ngf/how-to/traffic-security/integrating-cert-manager.md index ec46560e9..6c17cd145 100644 --- a/content/ngf/how-to/traffic-security/integrating-cert-manager.md +++ b/content/ngf/how-to/traffic-security/integrating-cert-manager.md @@ -23,6 +23,8 @@ Follow the steps in this guide to: ## Before you begin +You need: + - Administrator access to a Kubernetes cluster. - [Helm](https://helm.sh) and [kubectl](https://kubernetes.io/docs/tasks/tools/#kubectl) must be installed locally. - [NGINX Gateway Fabric deployed]({{< ref "/ngf/installation/" >}}) in the Kubernetes cluster. diff --git a/content/ngf/installation/installing-ngf/control-plane-certs.md b/content/ngf/installation/installing-ngf/control-plane-certs.md new file mode 100644 index 000000000..4a34e24d9 --- /dev/null +++ b/content/ngf/installation/installing-ngf/control-plane-certs.md @@ -0,0 +1,193 @@ +--- +title: Add secure authentication to the control and data planes +weight: 300 +toc: true +type: how-to +product: NGF +docs: DOCS-0000 +--- + +## Overview + +By default, NGINX Gateway Fabric installs self-signed certificates to secure the connection between the NGINX Gateway Fabric control plane and the NGINX data plane pods. These certificates are created by a `cert-generator` job when NGINX Gateway Fabric is first installed. However, because these certificates are self-signed and will expire after 3 years, it is recommended to use a solution such as [cert-manager](https://cert-manager.io) to create and manage these certificates in a production environment. + +This guide will step through how to install and use `cert-manager` to secure this connection. **This should be done _before_ you install NGINX Gateway Fabric.** + +## Before you begin + +You need: + +- Administrator access to a Kubernetes cluster. +- [Helm](https://helm.sh) and [kubectl](https://kubernetes.io/docs/tasks/tools/#kubectl) must be installed locally. + +## Install cert-manager + +Add the Helm repository: + +```shell +helm repo add jetstack https://charts.jetstack.io +helm repo update + +Install cert-manager: + +```shell +helm install \ + cert-manager jetstack/cert-manager \ + --namespace cert-manager \ + --create-namespace \ + --set config.apiVersion="controller.config.cert-manager.io/v1alpha1" \ + --set config.kind="ControllerConfiguration" \ + --set config.enableGatewayAPI=true \ + --set crds.enabled=true + + This also enables Gateway API features for cert-manager, which can be useful for [securing your workload traffic]({{< ref "/ngf/how-to/traffic-security/integrating-cert-manager.md" >}}). + +## Create the CA issuer + +The first step is to create the CA (certificate authority) issuer. + +{{< note >}} This example uses a self-signed Issuer, which should not be used in production environments. For production environments, you should use a real [CA issuer](https://cert-manager.io/docs/configuration/ca/). {{< /note >}} + +Create the namespace: + +```shell +kubectl create namespace nginx-gateway +``` + +```yaml +kubectl apply -f - <}} + +{{%tab name="Helm"%}} + +The full service name is of the format: `-nginx-gateway-fabric..svc`. + +The default Helm release name used in our installation docs is `ngf`, and the default namespace is `nginx-gateway`, so the `dnsName` should be `ngf-nginx-gateway-fabric.nginx-gateway.svc`. + +{{% /tab %}} + +{{%tab name="Manifests"%}} + +The full service name is of the format: `..svc`. + +By default, the base service name is `nginx-gateway`, and the namespace is `nginx-gateway`, so the `dnsName` should be `nginx-gateway.nginx-gateway.svc`. + +{{% /tab %}} + +{{}} + +```yaml +kubectl apply -f - <}} + +{{%tab name="Helm"%}} + +Specify the Secret name using the `certGenerator.agentTLSSecretName` helm value. + +{{% /tab %}} + +{{%tab name="Manifests"%}} + +Specify the Secret name using the `agent-tls-secret` command-line argument. + +{{% /tab %}} + +{{}} + +## Final steps + +You should see the Secrets created in the `nginx-gateway` namespace: + +```shell +kubectl -n nginx-gateway get secrets +``` + +```text +agent-tls kubernetes.io/tls 3 3s +nginx-gateway-ca kubernetes.io/tls 3 15s +server-tls kubernetes.io/tls 3 8s +``` + +**You can now [install NGINX Gateway Fabric]({{< ref "/ngf/installation/installing-ngf" >}}).** diff --git a/content/ngf/installation/installing-ngf/helm.md b/content/ngf/installation/installing-ngf/helm.md index dd859a459..e5d432432 100644 --- a/content/ngf/installation/installing-ngf/helm.md +++ b/content/ngf/installation/installing-ngf/helm.md @@ -19,6 +19,7 @@ To complete this guide, you'll need to install: - [kubectl](https://kubernetes.io/docs/tasks/tools/), a command-line tool for managing Kubernetes clusters. - [Helm 3.0 or later](https://helm.sh/docs/intro/install/), for deploying and managing applications on Kubernetes. +- If deploying into a production environment, we highly recommend [installing custom certificates]({{< ref "/ngf/installation/installing-ngf/control-plane-certs.md" >}}) for securing the connection between the NGINX Gateway Fabric control plane and NGINX data plane Pods. **This should be done _before_ you install NGINX Gateway Fabric.** The default certificates are self-signed and will expire after 3 years. {{< important >}} If you’d like to use NGINX Plus, some additional setup is also required: {{}} diff --git a/content/ngf/installation/installing-ngf/manifests.md b/content/ngf/installation/installing-ngf/manifests.md index a42ea9bd0..173ad5d41 100644 --- a/content/ngf/installation/installing-ngf/manifests.md +++ b/content/ngf/installation/installing-ngf/manifests.md @@ -18,6 +18,7 @@ Learn how to install, upgrade, and uninstall NGINX Gateway Fabric using Kubernet To complete this guide, you'll need to install: - [kubectl](https://kubernetes.io/docs/tasks/tools/), a command-line interface for managing Kubernetes clusters. +- If deploying into a production environment, we highly recommend [installing custom certificates]({{< ref "/ngf/installation/installing-ngf/control-plane-certs.md" >}}) for securing the connection between the NGINX Gateway Fabric control plane and NGINX data plane Pods. **This should be done _before_ you install NGINX Gateway Fabric.** The default certificates are self-signed and will expire after 3 years. {{< important >}} If you’d like to use NGINX Plus, some additional setup is also required: {{}} From 72ad28ed9c26ae3be6e1511bcdd1308fff7a93b7 Mon Sep 17 00:00:00 2001 From: salonichf5 <146118978+salonichf5@users.noreply.github.com> Date: Thu, 8 May 2025 04:18:17 +0530 Subject: [PATCH 12/22] NGF: Update data plane configuration doc (#529) docs: Updata data plane configuration doc to reflect changes to NginxProxy resource --- .../ngf/how-to/data-plane-configuration.md | 98 +++++++++---------- 1 file changed, 47 insertions(+), 51 deletions(-) diff --git a/content/ngf/how-to/data-plane-configuration.md b/content/ngf/how-to/data-plane-configuration.md index 61a1bc57d..c164f5318 100644 --- a/content/ngf/how-to/data-plane-configuration.md +++ b/content/ngf/how-to/data-plane-configuration.md @@ -11,9 +11,9 @@ Learn how to dynamically update the NGINX Gateway Fabric global data plane confi ## Overview -NGINX Gateway Fabric can dynamically update the global data plane configuration without restarting. The data plane configuration contains configuration for NGINX that is not available using the standard Gateway API resources. This includes such things as setting an OpenTelemetry collector config, disabling http2, changing the IP family, or setting the NGINX error log level. +NGINX Gateway Fabric can dynamically update the global data plane configuration without restarting. The data plane configuration contains configuration for NGINX that is not available using the standard Gateway API resources. This includes options such as configuring an OpenTelemetry collector, disabling HTTP/2, changing the IP family, modifying infrastructure-related fields, and setting the NGINX error log level. -The data plane configuration is stored in the NginxProxy custom resource, which is a namespace-scoped resource that can be attached to a GatewayClass or Gateway. When attached to a GatewayClass, the fields in the NginxProxy affect all Gateways that belong to the GatewayClass. +The data plane configuration is stored in the `NginxProxy` custom resource, which is a namespace-scoped resource that can be attached to a GatewayClass or Gateway. When attached to a GatewayClass, the fields in the NginxProxy affect all Gateways that belong to the GatewayClass. When attached to a Gateway, the fields in the NginxProxy only affect the Gateway. If a GatewayClass and its Gateway both specify an NginxProxy, the GatewayClass NginxProxy provides defaults that can be overridden by the Gateway NginxProxy. See the [Merging Semantics](#merging-semantics) section for more detail. --- @@ -172,21 +172,19 @@ telemetry: --- -## Configuring the GatewayClass NginxProxy on Install +## Configuring the GatewayClass NginxProxy on install -By default, the NginxProxy resource is not created when installing NGINX Gateway Fabric. However, you can set configuration options in the `nginx.config` Helm values, and the resource will be created and attached to the GatewayClass when NGINX Gateway Fabric is installed using Helm. You can also [manually create and attach](#manually-creating-nginxproxies) the resource after NGINX Gateway Fabric is already installed. +By default, an `NginxProxy` resource is created in the same namespace where NGINX Gateway Fabric is installed, attached to the GatewayClass. You can set configuration options in the `nginx` Helm value section, and the resource will be created and attached using the set values. You can also [manually create and attach](#manually-creating-nginxProxies) specific `NginxProxy` resources to target different Gateways. When installed using the Helm chart, the NginxProxy resource is named `-proxy-config` and is created in the release Namespace. -**For a full list of configuration options that can be set, see the `NginxProxy spec` in the [API reference]({{< ref "/ngf/reference/api.md" >}}).** - {{< note >}} Some global configuration also requires an [associated policy]({{< ref "/ngf/overview/custom-policies.md" >}}) to fully enable a feature (such as [tracing]({{< ref "/ngf/how-to/monitoring/tracing.md" >}}), for example). {{< /note >}} --- ## Manually Creating NginxProxies -The following command creates a basic `NginxProxy` configuration that sets the IP family to `ipv4` instead of the default value of `dual`: +The following command creates a basic `NginxProxy` configuration in the `default` namespace that sets the IP family to `ipv4` instead of the default value of `dual`: ```yaml kubectl apply -f - <}}).** - ---- - -### Attaching NginxProxy to GatewayClass - -To attach the `ngf-proxy-config` NginxProxy to the GatewayClass: - -```shell -kubectl edit gatewayclass nginx -``` - -This will open your default editor, allowing you to add the following to the `spec`: - -```yaml -parametersRef: - group: gateway.nginx.org - kind: NginxProxy - name: ngf-proxy-config - namespace: default -``` - -After updating, you can check the status of the GatewayClass to see if the configuration is valid: - -```shell -kubectl describe gatewayclass nginx -``` - -```text -... -Status: - Conditions: - ... - Message: parametersRef resource is resolved - Observed Generation: 1 - Reason: ResolvedRefs - Status: True - Type: ResolvedRefs -``` - -If everything is valid, the `ResolvedRefs` condition should be `True`. Otherwise, you will see an `InvalidParameters` condition in the status. +For a full list of configuration options that can be set, see the `NginxProxy spec` in the [API reference]({{< ref "/ngf/reference/api.md" >}}). --- @@ -262,6 +220,8 @@ infrastructure: name: ngf-proxy-config ``` +{{< note >}} The `NginxProxy` resource must reside in the same namespace as the Gateway it is attached to. {{< /note >}} + After updating, you can check the status of the Gateway to see if the configuration is valid: ```shell @@ -286,7 +246,7 @@ If everything is valid, the `ResolvedRefs` condition should be `True`. Otherwise ## Configure the data plane log level -You can use the `NginxProxy` resource to dynamically configure the Data Plane Log Level. +You can use the `NginxProxy` resource to dynamically configure the log level. The following command creates a basic `NginxProxy` configuration that sets the log level to `warn` instead of the default value of `info`: @@ -375,6 +335,42 @@ spec: EOF ``` -For the full configuration API, see the `NginxProxy spec` in the [API reference]({{< ref "/ngf/reference/api.md" >}}). - {{< note >}} When sending curl requests to a server expecting proxy information, use the flag `--haproxy-protocol` to avoid broken header errors. {{< /note >}} + +--- + +## Configure infrastructure-related settings + +You can configure deployment and service settings for all data plane instances by editing the `NginxProxy` resource at the Gateway or GatewayClass level. These settings can also be specified under the `nginx` section in the Helm values file. You can edit things such as replicas, pod scheduling options, container resource limits, extra volume mounts, service types and load balancer settings. + +The following command creates an `NginxProxy` resource with 2 replicas, sets `container.resources.requests` to 100m CPU and 128Mi memory, configures a 90 second `pod.terminationGracePeriodSeconds`, and sets the service type to `LoadBalancer` with IP `192.87.9.1` and AWS NLB annotation. + +```yaml +kubectl apply -f - <}}). + +--- + From 5c7a698d24c6819a82f62efc8bf3e94f861118a5 Mon Sep 17 00:00:00 2001 From: salonichf5 <146118978+salonichf5@users.noreply.github.com> Date: Thu, 8 May 2025 21:09:49 +0530 Subject: [PATCH 13/22] NGF: Scaling control plane and data plane pods (#490) docs: Introduces a new how-to guide on scaling control and data plane pods --- content/ngf/how-to/scaling.md | 96 +++++++++++++++++++ .../how-to/upgrade-apps-without-downtime.md | 2 +- 2 files changed, 97 insertions(+), 1 deletion(-) create mode 100644 content/ngf/how-to/scaling.md diff --git a/content/ngf/how-to/scaling.md b/content/ngf/how-to/scaling.md new file mode 100644 index 000000000..35cd132da --- /dev/null +++ b/content/ngf/how-to/scaling.md @@ -0,0 +1,96 @@ +--- +title: Scaling the control plane and data plane +weight: 700 +toc: true +type: how-to +product: NGF +docs: DOCS-0000 +--- + +This document describes how you can separately scale the NGINX Gateway Fabric control plane and data plane. + +It provides guidance on how to scale each plane effectively, and when you should do so based on your traffic patterns. + + +### Scaling the data plane + +The data plane is the NGINX deployment that handles user traffic to backend applications. Every Gateway object created provisions its own NGINX deployment and configuration. + +You have two options for scaling the data plane: + +- Increasing the number of replicas for an existing deployment +- Creating a new Gateway for a new data plane + +#### When to increase replicas or create a new Gateway + +Understanding when to increase replicas or create a new Gateway is key to managing traffic effectively. + +Increasing data plane replicas is ideal when you need to handle more traffic without changing the configuration. + +For example, if you're routing traffic to `api.example.com` and notice an increase in load, you can scale the replicas from 1 to 5 to better distribute the traffic and reduce latency. + +All replicas will share the same configuration from the Gateway used to set up the data plane, simplifying configuration management. + +There are two ways to modify the number of replicas for an NGINX deployment: + +First, at the time of installation you can modify the field `nginx.replicas` in the `values.yaml` or add the `--set nginx.replicas=` flag to the `helm install` command: + +```shell +helm install ngf oci://ghcr.io/nginx/charts/nginx-gateway-fabric --create-namespace -n nginx-gateway --set nginx.replicas=5 +``` + +Secondly, you can update the `NginxProxy` resource while NGINX is running to modify the `kubernetes.deployment.replicas` field and scale the data plane deployment dynamically: + +```shell +kubectl edit nginxproxies.gateway.nginx.org ngf-proxy-config -n nginx-gateway +``` + +The alternate way to scale the data plane is by creating a new Gateway. This is is beneficial when you need distinct configurations, isolation, or separate policies. + +For example, if you're routing traffic to a new domain `admin.example.com` and require a different TLS certificate, stricter rate limits, or separate authentication policies, creating a new Gateway could be a good approach. + +It allows for safe experimentation with isolated configurations and makes it easier to enforce security boundaries and specific routing rules. + +### Scaling the control plane + +The control plane builds configuration based on defined Gateway API resources and sends that configuration to the NGINX data planes. With leader election enabled by default, the control plane can be scaled horizontally by running multiple replicas, although only the pod with leader lease can actively manage configuration status updates. + +Scaling the control plane can be beneficial in the following scenarios: + +1. _Higher availability_ - When a control plane pod crashes, runs out of memory, or goes down during an upgrade, it can interrupt configuration delivery. By scaling to multiple replicas, another pod can quickly step in and take over, keeping things running smoothly with minimal downtime. +1. _Faster configuration distribution_ - As the number of connected NGINX instances grows, a single control plane pod may become a bottleneck in handling connections or streaming configuration updates. Scaling the control plane improves concurrency and responsiveness when delivering configuration over gRPC. + +To scale the control plane, use the `kubectl scale` command on the control plane deployment to increase or decrease the number of replicas. For example, the following command scales the control plane deployment to 3 replicas: + + ```shell + kubectl scale deployment -n nginx-gateway ngf-nginx-gateway-fabric --replicas 3 + ``` + +#### Known risks when scaling the control plane + +When scaling the control plane, it's important to understand how status updates are handled for Gateway API resources. + +All control plane pods can send NGINX configuration to the data planes. However, only the leader control plane pod is allowed to write status updates to Gateway API resources. + +If an NGINX instance connects to a non-leader pod, and an error occurs when applying the config, that error status will not be written to the Gateway object status. + +To mitigate the potential for this issue, ensure that the number of NGINX data plane pods equals or exceeds the number of control plane pods. + +This increases the likelihood that at least one of the data planes is connected to the leader control plane pod. If an applied configuration has an error, the leader pod will be aware of it and status can still be written. + +There is still a chance (however unlikely) that one of the data planes connected to a non-leader has an issue applying its configuration, while the rest of the data planes are successful, which could lead to that error status not being written. + +To identify which control plane pod currently holds the leader election lease, retrieve the leases in the same namespace as the control plane pods. For example: + +```shell +kubectl get leases -n nginx-gateway +``` + +The current leader lease is held by the pod `ngf-nginx-gateway-fabric-b45ffc8d6-d9z2g`: + +```shell +NAME HOLDER AGE +ngf-nginx-gateway-fabric-leader-election ngf-nginx-gateway-fabric-b45ffc8d6-d9z2g_2ef81ced-f19d-41a0-9fcd-a68d89380d10 16d +``` + +--- \ No newline at end of file diff --git a/content/ngf/how-to/upgrade-apps-without-downtime.md b/content/ngf/how-to/upgrade-apps-without-downtime.md index e66edd9ba..71e570f0b 100644 --- a/content/ngf/how-to/upgrade-apps-without-downtime.md +++ b/content/ngf/how-to/upgrade-apps-without-downtime.md @@ -1,6 +1,6 @@ --- title: Upgrade applications without downtime -weight: 500 +weight: 600 toc: true type: how-to product: NGF From 45b70e1b8021cb8a7d80f2b565c98e3ef9ebec18 Mon Sep 17 00:00:00 2001 From: bjee19 <139261241+bjee19@users.noreply.github.com> Date: Tue, 13 May 2025 02:52:01 -0700 Subject: [PATCH 14/22] Update aws nlb manifests installation (#543) --- content/ngf/installation/installing-ngf/manifests.md | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/content/ngf/installation/installing-ngf/manifests.md b/content/ngf/installation/installing-ngf/manifests.md index 173ad5d41..ec8ec590a 100644 --- a/content/ngf/installation/installing-ngf/manifests.md +++ b/content/ngf/installation/installing-ngf/manifests.md @@ -91,10 +91,17 @@ kubectl apply -f https://raw.githubusercontent.com/nginx/nginx-gateway-fabric/v{ {{%tab name="AWS NLB"%}} -Deploys NGINX Gateway Fabric with NGINX OSS and an AWS Network Load Balancer service. +Deploys NGINX Gateway Fabric with NGINX OSS. ```shell -kubectl apply -f https://raw.githubusercontent.com/nginx/nginx-gateway-fabric/v{{< version-ngf >}}/deploy/aws-nlb/deploy.yaml +kubectl apply -f https://raw.githubusercontent.com/nginx/nginx-gateway-fabric/v{{< version-ngf >}}/deploy/default/deploy.yaml +``` + +To set up an AWS Network Load Balancer service, add these annotations to your Gateway infrastructure fields: + +```yaml +service.beta.kubernetes.io/aws-load-balancer-type: "external" +service.beta.kubernetes.io/aws-load-balancer-nlb-target-type: "ip" ``` {{% /tab %}} From c589ea7dc461f90c81b42c6cea144bb3abfc08b6 Mon Sep 17 00:00:00 2001 From: Ciara Stacke <18287516+ciarams87@users.noreply.github.com> Date: Thu, 15 May 2025 08:41:24 +0100 Subject: [PATCH 15/22] NGF: Update Helm values where required for 2.0 (#550) Update tracing doc and Helm install doc --- content/ngf/how-to/monitoring/tracing.md | 15 ++++++++++----- content/ngf/installation/installing-ngf/helm.md | 8 +------- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/content/ngf/how-to/monitoring/tracing.md b/content/ngf/how-to/monitoring/tracing.md index db711b128..90718ade0 100644 --- a/content/ngf/how-to/monitoring/tracing.md +++ b/content/ngf/how-to/monitoring/tracing.md @@ -70,10 +70,14 @@ Visit [http://127.0.0.1:16686](http://127.0.0.1:16686) to view the dashboard. To enable tracing, you must configure two resources: -- `NginxProxy`: This resource contains global settings relating to the NGINX data plane. It is created and managed by the [cluster operator](https://gateway-api.sigs.k8s.io/concepts/roles-and-personas/), and is referenced in the `parametersRef` field of the GatewayClass. This resource can be created and linked when we install NGINX Gateway Fabric using its helm chart, or it can be added later. This guide installs the resource using the helm chart, but the resource can also be created for an existing deployment. +- `NginxProxy`: This resource contains global settings relating to the NGINX data plane. It is created and managed by the [cluster operator](https://gateway-api.sigs.k8s.io/concepts/roles-and-personas/), and is referenced in the `parametersRef` field of the GatewayClass. By default, an `NginxProxy` resource is created in the same namespace where NGINX Gateway Fabric is installed, attached to the GatewayClass. You can set configuration options in the `nginx` Helm value section, and the resource will be created and attached using the set values. + +When installed using the Helm chart, the NginxProxy resource is named `-proxy-config` and is created in the release Namespace. The `NginxProxy` resource contains configuration for the collector, and applies to all Gateways and routes under the GatewayClass. It does not enable tracing, but is a prerequisite to the next piece of configuration. +{{< note >}} You can also override the tracing configuration for a particular Gateway by manually creating and attaching specific `NginxProxy` resources to target the different Gateways. This guide covers the global tracing configuration only. {{< /note >}} + - `ObservabilityPolicy`: This resource is a [Direct PolicyAttachment](https://gateway-api.sigs.k8s.io/reference/policy-attachment/) that targets HTTPRoutes or GRPCRoutes. It is created by the [application developer](https://gateway-api.sigs.k8s.io/concepts/roles-and-personas/) and enables tracing for a specific route or routes. It requires the `NginxProxy` resource to exist in order to complete the tracing configuration. For all the possible configuration options for these resources, see the [API reference]({{< ref "/ngf/reference/api.md" >}}). @@ -110,11 +114,11 @@ helm install ngf oci://ghcr.io/nginx/charts/nginx-gateway-fabric --create-namesp You should see the following configuration: ```shell -kubectl get nginxproxies.gateway.nginx.org ngf-proxy-config -o yaml +kubectl get nginxproxies.gateway.nginx.org ngf-proxy-config -n nginx-gateway -o yaml ``` ```yaml -apiVersion: gateway.nginx.org/v1alpha1 +apiVersion: gateway.nginx.org/v1alpha2 kind: NginxProxy metadata: name: ngf-proxy-config @@ -164,10 +168,10 @@ status: type: ResolvedRefs ``` -If you already have NGINX Gateway Fabric installed, then you can create the `NginxProxy` resource and link it to the GatewayClass `parametersRef`: +If you already have NGINX Gateway Fabric installed, then you can modify the `NginxProxy` resource to include the tracing configuration: ```shell -kubectl edit gatewayclasses.gateway.networking.k8s.io nginx +kubectl edit nginxproxies.gateway.nginx.org ngf-proxy-config -n nginx-gateway ``` You can now create the application, route, and tracing policy. @@ -351,5 +355,6 @@ The trace includes the attribute from the global NginxProxy resource as well as ## See also +- [Data plane configuration]({{< ref "/ngf/how-to/data-plane-configuration.md" >}}): learn how to dynamically update the NGINX Gateway Fabric global data plane configuration, including how to override the telemetry configuration for a particular Gateway. - [Custom policies]({{< ref "/ngf/overview/custom-policies.md" >}}): learn about how NGINX Gateway Fabric custom policies work. - [API reference]({{< ref "/ngf/reference/api.md" >}}): all configuration fields for the policies mentioned in this guide diff --git a/content/ngf/installation/installing-ngf/helm.md b/content/ngf/installation/installing-ngf/helm.md index e5d432432..11bf320e0 100644 --- a/content/ngf/installation/installing-ngf/helm.md +++ b/content/ngf/installation/installing-ngf/helm.md @@ -147,13 +147,7 @@ By default, the NGINX Gateway Fabric helm chart deploys a LoadBalancer Service. To use a NodePort Service instead: ```shell -helm install ngf oci://ghcr.io/nginx/charts/nginx-gateway-fabric --create-namespace -n nginx-gateway --set service.type=NodePort -``` - -To disable the creation of a Service: - -```shell -helm install ngf oci://ghcr.io/nginx/charts/nginx-gateway-fabric --create-namespace -n nginx-gateway --set service.create=false +helm install ngf oci://ghcr.io/nginx/charts/nginx-gateway-fabric --create-namespace -n nginx-gateway --set nginx.service.type=NodePort ``` --- From 6644bf2aea26ebc2345c48b39a77c4d945529fa1 Mon Sep 17 00:00:00 2001 From: Saylor Berman Date: Tue, 20 May 2025 07:41:44 -0600 Subject: [PATCH 16/22] NGF: update nginx metrics (#558) Agent updated some metrics names and descriptions. Updating the NGF doc that describes them. --- content/ngf/how-to/monitoring/prometheus.md | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/content/ngf/how-to/monitoring/prometheus.md b/content/ngf/how-to/monitoring/prometheus.md index 1580e3789..9be5bd3e6 100644 --- a/content/ngf/how-to/monitoring/prometheus.md +++ b/content/ngf/how-to/monitoring/prometheus.md @@ -90,19 +90,23 @@ NGINX Gateway Fabric currently supports a subset of all metrics available throug the supported metrics along with a small accompanying description. Metrics provided by NGINX Open Source include: -- `nginx_http_connections`: NGINX-wide statistics describing HTTP connections. -- `nginx_http_requests`: The total number of client requests received from clients. +- `nginx_http_connection_count_connections`: The current number of connections. +- `nginx_http_connections_total`: The total number of connections, since NGINX was last started or reloaded. +- `nginx_http_request_count_requests`: The total number of client requests received, since the last collection interval. +- `nginx_http_requests_total`: The total number of client requests received, since NGINX was last started or reloaded. In addition to the previous metrics provided by NGINX Open Source, NGINX Plus includes: -- `nginx_config_reloads`: The total number of NGINX config reloads. -- `nginx_http_response_status_responses_total`: The number of responses, grouped by status code range. +- `nginx_config_reloads_total`: The total number of NGINX config reloads. +- `nginx_http_response_count_responses`: The total number of HTTP responses sent to clients since the last collection interval, grouped by status code range. +- `nginx_http_response_status_responses_total`: The total number of responses since NGINX was last started or reloaded, grouped by status code range. - `nginx_http_request_discarded_requests_total`: The total number of requests completed without sending a response. - `nginx_http_request_processing_count_requests`: The number of client requests that are currently being processed. - `nginx_http_request_byte_io_bytes_total`: The total number of HTTP byte IO. - `nginx_http_upstream_keepalive_count_connections`: The current number of idle keepalive connections per HTTP upstream. +- `nginx_http_upstream_peer_connection_count_connections`: The average number of active connections per HTTP upstream peer. - `nginx_http_upstream_peer_byte_io_bytes_total`: The total number of byte IO per HTTP upstream peer. - `nginx_http_upstream_peer_count_peers`: The current count of peers on the HTTP upstream grouped by state. -- `nginx_http_upstream_peer_fails_attempts`: The total number of unsuccessful attempts to communicate with the HTTP upstream peer. +- `nginx_http_upstream_peer_fails_attempts_total`: The total number of unsuccessful attempts to communicate with the HTTP upstream peer. - `nginx_http_upstream_peer_header_time_milliseconds`: The average time to get the response header from the HTTP upstream peer. - `nginx_http_upstream_peer_health_checks_requests_total`: The total number of health check requests made to a HTTP upstream peer. - `nginx_http_upstream_peer_requests_total`: The total number of client requests forwarded to the HTTP upstream peer. From c029fd2c0c7775922704dedff479eda7125c8aae Mon Sep 17 00:00:00 2001 From: bjee19 <139261241+bjee19@users.noreply.github.com> Date: Tue, 20 May 2025 12:07:08 -0700 Subject: [PATCH 17/22] NGF: Add Deploy data plane doc (#530) Add "Deploy Data plane document" to guide users on how to create and modify the NGINX Data Plane. Problem: Users want a guide on how to create and modify the NGINX Data Plane. Solution: Added the guide. --- .../installing-ngf/deploy-data-plane.md | 242 ++++++++++++++++++ .../installation/installing-ngf/manifests.md | 9 +- 2 files changed, 248 insertions(+), 3 deletions(-) create mode 100644 content/ngf/installation/installing-ngf/deploy-data-plane.md diff --git a/content/ngf/installation/installing-ngf/deploy-data-plane.md b/content/ngf/installation/installing-ngf/deploy-data-plane.md new file mode 100644 index 000000000..92d04248b --- /dev/null +++ b/content/ngf/installation/installing-ngf/deploy-data-plane.md @@ -0,0 +1,242 @@ +--- +title: Deploy a Gateway for data plane instances +weight: 500 +toc: true +type: how-to +product: NGF +docs: DOCS-000 +--- + +## Overview + +This document describes how to use a Gateway to deploy the NGINX data plane, and how to modify it using an NGINX custom resource. + +[A Gateway](https://gateway-api.sigs.k8s.io/concepts/api-overview/#gateway) is used to manage all inbound requests, and is a key Gateway API resource. + +When a Gateway is attached to a GatewayClass associated with NGINX Gateway Fabric, it creates a Service and an NGINX deployment. This forms the NGINX data plane, handling requests. + +A single GatewayClass can have multiple Gateways: each Gateway will create a separate Service and NGINX deployment. + +## Before you begin + +- [Install]({{< ref "/ngf/installation/" >}}) NGINX Gateway Fabric. + +## Create a Gateway + +To deploy a Gateway, run the following command: + +```yaml +kubectl apply -f - < 80:30180/TCP 5m2s +``` + +The Service type can be changed, as explained in the next section. + +## How to modify provisioned NGINX instances + +The NginxProxy custom resource can modify the provisioning of the Service object and NGINX deployment when a Gateway is created. + +{{< note >}} Updating most Kubernetes related fields in NginxProxy will trigger a restart of the related resources. {{< /note >}} + +An NginxProxy resource is created by default after deploying NGINX Gateway Fabric. This NginxProxy resource is attached to the GatewayClass (created on NGINX Gateway Fabric installation), and +its settings are applied globally to all Gateways. + +Use `kubectl get` and `kubectl describe` to get some more information on the resource: + +```shell +kubectl get nginxproxies -A +``` +```text +NAMESPACE NAME AGE +nginx-gateway ngf-proxy-config 19h +``` + +```shell +kubectl describe nginxproxy -n nginx-gateway ngf-proxy-config +``` +```text +Name: ngf-proxy-config +Namespace: nginx-gateway +Labels: app.kubernetes.io/instance=ngf + app.kubernetes.io/managed-by=Helm + app.kubernetes.io/name=nginx-gateway-fabric + app.kubernetes.io/version=edge + helm.sh/chart=nginx-gateway-fabric-1.6.2 +Annotations: meta.helm.sh/release-name: ngf + meta.helm.sh/release-namespace: nginx-gateway +API Version: gateway.nginx.org/v1alpha2 +Kind: NginxProxy +Metadata: + Creation Timestamp: 2025-05-05T23:01:28Z + Generation: 1 + Resource Version: 2245 + UID: b545aa9e-74f8-45c0-b472-f14d3cab936f +Spec: + Ip Family: dual + Kubernetes: + Deployment: + Container: + Image: + Pull Policy: IfNotPresent + Repository: nginx-gateway-fabric/nginx + Tag: edge + Replicas: 1 + Service: + External Traffic Policy: Local + Type: LoadBalancer +Events: +``` + +From the information obtained with `kubectl describe` you can see the default settings for the provisioned NGINX Deployment and Service. +Under `Spec.Kubernetes` you can see a few things: +- The NGINX container image settings +- How many NGINX Deployment replicas are specified +- The type of Service and external traffic policy + +{{< note >}} Depending on installation configuration, the default NginxProxy settings may be slightly different from what is shown in the example. +For more information on NginxProxy and its configurable fields, see the [API reference]({{< ref "/ngf/reference/api.md" >}}). {{< /note >}} + +Modify the NginxProxy resource to change the type of Service. + +Use `kubectl edit` to modify the default NginxProxy and insert the following under `spec.kubernetes.service`: + +```yaml +type: NodePort +``` + +After saving the changes, use `kubectl get` on the service, and you should see the service type has changed to `LoadBalancer`. + +```shell +kubectl get service cafe-nginx +``` +```text +NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE +cafe-nginx NodePort 10.96.172.204 80:32615/TCP 3h5m +``` + +### How to set annotations and labels on provisioned resources + +While the majority of configuration will happen on the NginxProxy resource, that is not always the case. Uniquely, if +you want to set any annotations or labels on the NGINX Deployment or Service, you need to set those annotations on the Gateway which +provisioned them. + +You can use `kubectl edit` on the Gateway and add the following to the `spec`: + +```yaml +infrastructure: + annotations: + annotationKey: annotationValue + labels: + labelKey: labelValue +``` + +After saving the changes, check the Service and NGINX deployment with `kubectl describe`. + +```shell +kubectl describe deployment cafe +``` +```text +Name: cafe-nginx +Namespace: default +CreationTimestamp: Mon, 05 May 2025 16:49:33 -0700 +... +Pod Template: + Labels: app.kubernetes.io/instance=ngf + app.kubernetes.io/managed-by=ngf-nginx + app.kubernetes.io/name=cafe-nginx + gateway.networking.k8s.io/gateway-name=cafe + labelKey=labelValue + Annotations: annotationKey: annotationValue + prometheus.io/port: 9113 + prometheus.io/scrape: true +... +``` + +```shell +kubectl describe service cafe-nginx +``` +```text +Name: cafe-nginx +Namespace: default +Labels: app.kubernetes.io/instance=ngf + app.kubernetes.io/managed-by=ngf-nginx + app.kubernetes.io/name=cafe-nginx + gateway.networking.k8s.io/gateway-name=cafe + labelKey=labelValue +Annotations: annotationKey: annotationValue +``` + +## See also + +For more guides on routing traffic to applications and more information on Data Plane configuration, check out the following resources: + +- [Routing traffic to applications]({{< ref "/ngf/how-to/traffic-management/routing-traffic-to-your-app.md" >}}) +- [Application routes using HTTP matching conditions]({{< ref "/ngf/how-to/traffic-management/advanced-routing.md" >}}) +- [Data plane configuration]({{< ref "/ngf/how-to/data-plane-configuration.md" >}}) +- [API reference]({{< ref "/ngf/reference/api.md" >}}) \ No newline at end of file diff --git a/content/ngf/installation/installing-ngf/manifests.md b/content/ngf/installation/installing-ngf/manifests.md index ec8ec590a..286e927d0 100644 --- a/content/ngf/installation/installing-ngf/manifests.md +++ b/content/ngf/installation/installing-ngf/manifests.md @@ -97,11 +97,14 @@ Deploys NGINX Gateway Fabric with NGINX OSS. kubectl apply -f https://raw.githubusercontent.com/nginx/nginx-gateway-fabric/v{{< version-ngf >}}/deploy/default/deploy.yaml ``` -To set up an AWS Network Load Balancer service, add these annotations to your Gateway infrastructure fields: +To set up an AWS Network Load Balancer service, add these annotations to your Gateway infrastructure field: ```yaml -service.beta.kubernetes.io/aws-load-balancer-type: "external" -service.beta.kubernetes.io/aws-load-balancer-nlb-target-type: "ip" +spec: + infrastructure: + annotations: + service.beta.kubernetes.io/aws-load-balancer-type: "external" + service.beta.kubernetes.io/aws-load-balancer-nlb-target-type: "ip" ``` {{% /tab %}} From c6c8bab1feff1ca82a61622c8bd342e9a66d0e33 Mon Sep 17 00:00:00 2001 From: salonichf5 <146118978+salonichf5@users.noreply.github.com> Date: Wed, 21 May 2025 00:55:09 +0530 Subject: [PATCH 18/22] NGF: Update Gateway Compatibility Document (#540) docs: Updates Gateway Compatibility document to reflect new architecture changes. --- .../ngf/overview/gateway-api-compatibility.md | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/content/ngf/overview/gateway-api-compatibility.md b/content/ngf/overview/gateway-api-compatibility.md index 4e08a90de..8ff59d32e 100644 --- a/content/ngf/overview/gateway-api-compatibility.md +++ b/content/ngf/overview/gateway-api-compatibility.md @@ -90,7 +90,7 @@ NGINX Gateway Fabric supports a single GatewayClass resource configured with the {{< /bootstrap-table >}} -NGINX Gateway Fabric supports a single Gateway resource. The Gateway resource must reference NGINX Gateway Fabric's corresponding GatewayClass. +NGINX Gateway Fabric supports multiple Gateway resources. The Gateway resources must reference NGINX Gateway Fabric's corresponding GatewayClass. See the [static-mode]({{< ref "/ngf/reference/cli-help.md#static-mode">}}) command for more information. @@ -98,10 +98,10 @@ See the [static-mode]({{< ref "/ngf/reference/cli-help.md#static-mode">}}) comma - `spec` - `gatewayClassName`: Supported. - - `infrastructure`: Partially Supported. + - `infrastructure`: Supported. - `parametersRef`: NginxProxy resource supported. - - `labels`: Not supported. - - `annotations`: Not supported. + - `labels`: Supported. + - `annotations`: Supported. - `listeners` - `name`: Supported. - `hostname`: Supported. @@ -113,21 +113,17 @@ See the [static-mode]({{< ref "/ngf/reference/cli-help.md#static-mode">}}) comma - `options`: Not supported. - `allowedRoutes`: Supported. - `addresses`: Not supported. - - `infrastructure`: Not supported. - `backendTLS`: Not supported. - `status` - - `addresses`: Partially supported (LoadBalancer and Pod IP). + - `addresses`: Partially supported (LoadBalancer and ClusterIP). - `conditions`: Supported (Condition/Status/Reason): - `Accepted/True/Accepted` - `Accepted/True/ListenersNotValid` - `Accepted/False/ListenersNotValid` - `Accepted/False/Invalid` - `Accepted/False/UnsupportedValue`: Custom reason for when a value of a field in a Gateway is invalid or not supported. - - `Accepted/False/GatewayConflict`: Custom reason for when the Gateway is ignored due to a conflicting Gateway. - NGINX Gateway Fabric only supports a single Gateway. - `Programmed/True/Programmed` - `Programmed/False/Invalid` - - `Programmed/False/GatewayConflict`: Custom reason for when the Gateway is ignored due to a conflicting Gateway. NGINX Gateway Fabric only supports a single Gateway. - `listeners` - `name`: Supported. - `supportedKinds`: Supported. @@ -139,7 +135,6 @@ See the [static-mode]({{< ref "/ngf/reference/cli-help.md#static-mode">}}) comma - `Accepted/False/ProtocolConflict` - `Accpeted/False/HostnameConflict` - `Accepted/False/UnsupportedValue`: Custom reason for when a value of a field in a Listener is invalid or not supported. - - `Accepted/False/GatewayConflict`: Custom reason for when the Gateway is ignored due to a conflicting Gateway. NGINX Gateway Fabric only supports a single Gateway. - `Programmed/True/Programmed` - `Programmed/False/Invalid` - `ResolvedRefs/True/ResolvedRefs` @@ -388,4 +383,4 @@ Fields: Custom policies are NGINX Gateway Fabric-specific CRDs (Custom Resource Definitions) that support features such as tracing, and client connection settings. These important data-plane features are not part of the Gateway API specifications. While these CRDs are not part of the Gateway API, the mechanism to attach them to Gateway API resources is part of the Gateway API. See the [Policy Attachment documentation](https://gateway-api.sigs.k8s.io/references/policy-attachment/). -See the [custom policies]({{< ref "/ngf/overview/custom-policies.md" >}}) document for more information. +See the [custom policies]({{< ref "/ngf/overview/custom-policies.md" >}}) document for more information. \ No newline at end of file From 1ffebbb86b926adf445c4bc4d2d7c8264436661a Mon Sep 17 00:00:00 2001 From: Ciara Stacke <18287516+ciarams87@users.noreply.github.com> Date: Thu, 22 May 2025 12:45:57 +0100 Subject: [PATCH 19/22] NGF: Update missed imagePullSecret helm values (#556) Update missed imagePullSecret helm values --- content/ngf/installation/installing-ngf/helm.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/content/ngf/installation/installing-ngf/helm.md b/content/ngf/installation/installing-ngf/helm.md index 11bf320e0..25aa0e4fb 100644 --- a/content/ngf/installation/installing-ngf/helm.md +++ b/content/ngf/installation/installing-ngf/helm.md @@ -77,7 +77,7 @@ helm install ngf oci://ghcr.io/nginx/charts/nginx-gateway-fabric --create-namesp To install the latest stable release of NGINX Gateway Fabric in the **nginx-gateway** namespace, run the following command: ```shell -helm install ngf oci://ghcr.io/nginx/charts/nginx-gateway-fabric --set nginx.image.repository=private-registry.nginx.com/nginx-gateway-fabric/nginx-plus --set nginx.plus=true --set serviceAccount.imagePullSecret=nginx-plus-registry-secret -n nginx-gateway +helm install ngf oci://ghcr.io/nginx/charts/nginx-gateway-fabric --set nginx.image.repository=private-registry.nginx.com/nginx-gateway-fabric/nginx-plus --set nginx.plus=true --set nginx.imagePullSecret=nginx-plus-registry-secret -n nginx-gateway ``` {{% /tab %}} @@ -121,7 +121,7 @@ helm install ngf . --create-namespace -n nginx-gateway To install the chart into the **nginx-gateway** namespace, run the following command: ```shell -helm install ngf . --set nginx.image.repository=private-registry.nginx.com/nginx-gateway-fabric/nginx-plus --set nginx.plus=true --set serviceAccount.imagePullSecret=nginx-plus-registry-secret -n nginx-gateway +helm install ngf . --set nginx.image.repository=private-registry.nginx.com/nginx-gateway-fabric/nginx-plus --set nginx.plus=true --set nginx.imagePullSecret=nginx-plus-registry-secret -n nginx-gateway ``` {{% /tab %}} @@ -260,7 +260,7 @@ To upgrade from NGINX OSS to NGINX Plus, update the Helm command to include the {{< important >}} Ensure that you [Create the required JWT Secrets]({{< ref "/ngf/installation/nginx-plus-jwt.md" >}}) before installing.{{< /important >}} ```shell -helm upgrade ngf oci://ghcr.io/nginx/charts/nginx-gateway-fabric --set nginx.image.repository=private-registry.nginx.com/nginx-gateway-fabric/nginx-plus --set nginx.plus=true --set serviceAccount.imagePullSecret=nginx-plus-registry-secret -n nginx-gateway +helm upgrade ngf oci://ghcr.io/nginx/charts/nginx-gateway-fabric --set nginx.image.repository=private-registry.nginx.com/nginx-gateway-fabric/nginx-plus --set nginx.plus=true --set nginx.imagePullSecret=nginx-plus-registry-secret -n nginx-gateway ``` If needed, replace `ngf` with your chosen release name. From 95f2d02e835a00b096ca934eb531353414125444 Mon Sep 17 00:00:00 2001 From: salonichf5 <146118978+salonichf5@users.noreply.github.com> Date: Thu, 22 May 2025 21:32:17 +0530 Subject: [PATCH 20/22] NGF: Upgrade NGF from 1.x to 2.x (#564) * docs: upgrade NGF from v1.x to v2.x --- content/ngf/how-to/_index.md | 2 +- .../installing-ngf/control-plane-certs.md | 6 +- content/ngf/reference/_index.md | 2 +- content/ngf/releases.md | 2 +- content/ngf/support.md | 2 +- content/ngf/upgrading-ngf.md | 95 +++++++++++++++++++ 6 files changed, 104 insertions(+), 5 deletions(-) create mode 100644 content/ngf/upgrading-ngf.md diff --git a/content/ngf/how-to/_index.md b/content/ngf/how-to/_index.md index b48bf630e..3d0b4588a 100644 --- a/content/ngf/how-to/_index.md +++ b/content/ngf/how-to/_index.md @@ -1,5 +1,5 @@ --- title: "How-to guides" url: /nginx-gateway-fabric/how-to/ -weight: 400 +weight: 500 --- diff --git a/content/ngf/installation/installing-ngf/control-plane-certs.md b/content/ngf/installation/installing-ngf/control-plane-certs.md index 4a34e24d9..763405e94 100644 --- a/content/ngf/installation/installing-ngf/control-plane-certs.md +++ b/content/ngf/installation/installing-ngf/control-plane-certs.md @@ -13,6 +13,8 @@ By default, NGINX Gateway Fabric installs self-signed certificates to secure the This guide will step through how to install and use `cert-manager` to secure this connection. **This should be done _before_ you install NGINX Gateway Fabric.** +--- + ## Before you begin You need: @@ -27,6 +29,7 @@ Add the Helm repository: ```shell helm repo add jetstack https://charts.jetstack.io helm repo update +``` Install cert-manager: @@ -39,8 +42,9 @@ helm install \ --set config.kind="ControllerConfiguration" \ --set config.enableGatewayAPI=true \ --set crds.enabled=true +``` - This also enables Gateway API features for cert-manager, which can be useful for [securing your workload traffic]({{< ref "/ngf/how-to/traffic-security/integrating-cert-manager.md" >}}). +This also enables Gateway API features for cert-manager, which can be useful for [securing your workload traffic]({{< ref "/ngf/how-to/traffic-security/integrating-cert-manager.md" >}}). ## Create the CA issuer diff --git a/content/ngf/reference/_index.md b/content/ngf/reference/_index.md index 7fad2be4f..075c35741 100644 --- a/content/ngf/reference/_index.md +++ b/content/ngf/reference/_index.md @@ -1,5 +1,5 @@ --- title: "Reference" -weight: 500 +weight: 600 url: /nginx-gateway-fabric/reference/ --- diff --git a/content/ngf/releases.md b/content/ngf/releases.md index f371d7a96..2dabcd11e 100644 --- a/content/ngf/releases.md +++ b/content/ngf/releases.md @@ -1,7 +1,7 @@ --- title: Releases description: "NGINX Gateway Fabric releases." -weight: 700 +weight: 800 toc: true type: reference product: NGF diff --git a/content/ngf/support.md b/content/ngf/support.md index c6f28eed2..198f88f3a 100644 --- a/content/ngf/support.md +++ b/content/ngf/support.md @@ -1,6 +1,6 @@ --- title: Support -weight: 600 +weight: 700 toc: true type: reference product: NGF diff --git a/content/ngf/upgrading-ngf.md b/content/ngf/upgrading-ngf.md new file mode 100644 index 000000000..d19aebed7 --- /dev/null +++ b/content/ngf/upgrading-ngf.md @@ -0,0 +1,95 @@ +--- +title: Upgrade NGINX Gateway Fabric to version 2.x +weight: 400 +toc: true +type: how-to +product: NGF +docs: DOCS-0000 +--- + +This guide provides step-by-step instructions for upgrading NGINX Gateway Fabric from version 1.x to 2.x, highlighting key architectural changes, expected downtime, and important considerations for custom resource definitions (CRDs). + + +### Upgrade from v1.x to v2.x + +To upgrade NGINX Gateway Fabric from version 1.x to the new architecture in version 2.x, you must uninstall the existing NGINX Gateway Fabric CRDs and deployment, and perform a fresh installation. This will cause brief downtime during the upgrade process. + +{{}} You do not need to uninstall the Gateway API CRDs during the upgrade. These resources are compatible with the new NGINX Gateway Fabric version. {{}} + +#### Uninstall NGINX Gateway Fabric v1.x + +To remove the previous version 1.x of NGINX Gateway Fabric, follow these steps: + +First, run the following command to uninstall NGINX Gateway Fabric from the `nginx-gateway` namespace, and update `ngf` to your release name if it is different: + +```shell +helm uninstall ngf -n nginx-gateway +``` + +Afterwards, remove CRDs associated with NGINX Gateway Fabric version 1.x with the following command: + +```shell +kubectl delete -f https://raw.githubusercontent.com/nginx/nginx-gateway-fabric/v1.6.2/deploy/crds.yaml +``` + +{{}} + +{{%tab name="Helm"%}} + +Follow these steps to install NGINX Gateway Fabric v2.x using Helm: + +Next, install the latest stable release of NGINX Gateway Fabric in the `nginx-gateway` namespace. The following `helm install` command will install the NGINX Gateway Fabric release along with the necessary CRDs required for the deployment: + +```shell +helm install ngf oci://ghcr.io/nginx/charts/nginx-gateway-fabric --create-namespace -n nginx-gateway +``` + +For additional customization options during the helm installation process, take a look at [Installation with Helm]({{< ref "/ngf/installation/installing-ngf/helm.md" >}}). + +{{% /tab %}} + +{{%tab name="Manifests"%}} + +Follow these steps to install NGINX Gateway Fabric v2.x using Manifests: + +Apply the new CRDs with the following command: + +```shell +kubectl apply -f https://raw.githubusercontent.com/nginx/nginx-gateway-fabric/v{{< version-ngf >}}/deploy/crds.yaml +``` + +Next, install the latest stable release of NGINX Gateway Fabric in the `nginx-gateway` namespace with the following command: + +```shell +kubectl apply -f https://raw.githubusercontent.com/nginx/nginx-gateway-fabric/v{{< version-ngf >}}/deploy/default/deploy.yaml +``` + +For additional customization options during the installation process using manifests, take a look at [Installation with Manifests]({{< ref "/ngf/installation/installing-ngf/manifests.md" >}}). + +{{% /tab %}} + +{{}} + + +### Architecture changes + +With this release, NGINX Gateway Fabric adopts a new architecture that separates the control plane and data plane into independent deployments. This separation improves scalability, security, and operational clarity. + +The control plane is a Kubernetes controller that watches Gateway API and Kubernetes resources (e.g., Services, Endpoints, Secrets) and dynamically provisions NGINX data plane deployments for each Gateway. + +NGINX configurations are generated by the control plane and securely delivered to the data planes via gRPC, using the NGINX Agent. TLS is enabled by default, with optional integration with `cert-manager`. + +Each data plane pod runs NGINX alongside the Agent, which applies config updates and handles reloads without shared volumes or signals. This design ensures dynamic, per-Gateway traffic management and operational isolation. + +New fields have been added to the `NginxProxy` resource to configure infrastructure-related settings for data plane deployments. The `NginxProxy` resource is now a namespaced-scoped resource, instead of a cluster-scoped resource, and can be modified at either the Gateway or GatewayClass level. These new fields provide the flexibility to customize deployment and service configurations. + +For detailed instructions on how to modify these settings, refer to the [Configure infrastructure-related settings]({{< ref "/ngf/how-to/data-plane-configuration.md#configure-infrastructure-related-settings" >}}) guide. + + +### Key links for the version 2.x update + +- To read more on [modifying data plane configuration]({{< ref "/ngf/how-to/data-plane-configuration.md" >}}). +- To learn more about [deploying a Gateway for data plane instances]({{< ref "/ngf/installation/installing-ngf/deploy-data-plane.md" >}}). +- To adding secure [authentication to control plane and data planes]({{< ref "/ngf/installation/installing-ngf/control-plane-certs.md" >}}). +- To read more about [architecture changes]({{< ref "/ngf/overview/gateway-architecture.md" >}}). +- For detailed [API reference]({{< ref "/ngf/reference/api.md" >}}). From fe11d3b9812ea38f53361f95791e8b34e24cd5b7 Mon Sep 17 00:00:00 2001 From: Saylor Berman Date: Thu, 22 May 2025 14:05:04 -0600 Subject: [PATCH 21/22] Fix NGF grafana for new metrics (#584) Problem: Agent metrics were updated, but the NGF sample dashboard was not. Solution: Update the dashboard with the new metrics name. --- static/ngf/ngf-grafana-dashboard.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/static/ngf/ngf-grafana-dashboard.json b/static/ngf/ngf-grafana-dashboard.json index 9af953ce1..fbd5f2963 100644 --- a/static/ngf/ngf-grafana-dashboard.json +++ b/static/ngf/ngf-grafana-dashboard.json @@ -339,7 +339,7 @@ "disableTextWrap": false, "editorMode": "builder", "exemplar": false, - "expr": "irate(nginx_http_connections_count{instance=~\"$nginx_instance\", nginx_connections_outcome=\"ACTIVE\"}[1m])", + "expr": "irate(nginx_http_connection_count_connections{instance=~\"$nginx_instance\", nginx_connections_outcome=\"ACTIVE\"}[1m])", "fullMetaSearch": false, "includeNullMetadata": true, "instant": false, @@ -355,7 +355,7 @@ }, "disableTextWrap": false, "editorMode": "builder", - "expr": "irate(nginx_http_connections_count{instance=~\"$nginx_instance\", nginx_connections_outcome=\"READING\"}[1m])", + "expr": "irate(nginx_http_connection_count_connections{instance=~\"$nginx_instance\", nginx_connections_outcome=\"READING\"}[1m])", "fullMetaSearch": false, "hide": false, "includeNullMetadata": true, @@ -372,7 +372,7 @@ }, "disableTextWrap": false, "editorMode": "builder", - "expr": "irate(nginx_http_connections_count{instance=~\"$nginx_instance\", nginx_connections_outcome=\"WAITING\"}[1m])", + "expr": "irate(nginx_http_connection_count_connections{instance=~\"$nginx_instance\", nginx_connections_outcome=\"WAITING\"}[1m])", "fullMetaSearch": false, "hide": false, "includeNullMetadata": true, @@ -389,7 +389,7 @@ }, "disableTextWrap": false, "editorMode": "builder", - "expr": "irate(nginx_http_connections_count{instance=~\"$nginx_instance\", nginx_connections_outcome=\"WRITING\"}[1m])", + "expr": "irate(nginx_http_connection_count_connections{instance=~\"$nginx_instance\", nginx_connections_outcome=\"WRITING\"}[1m])", "fullMetaSearch": false, "hide": false, "includeNullMetadata": true, From 4caf9c3e65ff55903923891362603682726b5d32 Mon Sep 17 00:00:00 2001 From: Saylor Berman Date: Thu, 22 May 2025 14:11:51 -0600 Subject: [PATCH 22/22] Revert ngf-dashboard name --- static/ngf/{ngf-grafana-dashboard.json => grafana-dashboard.json} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename static/ngf/{ngf-grafana-dashboard.json => grafana-dashboard.json} (100%) diff --git a/static/ngf/ngf-grafana-dashboard.json b/static/ngf/grafana-dashboard.json similarity index 100% rename from static/ngf/ngf-grafana-dashboard.json rename to static/ngf/grafana-dashboard.json