필사 모드: Kong Ingress Controller Guide — API Gateway-Style Ingress Through Its Plugin Ecosystem
EnglishIntroduction
Once you put a service on Kubernetes, a question follows almost immediately: how do you receive external traffic and route it to the right place? The most standard answer is the Ingress resource, and the implementation that has been used most widely is ingress-nginx. But as you actually operate real services, you reach a point where merely routing traffic by path is no longer enough.
Requirements like these start to pile up. A specific API needs a rate limit of 100 requests per minute. Partner calls need API key authentication. Requests going to a legacy backend need headers transformed and added. Every request must be traced with OpenTelemetry and exposed as Prometheus metrics. At this point, what you actually need is not a simple reverse proxy but an API Gateway.
Kong Ingress Controller (KIC from here on) targets exactly this gap. KIC wears the appearance of an Ingress controller, but behind it sits Kong Gateway, a full-stack API Gateway. In other words, you declare things in a Kubernetes-native way (Ingress resources, Gateway API, custom resources), and those declarations get translated into Kong Gateway's powerful plugin pipeline.
This article treats KIC not as a simple install guide but from the perspective of why it is designed this way and what you need to know operationally. We will cover the architecture and operating modes, the core CRDs, the representative plugins, Helm-based deployment, declarative config, and the relationship with Gateway API along with troubleshooting, all in a code-centric way. The reference versions are the Kong Gateway 3.x line, the KIC 3.x line, and the Kubernetes v1.32 line as of the first half of 2026.
The Ingress Landscape in 2026 — Why Look at Kong Now
Let us settle the big picture first. As of 2026, the Kubernetes ingress ecosystem is passing through an important inflection point.
First, the Ingress API is effectively frozen. The Kubernetes `networking.k8s.io/v1` Ingress is stable, but no new features are being added. The spec only includes standard capabilities like TLS termination and host/path-based routing, while everything more advanced (header routing, traffic splitting, auth, rate limiting) has been pushed into the non-standard territory of each controller's annotations.
Second, Gateway API has taken over the standard's seat as its successor. Gateway API is the next-generation standard designed around role separation (infrastructure operator versus application developer), expressive routing, and portable specification, and as of 2026 its core resources have reached GA and entered a stage usable in production.
Third, ingress-nginx, the most widely used controller, has clearly shifted toward a maintenance-mode posture. It is operated with a focus on responding to security issues rather than developing new features, and as vulnerabilities related to injecting arbitrary configuration through annotations have been repeatedly reported, organizations have begun seriously evaluating alternatives.
Where these three trends meet, Kong emerges as an attractive option. Kong supports both Ingress and Gateway API, replaces the annotation hell of ingress-nginx with structured CRD-based configuration, and above all provides API Gateway-grade features as plugins.
| Item | ingress-nginx | Kong Ingress Controller | Pure Gateway API implementations |
| --- | --- | --- | --- |
| Underlying data plane | NGINX | Kong Gateway (NGINX + Lua/OpenResty) | Varies by implementation |
| Standard interface | Ingress | Ingress + Gateway API | Gateway API |
| Advanced feature config | Annotations/ConfigMap | CRDs (KongPlugin etc.) + annotations | Policy CRDs/filters |
| Auth and rate limiting | Limited | Rich plugins | Implementation-dependent |
| Observability | Basic metrics | Prometheus/OTel plugins | Implementation-dependent |
| Project status | Maintenance-focused | Active | Active |
As the table shows, Kong's differentiator is that you can use API Gateway features in a Kubernetes-native, declarative manner. So let us take apart its structure piece by piece.
Kong Gateway and KIC — Understanding the Two Layers
The first thing to make clear is that Kong Gateway and Kong Ingress Controller are separate components. Many newcomers confuse the two, but if you understand their roles separately, every concept that follows becomes easy.
Kong Gateway is the data plane that actually handles traffic. It is built on top of NGINX and OpenResty (LuaJIT), matches incoming requests to routes and services, and runs the plugin pipeline in between. This is the engine responsible for authentication, rate limiting, transformation, and logging.
Kong Ingress Controller plays the control plane role. It watches the Kubernetes API server, and when resources such as Ingress, Gateway API objects, or Kong CRDs are created or changed, it translates them into configuration that Kong Gateway understands and injects it. In other words, KIC is a translator and synchronization loop that converts Kubernetes declarations into Kong configuration.
+-----------------------------------------------------------------------+
| Kubernetes cluster |
| |
| [control plane] [data plane] |
| Kong Ingress Controller ──inject config──▶ Kong Gateway (proxy) |
| | ^ |
| | watch | handles traffic |
| v | |
| kube-apiserver | |
| |- Ingress / HTTPRoute | |
| |- KongPlugin / KongConsumer | |
| |- Service / Endpoints <───────lookup endpoints┘ |
| |
+-----------------------------------------------------------------------+
^ |
| kubectl apply v
operator/developer external client request
Thanks to this separation, operators can choose one of two deployment patterns. One bundles the controller and gateway as sidecars in the same pod for simple operation. The other separates the control plane and data plane into distinct deployments so the data plane can scale horizontally on its own. When traffic grows large, the latter is the common choice.
DB-less Mode vs DB Mode — The Most Important Choice
When adopting KIC, the first and most important thing to decide is the data plane's operating mode. Kong Gateway runs in one of two modes depending on how it stores configuration.
In DB-less mode, Kong keeps no external database and operates from a declarative configuration loaded entirely in memory. KIC reads Kubernetes resources, generates a declarative configuration (JSON/YAML), and applies it wholesale into memory through Kong's Admin API. This is the recommended standard pattern in Kubernetes environments.
In DB mode, Kong uses PostgreSQL as a backend and persists configuration there. You can directly CRUD individual entities through the Admin API, which is flexible, but you take on the burden of operating an additional stateful store on top of Kubernetes and managing migration jobs.
| Comparison | DB-less mode | DB mode (PostgreSQL) |
| --- | --- | --- |
| Config store | Memory (declarative) | PostgreSQL |
| Single source of truth | Kubernetes resources | Database |
| Operational complexity | Low | High (DB ops and migrations) |
| Horizontal scaling | Easy, data plane is stateless | Possible DB bottleneck |
| Admin API writes | Disabled (read-only in nature) | Enabled |
| GitOps fit | Very high | Moderate |
| Recommended for | General Kubernetes use | When some enterprise features are needed |
The core principle in one line: if you run KIC on Kubernetes, make DB-less mode your default unless you have a specific reason not to. The Kubernetes resources themselves become the single source of truth, which meshes naturally with GitOps, and not operating a state store reduces your failure surface.
The following example shows the shape of the declarative configuration that KIC produces in DB-less mode. Operators rarely write it by hand, but knowing its shape helps you understand what Kong is actually looking at when you troubleshoot.
_format_version: "3.0"
services:
- name: example-service.default.80
host: example-service.default.svc
port: 80
protocol: http
routes:
- name: example-route
paths:
- /api
strip_path: true
plugins:
- name: rate-limiting
config:
minute: 100
policy: local
consumers:
- username: partner-a
keyauth_credentials:
- key: secret-api-key-value
Core CRDs — KongPlugin, KongConsumer, KongIngress
KIC's real power comes from custom resources. Everything that standard Ingress cannot express, Kong expresses cleanly with CRDs. Let us look at the three you will use most often.
KongPlugin and KongClusterPlugin
It is no exaggeration to say KongPlugin is the very reason to use KIC. You declare a single plugin, attach it via annotation to a target such as an Ingress, Service, HTTPRoute, or Consumer, and the plugin is applied to that traffic path.
The following example declares a rate-limiting plugin.
apiVersion: configuration.konghq.com/v1
kind: KongPlugin
metadata:
name: rl-by-minute
namespace: default
config:
minute: 100
policy: local
plugin: rate-limiting
To apply this declared plugin to a specific Ingress, add an annotation on the Ingress side. You can apply multiple plugins at once by listing them with commas.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: api-ingress
namespace: default
annotations:
konghq.com/plugins: rl-by-minute,key-auth-plugin
konghq.com/strip-path: "true"
spec:
ingressClassName: kong
rules:
- host: api.example.com
http:
paths:
- path: /api
pathType: Prefix
backend:
service:
name: example-service
port:
number: 80
KongPlugin is namespace-scoped, and when you want to apply the same role cluster-wide, you use KongClusterPlugin. It suits security headers or global logging plugins that you attach to every workload in common.
KongConsumer and Authentication
KongConsumer represents the calling party in the Kong world. You register partners, internal services, or specific clients as Consumers and attach authentication credentials (API keys, JWTs, and so on) to them. This lets you identify who made a call and apply different rate limits or permissions per Consumer.
apiVersion: configuration.konghq.com/v1
kind: KongConsumer
metadata:
name: partner-a
namespace: default
annotations:
kubernetes.io/ingress.class: kong
username: partner-a
credentials:
- partner-a-apikey
Credentials are usually managed separately as secrets. The following example defines a key-auth API key as a secret.
apiVersion: v1
kind: Secret
metadata:
name: partner-a-apikey
namespace: default
labels:
konghq.com/credential: key-auth
type: Opaque
stringData:
key: super-secret-partner-a-key
KongIngress and the Direction of Newer CRDs
KongIngress was the traditional CRD for tuning the detailed behavior of routes and services (protocol, timeouts, retries, path handling, and so on). However, as of 2026 this role is gradually splitting into KongUpstreamPolicy plus Service annotations and Gateway API policies. For a project starting fresh, rather than cramming all configuration into a single KongIngress, the recommended approach is to express upstream behavior with KongUpstreamPolicy and plugins with KongPlugin.
The following example defines upstream health checks and a load-balancing algorithm with KongUpstreamPolicy.
apiVersion: configuration.konghq.com/v1beta1
kind: KongUpstreamPolicy
metadata:
name: example-upstream-policy
namespace: default
spec:
algorithm: least-connections
healthchecks:
active:
type: http
httpPath: /healthz
healthy:
interval: 5
successes: 1
unhealthy:
interval: 5
httpFailures: 3
To apply this policy, you link it to the target Service with an annotation.
apiVersion: v1
kind: Service
metadata:
name: example-service
namespace: default
annotations:
konghq.com/upstream-policy: example-upstream-policy
spec:
selector:
app: example
ports:
- port: 80
targetPort: 8080
Touring the Core Plugin Ecosystem
Kong's true value lies in its plugin ecosystem. There are dozens of official plugins and community plugins, and it is convenient to understand them in five broad categories.
| Category | Representative plugins | What they do |
| --- | --- | --- |
| Authentication | key-auth, jwt, oauth2, basic-auth, ldap-auth, openid-connect | Identify and authenticate the caller |
| Traffic control | rate-limiting, request-termination, proxy-cache, request-size-limiting | Flow control and protection |
| Transformation | request-transformer, response-transformer, correlation-id | Manipulate headers, body, and query |
| Observability | prometheus, opentelemetry, http-log, file-log, datadog | Metrics, traces, and logs |
| Security | cors, ip-restriction, bot-detection, acl | Access control and defense |
Let us look at each category through a representative example.
Authentication — key-auth and OIDC
The simplest authentication is key-auth. As we saw, you attach an API key to a Consumer and apply the key-auth plugin to a route, and it verifies the key passed via header or query to identify the Consumer.
apiVersion: configuration.konghq.com/v1
kind: KongPlugin
metadata:
name: key-auth-plugin
namespace: default
config:
key_names:
- apikey
key_in_header: true
key_in_query: false
plugin: key-auth
In enterprise environments, it is common to use the openid-connect plugin to integrate with Keycloak or an in-house IdP and apply OIDC-based authentication. In this case the gateway handles token verification, so backend services are freed from authentication logic.
Traffic Control — rate-limiting
Rate limiting is the most frequently used plugin. You can set limits per minute, hour, or day, and you can choose local, cluster, or Redis as the limit calculation policy. To share limits across multiple data plane pods, the Redis policy is accurate. The local policy is fast, but remember that limits are calculated separately per pod.
apiVersion: configuration.konghq.com/v1
kind: KongPlugin
metadata:
name: rl-redis
namespace: default
config:
minute: 100
hour: 2000
policy: redis
redis:
host: redis-master.default.svc
port: 6379
plugin: rate-limiting
Transformation — request-transformer
When communicating with a legacy backend, you often need to add, remove, or change request headers. request-transformer handles this work at the gateway.
apiVersion: configuration.konghq.com/v1
kind: KongPlugin
metadata:
name: add-legacy-headers
namespace: default
config:
add:
headers:
- "X-Gateway: kong"
- "X-Forwarded-Prefix: /api"
remove:
headers:
- "X-Internal-Token"
plugin: request-transformer
Observability — prometheus and opentelemetry
The heart of operations is visibility. Apply the prometheus plugin globally and it exposes metrics such as request counts, latency, status codes, and upstream health in Prometheus format. The opentelemetry plugin exports distributed traces over OTLP, letting you trace the flow of requests passing through the gateway.
apiVersion: configuration.konghq.com/v1
kind: KongClusterPlugin
metadata:
name: prometheus
annotations:
kubernetes.io/ingress.class: kong
labels:
global: "true"
config:
status_code_metrics: true
latency_metrics: true
bandwidth_metrics: true
plugin: prometheus
A KongClusterPlugin labeled `global: "true"` is automatically applied to all routes. Observability plugins pair especially well with this global application style.
The Full Path a Request Travels
If we summarize in a single picture how the components we have seen so far fit together on an actual request, it looks like this.
external client
| GET https://api.example.com/api/orders (with apikey header)
v
[load balancer / Service type=LoadBalancer]
|
v
[Kong Gateway data plane pod]
|
|- 1. route match: host=api.example.com, path=/api --> example-service
|
|- 2. plugin pipeline (request phase)
| |- cors (handle preflight)
| |- key-auth (verify apikey -> identify Consumer=partner-a)
| |- acl (check partner-a is in the allowed group)
| |- rate-limiting (check partner-a per-minute limit)
| |- request-transformer (massage headers)
|
|- 3. upstream selection (KongUpstreamPolicy: least-connections + healthcheck)
|
v
[example-service -> pod endpoints]
|
v response
[Kong Gateway data plane]
|
|- 4. plugin pipeline (response phase)
| |- response-transformer
| |- prometheus / opentelemetry (record metrics and traces)
|
v
return response to external client
The important point in this flow is that plugins run in order according to phase and priority. For example, authentication (key-auth) must run before rate limiting (rate-limiting) so the gateway knows whose limit it is. Kong assigns each plugin a default priority that guarantees this order, and operators can adjust priorities if needed.
Simultaneous Support for Ingress and Gateway API
As noted earlier, the key theme of 2026 is Gateway API. A major advantage of KIC is that it supports both traditional Ingress and the new standard Gateway API. This lets you keep existing Ingress assets while gradually migrating to Gateway API.
In Gateway API, roles are separated. The infrastructure operator defines listeners and infrastructure with GatewayClass and Gateway, while the application developer declares routing rules with HTTPRoute. KIC handles all of these resources.
apiVersion: gateway.networking.k8s.io/v1
kind: GatewayClass
metadata:
name: kong
spec:
controllerName: konghq.com/kic-gateway-controller
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: kong-gateway
namespace: default
spec:
gatewayClassName: kong
listeners:
- name: http
protocol: HTTP
port: 80
HTTPRoute can express matching by header, method, and query parameter as a standard, not just by host and path. This was an area Ingress never managed to standardize.
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: orders-route
namespace: default
spec:
parentRefs:
- name: kong-gateway
hostnames:
- api.example.com
rules:
- matches:
- path:
type: PathPrefix
value: /api/orders
headers:
- name: X-Api-Version
value: v2
backendRefs:
- name: orders-service
port: 80
Plugins apply identically in a Gateway API environment. You attach a KongPlugin annotation to an HTTPRoute, or connect it through the Gateway API standard's policy attachment mechanism. In other words, you move the standard interface to Gateway API while still enjoying Kong's rich plugin ecosystem unchanged.
The practical recommended path is this. For a new cluster, start with Gateway API from the beginning. For an existing Ingress-based cluster, unify on KIC, run Ingress and Gateway API side by side, and migrate gradually with HTTPRoute. That two standards can coexist under the same controller is a major strength of KIC.
Deploying with Helm
Now let us move to actual deployment. The standard way to deploy KIC is the Helm chart, and a single chart can install both the controller and the gateway. First add the Helm repository.
helm repo add kong https://charts.konghq.com
helm repo update
kubectl create namespace kong
The following is an example values file for deploying in DB-less mode. It enables the controller, exposes the gateway as a LoadBalancer, and specifies the proxy and Admin API configuration.
ingressController:
enabled: true
installCRDs: false
ingressClass: kong
env:
database: "off"
router_flavor: expressions
proxy:
enabled: true
type: LoadBalancer
http:
enabled: true
servicePort: 80
tls:
enabled: true
servicePort: 443
admin:
enabled: true
type: ClusterIP
http:
enabled: true
resources:
requests:
cpu: 500m
memory: 512Mi
limits:
cpu: "2"
memory: 1Gi
replicaCount: 2
It is safer to install CRDs separately and first. If you let the chart install CRDs, conflicts can occur during upgrades, so managing CRDs explicitly is operationally cleaner.
kubectl apply -f https://github.com/Kong/kubernetes-ingress-controller/releases/latest/download/all-in-one-dbless.yaml
Once the values file is ready, install it.
helm install kong kong/ingress \
--namespace kong \
--values values-dbless.yaml
After installation completes, check the gateway service's external IP and the controller's status.
kubectl get pods -n kong
kubectl get svc -n kong
kubectl get ingressclass
If you see `kong` in IngressClass and an EXTERNAL-IP assigned to the gateway service, it is ready to receive traffic. From there, apply the Ingress, HTTPRoute, and KongPlugin resources we saw earlier to configure routing and policies.
Declarative Config and GitOps
The biggest appeal of DB-less mode is that all configuration is expressed as Kubernetes resources and lands directly in Git. This meshes naturally with GitOps. If you synchronize manifests with Argo CD or Flux, the change history and rollback of gateway configuration are managed entirely within the Git workflow.
If your organization uses Kong outside Kubernetes as well, the tool decK is worth knowing. decK is a CLI that manages Kong's declarative configuration as code, shows the diff between current and desired state, and synchronizes it. It is useful for dumping and validating the configuration KIC produces, or for comparing configuration across environments.
deck gateway dump --kong-addr http://localhost:8001 -o kong-state.yaml
deck gateway diff kong-state.yaml --kong-addr http://localhost:8001
That said, you need caution when using KIC and decK against the same gateway at once. In DB-less mode the single source of truth must be the Kubernetes resources, so limit decK to export and validation, and keep the discipline of changing configuration only through Kubernetes resources. That is the way to avoid conflicts.
Operations and Tuning
To run KIC reliably in production, you need to take care of a few core points.
First, horizontal scaling of the data plane. The gateway in DB-less mode is nearly stateless, so you can grow throughput just by increasing replicas. However, the local policy of rate-limiting calculates limits separately per pod, so if you need an accurate global limit, you must switch to the Redis policy.
Second, health checks and probes. Kong provides a status endpoint, so connect it to readiness and liveness probes to quickly isolate unhealthy pods. Also configure upstream health checks (active/passive) with KongUpstreamPolicy so traffic does not go to dead backend pods.
Third, resource and worker tuning. Values such as the number of NGINX worker processes, connection limits, and timeouts must be adjusted to your traffic characteristics. In particular, growing the upstream keepalive connection pool appropriately reduces the cost of opening a new connection to the backend on every request.
Fourth, TLS and certificate management. Integrating with cert-manager to automate certificate issuance and renewal is standard. Connect a certificate secret to the TLS section of an Ingress or to a Gateway listener, and configure cert-manager to renew automatically via Let's Encrypt or similar.
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: api-example-com-tls
namespace: default
spec:
secretName: api-example-com-tls
dnsNames:
- api.example.com
issuerRef:
name: letsencrypt-prod
kind: ClusterIssuer
Fifth, the security boundary. The Admin API must never be exposed externally. Keep it as ClusterIP or restrict access with network policies, and in DB-less mode operate the Admin API close to read-only for safety. To avoid the kind of arbitrary configuration injection vulnerabilities that repeatedly plagued ingress-nginx, manage plugin configuration only from trusted sources (Git, reviewed manifests).
Common Pitfalls and Troubleshooting
Here are problems you frequently hit in operations, along with their causes.
First, a missing IngressClass. If you do not specify `ingressClassName: kong` on an Ingress, KIC ignores that Ingress. If routing does not work at all and the logs are also quiet, suspect this first. In Gateway API, check that the GatewayClass `controllerName` exactly matches KIC's controller name.
Second, plugin annotation typos. If the name written in the `konghq.com/plugins` annotation differs from the actual KongPlugin resource name, or the namespace is off, the plugin is not applied. When a plugin seems not to attach, compare the KongPlugin resource's name and namespace against the annotation string.
Third, strip_path confusion. If you set `konghq.com/strip-path` to true, the matched path prefix is removed before forwarding to the backend. If the path the backend receives differs from what you expected, check this setting. Whether a request arriving at `/api` reaches the backend as `/` or as `/api` is decided here.
Fourth, config propagation delay. KIC detects changes and synchronizes them to the gateway, but on bulk changes or large clusters there can be a slight delay. When a change appears not to take effect, check the controller logs for synchronization success and the last sync timestamp.
Fifth, declarative config validation failure. If the declarative configuration KIC generates has an error (for example, an invalid plugin config schema), the gateway rejects the new configuration and keeps the last good one. So it can look like you applied a bad change and nothing happened. The key here is to find the validation error message in the controller logs.
A useful set of commands for diagnosis is as follows.
kubectl logs -n kong deploy/kong-controller -c ingress-controller --tail=200
kubectl describe ingress api-ingress -n default
kubectl get kongplugin -A
kubectl get kongconsumer -A
kubectl port-forward -n kong svc/kong-admin 8001:8001
After port-forwarding to the Admin API with the last command and directly querying the routes, services, and plugin state the gateway actually holds, you can most quickly close the gap between Kubernetes declarations and what is actually applied.
Sixth, admission webhook rejection. KIC can use a validating webhook to block invalid plugin configuration or duplicate credentials in advance. If `kubectl apply` is rejected, reading the webhook message verbatim is the fastest fix. The webhook is a safety net that stops bad configuration before it reaches the gateway, so it is better to interpret and fix the message than to disable it.
Conclusion
KIC is not merely an Ingress controller but a bridge connecting Kubernetes-native declarations to a full-stack API Gateway. In the 2026 landscape where the Ingress API is frozen and Gateway API has taken the standard's seat, KIC supports both standards while offering its plugin ecosystem as a powerful differentiator.
If you are weighing adoption, here is the order we recommend. First, make DB-less mode your default to lower operational complexity, and express all configuration as Kubernetes resources to ride GitOps. Cleanly separate core features such as auth, rate limiting, and observability into plugins from the start to keep backends light. Express new routing with Gateway API's HTTPRoute, but run existing Ingress assets side by side under the same controller and migrate gradually.
Above all, what matters is understanding the shift from an era of cramming everything into annotations to an era of expressing policy with structured CRDs and the standard Gateway API. Kong is a tool that lets you walk that transition relatively smoothly, and for any organization that needs an API Gateway, it is well worth serious consideration.
References
- Kong Ingress Controller official documentation: https://docs.konghq.com/kubernetes-ingress-controller/
- Kong Gateway official documentation: https://docs.konghq.com/gateway/
- Kong Plugin Hub: https://docs.konghq.com/hub/
- Kong KIC GitHub repository: https://github.com/Kong/kubernetes-ingress-controller
- Kubernetes Ingress concept documentation: https://kubernetes.io/docs/concepts/services-networking/ingress/
- Gateway API official documentation: https://gateway-api.sigs.k8s.io/
- ingress-nginx documentation: https://kubernetes.github.io/ingress-nginx/
- cert-manager official documentation: https://cert-manager.io/docs/
- decK documentation: https://docs.konghq.com/deck/
- Kong Helm charts repository: https://github.com/Kong/charts
현재 단락 (1/400)
Once you put a service on Kubernetes, a question follows almost immediately: how do you receive exte...