From 4d79fd6901ca70026075c595fc52fd40e4a63f73 Mon Sep 17 00:00:00 2001 From: Ciara Stacke Date: Tue, 30 Apr 2024 12:21:08 +0100 Subject: [PATCH 1/3] Add basic example --- examples/grpc-routing/README.md | 224 ++++++++++++++++++++++++ examples/grpc-routing/exact-method.yaml | 29 +++ examples/grpc-routing/grpc.proto | 38 ++++ examples/grpc-routing/headers.yaml | 70 ++++++++ examples/grpc-routing/helloworld.yaml | 79 +++++++++ examples/grpc-routing/hostname.yaml | 49 ++++++ 6 files changed, 489 insertions(+) create mode 100644 examples/grpc-routing/README.md create mode 100644 examples/grpc-routing/exact-method.yaml create mode 100644 examples/grpc-routing/grpc.proto create mode 100644 examples/grpc-routing/headers.yaml create mode 100644 examples/grpc-routing/helloworld.yaml create mode 100644 examples/grpc-routing/hostname.yaml diff --git a/examples/grpc-routing/README.md b/examples/grpc-routing/README.md new file mode 100644 index 0000000000..b8b2e54cf9 --- /dev/null +++ b/examples/grpc-routing/README.md @@ -0,0 +1,224 @@ +# gRPC Routing Example + +In this example, we deploy NGINX Gateway Fabric, a simple gRPC web application, and then configure NGINX Gateway Fabric +to route traffic to that application using GRPCRoute resources. + +## Running the Example + +## 1. Deploy NGINX Gateway Fabric + +1. Follow the [installation instructions](https://docs.nginx.com/nginx-gateway-fabric/installation/) to deploy NGINX Gateway Fabric. + NB: Ensure the Gateway APIs from the experimental channel are installed and that NGF is deployed with the Gateway experimental features enabled. + +1. Save the public IP address of NGINX Gateway Fabric into a shell variable: + + ```text + GW_IP=XXX.YYY.ZZZ.III + ``` + +1. Save the port of NGINX Gateway Fabric: + + ```text + GW_PORT= + ``` + +## 2. Deploy the Helloworld Application + +1. Create the two helloworld Deployments and Services: + + ```shell + kubectl apply -f helloworld.yaml + ``` + +1. Check that the Pods are running in the `default` Namespace: + + ```shell + kubectl -n default get pods + ``` + + ```text + NAME READY STATUS RESTARTS AGE + grpc-infra-backend-v1-766c7d6788-rg92p 1/1 Running 0 12s + grpc-infra-backend-v2-546f7c8d48-mjkkx 1/1 Running 0 12s + ``` + + Save these pod names into variables: + + ```text + POD_V1= + POD_V2= + ``` + +## 3. Configure Routing + +There are 3 options to configure gRPC routing. To access the application and test the routing rules, we will use [grpcurl](https://github.com/fullstorydev/grpcurl?tab=readme-ov-file#installation). + +### 3a. Configure exact method matching based routing + +1. Create the Gateway and GRPCRoute resources: + + ```shell + kubectl apply -f exact-method.yaml + ``` + +2. Test the Application: + + ```shell + grpcurl -plaintext -proto grpc.proto -authority bar.com -d '{"name": "exact"}' ${GW_IP}:${GW_PORT} helloworld.Greeter/SayHello + ``` + + ```text + { + "message": "Hello exact" + } + ``` + +3. Clean up the Gateway and GRPCRoute resources: + + ```shell + kubectl delete -f exact-method.yaml + ``` + +### 3b. Configure hostname based routing + +1. Create the Gateway and GRPCRoute resources: + + ```shell + kubectl apply -f hostname.yaml + ``` + +2. Test the Application: + + ```shell + grpcurl -plaintext -proto grpc.proto -authority bar.com -d '{"name": "bar server"}' ${GW_IP}:${GW_PORT} helloworld.Greeter/SayHello + ``` + + ```text + { + "message": "Hello bar server" + } + ``` + + To make sure this came from the correct server, we can check the application server logs: + + ```shell + kubectl logs ${POD_V1} + ``` + + ```text + 2024/04/29 09:26:54 server listening at [::]:50051 + 2024/04/29 09:28:54 Received: bar server + ``` + + Now we'll send a request to `foo.bar.com` + + ```shell + grpcurl -plaintext -proto grpc.proto -authority foo.bar.com -d '{"name": "foo bar server"}' ${GW_IP}:${GW_PORT} helloworld.Greeter/SayHello + ``` + + ```text + { + "message": "Hello foo bar server" + } + ``` + + This time, we'll check the POD_V2 logs: + + ```shell + kubectl logs ${POD_V2} + ``` + + ```text + 2024/04/29 09:26:55 server listening at [::]:50051 + 2024/04/29 09:29:46 Received: foo bar server + ``` + +3. Clean up the Gateway and GRPCRoute resources: + + ```shell + kubectl delete -f hostname.yaml + ``` + +### 3c. Configure headers based routing + +1. Create the Gateway and GRPCRoute resources: + + ```shell + kubectl apply -f headers.yaml + ``` + +2. Test the Application: + + ```shell + grpcurl -plaintext -proto grpc.proto -authority bar.com -d '{"name": "version one"}' -H 'version: one' ${GW_IP}:${GW_PORT} helloworld.Greeter/SayHello + ``` + + ```text + { + "message": "Hello version one" + } + ``` + + To make sure this came from the correct server, we can check the application server logs: + + ```shell + kubectl logs ${POD_V1} + ``` + + ```text + <...> + 2024/04/29 09:30:27 Received: version one + ``` + + Now we'll send a request with the header `version: two` + + ```shell + grpcurl -plaintext -proto grpc.proto -authority bar.com -d '{"name": "version two"}' -H 'version: two' ${GW_IP}:${GW_PORT} helloworld.Greeter/SayHello + ``` + + ```text + { + "message": "Hello version two" + } + ``` + + This time, we'll check the POD_V2 logs: + + ```shell + kubectl logs ${POD_V2} + ``` + + ```text + <...> + 2024/04/29 09:32:46 Received: version two + ``` + + Finally, we'll send a request with the headers `version: two` and `color: orange` + + ```shell + grpcurl -plaintext -proto grpc.proto -authority bar.com -d '{"name": "version two orange"}' -H 'version: two' -H 'color: orange' ${GW_IP}:${GW_PORT} helloworld.Greeter/SayHello + ``` + + ```text + { + "message": "Hello version two orange" + } + ``` + + Now check the POD_V1 logs again: + + ```shell + kubectl logs ${POD_V1} + ``` + + ```text + <...> + 2024/04/29 09:30:27 Received: version one + 2024/04/29 09:33:26 Received: version two orange + ``` + +3. Clean up the Gateway and GRPCRoute resources: + + ```shell + kubectl delete -f headers.yaml + ``` diff --git a/examples/grpc-routing/exact-method.yaml b/examples/grpc-routing/exact-method.yaml new file mode 100644 index 0000000000..b47b0a8018 --- /dev/null +++ b/examples/grpc-routing/exact-method.yaml @@ -0,0 +1,29 @@ +apiVersion: gateway.networking.k8s.io/v1beta1 +kind: Gateway +metadata: + name: same-namespace +spec: + gatewayClassName: nginx + listeners: + - name: http + port: 80 + protocol: HTTP + allowedRoutes: + namespaces: + from: Same +--- +apiVersion: gateway.networking.k8s.io/v1alpha2 +kind: GRPCRoute +metadata: + name: exact-matching +spec: + parentRefs: + - name: same-namespace + rules: + - matches: + - method: + service: helloworld.Greeter + method: SayHello + backendRefs: + - name: grpc-infra-backend-v1 + port: 8080 diff --git a/examples/grpc-routing/grpc.proto b/examples/grpc-routing/grpc.proto new file mode 100644 index 0000000000..692ef9deda --- /dev/null +++ b/examples/grpc-routing/grpc.proto @@ -0,0 +1,38 @@ +// Copyright 2015 gRPC authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +option go_package = "google.golang.org/grpc/examples/helloworld/helloworld"; +option java_multiple_files = true; +option java_package = "io.grpc.examples.helloworld"; +option java_outer_classname = "HelloWorldProto"; + +package helloworld; + +// The greeting service definition. +service Greeter { + // Sends a greeting + rpc SayHello (HelloRequest) returns (HelloReply) {} +} + +// The request message containing the user's name. +message HelloRequest { + string name = 1; +} + +// The response message containing the greetings +message HelloReply { + string message = 1; +} diff --git a/examples/grpc-routing/headers.yaml b/examples/grpc-routing/headers.yaml new file mode 100644 index 0000000000..fcd3b256df --- /dev/null +++ b/examples/grpc-routing/headers.yaml @@ -0,0 +1,70 @@ +apiVersion: gateway.networking.k8s.io/v1beta1 +kind: Gateway +metadata: + name: same-namespace +spec: + gatewayClassName: nginx + listeners: + - name: http + port: 80 + protocol: HTTP + allowedRoutes: + namespaces: + from: Same +--- +apiVersion: gateway.networking.k8s.io/v1alpha2 +kind: GRPCRoute +metadata: + name: grpc-header-matching +spec: + parentRefs: + - name: same-namespace + rules: + # Matches "version: one" + - matches: + - headers: + - name: version + value: one + backendRefs: + - name: grpc-infra-backend-v1 + port: 8080 + # Matches "version: two" + - matches: + - headers: + - name: version + value: two + backendRefs: + - name: grpc-infra-backend-v2 + port: 8080 + # Matches "version: two" AND "color: orange" + - matches: + - headers: + - name: version + value: two + - name: color + value: orange + backendRefs: + - name: grpc-infra-backend-v1 + port: 8080 + # Matches "color: blue" OR "color: green" + - matches: + - headers: + - name: color + value: blue + - headers: + - name: color + value: green + backendRefs: + - name: grpc-infra-backend-v1 + port: 8080 + # Matches "color: red" OR "color: yellow" + - matches: + - headers: + - name: color + value: red + - headers: + - name: color + value: yellow + backendRefs: + - name: grpc-infra-backend-v2 + port: 8080 diff --git a/examples/grpc-routing/helloworld.yaml b/examples/grpc-routing/helloworld.yaml new file mode 100644 index 0000000000..57c54952fb --- /dev/null +++ b/examples/grpc-routing/helloworld.yaml @@ -0,0 +1,79 @@ +apiVersion: v1 +kind: Service +metadata: + name: grpc-infra-backend-v1 +spec: + selector: + app: grpc-infra-backend-v1 + ports: + - protocol: TCP + port: 8080 + targetPort: 50051 +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: grpc-infra-backend-v1 + labels: + app: grpc-infra-backend-v1 +spec: + replicas: 1 + selector: + matchLabels: + app: grpc-infra-backend-v1 + template: + metadata: + labels: + app: grpc-infra-backend-v1 + spec: + containers: + - name: grpc-infra-backend-v1 + image: ghcr.io/nginxinc/kic-test-grpc-server:edge + env: + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + resources: + requests: + cpu: 10m +--- +apiVersion: v1 +kind: Service +metadata: + name: grpc-infra-backend-v2 +spec: + selector: + app: grpc-infra-backend-v2 + ports: + - protocol: TCP + port: 8080 + targetPort: 50051 +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: grpc-infra-backend-v2 + labels: + app: grpc-infra-backend-v2 +spec: + replicas: 1 + selector: + matchLabels: + app: grpc-infra-backend-v2 + template: + metadata: + labels: + app: grpc-infra-backend-v2 + spec: + containers: + - name: grpc-infra-backend-v2 + image: ghcr.io/nginxinc/kic-test-grpc-server:edge + env: + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + resources: + requests: + cpu: 10m diff --git a/examples/grpc-routing/hostname.yaml b/examples/grpc-routing/hostname.yaml new file mode 100644 index 0000000000..4da0940644 --- /dev/null +++ b/examples/grpc-routing/hostname.yaml @@ -0,0 +1,49 @@ +apiVersion: gateway.networking.k8s.io/v1beta1 +kind: Gateway +metadata: + name: grpcroute-listener-hostname-matching +spec: + gatewayClassName: nginx + listeners: + - name: listener-1 + port: 80 + protocol: HTTP + allowedRoutes: + namespaces: + from: Same + kinds: + - kind: GRPCRoute + hostname: bar.com + - name: listener-2 + port: 80 + protocol: HTTP + allowedRoutes: + namespaces: + from: Same + hostname: foo.bar.com +--- +apiVersion: gateway.networking.k8s.io/v1alpha2 +kind: GRPCRoute +metadata: + name: backend-v1 +spec: + parentRefs: + - name: grpcroute-listener-hostname-matching + sectionName: listener-1 + rules: + - backendRefs: + - name: grpc-infra-backend-v1 + port: 8080 +--- +apiVersion: gateway.networking.k8s.io/v1alpha2 +kind: GRPCRoute +metadata: + name: backend-v2 +spec: + parentRefs: + - name: grpcroute-listener-hostname-matching + sectionName: listener-2 + rules: + - backendRefs: + - name: grpc-infra-backend-v2 + port: 8080 From f7e5601ee412ebe103dfebcdb8548406976d0aa4 Mon Sep 17 00:00:00 2001 From: Ciara Stacke Date: Wed, 1 May 2024 14:51:23 +0100 Subject: [PATCH 2/3] Change note wording and code block white spaces --- examples/grpc-routing/README.md | 222 ++++++++++++++++---------------- 1 file changed, 111 insertions(+), 111 deletions(-) diff --git a/examples/grpc-routing/README.md b/examples/grpc-routing/README.md index b8b2e54cf9..1feffee6dc 100644 --- a/examples/grpc-routing/README.md +++ b/examples/grpc-routing/README.md @@ -8,46 +8,46 @@ to route traffic to that application using GRPCRoute resources. ## 1. Deploy NGINX Gateway Fabric 1. Follow the [installation instructions](https://docs.nginx.com/nginx-gateway-fabric/installation/) to deploy NGINX Gateway Fabric. - NB: Ensure the Gateway APIs from the experimental channel are installed and that NGF is deployed with the Gateway experimental features enabled. + > **Important**: Ensure the Gateway APIs from the experimental channel are installed and that NGF is deployed with the Gateway experimental features enabled. 1. Save the public IP address of NGINX Gateway Fabric into a shell variable: - ```text - GW_IP=XXX.YYY.ZZZ.III - ``` + ```text + GW_IP=XXX.YYY.ZZZ.III + ``` 1. Save the port of NGINX Gateway Fabric: - ```text - GW_PORT= - ``` + ```text + GW_PORT= + ``` ## 2. Deploy the Helloworld Application 1. Create the two helloworld Deployments and Services: - ```shell - kubectl apply -f helloworld.yaml - ``` + ```shell + kubectl apply -f helloworld.yaml + ``` 1. Check that the Pods are running in the `default` Namespace: - ```shell - kubectl -n default get pods - ``` + ```shell + kubectl -n default get pods + ``` - ```text - NAME READY STATUS RESTARTS AGE - grpc-infra-backend-v1-766c7d6788-rg92p 1/1 Running 0 12s - grpc-infra-backend-v2-546f7c8d48-mjkkx 1/1 Running 0 12s - ``` + ```text + NAME READY STATUS RESTARTS AGE + grpc-infra-backend-v1-766c7d6788-rg92p 1/1 Running 0 12s + grpc-infra-backend-v2-546f7c8d48-mjkkx 1/1 Running 0 12s + ``` Save these pod names into variables: - ```text - POD_V1= - POD_V2= - ``` + ```text + POD_V1= + POD_V2= + ``` ## 3. Configure Routing @@ -57,147 +57,147 @@ There are 3 options to configure gRPC routing. To access the application and tes 1. Create the Gateway and GRPCRoute resources: - ```shell - kubectl apply -f exact-method.yaml - ``` + ```shell + kubectl apply -f exact-method.yaml + ``` 2. Test the Application: - ```shell - grpcurl -plaintext -proto grpc.proto -authority bar.com -d '{"name": "exact"}' ${GW_IP}:${GW_PORT} helloworld.Greeter/SayHello - ``` + ```shell + grpcurl -plaintext -proto grpc.proto -authority bar.com -d '{"name": "exact"}' ${GW_IP}:${GW_PORT} helloworld.Greeter/SayHello + ``` - ```text - { - "message": "Hello exact" - } - ``` + ```text + { + "message": "Hello exact" + } + ``` 3. Clean up the Gateway and GRPCRoute resources: - ```shell - kubectl delete -f exact-method.yaml - ``` + ```shell + kubectl delete -f exact-method.yaml + ``` ### 3b. Configure hostname based routing 1. Create the Gateway and GRPCRoute resources: - ```shell - kubectl apply -f hostname.yaml - ``` + ```shell + kubectl apply -f hostname.yaml + ``` 2. Test the Application: - ```shell - grpcurl -plaintext -proto grpc.proto -authority bar.com -d '{"name": "bar server"}' ${GW_IP}:${GW_PORT} helloworld.Greeter/SayHello - ``` + ```shell + grpcurl -plaintext -proto grpc.proto -authority bar.com -d '{"name": "bar server"}' ${GW_IP}:${GW_PORT} helloworld.Greeter/SayHello + ``` - ```text - { - "message": "Hello bar server" - } - ``` + ```text + { + "message": "Hello bar server" + } + ``` To make sure this came from the correct server, we can check the application server logs: - ```shell - kubectl logs ${POD_V1} - ``` + ```shell + kubectl logs ${POD_V1} + ``` - ```text - 2024/04/29 09:26:54 server listening at [::]:50051 - 2024/04/29 09:28:54 Received: bar server - ``` + ```text + 2024/04/29 09:26:54 server listening at [::]:50051 + 2024/04/29 09:28:54 Received: bar server + ``` Now we'll send a request to `foo.bar.com` - ```shell - grpcurl -plaintext -proto grpc.proto -authority foo.bar.com -d '{"name": "foo bar server"}' ${GW_IP}:${GW_PORT} helloworld.Greeter/SayHello - ``` + ```shell + grpcurl -plaintext -proto grpc.proto -authority foo.bar.com -d '{"name": "foo bar server"}' ${GW_IP}:${GW_PORT} helloworld.Greeter/SayHello + ``` - ```text - { - "message": "Hello foo bar server" - } - ``` + ```text + { + "message": "Hello foo bar server" + } + ``` This time, we'll check the POD_V2 logs: - ```shell - kubectl logs ${POD_V2} - ``` + ```shell + kubectl logs ${POD_V2} + ``` - ```text - 2024/04/29 09:26:55 server listening at [::]:50051 - 2024/04/29 09:29:46 Received: foo bar server - ``` + ```text + 2024/04/29 09:26:55 server listening at [::]:50051 + 2024/04/29 09:29:46 Received: foo bar server + ``` 3. Clean up the Gateway and GRPCRoute resources: - ```shell - kubectl delete -f hostname.yaml - ``` + ```shell + kubectl delete -f hostname.yaml + ``` ### 3c. Configure headers based routing 1. Create the Gateway and GRPCRoute resources: - ```shell - kubectl apply -f headers.yaml - ``` + ```shell + kubectl apply -f headers.yaml + ``` 2. Test the Application: - ```shell - grpcurl -plaintext -proto grpc.proto -authority bar.com -d '{"name": "version one"}' -H 'version: one' ${GW_IP}:${GW_PORT} helloworld.Greeter/SayHello - ``` + ```shell + grpcurl -plaintext -proto grpc.proto -authority bar.com -d '{"name": "version one"}' -H 'version: one' ${GW_IP}:${GW_PORT} helloworld.Greeter/SayHello + ``` - ```text - { - "message": "Hello version one" - } - ``` + ```text + { + "message": "Hello version one" + } + ``` To make sure this came from the correct server, we can check the application server logs: - ```shell - kubectl logs ${POD_V1} - ``` + ```shell + kubectl logs ${POD_V1} + ``` - ```text - <...> - 2024/04/29 09:30:27 Received: version one - ``` + ```text + <...> + 2024/04/29 09:30:27 Received: version one + ``` Now we'll send a request with the header `version: two` - ```shell - grpcurl -plaintext -proto grpc.proto -authority bar.com -d '{"name": "version two"}' -H 'version: two' ${GW_IP}:${GW_PORT} helloworld.Greeter/SayHello - ``` + ```shell + grpcurl -plaintext -proto grpc.proto -authority bar.com -d '{"name": "version two"}' -H 'version: two' ${GW_IP}:${GW_PORT} helloworld.Greeter/SayHello + ``` - ```text - { - "message": "Hello version two" - } - ``` + ```text + { + "message": "Hello version two" + } + ``` This time, we'll check the POD_V2 logs: - ```shell - kubectl logs ${POD_V2} - ``` + ```shell + kubectl logs ${POD_V2} + ``` - ```text - <...> - 2024/04/29 09:32:46 Received: version two - ``` + ```text + <...> + 2024/04/29 09:32:46 Received: version two + ``` Finally, we'll send a request with the headers `version: two` and `color: orange` - ```shell - grpcurl -plaintext -proto grpc.proto -authority bar.com -d '{"name": "version two orange"}' -H 'version: two' -H 'color: orange' ${GW_IP}:${GW_PORT} helloworld.Greeter/SayHello - ``` + ```shell + grpcurl -plaintext -proto grpc.proto -authority bar.com -d '{"name": "version two orange"}' -H 'version: two' -H 'color: orange' ${GW_IP}:${GW_PORT} helloworld.Greeter/SayHello + ``` ```text { @@ -219,6 +219,6 @@ There are 3 options to configure gRPC routing. To access the application and tes 3. Clean up the Gateway and GRPCRoute resources: - ```shell - kubectl delete -f headers.yaml - ``` + ```shell + kubectl delete -f headers.yaml + ``` From a5e0434fca0f5dd41bd7449fb5e02d7396b3951c Mon Sep 17 00:00:00 2001 From: Ciara Stacke Date: Thu, 2 May 2024 10:57:58 +0100 Subject: [PATCH 3/3] Change grpc app tag --- examples/grpc-routing/helloworld.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/grpc-routing/helloworld.yaml b/examples/grpc-routing/helloworld.yaml index 57c54952fb..7a554c484c 100644 --- a/examples/grpc-routing/helloworld.yaml +++ b/examples/grpc-routing/helloworld.yaml @@ -28,7 +28,7 @@ spec: spec: containers: - name: grpc-infra-backend-v1 - image: ghcr.io/nginxinc/kic-test-grpc-server:edge + image: ghcr.io/nginxinc/kic-test-grpc-server:0.2.1 env: - name: POD_NAME valueFrom: