Skip to content

The “Reverse Proxy” Illusion: Understanding Kubernetes Services and Gateway API

Modern application stacks are a bit like a game of musical chairs. You’ve got multiple APIs, sleek UIs, background workers, and data stores, all scaling independently, restarting at 3 AM, and shifting IP addresses every time a node gets a slight breeze.

To keep sanity, we usually reach for a reverse proxy. It provides that one stable “front door” while the chaos happens in the back. If you’ve spent five minutes in Kubernetes, you’ve likely noticed that a Service does something remarkably similar. It sits in front of pods and forwards traffic.

It’s a great mental shortcut, but like many things in K8s, the closer you look, the more nuanced it gets. Let’s look at why a Kubernetes Service feels like a reverse proxy, why it technically isn’t one, and how the Gateway API finally bridge the gap.


What exactly is a Reverse Proxy?

In the simplest terms, a reverse proxy is a server that stands between a client and a “pool” of backend servers. The client thinks it’s talking to the source of truth, but the proxy is actually taking the request, making a decision, and fetching the data from an upstream server.

Typical reverse proxies like NGINX, HAProxy, or Envoy are the “Swiss Army Knives” of networking. They don’t just move packets; they understand the conversation. Key features include:

  • Layer 7 Routing: “If the path starts with /api, send it to the Python backend. If it’s /, send it to the React frontend.”
  • TLS Termination: Handling the heavy lifting of HTTPS encryption so the backends don’t have to.
  • Health Checks: Knowing which backends are “alive” and which are having a bad day.
  • Policy & Security: Rate limiting, WAF (Web Application Firewall) features, and header manipulation.

Kubernetes Services: The Stable Anchor

In Kubernetes, a Service is an abstraction. Since Pods are ephemeral (they die and get replaced with new IPs constantly), you can’t rely on a Pod’s IP address. The Service provides a stable Virtual IP (ClusterIP) and a DNS name that stays the same for the life of the application.

The Service “Flavor” Palette

  1. ClusterIP (Default): The Service is only reachable inside the cluster. Great for internal database or API traffic.
  2. NodePort: Opens a specific port on every single Node. Traffic to NodeIP:NodePort gets routed to the Service.
  3. LoadBalancer: Tells your cloud provider (AWS, GCP, Azure) to spin up a “real” external load balancer that points to your Service.
  4. ExternalName: A DNS trick to point a K8s service name to an external DNS record (like an RDS database).

Why the “Reverse Proxy” Comparison Holds Water

On the surface, the intuition is 100% correct. You hit a stable IP, and your traffic is load-balanced across a set of pods identified by labels.

Behind the scenes, kube-proxy (the component managing this) or modern eBPF-based dataplanes like Cilium are doing the heavy lifting. To the end-user, it looks, smells, and acts like a forwarding proxy.


Where the Comparison Breaks (The “Candid” Part)

If you try to use a Kubernetes Service as your only “proxy,” you’ll hit a wall pretty fast. Here is why a Service is more like a traffic redirector than a full-blown proxy:

1. Layer 4 vs. Layer 7

Standard Kubernetes Services operate at Layer 4 (Transport). They deal with IP addresses and ports. They have no idea what an “HTTP Header” is or what a “URL path” looks like.

The Takeaway: A Service can’t say “Route /v2/api to this new pod.” It just sees packets heading for port 80.

2. Feature Set

Reverse proxies are policy engines. They can rewrite URLs, retry failed requests, or time out a connection after 5 seconds. A Service is much simpler; it’s basically a set of iptables or IPVS rules in the Linux kernel that “nat” (Network Address Translate) the traffic to a pod.

3. Forwarding vs. Proxying

A true proxy (like NGINX) terminates the TCP connection and starts a new one to the backend. A Kubernetes Service (in most modes) just redirects the existing packets to the right destination. It’s a subtle distinction, but it matters for things like connection persistent and header transparency.


The “Glue”: Pods, Ports, and Traffic Flow

To understand how traffic actually flows, we have to look at the port mappings. This is usually where the first “head-scratching” moment happens for developers.

Port NameWhat it represents
containerPortThe port your app is actually listening on inside the container (for example, 8080).
targetPortThe port on the pod that the Service should send traffic to (usually matches containerPort).
portThe port exposed by the Service itself (the one other pods inside the cluster call).

The Flow:

Client → Service IP:port → Pod IP:targetPort → App:containerPort


Enter the Real Proxy: Gateway API

If Services are just “stable destinations,” what handles the smart routing? In the old days, we used Ingress. Today, we use the Gateway API.

The Gateway API is the evolution of Kubernetes networking. It separates the infrastructure (the Gateway) from the routing rules (the HTTPRoute). This is where the reverse proxy lives.

Let’s look at a “textbook” reverse-proxy rule using the Gateway API taken from the semantic-sentiment-platform project:

YAML

apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: sentiment-route
spec:
  parentRefs:
    - name: sentiment-gw # This is your Reverse Proxy/Load Balancer
  rules:
    - matches:
        - path:
            type: PathPrefix
            value: /api
      filters:
        - type: URLRewrite
          urlRewrite:
            path:
              type: ReplacePrefixMatch
              replacePrefixMatch: /
      backendRefs:
        - name: api # This is the Service
          port: 8000
    - matches:
        - path:
            type: PathPrefix
            value: /
      backendRefs:
        - name: dashboard # This is another Service
          port: 8501

What’s happening here?

  1. L7 Routing: The Gateway looks at the path. /api goes one way, / goes another.
  2. Transformation: It uses a URLRewrite filter. It strips /api off before sending it to the backend. A standard K8s Service could never do this.
  3. The Hand-off: The backendRefs point to Services.

Summary: Service vs. Reverse Proxy

FeatureKubernetes ServiceReverse Proxy (Gateway/Ingress)
OSI LayerLayer 4 (TCP/UDP)Layer 7 (HTTP/gRPC/TLS)
URL RewritingNoYes
Path RoutingNoYes
TLS TerminationNo (usually)Yes
Main JobService Discovery & StabilityTraffic Intelligence & Policy

Conclusion

Is a Kubernetes Service a reverse proxy? Kind of. It’s a transparent forwarding layer that gives you a stable entry point, which is half the battle.

However, for the “smart” stuff, routing by path, rewriting URLs, or handling complex retries, you need a real reverse proxy sitting on top of those services. In the modern Kubernetes world, that means the Gateway API.

The Golden Rule: Services make your backends stable. Gateways make your routing smart.