diff --git a/docs/content/guides/recipes/howto-nginx-gateway-routes/index.md b/docs/content/guides/recipes/howto-nginx-gateway-routes/index.md new file mode 100644 index 000000000..be7d91c06 --- /dev/null +++ b/docs/content/guides/recipes/howto-nginx-gateway-routes/index.md @@ -0,0 +1,212 @@ +--- +type: docs +title: "How-To: Use NGINX Gateway Fabric with Radius routes" +linkTitle: "NGINX Gateway routes" +description: "Configure Radius.Compute/routes recipes to use NGINX Gateway Fabric." +weight: 300 +categories: "How-To" +tags: ["recipes", "Kubernetes", "Networking"] +--- + +This guide shows platform operators how to install Radius without the default Contour ingress controller, install [NGINX Gateway Fabric](https://docs.nginx.com/nginx-gateway-fabric/), and configure the `Radius.Compute/routes` recipe to attach application routes to a Kubernetes Gateway API `Gateway`. + +Use this pattern when your platform team wants to manage the Kubernetes Gateway controller separately from Radius while still letting application authors use portable Radius route resources. + +## Prerequisites + +- [Setup a supported Kubernetes cluster]({{< ref "/guides/installation/overview#supported-clusters" >}}) +- [kubectl](https://kubernetes.io/docs/tasks/tools/install-kubectl/) +- [Helm](https://helm.sh/docs/intro/install/) +- [rad CLI]({{< ref "installation#step-1-install-the-rad-cli" >}}) + +The examples use: + +- Radius environment name: `default` +- Application namespace: `nginx-radius-demo` +- Gateway name: `radius` +- Route hostname: `nginx.example.com` + +## Step 1: Install Radius without Contour + +Install Radius and skip the default Contour installation: + +```bash +rad install kubernetes --skip-contour-install +``` + +Create a resource group, workspace, and environment: + +```bash +rad group create default +rad workspace create kubernetes default --group default --force +rad group switch default + +rad env create default --preview +kubectl create namespace nginx-radius-demo +rad env update default --kubernetes-namespace nginx-radius-demo --preview +``` + +## Step 2: Install NGINX Gateway Fabric + +Install the Gateway API standard channel CRDs: + +```bash +kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.5.0/standard-install.yaml +``` + +The standard channel includes the `GatewayClass`, `Gateway`, and `HTTPRoute` resources used in this guide. Use the experimental channel only if your route recipes need experimental Gateway API resources such as `TLSRoute`, `TCPRoute`, or `UDPRoute`. + +Install NGINX Gateway Fabric: + +```bash +helm upgrade --install ngf oci://ghcr.io/nginx/charts/nginx-gateway-fabric \ + --namespace nginx-gateway \ + --create-namespace \ + --wait + +kubectl wait --timeout=5m \ + --namespace nginx-gateway \ + deployment/ngf-nginx-gateway-fabric \ + --for=condition=Available +``` + +Create `gateway.yaml`: + +```yaml +apiVersion: gateway.networking.k8s.io/v1 +kind: Gateway +metadata: + name: radius + namespace: nginx-radius-demo +spec: + gatewayClassName: nginx + listeners: + - name: http + protocol: HTTP + port: 80 + allowedRoutes: + namespaces: + from: All +``` + +Apply the Gateway: + +```bash +kubectl apply -f gateway.yaml +kubectl wait --timeout=5m \ + --namespace nginx-radius-demo \ + gateway/radius \ + --for=condition=Programmed +``` + +## Step 3: Configure Bicep extensions + +Create `bicepconfig.json`. Use the current Radius release version, such as `0.58`. + +```json +{ + "experimentalFeaturesEnabled": { + "extensibility": true + }, + "extensions": { + "radius": "br:biceptypes.azurecr.io/radius:" + } +} +``` + +## Step 4: Register a routes recipe pack + +Create `nginx-routes-recipe-pack.bicep`: + +{{< rad file="snippets/nginx-routes-recipe-pack.bicep" embed=true >}} + +Deploy the recipe pack and attach it to the environment: + +```bash +rad deploy nginx-routes-recipe-pack.bicep \ + --group default \ + --environment /planes/radius/local/resourceGroups/default/providers/Radius.Core/environments/default + +rad env update default --recipe-packs nginx-gateway --preview +``` + +The `gatewayName` and `gatewayNamespace` parameters tell the `Radius.Compute/routes` recipe which Kubernetes Gateway should receive generated `HTTPRoute` resources. This changes the route implementation in the environment without changing application code. + +## Step 5: Deploy an application with a route + +Create `app.bicep`: + +{{< rad file="snippets/app.bicep" embed=true >}} + +Deploy the application: + +```bash +rad deploy app.bicep \ + --group default \ + --environment /planes/radius/local/resourceGroups/default/providers/Radius.Core/environments/default \ + --parameters routeHostname=nginx.example.com +``` + +Radius deploys the container through the `Radius.Compute/containers` recipe and creates a Kubernetes `HTTPRoute` through the `Radius.Compute/routes` recipe. + +## Step 6: Verify traffic + +Check that the Gateway and route are accepted: + +```bash +kubectl get gateway radius --namespace nginx-radius-demo +kubectl get httproute --namespace nginx-radius-demo +``` + +For local clusters, port-forward the NGINX Gateway service: + +```bash +kubectl get service \ + --namespace nginx-radius-demo \ + --selector gateway.networking.k8s.io/gateway-name=radius \ + --output name +``` + +Use the returned service name to port-forward traffic: + +```bash +kubectl port-forward \ + --namespace nginx-radius-demo \ + service/ \ + 8080:80 +``` + +In another terminal, send a request with the route hostname: + +```bash +curl -H "Host: nginx.example.com" http://127.0.0.1:8080/ +``` + +You should see the default NGINX welcome page. + +## Clean up + +Delete the application: + +```bash +rad app delete nginx-radius-demo --yes +``` + +If you no longer need the NGINX recipe pack, first update the environment to use another recipe pack or delete the environment that references it. Then delete the recipe pack: + +```bash +rad recipe-pack delete nginx-gateway --group default --yes +``` + +Uninstall NGINX Gateway Fabric: + +```bash +helm uninstall ngf --namespace nginx-gateway +kubectl delete namespace nginx-gateway +``` + +## Further reading + +- [Radius Recipes]({{< ref "/guides/recipes" >}}) +- [Kubernetes installation]({{< ref "/guides/installation/kubernetes-install" >}}) +- [Application networking]({{< ref "/guides/applications/networking/overview" >}}) diff --git a/docs/content/guides/recipes/howto-nginx-gateway-routes/snippets/app.bicep b/docs/content/guides/recipes/howto-nginx-gateway-routes/snippets/app.bicep new file mode 100644 index 000000000..32f9d1ba4 --- /dev/null +++ b/docs/content/guides/recipes/howto-nginx-gateway-routes/snippets/app.bicep @@ -0,0 +1,56 @@ +extension radius + +param environment string +param routeHostname string = 'nginx.example.com' + +resource app 'Radius.Core/applications@2025-08-01-preview' = { + name: 'nginx-radius-demo' + properties: { + environment: environment + } +} + +resource web 'Radius.Compute/containers@2025-08-01-preview' = { + name: 'web' + properties: { + environment: environment + application: app.id + containers: { + web: { + image: 'nginx:alpine' + ports: { + http: { + containerPort: 80 + protocol: 'TCP' + } + } + } + } + } +} + +resource route 'Radius.Compute/routes@2025-08-01-preview' = { + name: 'web' + properties: { + environment: environment + application: app.id + kind: 'HTTP' + hostnames: [ + routeHostname + ] + rules: [ + { + matches: [ + { + httpPath: '/' + } + ] + destinationContainer: { + resourceId: web.id + containerName: 'web' + containerPort: web.properties.containers.web.ports.http.containerPort + } + } + ] + } +} diff --git a/docs/content/guides/recipes/howto-nginx-gateway-routes/snippets/nginx-routes-recipe-pack.bicep b/docs/content/guides/recipes/howto-nginx-gateway-routes/snippets/nginx-routes-recipe-pack.bicep new file mode 100644 index 000000000..dc16c0a13 --- /dev/null +++ b/docs/content/guides/recipes/howto-nginx-gateway-routes/snippets/nginx-routes-recipe-pack.bicep @@ -0,0 +1,24 @@ +extension radius + +param recipeTag string = '0.58' + +resource recipePack 'Radius.Core/recipePacks@2025-08-01-preview' = { + name: 'nginx-gateway' + location: 'global' + properties: { + recipes: { + 'Radius.Compute/containers': { + recipeKind: 'bicep' + recipeLocation: 'ghcr.io/radius-project/kube-recipes/containers:${recipeTag}' + } + 'Radius.Compute/routes': { + recipeKind: 'bicep' + recipeLocation: 'ghcr.io/radius-project/kube-recipes/routes:${recipeTag}' + parameters: { + gatewayName: 'radius' + gatewayNamespace: 'nginx-radius-demo' + } + } + } + } +}