Introduction to Kong Ingress Controller
Intro
There are so many Ingress Controllers on the market and sometimes it is hard to choose. I’ve covered Traefik Ingress Controller in my previous post and today I will talk about using Kong Ingress Controller.
First of all, I would like to talk about how Kong ingress controller works. Unlike Nginx or Traefik Ingress Controller, you can see there are two containers in Kong pod, one is ingress-controller
and the other is proxy
. How this work is, when ingress-controller
detects resources that is associated to Kong (through IngressClass or CRD), it will convert these resources to Kong objects and push it to proxy
container. When we talk about Kong ingress controller, we are using Kong proxy at the same time. That means installing Kong and installing KIC on kubernetes are actually the same. The proxy container can work on its own, the KIC container howerver needs a proxy container to do the proxy part.
1 | 📎 deployments(5) |
This information might not be important for a fresh installation, but you need to consider the changes to KIC and Kong when you need to upgrade.
I think that’s enough background information, let’s start using it. If you don’t know how to deploy Kong Ingress Controller on Kubernetes, please check my previous post.
You can find official docs below:
Let’s get started.
Preparation
Add Kong helm repo
Before we start, we need to add Kong repo.
1 | helm repo add kong https://charts.konghq.com |
Install Kong
Let’s install Kong in DBless mode with below command first. This will create proxy service as LoadBalancer and I enable Admin API specifically.
1 | helm upgrade -i my-kong kong/kong -n kong \ |
Let me assign proxy.li.k8s
to the IP address 172.18.18.150
of the proxy loadbalancer.
Similar to Traefik, you can use annotation
or CRDs
to config Kong. Howerver, annotations do not cover ALL features of CRD and Kong CRDs are used to extend Kubernetes native objects not to replace them.
If you have used Kong before, you would know you can use
- Service object to set upstream.
- Route objects to match requests and route to a service.
- Consumer objects to be used to store credentials and rate limited when needed.
- Plugins to do Magics.
This rules also apply when we use KIC.
To better understand how it works, let me give you a demo.
Deploy demo app
I will create a httpbin deployment for this demo.
- Create httpbin deployment.
1
kubectl create deployment httpbin --image=kennethreitz/httpbin
- Expose this httpbin deployment as
httpbin-svc
service at port 80.1
kubectl expose deployment httpbin --name httpbin-svc --port 80
- Create Ingress and use Kong to route requests to this service.
1
kubectl create ingress httpbin-route --class kong --rule '/test*=httpbin-svc:80'
Let’s visit our path and we should see below, which means it works.
1 | curl http://proxy.li.k8s/test -H "kong-debug:1" -i |
How do I know it works? As you can see I passed in kong-debug:1
header in my request and I got service and route information in the response header. These headers confirms my request matched a Kong route.
1 | Kong-Route-Id: 2aa771dc-2f8e-5750-97b4-1d2da407764c |
Apparently we don’t want to see 404 from our app. So let’s try to extend our ingress object to make it work.
I will show you how to config Ingress
or Service
with annotations and KongIngress
CRD. You can check the latest KongIngress
CRD with below command:
1 | kubectl kustomize \ |
Config on Ingress
Ingress Object will be converted to Kong route object once it is picked up by Kong ingress controller. To achieve the same Kong Route object features, we can use both annotation and KongIngress
resource to extend Ingress.
Annotations on Ingress
konghq.com/strip-path
Let’s apply this annotation to our ingress first. This annotation will remove /test
from our request sent to upstream.
1 | kubectl annotate ingress httpbin-route konghq.com/strip-path=true |
Let’s visit our route again, we should see HTTP/1.1 200 OK
now because /test
is striped, upstream receive our request at /
hence it returns 200.
1 | curl http://proxy.li.k8s/test -I |
konghq.com/protocols
Don’t confuse this annotation with konghq.com/protocol
for service resource.
1 | kubectl annotate ingress httpbin-route konghq.com/protocols=https |
This annotation is directly related to protocols
in the route object which is about what protocol users want their client to send their request at. Because we only allow https
through this annotation, you will see below if you access route via http
.
1 | curl http://proxy.li.k8s/test -i |
By default Kong sends 426 response code for requests that need to be redirected to HTTPS.
konghq.com/https-redirect-status-code
If we want to send a redirect status code, we can use this annotation.
1 | kubectl annotate ingress httpbin-route konghq.com/https-redirect-status-code=302 |
Now when we visit this route again, you can see we get a 302 response with a Location: https://proxy.li.k8s/test
header. If you are using a browser it will redirect you to https automatically.
1 | curl http://proxy.li.k8s/test -I |
konghq.com/preserve-host
This is used to preserve the Host header to upstream. As you can see, by default it is set to true
1 | kubectl annotate ingress httpbin-route konghq.com/preserve-host=false |
After we turn it off. We can see the Host
header changed to an IP -> This is the IP of httpbin pod
1 | curl https://proxy.li.k8s/test/anything -k |
konghq.com/methods
If we don’t set any methods, Kong accepts any request except TRACE.
Let’s limit this route to accept GET and POST method only.
1 | kubectl annotate ingress httpbin-route konghq.com/methods=GET,POST |
Now if we try PUT method, we will get route not match error because the method is a matching criteria now.
1 | curl -XPUT https://proxy.li.k8s/test -ik |
If we take a look at our Ingress Object now, it looks like below.
1 | apiVersion: networking.k8s.io/v1 |
KongIngress on Ingress
We used 5 annotations on our ingress above. We can achieve the same configs with KongIngress
object below.
Let’s start by removing existing Ingress object and create a new one
1
2kubectl delete ingress httpbin-route
kubectl create ingress httpbin-route --class kong --rule '/test*=httpbin-svc:80'Let’s save this file to
kong-ingress-demo.yaml
and then apply itkubectl apply -f kong-ingress-demo.yaml
.1
2
3
4
5
6
7
8
9
10
11
12
13
14apiVersion: configuration.konghq.com/v1
kind: KongIngress
metadata:
name: kong-ingress-demo
namespace: default
route:
methods:
- POST
- GET
strip_path: true
preserve_host: false
https_redirect_status_code: 302
protocols:
- httpsLet’s associate this
KongIngress
to our ingress1
kubectl annotate ingress httpbin-route konghq.com/override=kong-ingress-demo
Now we have the same config as using 5 annotation above. If we need to apply the same config to another ingress object, we just need to associate the same KongIngress
resource to the new ingress object.
Unique Features
There are features that are only available with annotation or KongIngress. I will show you a couple below.
konghq.com/host-aliases
You can add multiple hostnames as a matching criterial on the same ingress object. Let’s add annotation to our ingress.
1 | kubectl annotate ingress httpbin-route konghq.com/host-aliases=foo.li.k8s,bar.li.k8s |
Now when we vist curl https://proxy.li.k8s/test -Ik
again, we will get 404 not found because our request does not match any route objects. If we send our request with foo.li.k8s
or bar.li.k8s
host header, we will see 200 response again.
1 | curl https://proxy.li.k8s/test -Ik -H "Host: foo.li.k8s" |
This is handy when you need to match matching multiple Host values to the same set of routes.
Match Headers with KongIngress
If you need direct traffics to different back ends for different headers, you can use KongIngress to do it. Let’s extend our KongIngress a little bit.
This will add host header demo-header-1
to match value demo1
or demo2
and header demo-header-2
to match value demo3
.
1 | apiVersion: configuration.konghq.com/v1 |
Let’s visit our route again.
We will be getting no Route matched
error now.
1 | curl https://proxy.li.k8s/test -iLk |
Let’s try adding some headers to our request
1 | curl https://proxy.li.k8s/test -iLk \ |
We should see HTTP/2 200
again.
Config on service
You can also extend service with both annotations and KongIngress object.
Same KongIngress object can be applied on both Ingress and Service object with different features.
Annotations on Service
konghq.com/protocol
Don’t confuse this with konghq.com/protocols
annotation on ingress resources, You can use this annotation to define what protocol Kong use to communicate with upstream services. Accepted values are http
,https
,grpc
,grpcs
,tcp
,tls
.
1 | kubectl annotate service httpbin-svc konghq.com/protocol=http |
konghq.com/path
This annotation can be used to prepend an HTTP path of a request before the request is forwarded.
1 | kubectl annotate service httpbin-svc konghq.com/path=/anything |
If we visit our route at /test
again
1 | curl http://proxy.li.k8s/test -i |
As you can see the upstream has the path /anything
prepended.
1 | { |
KongIngress on Service
We can also achieve the same feature as above annotations with KongIngress object.
To remove the annocations quickly, let’s remove and re-create the same service.
1
2kubectl delete service httpbin-svc
kubectl expose deployment httpbin --name httpbin-svc --port 80Then we need to create our KongIngress resource.
1
2
3
4
5
6
7
8apiVersion: configuration.konghq.com/v1
kind: KongIngress
metadata:
name: kong-service-demo
namespace: default
proxy:
protocol: http
path: /anythingSave it to
kong-service-demo.yaml
and then applykubectl apply -f kong-service-demo.yaml
.Lastly let’s associate this KongIngress resource to our service
1
kubectl annotate service httpbin-svc konghq.com/override=kong-service-demo
After that we can visit /test
route again and we should see the same result as above.
Unique Features
There are more unique features that is only available with KongIngress for service.
konghq.com/client-cert
This annotation is used to provide a client-certificate to upstream server if it requires mutual authentication.
We need to make sure either use
konghq.com/protocol
annotation or KongIngress to communicate upstream service with https protocol only.
We need to create the client certificate as secret first. My client certificate is stored in example-client-cert
in default namespace, same as my ingress.
1 | kubectl create secret tls example-client-cert --cert=example.cert.pem --key=example.key.pem |
Then we just apply this annotation to our service.
1 | kubectl annotate service httpbin-svc konghq.com/client-cert=example-client-cert |
We can port forward admin api and check the service object. We should see something similar on it.
1 | "client_certificate": { |
Health Check
You can use KongIngress to change the behaviour of an upstream object or service object. One unique feature is health check and circuit breaks on upstream object. We can also config healthcheck with KongIngress CRD.
Let’s modify our KongIngress resource to below. This will instruct Kong to do active health check to upstream service at /health
endpoint every second. If the health check at one target fail 5 times, this target will be marked as unhealthy and Kong will not send request to it.
1 | apiVersion: configuration.konghq.com/v1 |
That’s all I want to share in this post. The other CRDs like KongPlugin, KongClusterPlugin and KongConsumers are hard to wirte one post to cover them all. I will cover those CRDs in my plugin posts like I did before.
Thanks for reading, see you next time.