Search code examples
kubernetesapi-gatewaykongingress-controllerkong-ingress

Kong Ingress Controller: prevent stripping the path when routing the request to a service


I'm learning Kong API Gateway, in particular the installation on Kubernetes with the Kong Ingress Controller, and I've completed this tutorial.

TL;DR

The HTTP request I send:

GET 127.0.0.1:80/weather/London

The HTTP request the service receives:

GET 127.0.0.1:3000/London

When sending an HTTP request to a Kong service, how can I route the request, so that the full path of the URL is preserved, without stripping the first part (/weather)?

Long version

I'm trying to create a Node.js microservice that provides an API to retrieve the weather: the API is called with /weather/:countryName and returns a JSON with weather information (using OpenWeatherAPIs).

Example

Sending the following request

curl -i localhost:3000/weather/London

Return the following JSON:

{
    "cityName": "London (GB)",
    "temperature": {
        "actual": 14.31,
        "min": 12.56,
        "max": 15.71
    },
    "humidity": 81,
    "windSpeed": 3.09,
    "description": "broken clouds",
    "iconURL": "http://openweathermap.org/img/wn/[email protected]"
}

Kong

My setup is the one from the tutorial I linked previously:

  • local cluster with minikube;
  • minikube tunnel (docker driver) running in background;

Service and Deployment resources

File weather.yml:

apiVersion: v1
kind: Service
metadata:
  labels:
    app: weather
  name: weather
spec:
  ports:
  - port: 1025
    name: tcp
    protocol: TCP
    targetPort: 1025
  - port: 1026
    name: udp
    protocol: TCP
    targetPort: 1026
  - port: 3000
    name: http
    protocol: TCP
    targetPort: 3000
  selector:
    app: weather
---
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: weather
  name: weather
spec:
  replicas: 1
  selector:
    matchLabels:
      app: weather
  strategy: {}
  template:
    metadata:
      creationTimestamp: null
      labels:
        app: weather
    spec:
      containers:
      - image: mikyll/api-weather:v1.0
        name: weather
        ports:
        - containerPort: 3000
        env:
          - name: NODE_NAME
            valueFrom:
              fieldRef:
                fieldPath: spec.nodeName
          - name: POD_NAME
            valueFrom:
              fieldRef:
                fieldPath: metadata.name
          - name: POD_NAMESPACE
            valueFrom:
              fieldRef:
                fieldPath: metadata.namespace
          - name: POD_IP
            valueFrom:
              fieldRef:
                fieldPath: status.podIP
        resources: {}

Applied with cat .\weather.yml | kubectl apply -f -

Routing Configuration

File weather-routing.yml

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: weather-route
  annotations:
    konghq.com/strip-path: 'false'
spec:
  ingressClassName: kong
  rules:
  - http:
      paths:
      - path: /weather
        pathType: ImplementationSpecific
        backend:
          service:
            name: weather
            port:
              number: 3000

Applied with cat .\weather-routing.yml | kubectl apply -f -

Problem

When I send a request to the proxy, the first part of the URL is removed when calling the service:

curl -i 127.0.0.1:80/weather/London

Gives the following result:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Error</title>
</head>
<body>
<pre>Cannot GET /London</pre>
</body>
</html>

Question

How can I pass the same path, without stripping the first part (/weather) to the service?


Solution

  • Turns out the problem was that I had mistakenly created 2 routes: "weather" and "weather-route":

    PS D:\kong-kubernetes> kubectl get ingress
    NAME            CLASS   HOSTS          ADDRESS     PORTS   AGE
    weather         kong    *              127.0.0.1   80      3h9m
    weather-route   kong    *              127.0.0.1   80      25m
    

    Therefore, when editing "weather-route", even if I set konghq.com/strip-path to 'false', the other route rule had it set to 'true' and was getting applied earlier, causing the request to fail.

    Removing it fixed the issue:

    kubectl delete ingress weather
    
    PS D:\kong-kubernetes> kubectl get ingress
    NAME            CLASS   HOSTS          ADDRESS     PORTS   AGE
    weather-route   kong    *              127.0.0.1   80      25m
    

    HTTP request:

    PS D:\kong-kubernetes> curl -i 127.0.0.1:80/weather/London
    
    {
        "cityName": "London (GB)",
        "temperature": {
            "actual": 14.53,
            "min": 12.64,
            "max": 15.76
        },
        "humidity": 79,
        "windSpeed": 5.66,
        "description": "scattered clouds",
        "iconURL": "http://openweathermap.org/img/wn/[email protected]"
    }
    

    A special thanks to Botje for making me notice the first most important issue :)