Ingress Controllers

A K8s component that allows external traffic into our cluster.

Definition

An Ingress controller is a specialized load-balancer that manages external access to Services within a K8s cluster, typically providing HTTP and HTTPS routing. Simply put, it is a set of rules (a configuration file). It is the actual software (the "engine") that reads these rules and carries out the traffic routing. It can be both a load-balancer and a reverse-proxy simultaneously.

On the other hand, a K8s Service (like NodePort or LoadBalancer) handles basic traffic routing inside our clusters between pods.

How Ingress Controller work

Table 1. Steps
# Step Activity Resides

1

Service of type LoadBalancer or NodePort

The K8s Service that fronts the Ingress Controller pod(s) requests a cloud-provider load-balancer. The provider creates a public IP/DNS name.

Cloud-provider LB → Ingress Controller Pod

2

Ingress Controller pod (NGINX, HAProxy, Envoy, Traefik, …​)

The controller runs a revers-proxy server. It watches all Ingress objects, renders a proxy configuration (virtual hosts, path rules, TLS, rate-limiting, etc.) and reloads the proxy whenever the rules change.

reverse-proxy logic inside the pod

3

Proxy→Service

The reverse-proxy forwards the request (HTTP/HTTPS, gRPC, etc.) to the target K8s Service (ClusterIP) that selects the backend Pods.

Proxy → ClusterIP Service → Pods

So the external LoadBalancer distributes inbound connections across the actual Ingress Controller Pods, while the reverse-proxy inside each pod does the actual HTTP routing to our workloads.

Table 2. Production-grade Ingress Controllers
Name Primary proxy engine Notable features Typical use cases Typical LoadBalancer integration Why

NGINX Ingress Controller

NGINX (commercial-features)

Rich annotations, extensive community support, robust TLS & JWT handling

General purpose, works on most clouds and on-perms

Deploys a Service (type: LoadBalancer) that automatically provisions a Cloud LB.

It has a

  • Long-standing community

  • More that 10K GitHub stars

  • Many production case studies

  • Solid TLS and rewrite support

HAProxy

HAProxy

Native TCP/UDP support, advanced rate-limiting, connection-pooling, easy to enable HAProxy Enterprise features

High-performance, latency-sensitive workloads

Same patterns - a LoadBalancer Service in front of HAProxy load-balancer.

  • High-performance TCP/UDP handling

  • battle-tested in fintech and eco environments

Traefik

Traefik

Built-in Let’s Encrypt, dynamic configuration via CRDs, middleware pipeline, good for microservice meshes

Cloud-native stacks, easy TLS automation

It can expose itself with a LoadBalancer Service or use the cloud-provider’s Ingress-class "traefik" which creates the LB automatically

  • Built-in ACME (Let’s envrypt) automation

  • Dynamic configuration

  • Popular with Docker-Swarm-to-K8s migrations

Kong Ingress Controller

NGINX-based

Plugin ecosystem (authentication, rate-limiting, logging), Kong Enterprise integration

API-first platforms, need plugin extensibility

https://[Istio Gateway]

Envoy (via Istio)

Full service-mesh capabilities, advanced traffic management, mTLS, fault injection

Environment already using Istio or needing mesh-wide policies

The Gateway runs as a Deployment behind a LoadBalancer Service (or NodePort for on-prem) providing L7 routing and L4 TCP/UDP capabilities.

  • Full service-mesh integration

  • Used by large enterprises for zero-trust ingress

AWS LoadBalancer controller

AWS ALB/NLB

Directly provisions AWS Application Load Balancers from Ingress resources, supports target-group health checks

Clusters running on AWS, want native ALB/NLB features

GKE/GCE Ingress

GCE L7 load balancer

Managed by Google Cloud, automatic SSL cert provisioning via Google Managed Certificates

Google cloud-only deployments

Good for

All the above, table-1, are battle-tested in large-scale production environments.

Runtime performance

HAProxy & Nginx are classic high-throughput choices.

Feature set

Traefik and Kong excel in middleware and plugins; Istio provides

Cloud integration

Cloud-specific controllers

Protocol support

Table 3. Protocol support
Protocol/use-case Can a typical Ingress controller route it? How it’s usually done?

HTTP/HTTPS(REST, graphQL, gRPC-HTTP/2)

✅Yes, most Ingress controllers (NGINX, HAProxy, Kong, Traefik, Istio Gateway) understand HTTP/2 and can terminate TLS, then forward the stream to the backend service. gRPC works because it is just HTTP/2 with a different content-type (application/grpc).

Use an Ingress rule with the appropriate host/path and optional nginx.ingress.kubernetes.io/backend-protocol:"GRPC"; or the equivalent annotation for the controller

✅

Pure gRPC (non-HTTP/2-aware proxies)

❌Not directly - the Ingress resource is defined for Layer 7 (HTTP) traffic. If the underlying proxy can terminate HTTP/2 and forward the gRPC payload, it works; otherwise you need a Gateway (e.g., Istio Gateway or a dedicated gRPC-proxy such as Envoy).

Deploy an Envoy or Istio gateway that advertises the gRPC ports, and expose it via a Service of type LoadBalancer. Do not rely on the vanilla NGINX Ingress unless you add the gRPC-specific annotation.

❌

GraphQL over HTTP

✅Yes, GraphQL is just an HTTP POST (or WebSocket) request, so any HTTP-aware Ingress works.

No special configuration beyond normal HTTP rules; you may want to enable WebSocket support (nginx.ingress.kubernetes.io/enable-websocket: "true").

✅

UDP(e.g., DNS, SIP, FTP data channel)

❌Not with the standard Ingress API, because Ingress is defined only for L7 HTTP(S) traffic. Some controllers (HAProxy, NGINX Plus) expose additional CRDs (e.g., TCPIngress, UDPIngress) or use a separate Service of type LoadBalancer with protocol: UDP.

For UDP we typically: 1. Create a Service with type: LoadBalancer (or NodePort) and protocol: UDP. 2. If we need a single external IP for many UDP services, use a custom controller that supports a UDPIngress CRD (HAProxy Ingress provides this).

❌

FTP (control + data channels)

❌Not via standard Ingress. FTP uses both TCP control (port 21) and a dynamic data channel (active/passive ports). You need a LoadBalancer Service for the control port and configure the data-port range via a Service or a dedicated FTP-proxy pod.

Use a StatefulSet with a Service that opens a range of UDP/TCP ports, or run an FTP reverse-proxy (e.g., nginx-stream or HAProxy in TCP mode) behind a LoadBalancer.

❌

Table 4. Useful commands to verify Ingress Controller

Step

Action

Commands

Deploy the controller

Installation is possible using Helm, Kustomize, or manifests

curl -C- -LO https://github.com/kubernetes/ingress-nginx/releases/download/helm-chart-4.15.1/ingress-nginx-4.15.1.tgz
curl --binary-data ingress-nginx.tgz local-museum:3000/api/charts
helm install ingress-nginx local-museum/ingress-nginx

Confirm Pods are running

Check the health of controller pods

kubectl -n ingress-nginx get pods -owide

Check the Service

Verify the external IP (LoadBalancer) or node ports

kubectl -n ingress-nginx get service -owide

Create a test Ingress object

Creating a simple rule pointing to a Service

echo >> /tmp/test-ingress.yml < "EOF"
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
    name: test-ingress
spec:

Client-side testing

Observe routing using curl to host:port/uri

curl -H "Host: example.com" https://<external-ip>/uri

TLS verification

Checking for TLS; CRTs

openssl s_client -servername example.com -connect <external-ip>:443

Logs & metrics

Check Pods' logs; or metrics in Prometheous

kubectl -n ingress-nginx logs <controller-pod>

Debug config

Read the generated proxy config (e.g., NGINX config) to ensure rules are applied

kubectl -n ingress-nginx exec <controller-pod> -- cat /etc/nginx/nginx.conf

FAQ

  1. Is Envoy an Ingress controller?

    • It can act as one, but it is not the default K8s Ingress implementation.

    • When an Envoy runs behind a K8s Service of type LoadBalancer and configure it via Istio Gateway CRD, Kong-mesh, or the NGINX-like Ingress CRD offered by Envoy-Ingress-Controller project, Envoy becomes the data plane that fulfills the Ingress semantics.

    • In the Istio ecosystem, the Istio Gateway (which runs Envoy internally) is the production-grade replacement for a generic Ingress Controller and can handle HTTP, gRPC, TCP, and UDP traffic.

  2. Layer-7 vs. Layer-4

    • Ths standard K8s Ingress Controller contracts just require Layer-7 support (meaning that HTTP and HTTPS)

    • A couple of Ingress Controllers (e.g., HAProxy or NGINX Plus) extend the model via supporting TCPIngress, UDPIngress to expose Layer 4 TCP and UDP.

    • For a pure Layer 4 (raw TCP/UDP, FTP, DNS, etc.), the usual pattern is exposing via a K8s Service of type LoadBalancer or NodePort and let the cloud provider’s handle the traffic, or running a specialized controller that supports those CRDs.

  3. A K8s Service defines a stable Virtual IP (CLusterIP) and DNS name that load-balances traffic inside the cluster to the set of Pods selected by its selector. The traffic never leaves the cluster network unless the Service type is NodePort or LoadBalancer.

  4. Pods in different namespaces can reach each other if they know the appropriate DNS name or IP. A Service created in one namespace is reachable from another namespace by using the fully-qualified name:

    ===
    <service-name>.<namespace>.svc.cluster.local
    ===
    • Thus a Service can serve Pods from a namespace to another Services/Pods inside another namespace via ExternalName or by selecting the same label set.

    • Network Policies may restrict the communication, but from a pure networking standpoint is allowed.

  5. An Ingress Controller watches Ingress resources and configures a load-balancer or reverse-proxy that accepts incoming traffic from outside the cluster and routes it to the appropriate Service inside the cluster. It is entry point for external clients.

  6. An Ingress Controller can be both a load-balancer and a reverse-proxy simultaneously.