Add sample for custom routing with Kong Gateway (#4110)

* Add sample for custom routing with Kong Gateway

* Remove frontmatter

* Fix Markdown formatting
This commit is contained in:
Sigurd Spieckermann 2021-09-27 20:44:12 +02:00 committed by GitHub
parent d45fdde421
commit d2f9187c60
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 482 additions and 0 deletions

View File

@ -173,6 +173,7 @@ nav:
- Scala: serving/samples/hello-world/helloworld-scala/README.md
- Shell: serving/samples/hello-world/helloworld-shell/README.md
- Routing services - Go: serving/samples/knative-routing-go/README.md
- Routing services with Kong - Go: serving/samples/kong-routing-go/README.md
- multi-container samples: serving/samples/multi-container/README.md
- RESTful service - Go: serving/samples/rest-api-go/README.md
- Secrets - Go: serving/samples/secrets-go/README.md

View File

@ -14,6 +14,7 @@ Serving resources and how they can be applied across common use cases.
| Github Webhook | A simple webhook handler that demonstrates interacting with Github. | [Go](gitwebhook-go/README.md) |
| gRPC | A simple gRPC server. | [Go](grpc-ping-go/README.md) |
| Knative Routing | An example of mapping multiple Knative services to different paths under a single domain name using the Istio VirtualService concept. | [Go](knative-routing-go/README.md) |
| Kong Routing | An example of mapping multiple Knative services to different paths under a single domain name using the Kong API gateway. | [Go](kong-routing-go/README.md) |
| Knative Secrets | A simple app that demonstrates how to use a Kubernetes secret as a Volume in Knative. | [Go](secrets-go/README.md) |
| REST API | A simple Restful service that exposes an endpoint defined by an environment variable described in the Knative Configuration. | [Go](rest-api-go/README.md) |
| Traffic Splitting | This samples builds off the [Creating a RESTful Service](rest-api-go) sample to illustrate applying a revision, then using that revision for manual traffic splitting. | [YAML](../../developer/serving/traffic-management.md) |

View File

@ -0,0 +1,27 @@
# Copyright 2021 The Knative 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
#
# https://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.
FROM golang AS builder
WORKDIR /go/src/github.com/knative/docs/
ADD . /go/src/github.com/knative/docs/
RUN CGO_ENABLED=0 go build ./docs/serving/samples/kong-routing-go/
FROM gcr.io/distroless/base
EXPOSE 8080
COPY --from=builder /go/src/github.com/knative/docs/kong-routing-go /sample
ENTRYPOINT ["/sample"]

View File

@ -0,0 +1,257 @@
# 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](https://docs.konghq.com/gateway-oss/).
Kong Gateway is a general-purpose reverse proxy and API gateway built on
[Nginx](https://www.nginx.com/), 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](https://docs.konghq.com/kubernetes-ingress-controller/) and [Kong's
request transformer
plugin](https://docs.konghq.com/hub/kong-inc/request-transformer/), 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](../../../install/) and
[Kong](https://docs.konghq.com/kubernetes-ingress-controller/1.3.x/guides/using-kong-with-knative/)
installed.
1. Install
[Docker](https://docs.docker.com/get-started/#prepare-your-docker-environment).
1. 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
1. Check out the code:
```bash
go get -d github.com/knative/docs/docs/serving/samples/kong-routing-go
```
## Setup
To check the domain name, run the following command:
```bash
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:
```bash
cd $GOPATH/src/github.com/knative/docs
```
1. Set your preferred container registry:
If you use Google Container Registry (GCR), you will need to enable the [GCR
API](https://console.cloud.google.com/apis/library/containerregistry.googleapis.com)
in your GCP project.
```bash
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:
```bash
export REPO="docker.io/<username>"
```
1. Use Docker to build your application container:
```bash
docker build \
--tag "${REPO}/kong-routing-go" \
--file=docs/serving/samples/kong-routing-go/Dockerfile .
```
1. Push your container to a container registry:
```bash
docker push "${REPO}/kong-routing-go"
```
1. 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:
```bash
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:
```bash
kubectl apply -f docs/serving/samples/kong-routing-go/sample.yaml
```
Inspect the deployed Knative services with:
```bash
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:
```bash
INGRESSGATEWAY=kong-proxy
kubectl get svc $INGRESSGATEWAY -n kong --output yaml
```
### Access the Services
1. Find the gateway IP and export it as an environment variable:
```bash
export GATEWAY_IP=`kubectl get svc $INGRESSGATEWAY -n kong \
--output jsonpath="{.status.loadBalancer.ingress[*]['ip']}"`
```
1. Find the _Search_ service URL:
```bash
kubectl get route search-service --output=custom-columns=NAME:.metadata.name,URL:.status.url
```
The output should looks like this:
```
NAME URL
search-service http://search-service.default.example.com
```
1. Make a cURL request to the service:
```bash
curl http://${GATEWAY_IP} --header "Host:search-service.default.example.com"
```
The output should look like this:
```
Search Service is called!
```
1. Similarly, you can also directly access _Login_ service:
```bash
curl http://${GATEWAY_IP} --header "Host:login-service.default.example.com"
```
The output should look like this:
```
Login Service is called!
```
## Apply Custom Routing Rule
1. Apply the custom routing rules defined in the `routing.yaml` file:
```bash
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 {% raw %}`{{.Name}}.{{.Namespace}}`{% endraw
%}, like `search-service.default` and `login-service.default`. However, some
Knative environments may use other formats like {% raw
%}`{{.Name}}-{{.Namespace}}`{% endraw %}. You can find out the format by
running the command:
```bash
kubectl get cm config-network -n knative-serving -o yaml
```
Then, look for the value for `domainTemplate`. If it is {% raw
%}`{{.Name}}-{{.Namespace}}.{{.Domain}}`{% endraw %}, you need to change
`search-service.default` into `search-service-default` and
`login-service.default` into `login-service-default` as well in
`routing.yaml`.
1. 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.
```bash
kubectl get ingress {search,login}-service-ingress -n kong --output yaml
```
1. 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:
```bash
curl http://${GATEWAY_IP}/search --header "Host: example.com"
```
or
```bash
curl http://${GATEWAY_IP}/search --header "Host: <YOUR_DOMAIN_NAME>"
```
for the case using your own domain.
- Send a request to the _Login_ service:
```bash
curl http://${GATEWAY_IP}/login --header "Host: example.com"
```
or
```bash
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](images/kong-routing-sample-flow.png)
## Clean Up
To clean up the sample resources:
```bash
kubectl delete --filename docs/serving/samples/kong-routing-go/sample.yaml
kubectl delete --filename docs/serving/samples/kong-routing-go/routing.yaml
```

Binary file not shown.

After

Width:  |  Height:  |  Size: 102 KiB

View File

@ -0,0 +1,101 @@
# Copyright 2021 The Knative 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
#
# https://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.
# Create a Kong request transformer plugin to rewrite the original host header
# to the host header of Search service in order to redirect requests to Search
# service.
apiVersion: configuration.konghq.com/v1
kind: KongPlugin
metadata:
name: search-service-host-rewrite
# The plugin must be created in the same namespace as the ingress.
namespace: kong
plugin: request-transformer
config:
add:
headers:
- "Host: search-service.default.example.com"
replace:
headers:
- "Host: search-service.default.example.com"
---
# Create an ingress that forwards an incoming request 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.
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: search-service-ingress
# The ingress must be created in the same namespace as the kong-proxy service.
namespace: kong
annotations:
kubernetes.io/ingress.class: kong
konghq.com/strip-path: "true"
konghq.com/plugins: search-service-host-rewrite
spec:
rules:
- http:
paths:
- host: example.com
path: /search
backend:
serviceName: kong-proxy
servicePort: 80
---
# Create a Kong request transformer plugin to rewrite the original host header
# to the host header of Login service in order to redirect requests to Login
# service.
apiVersion: configuration.konghq.com/v1
kind: KongPlugin
metadata:
name: login-service-host-rewrite
# The plugin must be created in the same namespace as the ingress.
namespace: kong
plugin: request-transformer
config:
add:
headers:
- "Host: login-service.default.example.com"
replace:
headers:
- "Host: login-service.default.example.com"
---
# Create an ingress that forwards an incoming request at example.com/login to
# "login-service.default.example.com" by updating the "Host" header to
# "login-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.
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: login-service-ingress
# The ingress must be created in the same namespace as the kong-proxy service.
namespace: kong
annotations:
kubernetes.io/ingress.class: kong
konghq.com/strip-path: "true"
konghq.com/plugins: login-service-host-rewrite
spec:
rules:
- http:
paths:
- host: example.com
path: /login
backend:
serviceName: kong-proxy
servicePort: 80

View File

@ -0,0 +1,42 @@
/*
Copyright 2021 The Knative 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
https://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.
*/
package main
import (
"flag"
"fmt"
"log"
"net/http"
"os"
)
func handler(w http.ResponseWriter, r *http.Request) {
serviceName := os.Getenv("SERVICE_NAME")
if serviceName == "" {
serviceName = "NOT SPECIFIED"
}
log.Printf("%s received a request.", serviceName)
fmt.Fprintf(w, "%s is called!\n", serviceName)
}
func main() {
flag.Parse()
log.Print("Sample started.")
http.HandleFunc("/", handler)
http.ListenAndServe(":8080", nil)
}

View File

@ -0,0 +1,53 @@
# Copyright 2021 The Knative 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
#
# https://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.
apiVersion: serving.knative.dev/v1
kind: Service
metadata:
name: search-service
namespace: default
spec:
template:
spec:
containers:
- # This is the Go import path for the binary to containerize
# and substitute here.
image: github.com/knative/docs/docs/serving/samples/kong-routing-go
env:
- name: SERVICE_NAME
value: Search Service
readinessProbe:
httpGet:
path: /
initialDelaySeconds: 3
---
apiVersion: serving.knative.dev/v1
kind: Service
metadata:
name: login-service
namespace: default
spec:
template:
spec:
containers:
- # This is the Go import path for the binary to containerize
# and substitute here.
image: github.com/knative/docs/docs/serving/samples/kong-routing-go
env:
- name: SERVICE_NAME
value: Login Service
readinessProbe:
httpGet:
path: /
initialDelaySeconds: 3