Why a Gateway on top of Knative application
To explain this let me touch on my previous blog post. Assuming that Knative serving is already available in a Kubernetes environment, the way to deploy an application is using a manifest which looks like this:
apiVersion: serving.knative.dev/v1alpha1 kind: Service metadata: name: sample-boot-knative-service namespace: default spec: runLatest: configuration: revisionTemplate: spec: container: image: bijukunjummen/sample-boot-knative-app:0.0.3-SNAPSHOT env: - name: ASAMPLE_ENV value: "sample-env-val"
Now to invoke this application, I have to make the call via an ingress created by Knative serving, which can be obtained the following way in a minikube environment:
export GATEWAY_URL=$(echo $(minikube ip):$(kubectl get svc knative-ingressgateway -n istio-system -o 'jsonpath={.spec.ports[?(@.port==80)].nodePort}'))
The request now has to go through the ingress and the ingress uses a Host http header to then route the request to the app. The host header for the deployed service can be obtained using the following bash script:
export APP_DOMAIN=$(kubectl get services.serving.knative.dev sample-boot-knative-service -o="jsonpath={.status.domain}")
and then a call via the knative ingress gateway made the following way, using CURL:
curl -X "POST" "http://${GATEWAY_URL}/messages" \ -H "Accept: application/json" \ -H "Content-Type: application/json" \ -H "Host: ${APP_DOMAIN}" \ -d $'{ "id": "1", "payload": "one", "delay": "300" }'
or using httpie:
http http://${GATEWAY_URL}/messages Host:"${APP_DOMAIN}" id=1 payload=test delay=1
There are too many steps involved in making a call to the application via the knative ingress:
My objective in this post is to simplify the users experience in making a call to the app by using a Gateway like Ambassador.
Integrating Ambassador to Knative
There is nothing special about installing Ambassador into a Knative environment, the excellent instructions provided here worked cleanly in my minikube environment.
Now my objective with the gateway is summarized in this picture:
With Ambassador in place, all the user has to do is to send a request to Ambassador Gateway and it would take care of plugging in the Host header before making a request to the Knative Ingress.
So how does this work, fairly easily! assuming Ambassador is in place, all it needs is a configuration which piggybacks on a Kubernetes service the following way:
--- apiVersion: v1 kind: Service metadata: name: sample-knative-app-gateway annotations: getambassador.io/config: | --- apiVersion: ambassador/v0 kind: Mapping name: sample-boot-knative-app prefix: /messages rewrite: /messages service: knative-ingressgateway.istio-system.svc.cluster.local host_rewrite: sample-boot-knative-service.default.example.com spec: type: LoadBalancer ports: - name: ambassador port: 80 targetPort: 80 selector: service: ambassador
Here I am providing configuration via a Service annotations, intercepting any calls to /messages uri and forwarding these request to the knative ingressgatway service (knative-ingressgateway.istio-system.svc.cluster.local) and adding the host header of "sample-boot-knative-service.default.example.com".
Now the interaction from a user perspective is far simpler, all I have to do is to get the url for this new service and to make the api call, in a minikube environment using the following bash script:
export AMB_URL=$(echo $(minikube ip):$(kubectl get svc sample-knative-app-gateway -n default -o 'jsonpath={.spec.ports[?(@.port==80)].nodePort}')) http http://${AMB_URL}/messages id=1 payload=test delay=1
It may be easier to try this on a real code, which is available my github repo here.
No comments:
Post a Comment