Consul API Gateway doesn’t actually route traffic; it’s the piece that declares the intent for traffic to be routed, and the underlying Envoy proxies are the ones doing the heavy lifting.
Let’s see this in action. Imagine you have a service named frontend running in your Kubernetes cluster, exposed internally via a Kubernetes Service frontend-svc. You want to make this service accessible from the outside world via api.example.com.
Here’s a Gateway resource defining that intent:
apiVersion: gateway.consul.io/v1alpha1
kind: Gateway
metadata:
name: frontend-gateway
namespace: consul
spec:
servers:
- name: http
port:
number: 80
listeners:
- protocol: http
routes:
- name: frontend-route
servers:
- http
expose:
- name: frontend-svc
namespace: default # Namespace of the Kubernetes Service
methods: ["GET", "POST"] # Allow GET and POST requests
path:
type: PathPrefix
value: /api/v1/ # Match requests starting with /api/v1/
When you apply this Gateway resource, Consul’s control plane watches it. It then configures the Envoy proxies that are running as part of the Consul integration (often as a sidecar or a dedicated ingress gateway deployment). These Envoy proxies are now listening on port 80. When a request comes in for api.example.com with a path starting with /api/v1/, Envoy will:
- Match the incoming request to the
frontend-routedefined in theGatewayresource. - See that this route is configured to
exposethefrontend-svcin thedefaultnamespace. - Consult its internal service discovery information (populated by Consul) to find the current IP addresses and ports for the pods backing
frontend-svc. - Forward the request to one of those backend pods.
The Gateway resource is essentially a declarative API that tells Consul’s control plane what traffic to allow and how it should be mapped to internal services. Consul then translates this declaration into specific configurations for the data plane (Envoy).
This approach decouples the definition of your API surface from the underlying infrastructure. You can manage your API routes and expose them through Consul API Gateway without needing to directly manage Ingress controllers or complex LoadBalancer configurations for every service. Consul handles the dynamic provisioning of Envoy configurations based on these Gateway resources.
The expose field is crucial here. It’s a direct link from the external-facing route to an internal Kubernetes Service. Consul uses this to program Envoy to route traffic not just to the service name, but to the actual IP addresses and ports of the pods backing that service.
What most people don’t realize is that the Gateway resource itself doesn’t perform any network I/O. It’s a purely declarative object that influences the configuration of the Envoy proxies managed by Consul. The actual routing, load balancing, and TLS termination happen within those Envoy instances, which are dynamically configured by Consul’s control plane based on your Gateway and Service resources.
The next step in managing external traffic is understanding how to configure TLS termination for your API Gateway.