Gateway API with Envoy Gateway
In this setup, we will use the AWS Load Balancer Controller to provision a high-performance NLB that terminates TLS via ACM, and then passes the traffic to Envoy pods which handle the smart routing to your apps.High-Level Architecture
Step 1: Prerequisites
Before we start, ensure your EKS cluster has the following:- AWS Load Balancer Controller (LBC) installed. This is mandatory as it’s the component that actually talks to AWS to create the NLB.
- VPC CNI (standard on EKS) for “IP” target mode (faster performance).
- An ACM Certificate ARN (e.g.,
arn:aws:acm:region:account:certificate/ID) for your domain.
Step 2: Install Gateway API CRDs & Envoy Gateway
Gateway API is not installed by default in K8s clusters. You must install the definitions first.Step 3: Configure the NLB (EnvoyProxy & GatewayClass)
We need to tell Envoy Gateway how to provision the AWS infrastructure. We do this using a provider-specific configuration.1. Define the EnvoyProxy (The AWS Settings)
This is where we put our NLB annotations.2. Define the GatewayClass
This links the Envoy controller to your specific AWS config.Step 4: Provision the Gateway (The NLB)
Creating this resource triggers the AWS Load Balancer Controller to spin up your NLB.kubectl get gateway. Once the PROGRAMMED status is True, you will see an ADDRESS which is your NLB DNS.
Step 5: Route-Based Routing (HTTPRoute)
Now, let’s pointexample.com/app1 to Service A and example.com/app2 to Service B.
Step 6: Finalize Route 53
- Go to the Route 53 Console.
- Create an A Record for
example.com. - Select Alias to Network Load Balancer.
- Choose your region and select the NLB created by the Gateway.
Why this approach in 2026?
- Role Separation: Your infrastructure team manages the
Gateway, while app teams just manage their ownHTTPRoutewithout breaking each other’s configurations. - Performance: Envoy is C++ based and extremely lightweight compared to the Lua-heavy NGINX Ingress.
- Future Proof: Most cloud providers are moving away from Ingress annotations in favor of this standardized API.
/app1 becomes / when it hits the pod), or “Rate Limiting” to this setup?