diff --git a/.gitignore b/.gitignore index f1c85c102e..7b75ba804a 100644 --- a/.gitignore +++ b/.gitignore @@ -33,3 +33,6 @@ node_modules/ # JS test coverage internal/mode/static/nginx/modules/coverage + +# MacOS Finder +.DS_Store diff --git a/docs/guides/README.md b/docs/guides/README.md index 60ca218e34..7aceccb35b 100644 --- a/docs/guides/README.md +++ b/docs/guides/README.md @@ -4,6 +4,8 @@ This directory contains guides for configuring NGINX Kubernetes Gateway for vari ## Contents +- [Routing Traffic to Your Application](routing-traffic-to-your-app.md): How to use NGINX Kubernetes Gateway to route + all Ingress traffic to your Kubernetes application. - [Securing Traffic using Let's Encrypt and Cert-Manager](integrating-cert-manager.md): Shows how to secure traffic from clients to NGINX Kubernetes Gateway with TLS using Let's Encrypt and Cert-Manager. - [Using NGINX Kubernetes Gateway to Upgrade Applications without Downtime](upgrade-apps-without-downtime.md): diff --git a/docs/guides/routing-traffic-to-your-app.md b/docs/guides/routing-traffic-to-your-app.md new file mode 100644 index 0000000000..5316aaff43 --- /dev/null +++ b/docs/guides/routing-traffic-to-your-app.md @@ -0,0 +1,405 @@ +# Routing Traffic to Your Application + +In this guide, you will learn how to route external traffic to your Kubernetes applications using the Gateway API and +NGINX Kubernetes Gateway. Whether you're managing a web application or a REST backend API, you can use NGINX Kubernetes +Gateway to expose your application outside the cluster. + +## Prerequisites + +- [Install](/docs/installation.md) NGINX Kubernetes Gateway. +- [Expose NGINX Kubernetes Gateway](/docs/installation.md#expose-nginx-kubernetes-gateway) and save the public IP + address and port of NGINX Kubernetes Gateway into shell variables: + + ```text + GW_IP=XXX.YYY.ZZZ.III + GW_PORT= + ``` + +## The Application + +The application we are going to use in this guide is a simple coffee application comprised of one Service and two Pods: + +![coffee app](/docs/images/route-all-traffic-app.png) + +With this architecture, the coffee application is not accessible outside the cluster. We want to expose this application +on the hostname `cafe.example.com` so that clients outside the cluster can access it. + +To do this, we will install NGINX Kubernetes Gateway and create two Gateway API resources: +a [Gateway](https://gateway-api.sigs.k8s.io/v1alpha2/references/spec/#gateway.networking.k8s.io/v1beta1.Gateway) and +an [HTTPRoute](https://gateway-api.sigs.k8s.io/v1alpha2/references/spec/#gateway.networking.k8s.io/v1beta1.HTTPRoute). +With these resources, we will configure a simple routing rule to match all HTTP traffic with the +hostname `cafe.example.com` and route it to the coffee Service. + +## Setup + +Create the coffee application in Kubernetes by copying and pasting the following into your terminal: + +```yaml +kubectl apply -f - < 80/TCP 77s +``` + +## Application Architecture with NGINX Kubernetes Gateway + +To route traffic to the coffee application, we will create a Gateway and HTTPRoute. The following diagram shows the +configuration we'll be creating in the next step: + +![Configuration](/docs/images/route-all-traffic-config.png) + +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 +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 Kubernetes Gateway processes the `cafe` Gateway and `coffee` HTTPRoute, it will configure its dataplane, NGINX, +to route all HTTP requests to `cafe.example.com` to the Pods that the `coffee` Service targets: + +![Traffic Flow](/docs/images/route-all-traffic-flow.png) + +The coffee Service is omitted from the diagram above because the NGINX Kubernetes Gateway 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 green. +> The orange resources are the responsibility of the application developers. +> See the [roles and personas](https://gateway-api.sigs.k8s.io/concepts/roles-and-personas/#roles-and-personas_1) +> Gateway API document for more information on these roles. + +## Create the Gateway API Resources + +To create the `cafe` Gateway, copy and paste the following into your terminal: + +```yaml +kubectl apply -f - < **Note** +> Your clients should be able to resolve the domain name `cafe.example.com` to the public IP of the +> NGINX Kubernetes Gateway. In this guide we will simulate that using curl's `--resolve` option. + + +First, let's send a request to the path `/`: + +```shell +curl --resolve cafe.example.com:$GW_PORT:$GW_IP http://cafe.example.com:$GW_PORT/ +``` + +We should get a response from one of the coffee Pods: + +```text +Server address: 10.12.0.18:8080 +Server name: coffee-7dd75bc79b-cqvb7 +``` + +Since the `cafe` HTTPRoute routes all traffic on any path to the coffee application, the following requests should also +be handled by the coffee Pods: + +```shell +curl --resolve cafe.example.com:$GW_PORT:$GW_IP http://cafe.example.com:$GW_PORT/some-path +``` + +```text +Server address: 10.12.0.18:8080 +Server name: coffee-7dd75bc79b-cqvb7 +``` + +```shell +curl --resolve cafe.example.com:$GW_PORT:$GW_IP http://cafe.example.com:$GW_PORT/some/path +``` + +```text +Server address: 10.12.0.19:8080 +Server name: coffee-7dd75bc79b-dett3 +``` + +Requests to hostnames other than `cafe.example.com` should _not_ be routed to the coffee application, since the `cafe` +HTTPRoute only matches requests with the `cafe.example.com` hostname. To verify this, send a request to the hostname +`pub.example.com`: + +```shell +curl --resolve pub.example.com:$GW_PORT:$GW_IP http://pub.example.com:$GW_PORT/ +``` + +You should receive a 404 Not Found error: + +```text + +404 Not Found + +

404 Not Found

+
nginx/1.25.2
+ + +``` + +## Troubleshooting + +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 Kubernetes Gateway + Service. Instructions for finding those values are [here](/docs/installation.md#expose-nginx-kubernetes-gateway). + +- Check the status of the Gateway: + + ```shell + kubectl describe gateway cafe + ``` + + The Gateway status should look similar to this: + + ```text + Status: + Addresses: + Type: IPAddress + Value: 10.244.0.85 + Conditions: + Last Transition Time: 2023-08-15T20:57:21Z + Message: Gateway is accepted + Observed Generation: 1 + Reason: Accepted + Status: True + Type: Accepted + Last Transition Time: 2023-08-15T20:57:21Z + Message: Gateway is programmed + Observed Generation: 1 + Reason: Programmed + Status: True + Type: Programmed + Listeners: + Attached Routes: 1 + Conditions: + Last Transition Time: 2023-08-15T20:57:21Z + Message: Listener is accepted + Observed Generation: 1 + Reason: Accepted + Status: True + Type: Accepted + Last Transition Time: 2023-08-15T20:57:21Z + Message: Listener is programmed + Observed Generation: 1 + Reason: Programmed + Status: True + Type: Programmed + Last Transition Time: 2023-08-15T20:57:21Z + Message: All references are resolved + Observed Generation: 1 + Reason: ResolvedRefs + Status: True + Type: ResolvedRefs + Last Transition Time: 2023-08-15T20:57:21Z + Message: No conflicts + Observed Generation: 1 + Reason: NoConflicts + Status: False + Type: Conflicted + Name: http + ``` + + Check that the conditions match and that the attached routes for the `http` listener equals 1. If it is 0, there may + be an issue with the HTTPRoute. + +- Check the status of the HTTPRoute: + + ```shell + kubectl describe httproute coffee + ``` + + The HTTPRoute status should look similar to this: + + ```text + Status: + Parents: + Conditions: + Last Transition Time: 2023-08-15T20:57:21Z + Message: The route is accepted + Observed Generation: 1 + Reason: Accepted + Status: True + Type: Accepted + Last Transition Time: 2023-08-15T20:57:21Z + Message: All references are resolved + Observed Generation: 1 + Reason: ResolvedRefs + Status: True + Type: ResolvedRefs + Controller Name: gateway.nginx.org/nginx-gateway-controller + Parent Ref: + Group: gateway.networking.k8s.io + Kind: Gateway + Name: cafe + Namespace: default + ``` + + Check for any error messages in the conditions. + +- Check the generated nginx config: + + ```shell + kubectl exec -it -n nginx-gateway -c nginx -- 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: + + ```nginx configuration + server { + listen 80; + + server_name cafe.example.com; + + location / { + ... + proxy_pass http://default_coffee_80$request_uri; # the upstream is named default_coffee_80 + ... + } + } + ``` + + There should also be an upstream block with a name that matches the upstream in the `proxy_pass` directive. This + upstream block should contain the Pod IPs of the coffee Pods: + + ```nginx configuration + upstream default_coffee_80 { + ... + server 10.12.0.18:8080; # these should be the Pod IPs of the coffee Pods + server 10.12.0.19:8080; + ... + } + ``` + + > **Note** + > The entire configuration is not shown because it is subject to change. + > Ellipses indicate that there's configuration not shown. + +If your issue persists, [contact us](https://github.com/nginxinc/nginx-kubernetes-gateway#contacts). + +## Further Reading + +To learn more about the Gateway API and the resources we created in this guide, check out the following resources: + +- [Gateway API Overview](https://gateway-api.sigs.k8s.io/concepts/api-overview/) +- [Deploying a simple Gateway](https://gateway-api.sigs.k8s.io/guides/simple-gateway/) +- [HTTP Routing](https://gateway-api.sigs.k8s.io/guides/http-routing/) diff --git a/docs/images/route-all-traffic-app.png b/docs/images/route-all-traffic-app.png new file mode 100644 index 0000000000..6de84f7b09 Binary files /dev/null and b/docs/images/route-all-traffic-app.png differ diff --git a/docs/images/route-all-traffic-config.png b/docs/images/route-all-traffic-config.png new file mode 100644 index 0000000000..38c4e08a6e Binary files /dev/null and b/docs/images/route-all-traffic-config.png differ diff --git a/docs/images/route-all-traffic-flow.png b/docs/images/route-all-traffic-flow.png new file mode 100644 index 0000000000..9fc2089c73 Binary files /dev/null and b/docs/images/route-all-traffic-flow.png differ diff --git a/docs/images/src/README.md b/docs/images/src/README.md new file mode 100644 index 0000000000..02c93c4d41 --- /dev/null +++ b/docs/images/src/README.md @@ -0,0 +1,3 @@ +# Diagram Source Files + +This directory contains the source files for the diagrams used in the docs. Source files are named after the image name. diff --git a/docs/images/src/route-all-traffic-app.mermaid b/docs/images/src/route-all-traffic-app.mermaid new file mode 100644 index 0000000000..bc2d4d7063 --- /dev/null +++ b/docs/images/src/route-all-traffic-app.mermaid @@ -0,0 +1,13 @@ +%% mermaid source for route-all-traffic-app.png diagram +graph TB + subgraph cluster [Kubernetes Cluster] + style cluster fill:#FFFFFF,stroke:#000000 + svc[Service\ncoffee] + pod1[Pod\ncoffee] + pod2[Pod\ncoffee] + end + + svc --> pod1 & pod2 + + class pod1,pod2,svc appNode + classDef appNode fill:#edbd8c,stroke:#D9822B diff --git a/docs/images/src/route-all-traffic-config.mermaid b/docs/images/src/route-all-traffic-config.mermaid new file mode 100644 index 0000000000..d2e0a4ffc9 --- /dev/null +++ b/docs/images/src/route-all-traffic-config.mermaid @@ -0,0 +1,42 @@ +%% mermaid source for route-all-traffic-config.png diagram +graph LR + subgraph config [Namespace default] + subgraph padding [" "] + direction LR + style config fill:#FFFFFF,stroke:#000000 + subgraph gw[Gateway cafe] + subgraph gwPadding [" "] + gwContents[HTTP/80] + end + end + subgraph hr[HTTPRoute coffee] + subgraph hrPadding [" "] + hrContents[cafe.example.com] + subgraph describeMatchAll [Match all\ntraffic] + subgraph describeMatchPadding [" "] + matchAll[Host: *\nPath: *] + end + end + subgraph describeService [Group matching\npods within a Service] + subgraph describePadding [" "] + coffeeSvc[Service\ncoffee] + end + end + end + end + end + end + + gwContents --> hrContents --> matchAll --> coffeeSvc + class padding,gwPadding,hrPadding,describeMatchAll,describeService,describePadding,describeMatchPadding noBorder + class gw gateway + class hr httpRoute + class matchAll,hrContents,coffeeSvc appDevNode + class gwContents clusterOppNode + + classDef noBorder stroke:none,fill:none,text-align:center + classDef default fill:#FFFFFF,stroke:#000000 + classDef gateway fill:#FFFFFF,stroke:#2AA317,stroke-dasharray: 3 3,text-align:center + classDef httpRoute fill:#FFFFFF,stroke:#D9822B,stroke-dasharray: 3 3,text-align:center + classDef appDevNode fill:#edbd8c,stroke:#D9822B + classDef clusterOppNode fill:#b4e0ad,stroke:#2AA317 diff --git a/docs/images/src/route-all-traffic-flow.mermaid b/docs/images/src/route-all-traffic-flow.mermaid new file mode 100644 index 0000000000..c136618128 --- /dev/null +++ b/docs/images/src/route-all-traffic-flow.mermaid @@ -0,0 +1,42 @@ +%% mermaid source for route-all-traffic-flow.png diagram +graph LR + clients[Clients] + nkgSvc["Public IP Address\nfor\ncafe.example.com"] + + subgraph cluster [Kubernetes Cluster] + style cluster fill:#FFFFFF,stroke:#000000 + subgraph clusterPadding [" "] + subgraph clusterPadding2 [" "] + subgraph gwNS [Namespace\nnginx-gateway] + nkgPod[Pod\nnginx-gateway] + end + end + end + + subgraph appNs [Namespace\ndefault] + subgraph nsPadding [" "] + coffeePod1[Pod\ncoffee] + coffeePod2[Pod\ncoffee] + end + end + end + + + + nkgSvc --> nkgPod + nkgPod --> coffeePod1 & coffeePod2 + clients --> nkgSvc + + class clusterPadding,nsPadding,clusterPadding2 noBorder + class gwNS,appNs namespace + class nkgPod,nkgSvc nginxNode + class coffeePod1,coffeePod2 coffeeNode + class clients clientNode + + + classDef noBorder stroke:none,fill:none + classDef default fill:#FFFFFF,stroke:#000000 + classDef namespace fill:#FFFFFF,stroke:#036ffc,stroke-dasharray: 5 5,text-align:center + classDef nginxNode fill:#b4e0ad,stroke:#2AA317 + classDef coffeeNode fill:#edbd8c,stroke:#D9822B + classDef clientNode fill:#D3D3D3