Routing across multiple Knative services with Kong

This example shows how to map multiple Knative services to different paths under a single domain name using Kong Gateway. Kong Gateway is a general-purpose reverse proxy and API gateway built on Nginx, therefore these directions can also be used to configure routing based on other request data such as headers, or even to map Knative and external resources under the same domain name.

In this sample, we set up two web services: Search service and Login service, which simply read in an env variable SERVICE_NAME and print "${SERVICE_NAME} is called". We’ll then define routing rules via Kong’s Kubernetes Ingress Controller and Kong’s request transformer plugin, so that example.com/search maps to the Search service, and example.com/login maps to the Login service.

Prerequisites

  1. A Kubernetes cluster with Knative Serving and Kong installed.
  2. Install Docker.
  3. Acquire a domain name.
    • In this example, we use example.com. If you don’t have a domain name, you can modify your hosts file (on macOS or Linux) to map example.com to your cluster’s ingress IP.
    • If you have configured a custom domain for your Knative installation, we will refer to it as <YOUR_DOMAIN_NAME> in the rest of this document
  4. Check out the code:

    1. go get -d github.com/knative/docs/docs/serving/samples/kong-routing-go

Setup

To check the domain name, run the following command:

  1. kubectl get cm -n knative-serving config-domain -o yaml

Then, check the value for data. The domain name should be in the format of <YOUR_DOMAIN_NAME>: "", if it is available.

Build the application container and publish it to a container registry:

  1. Move into the sample directory:

    1. cd $GOPATH/src/github.com/knative/docs
  2. Set your preferred container registry:

    If you use Google Container Registry (GCR), you will need to enable the GCR API in your GCP project.

    1. export REPO="gcr.io/<YOUR_PROJECT_ID>"

    If you use Docker Hub as your Docker image registry, replace <username> with your Docker Hub username and run the following command:

    1. export REPO="docker.io/<username>"
  3. Use Docker to build your application container:

    1. docker build \
    2. --tag "${REPO}/kong-routing-go" \
    3. --file=docs/serving/samples/kong-routing-go/Dockerfile .
  4. Push your container to a container registry:

    1. docker push "${REPO}/kong-routing-go"
  5. Replace the image reference path with our published image path in the configuration file docs/serving/samples/kong-routing-go/sample.yaml in one of the following ways:

    • Manually replace image: github.com/knative/docs/docs/serving/samples/kong-routing-go with image: ${REPO}/kong-routing-go. If you manually changed the .yaml file, you must replace ${REPO} with the correct path on your local machine.
    • Run this command:

      1. perl -pi -e "s@github.com/knative/docs/docs/serving/samples@${REPO}@g" docs/serving/samples/kong-routing-go/sample.yaml

Deploy the Service

Deploy the Knative Serving sample:

  1. kubectl apply -f docs/serving/samples/kong-routing-go/sample.yaml

Inspect the deployed Knative services with:

  1. kubectl get ksvc

You should see 2 Knative services: search-service and login-service.

Exploring the Routes

Kong Gateway serves all incoming traffic to services managed by Knative. You can inspect the corresponding Kubernetes service for the gateway:

  1. INGRESSGATEWAY=kong-proxy
  2. kubectl get svc $INGRESSGATEWAY -n kong --output yaml

Access the Services

  1. Find the gateway IP and export it as an environment variable:

    1. export GATEWAY_IP=`kubectl get svc $INGRESSGATEWAY -n kong \
    2. --output jsonpath="{.status.loadBalancer.ingress[*]['ip']}"`
  2. Find the Search service URL:

    1. kubectl get route search-service --output=custom-columns=NAME:.metadata.name,URL:.status.url

    The output should looks like this:

    1. NAME URL
    2. search-service http://search-service.default.example.com
  3. Make a cURL request to the service:

    1. curl http://${GATEWAY_IP} --header "Host:search-service.default.example.com"

    The output should look like this:

    1. Search Service is called!
  4. Similarly, you can also directly access Login service:

    1. curl http://${GATEWAY_IP} --header "Host:login-service.default.example.com"

    The output should look like this:

    1. Login Service is called!

Apply Custom Routing Rule

  1. Apply the custom routing rules defined in the routing.yaml file:

    1. kubectl apply -f docs/serving/samples/kong-routing-go/routing.yaml

    If you have configured a custom domain name for your service, please replace all mentions of example.com in routing.yaml with <YOUR_DOMAIN_NAME>.

    In addition, you need to verify how your domain template is defined. By default, we use the format of {{.Name}}.{{.Namespace}}, like search-service.default and login-service.default. However, some Knative environments may use other formats like {{.Name}}-{{.Namespace}}. You can find out the format by running the command:

    1. kubectl get cm config-network -n knative-serving -o yaml

    Then, look for the value for domainTemplate. If it is {{.Name}}-{{.Namespace}}.{{.Domain}}, you need to change search-service.default into search-service-default and login-service.default into login-service-default as well in routing.yaml.

  2. The routing.yaml file will create an ingress that forwards incoming requests at example.com/search to search-service.default.example.com by updating the “Host” header to search-service.default.example.com and stripping the request path. This modified request is then forwarded to the Knative ingress (Kong) and routed to the service as usual. Another ingress like this is also created for the Login service.

    1. kubectl get ingress {search,login}-service-ingress -n kong --output yaml
  3. Send a request to the Search service and the Login service by using their corresponding URLs. You should get the same results as directly accessing these services.

    • Send a request to the Search service:

      1. curl http://${GATEWAY_IP}/search --header "Host: example.com"

      or

      1. curl http://${GATEWAY_IP}/search --header "Host: <YOUR_DOMAIN_NAME>"

      for the case using your own domain.

    • Send a request to the Login service:

      1. curl http://${GATEWAY_IP}/login --header "Host: example.com"

      or

      1. curl http://${GATEWAY_IP}/login --header "Host: <YOUR_DOMAIN_NAME>"

      for the case using your own domain.

How It Works

When a request with host example.com or your own domain name reaches Kong Gateway, Kong will check if the URL path prefix is /search or /login. If the URL matches on of the two rules, then the “Host” header of the request will be rewritten into the host of the Search service or Login service, respectively, and the path will be stripped. The modified request will be forwarded to Kong again. Kong will check the “Host” header and forward the request to the Search or Login service according to the header value.

Object model

Clean Up

To clean up the sample resources:

  1. kubectl delete --filename docs/serving/samples/kong-routing-go/sample.yaml
  2. kubectl delete --filename docs/serving/samples/kong-routing-go/routing.yaml