Ingress with Kong
Kong is the cluster’s ingress: the component that receives HTTP and HTTPS from outside and routes each request to the right application. BKE installs it ready to use — this page shows how to put an application behind it, give it a certificate, and switch on the traffic controls most clusters want first.
Kong is configured through Kubernetes resources, applied with kubectl like
anything else. There is no separate Kong console or admin API to operate:
create an Ingress, and the routing exists; delete it, and it is gone.
BKE’s part of Kong is installing and upgrading it at tested versions. What you route, limit and cache — the resources and examples on this page — is your application configuration: the examples are starting points offered to help you, not part of BKE, and what you build from them is yours to operate.
Reference architecture covers how outside traffic reaches Kong in the first
place — the load balancer, ports 32080/32443, and the firewall rules. This
page assumes that path exists.
Exposing an application
Suppose a Deployment called shop runs in namespace retail, listening on
port 8080. Two resources put it on the internet.
A Service, giving the pods one stable address inside the cluster:
apiVersion: v1
kind: Service
metadata:
name: shop
namespace: retail
spec:
selector:
app: shop
ports:
- port: 80
targetPort: 8080
And an Ingress, telling Kong which hostname routes to it:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: shop
namespace: retail
spec:
ingressClassName: kong
rules:
- host: shop.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: shop
port:
number: 80
Resources like these are applied from any machine with a kubeconfig — the first control-plane node works. Save each as a file and apply it:
kubectl apply -f shop-service.yaml -f shop-ingress.yaml
Changing a resource is the same motion — edit the file, kubectl apply -f it
again — and kubectl delete -f <file> removes what it created. These files
are yours, not BKE’s: BKE neither creates nor reconciles them, so keep them
in your own source control the way you keep anything that decides what runs.
ingressClassName: kong is what hands the route to Kong; without it, the
Ingress belongs to nothing and does nothing. With DNS for shop.example.com
pointing at your ingress load balancer:
curl http://shop.example.com/
A 404 from Kong rather than your application means the request arrived but no
route matched — almost always a hostname that does not match the host: rule.
kubectl -n retail describe ingress shop shows what Kong made of it.
TLS certificates
cert-manager obtains and renews certificates; Kong serves them. BKE installs cert-manager but deliberately ships no certificate issuer, because an issuer names things that are yours — your registration email, your DNS provider, your domains. You create one, once, and every application after that is two lines on its Ingress.
An issuer for Let’s Encrypt, proving domain ownership over HTTP through Kong:
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt
spec:
acme:
server: https://acme-v02.api.letsencrypt.org/directory
email: platform@example.com
privateKeySecretRef:
name: letsencrypt-account
solvers:
- http01:
ingress:
ingressClassName: kong
Two things must be true for this http01 proof to work: the hostname’s DNS
already points at your ingress load balancer, and port 80 is reachable from
the internet — the certificate authority makes a plain-HTTP request to the
hostname and must get through. If port 80 cannot be open in your environment,
use a dns01 solver instead: the proof is a DNS record rather than an HTTP
request, cert-manager’s documentation lists the supported DNS providers, and
the rest of this page is unchanged.
While testing, point server: at
https://acme-staging-v02.api.letsencrypt.org/directory — the staging
environment issues certificates browsers do not trust, but it does not apply
the rate limits that can lock a domain out of the production environment for
days after repeated failed attempts.
Then ask for a certificate on the Ingress:
metadata:
name: shop
namespace: retail
annotations:
cert-manager.io/cluster-issuer: letsencrypt
spec:
ingressClassName: kong
tls:
- hosts:
- shop.example.com
secretName: shop-tls
...
cert-manager sees the annotation, performs the proof, and writes the
certificate into the shop-tls Secret; Kong serves it and https:// works.
Renewal is automatic. Progress, when you want to watch it:
kubectl -n retail get certificate
kubectl -n retail describe certificate shop-tls
Plugins
Kong’s traffic behaviour beyond routing — limits, caching, restrictions — comes
from plugins. A plugin is declared once as a KongPlugin resource and
attached by name to whatever it should govern, through an annotation:
- on an Ingress — governs those routes;
- on a Service — governs everything reaching that Service;
- as a KongClusterPlugin with the label
global: "true"— governs all traffic through Kong.
The plugins below are part of Kong’s open-source plugin set, which is what BKE installs.
Rate limiting
Sixty requests per minute, per client address:
apiVersion: configuration.konghq.com/v1
kind: KongPlugin
metadata:
name: shop-rate-limit
namespace: retail
plugin: rate-limiting
config:
minute: 60
policy: local
Attached to the application’s Ingress:
metadata:
name: shop
namespace: retail
annotations:
konghq.com/plugins: shop-rate-limit
A client over the limit receives 429, and every response carries
RateLimit-Remaining so well-behaved clients can pace themselves.
policy: local counts on each Kong instance separately. Kong runs at least
two instances for availability, so a client spreading requests across them can
reach roughly the limit multiplied by the instance count. For most uses —
protecting an application from a runaway caller — that is accurate enough. If
you need one exact shared count, policy: redis keeps the counters in a Redis
you provide; the plugin’s redis settings name the host.
Note that the address the limit counts is the address Kong sees. Behind a load balancer that is the balancer’s own address — one counter for everyone — unless the client address is being passed through. Reference architecture covers that under The client address, stated honestly.
Response caching
Caching responses in Kong takes repeated identical requests off your application:
apiVersion: configuration.konghq.com/v1
kind: KongPlugin
metadata:
name: shop-cache
namespace: retail
plugin: proxy-cache
config:
response_code: [200, 301]
request_method: [GET, HEAD]
content_type:
- text/html
- application/json
cache_ttl: 300
strategy: memory
Attach it through the same annotation — several plugins are a comma-separated list:
konghq.com/plugins: shop-rate-limit,shop-cache
Every response then carries X-Cache-Status: Miss, Hit, or Bypass for
requests the configuration excludes. Two properties to know before relying on
it: the cache lives in each Kong instance’s memory, so it is emptied whenever
Kong restarts and warmed separately per instance; and only responses matching
the codes, methods and content types listed are stored. It is a load-shedding
cache, not a store — an application that must not serve stale data for longer
than cache_ttl seconds should set it accordingly.
Others worth knowing
| Plugin | What it does |
|---|---|
ip-restriction |
allow or deny listed client networks |
cors |
sets cross-origin headers for browser-facing APIs |
request-size-limiting |
rejects request bodies over a stated size |
request-termination |
answers with a fixed status — a maintenance switch for one route |
bot-detection |
rejects known crawler and script user-agents |
Each follows the same pattern: a KongPlugin naming the plugin and its
config, attached with the konghq.com/plugins annotation.
Seeing what Kong is doing
Kong writes one JSON line per request to its own log, including the route, the
status, the caller as Kong saw it, latency figures, and — when caching is on —
upstream_cache_status:
kubectl -n kong logs -l app.kubernetes.io/name=kong --tail=50
Substitute the namespace your config.yaml installs Kong into. For a request
that behaves unexpectedly, this log answers the first question — did it reach
Kong, what did Kong decide, and how long did the application take.