Kong API Gateway with Kubernetes

In this article, we install Kong, use it to access our echo service, introduce Kong's correlation id plugin and a GUI dashboard.

Kong API Gateway with Kubernetes

Previously, we created some basic services on Kubernetes. These services did not have any logic to control access, limit the requests, perform load balancing or any such concerns.  To manage these concerns we will use Kong API Gateway. We will create another simple echo service with no discovery annotation, circuit breaker or security added. With this architectural pattern, your services remain focused on the business capability, while the non-functional concerns above are handled by the API gateway.

In this article, we install Kong, use it to access our echo service, introduce Kong's correlation id plugin and a GUI dashboard.

Note: We can use Lens to view and manage the K8s cluster
https://k8slens.dev

Vadal Echo Example Service

We are going to use this VadalEcho service.

@SpringBootApplication
@RestController
public class VadalEcho {

    public static void main(String[] args) {
        SpringApplication.run(VadalEcho.class, args);
    }

    @GetMapping("/")
    public Echo echo(@RequestHeader Map<String, String> headers, HttpServletRequest request) {
        return new Echo(LocalDateTime.now(), headers);
    }

    @AllArgsConstructor
    @Data
    private static class Echo {
        LocalDateTime timestamp;
        Map<String, String> headers;
    }
}

application.yml

spring:
  application:
    name: vadalecho

server.port: 8080

Build and deploy to K8s as per previous blogs.

mvn spring-boot:build-image
kubectl create deployment vadal-echo --image=vadal-echo:0.0.1-SNAPSHOT

Add as a service, but no need to expose the NodePort, we will access this from Kong as a K8s ingress.

echo "
apiVersion: v1
kind: Service
metadata:
 labels:
   app: vadal-echo
 name: vadal-echo
spec:
 ports:
     port: 80
     protocol: TCP
     targetPort: 8080
 selector:
   app: vadal-echo
" | kubectl apply -f -

Install Kong

In installing Kong we will also add the database (not enabled by default) and expose the admin port on 8001.

$ helm repo add kong https://charts.konghq.com
$ helm repo update  

# Helm 2
$ helm install kong/kong --name kong --set admin.enabled=true --set admin.http.enabled=true --set postgresql.enabled=true   --set postgresql.postgresqlUsername=kong  --set postgresql.postgresqlDatabase=kong --set env.database=postgres

Note: if you delete the chart and re-install also delete the PVC holding the db in storage.

Check our kong services.

kubectl get svc | grep kong
NAME                      TYPE          CLUSTER-IP     EXTERNAL-IP  PORT(S)                        AGE
kong-kong-admin           NodePort      10.110.21.157         8001:31846/TCP,8444:31320/TCP  1s
kong-kong-proxy           LoadBalancer  10.97.155.4    localhost    80:32109/TCP,443:32390/TCP     1s
kong-postgresql           ClusterIP     10.96.43.206          5432/TCP                       1s
kong-postgresql-headless  ClusterIP     None                  5432/TCP                       1s

The password for postgresql will be in secrets but we will not be needing it (we add postgres in order for the Konga dashboard to update plugin details).

We will use the admin port 31846 to connect the Konga dashboard to Konga.

If you are using Lens (highly recommended), we can see the services in Lens -> Network -> Services.

Kong Gateway

curl localhost
{"message":"no Route matched with those values"}

We need to add a route (our echo service above).

Load balance our service with the following:

echo "
kind: Ingress
apiVersion: extensions/v1beta1
metadata:
 name: vadal
 annotations:
   konghq.com/strip-path: "true"
spec:
 rules:
   - host: localhost
     http:
       paths:
         - path: /echo
           backend:
             serviceName: vadal-echo
             servicePort: 80" | kubectl apply -f -

Kong is now serving our service.

http://localhost/echo

Result:

{
timestamp: "2020-07-06T18:56:26.169",
headers: {
    host: "localhost",
    connection: "keep-alive",
    x-forwarded-proto: "http",
    x-forwarded-host: "localhost",
    x-forwarded-port: "8000",
    x-real-ip: "192.168.65.3",
    upgrade-insecure-requests: "1",
    user-agent: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36",
    accept: "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9",
    sec-fetch-site: "none",
    sec-fetch-mode: "navigate",
    sec-fetch-user: "?1",
    sec-fetch-dest: "document",
    accept-encoding: "gzip, deflate, br",
    accept-language: "en-GB,en-US;q=0.9,en;q=0.8",
    cookie: "io=27Pjzcnt6E6AEnt1AAAA"
    }
}

Should return the json payload like the above.

Note the setting of this annotation:
konghq.com/strip-path: "true"

Needed if you want to access subpaths

eg:

localhost:31638/echo/actuator/health

Correlation Plugin

Add a custom correlation id (vadal-request-id) to kong via it's plugin mechanism.

echo "
apiVersion: configuration.konghq.com/v1
kind: KongPlugin
metadata:
 name: request-id
config:
 header_name: vadal-request-id
plugin: correlation-id
" | kubectl apply -f -

Add it to the ingress file above

echo "
kind: Ingress
apiVersion: extensions/v1beta1
metadata:
 name: vadal
 annotations:
   konghq.com/strip-path: "true"
  konghq.com/plugins: request-id
spec:
 rules:
   - host: localhost
     http:
       paths:
         - path: /echo
           backend:
             serviceName: vadal-echo
             servicePort: 80" | kubectl apply -f -

Call the echo service and notice the vadal-request-id, added by Kong.

curl localhost/echo
{
timestamp: "2020-07-04T22:03:01.78",
headers: {
    host: "localhost",
    connection: "keep-alive",
    vadal-request-id: "51835d40-967d-448c-9055-57df9f347a6d#2",
    x-forwarded-proto: "http",
    x-forwarded-host: "localhost",
    x-forwarded-port: "8000",
    x-real-ip: "192.168.65.3",
    upgrade-insecure-requests: "1",
    user-agent: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36",
    accept: "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9",
    sec-fetch-site: "none",
    sec-fetch-mode: "navigate",
    sec-fetch-user: "?1",
    sec-fetch-dest: "document",
    accept-encoding: "gzip, deflate, br",
    accept-language: "en-GB,en-US;q=0.9,en;q=0.8"
  }
}

Konga Dashboard

Create konga.yml

apiVersion: v1
kind: Service
metadata:
  name: konga-svc
spec:
  type: NodePort
  ports:
    - name: kong-proxy
      port: 1337
      targetPort: 1337
      protocol: TCP
  selector:
    app: konga
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: konga
spec:
  replicas: 1
  selector:
    matchLabels:
      app: konga
  template:
    metadata:
      labels:
        name: konga
        app: konga
    spec:
      containers:
        - name: konga
          image: pantsel/konga
          ports:
            - containerPort: 1337
          env:
            - name: NO_AUTH
              value: "true"

kubectl apply -f konga.yml

kubectl get svc | grep svc
konga-svc         NodePort       10.98.39.197             1337:32615/TCP                  33m

Navigate to the dashboard

http://localhost:32615/

Connect with host ip (not localhost) and admin port (8001: -> 31846 in this blog). Eg http://192.168.0.111:31846 (ip of your machine and the port from the helm installation). Note: the connection to kong can be a bit flakey, delete the connection and try again and check the pod logs.

Conclusion

We have installed Kong in Kubernetes, deployed a service vadal-echo, managed by Kong, added a custom correlation id and added Konga, an open source GUI dashboard for Kong.

Next time we add security features such as API Keys and JWTs to secure access to the service.

Source code can be found here (vadal-echo) and under infra/kong:

https://gitlab.com/lightphos/spring/vadal

Further Details

For more details on the chart values see: https://github.com/Kong/charts/blob/master/charts/kong/values.yaml

Kong Ingress:
https://github.com/Kong/kubernetes-ingress-controller/blob/master/docs/guides/getting-started.md

For more details on the postgres chart see: https://github.com/helm/charts/tree/master/stable/postgresql

Related Article