This is an example of using the Kong Ingress Controller to two different services, both on the same port. The first service is echo, the second service is nginx, say as a simple web server. Each service is in it's own namespace. This also is part of onboarding.
We will install k3d without traefik nor serverlb for consistency so we can use Metallb in either type of cluster
minikube addons enable metallb
❗ metallb is a 3rd party addon and is not maintained or verified by minikube maintainers, enable at your own risk.
❗ metallb does not currently have an associated maintainer.
▪ Using image quay.io/metallb/speaker:v0.9.6
▪ Using image quay.io/metallb/controller:v0.9.6
🌟 The 'metallb' addon is enabled
minikube profile list
┌──────────┬────────┬─────────┬──────────────┬─────────┬────────┬───────┬────────────────┬────────────────────┐
│ PROFILE │ DRIVER │ RUNTIME │ IP │ VERSION │ STATUS │ NODES │ ACTIVE PROFILE │ ACTIVE KUBECONTEXT │
├──────────┼────────┼─────────┼──────────────┼─────────┼────────┼───────┼────────────────┼────────────────────┤
│ minikube │ docker │ docker │ 192.168.49.2 │ v1.34.0 │ OK │ 1 │ * │ * │
└──────────┴────────┴─────────┴──────────────┴─────────┴────────┴───────┴────────────────┴────────────────────┘
minikube addons configure metallb
-- Enter Load Balancer Start IP: 192.168.49.100
-- Enter Load Balancer End IP: 192.168.49.101
▪ Using image quay.io/metallb/speaker:v0.9.6
▪ Using image quay.io/metallb/controller:v0.9.6
✅ metallb was successfully configured
# install k3d and create a cluster WITHOUT traefik and WITHOUT serverlb
k3d cluster create cluster1 --k3s-arg="--disable=traefik@server:*" --k3s-arg="--disable=serverlb@server:*"
# install metallb generically
kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.15.3/config/manifests/metallb-native.yaml
docker network inspect k3d-cluster1 | grep Subnet
# edit and modify the metallb-address-pool-for-k3d.yaml to have a range on the k3d subnet
k apply -f metallb-address-pool-for-k3d.yaml
k create ns nginx
k apply -f nginx-nodeport-deployment-and-service.yaml
k get svc -A
NAMESPACE NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
default kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 5d17h
kube-system kube-dns ClusterIP 10.96.0.10 <none> 53/UDP,53/TCP,9153/TCP 5d17h
nginx nginx NodePort 10.97.204.222 <none> 8080:31572/TCP 72s
k get nodes -o wide
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
minikube Ready control-plane 5d17h v1.34.0 192.168.49.2 <none> Ubuntu 22.04.5 LTS 5.15.0-164-generic docker://28.4.0
curl 192.168.49.2:31572
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
...
# cleanup
k delete ns nginx
k create ns nginx
k apply -f nginx-deployment.yaml
deployment.apps/nginx created
k expose deployment nginx --type LoadBalancer --port 8888 --target-port 80 -n nginx
service/nginx exposed
k get svc -A
NAMESPACE NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
default kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 5d17h
kube-system kube-dns ClusterIP 10.96.0.10 <none> 53/UDP,53/TCP,9153/TCP 5d17h
nginx nginx LoadBalancer 10.103.120.235 192.168.49.100 8888:31720/TCP 9s
export PROXY_IP=$(kubectl get svc --namespace nginx nginx -o jsonpath='{range .status.loadBalancer.ingress[0]}{@.ip}{@.hostname}{end}')
curl $PROXY_IP:8888
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
...
# cleanup
k delete ns nginx
When we do this, it will actually create another LoadBalancer service on 192.168.49.101, in my examples below, it uses 192.168.49.100 because I did not actually do the MetalLB method before capturing that output.
k create ns kong
# set env vars for your KONNECT cert and key TLS_CERT and TLS_KEY
# first export your Konnect cert and key to TLS_CERT and TLS_KEY env vars
# you must enclose these in double quotes, must use multi-line do not concat the line, do not put backslashes at the end of lines or it does not work
# example:
# export TLS_CERT="---BEGIN CERT---
# blahblahblah
# blahblahblah
# blahblahblah
# ---END CERT---"
# export TLS_KEY="---BEGIN KEY---
# blahblahblah
# blahblahblah
# blahblahblah
# ---END KEY---"
kubectl create secret tls konnect-client-tls -n kong --cert=<(echo "$TLS_CERT") --key=<(echo "$TLS_KEY")
helm repo add kong https://charts.konghq.com
helm repo update
# The helm chart kic-to-konnect-ingresscontroller-and-gw-helm-chart.yaml is an example circa 1/30/2026 but take a look at it.
# Copy the helm chart from Konnect GUI itself by going to your KIC Gateway, clicking connect or dataplane noes, and selecting the Helm method. You may have to select the text and copy it instead of using copy widget. This is so you don't accidently save a values.yaml in your working dir.
helm install kong kong/ingress -n kong -f - <<EOF (paste entire helm chart) EOF
k create ns echo
k apply -f echo-deployment-and-service.yaml
k create ns nginx
k apply -f nginx-deployment-and-service.yaml
# NOTE: Ingress rules must reside in the namespace where the app that they configure reside.
k apply -f kic-ingress-for-echo.yaml -n echo
k apply -f kic-ingress-for-nginx.yaml
k get svc -A
NAMESPACE NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
default kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 5d16h
echo echo ClusterIP 10.97.20.125 <none> 1025/TCP,1026/TCP,8080/TCP,1030/TCP 5m37s
kong kong-controller-metrics ClusterIP 10.110.148.227 <none> 10255/TCP,10254/TCP 6m43s
kong kong-controller-validation-webhook ClusterIP 10.107.14.43 <none> 443/TCP 6m43s
kong kong-gateway-admin ClusterIP None <none> 8444/TCP 6m42s
kong kong-gateway-proxy LoadBalancer 10.103.8.238 192.168.49.100 80:31142/TCP,443:31781/TCP 6m42s
kube-system kube-dns ClusterIP 10.96.0.10 <none> 53/UDP,53/TCP,9153/TCP 5d16h
nginx nginx ClusterIP 10.96.176.190 <none> 8080/TCP 4m52s
k describe ingress echo -n echo
Name: echo
Labels: <none>
Namespace: echo
Address: 192.168.97.100
Ingress Class: kong
Default backend: <default>
Rules:
Host Path Backends
---- ---- --------
*
/echo echo:8080 (10.42.0.46:1027)
Annotations: konghq.com/strip-path: true
Events: <none>
export PROXY_IP=$(kubectl get svc --namespace kong kong-gateway-proxy -o jsonpath='{range .status.loadBalancer.ingress[0]}{@.ip}{@.hostname}{end}')
echo $PROXY_IP
curl $PROXY_IP
{
"message":"no Route matched with those values",
"request_id":"01051e5d5aa7d823e361eb4bfd4fa35b"
}
curl $PROXY_IP/echo
Welcome, you are connected to node minikube.
Running on Pod echo-79d4b9b8bc-mdlkx.
In namespace echo.
With IP address 10.244.0.21.
curl $PROXY_IP/nginx
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
...
# ensure this goes into the SAME namespace as the Service, so in this case, into the echo namespace
k apply -n echo -f create-rate-limit-plugin.yaml
kongplugin.configuration.konghq.com/rate-limit-5-min created
# note you MUST annote it using the ns of the service, so here it is scoped to ns echo
k annotate -n echo service echo konghq.com/plugins=rate-limit-5-min
service/echo annotated
k describe service echo -n echo
Name: echo
Namespace: echo
Labels: app=echo
Annotations: konghq.com/plugins: rate-limit-5-min
Selector: app=echo
Type: ClusterIP
IP Family Policy: SingleStack
IP Families: IPv4
IP: 10.43.69.188
IPs: 10.43.69.188
Port: tcp 1025/TCP
TargetPort: 1025/TCP
Endpoints: 10.42.0.46:1025
Port: udp 1026/TCP
TargetPort: 1026/TCP
Endpoints: 10.42.0.46:1026
Port: http 8080/TCP
TargetPort: 1027/TCP
Endpoints: 10.42.0.46:1027
Port: tls 1030/TCP
TargetPort: 1030/TCP
Endpoints: 10.42.0.46:1030
Session Affinity: None
Internal Traffic Policy: Cluster
Events: <none>
$
for i in {1..10}; do curl $PROXY_IP/echo; done;
Welcome, you are connected to node minikube. Running on Pod echo-79d4b9b8bc-vh85x. In namespace kong. With IP address 10.244.0.10.
Welcome, you are connected to node minikube. Running on Pod echo-79d4b9b8bc-vh85x. In namespace kong. With IP address 10.244.0.10.
Welcome, you are connected to node minikube. Running on Pod echo-79d4b9b8bc-vh85x. In namespace kong. With IP address 10.244.0.10.
Welcome, you are connected to node minikube. Running on Pod echo-79d4b9b8bc-vh85x. In namespace kong. With IP address 10.244.0.10.
Welcome, you are connected to node minikube. Running on Pod echo-79d4b9b8bc-vh85x. In namespace kong. With IP address 10.244.0.10.
{ "message":"API rate limit exceeded", "request_id":"915b65533f446f58813b076a9059646c" }