Introduction
In the complex landscape of modern cloud-native applications, managing external traffic into your Kubernetes clusters is a critical, yet often challenging, endeavor. Traditional Ingress resources, while functional, have shown their limitations in expressing advanced routing, policy, and cross-team collaboration requirements. This is where the Kubernetes Gateway API steps in, offering a more expressive, role-oriented, and extensible approach to traffic management. Designed to overcome the shortcomings of Ingress, Gateway API provides a structured way to define how traffic enters your cluster, from basic HTTP routing to complex L4/L7 policies.
Among the various implementations of the Gateway API, Envoy Gateway stands out as a robust, open-source solution built on the power of Envoy Proxy. Envoy Gateway provides a production-ready, highly performant data plane for your Gateway API resources, offering features like advanced load balancing, traffic splitting, TLS termination, and more. This guide will walk you through a comprehensive production deployment of the Gateway API using Envoy Gateway, empowering you to effectively manage north-south traffic in your Kubernetes environment with confidence and precision. For a deeper dive into the transition from Ingress to Gateway API, check out our Kubernetes Gateway API vs Ingress: The Complete Migration Guide.
TL;DR: Envoy Gateway Production Deployment
Deploying Gateway API with Envoy Gateway involves installing the Gateway API CRDs, then deploying Envoy Gateway itself. You’ll then define GatewayClass, Gateway, and HTTPRoute resources to expose your applications. This setup provides advanced traffic management capabilities, acting as a modern ingress solution.
Key Commands:
# Install Gateway API CRDs
kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.0.0/standard-install.yaml
# Install Envoy Gateway
helm install envoy-gateway oci://docker.io/envoyproxy/envoy-gateway-charts/envoy-gateway --version v1.0.0 -n envoy-gateway-system --create-namespace
# Deploy a sample application
kubectl create deployment my-app --image=nginx --replicas=3
kubectl expose deployment my-app --port=80 --type=ClusterIP
# Create GatewayClass (usually handled by Envoy Gateway install)
# Create Gateway
kubectl apply -f - <<EOF
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: my-gateway
spec:
gatewayClassName: envoy-gateway
listeners:
- name: http
protocol: HTTP
port: 80
allowedRoutes:
namespaces:
from: All
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: my-app-route
spec:
parentRefs:
- name: my-gateway
hostnames:
- "my-app.example.com"
rules:
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
- name: my-app
port: 80
EOF
# Get external IP of the Gateway
kubectl get svc -n envoy-gateway-system envoy-gateway -o jsonpath='{.status.loadBalancer.ingress[0].ip}'
Prerequisites
Before embarking on your Envoy Gateway production deployment, ensure you have the following:
- A Running Kubernetes Cluster: Version 1.25 or higher is recommended to ensure full compatibility with the latest Gateway API features. This can be a local cluster (e.g., Minikube, Kind) for testing, or a cloud-managed cluster (EKS, GKE, AKS) for production.
kubectl: The Kubernetes command-line tool, configured to connect to your cluster. Refer to the official Kubernetes documentation for installation instructions.helm: The Kubernetes package manager, version 3.x or higher. Envoy Gateway is primarily deployed via Helm charts. Install Helm from its official website.- Basic Kubernetes Knowledge: Familiarity with core Kubernetes concepts such as Deployments, Services, Pods, and Namespaces is essential.
- Domain Name (Optional but Recommended): For production deployments, having a registered domain name and access to its DNS configuration will allow you to properly configure hostnames and TLS certificates.
Step-by-Step Guide: Envoy Gateway Production Deployment
Step 1: Install Gateway API CRDs
The Kubernetes Gateway API defines a set of Custom Resource Definitions (CRDs) that extend Kubernetes to understand new traffic management concepts. These CRDs must be installed in your cluster before you can deploy any Gateway API resources or an implementation like Envoy Gateway. Installing them separately ensures that your cluster has the foundational definitions, allowing for independent upgrades of the API itself.
It’s crucial to install the correct version of the CRDs to match the Gateway API version supported by your chosen Envoy Gateway release. The official Kubernetes SIGs Gateway API repository provides these standard installation manifests.
kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.0.0/standard-install.yaml
Verify
Confirm that the Gateway API CRDs have been installed successfully by listing them. You should see resources like gateways.gateway.networking.k8s.io, httproutes.gateway.networking.k8s.io, etc.
kubectl get crd | grep gateway.networking.k8s.io
Expected Output:
gatewayclasses.gateway.networking.k8s.io 2023-11-20T12:00:00Z
gateways.gateway.networking.k8s.io 2023-11-20T12:00:00Z
httproutes.gateway.networking.k8s.io 2023-11-20T12:00:00Z
referencegrants.gateway.networking.k8s.io 2023-11-20T12:00:00Z
tcproutes.gateway.networking.k8s.io 2023-11-20T12:00:00Z
tlsroutes.gateway.networking.k8s.io 2023-11-20T12:00:00Z
udproutes.gateway.networking.k8s.io 2023-11-20T12:00:00Z
Step 2: Install Envoy Gateway
Envoy Gateway is a production-grade implementation of the Gateway API that uses Envoy Proxy as its data plane. Deploying it involves adding the Envoy Gateway Helm repository and then installing the chart. This will create a dedicated namespace (envoy-gateway-system by default) and deploy the necessary controller components, along with an Envoy Proxy deployment and service.
The Helm chart simplifies the deployment process, handling the creation of Deployments, Services, RBAC roles, and the default GatewayClass resource that Envoy Gateway manages. For advanced networking scenarios, consider integrating with solutions like Cilium WireGuard Encryption to secure traffic within your cluster.
helm install envoy-gateway oci://docker.io/envoyproxy/envoy-gateway-charts/envoy-gateway --version v1.0.0 -n envoy-gateway-system --create-namespace
Verify
Check the status of the Envoy Gateway deployment. It may take a few minutes for all pods to become ready and for the LoadBalancer service to provision an external IP.
kubectl get all -n envoy-gateway-system
Expected Output (truncated):
NAME READY STATUS RESTARTS AGE
pod/envoy-gateway-65b79c5c7d-abcde 1/1 Running 0 2m
pod/envoy-gateway-envoy-6789abcd-efgh 1/1 Running 0 1m
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/envoy-gateway LoadBalancer 10.43.123.45 34.123.45.67 80:30080/TCP,443:30443/TCP 2m
service/envoy-gateway-metrics ClusterIP 10.43.54.32 <none> 8080/TCP 2m
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/envoy-gateway 1/1 1 1 2m
deployment.apps/envoy-gateway-envoy 1/1 1 1 1m
NAME DESIRED CURRENT READY AGE
replicaset.apps/envoy-gateway-65b79c5c7d 1 1 1 2m
replicaset.apps/envoy-gateway-envoy-6789abcd 1 1 1 1m
Note the EXTERNAL-IP for the envoy-gateway service. This is your entry point to the cluster.
Step 3: Deploy a Sample Application
To demonstrate traffic routing, we’ll deploy a simple Nginx application. This application will serve as the backend for our Gateway API configuration. We’ll create a Deployment and expose it via a ClusterIP Service.
This mimics a typical microservice that you want to expose to external users. For more advanced application deployments, consider practices like GPU scheduling for LLMs if your application has specific hardware requirements.
kubectl create deployment my-app --image=nginx --replicas=3
kubectl expose deployment my-app --port=80 --type=ClusterIP
Verify
Ensure the deployment and service are up and running in the default namespace.
kubectl get deploy,svc my-app
Expected Output:
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/my-app 3/3 3 3 30s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/my-app ClusterIP 10.43.200.100 <none> 80/TCP 20s
Step 4: Create a Gateway Resource
The Gateway resource is the entry point for traffic into your cluster. It defines the listeners (ports, protocols) and references a GatewayClass, which specifies the controller responsible for implementing the Gateway (in our case, Envoy Gateway). This resource is typically managed by infrastructure providers or cluster operators.
Here, we define an HTTP listener on port 80. The allowedRoutes section specifies which namespaces are permitted to attach routes to this Gateway. Setting from: All is common for initial setups but should be refined for production environments using specific namespace selectors for better isolation, aligning with principles discussed in our Network Policies Security Guide.
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: my-gateway
namespace: default
spec:
gatewayClassName: envoy-gateway
listeners:
- name: http
protocol: HTTP
port: 80
allowedRoutes:
namespaces:
from: All # In production, restrict this to specific namespaces
kubectl apply -f - <<EOF
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: my-gateway
namespace: default
spec:
gatewayClassName: envoy-gateway
listeners:
- name: http
protocol: HTTP
port: 80
allowedRoutes:
namespaces:
from: All # In production, restrict this to specific namespaces
EOF
Verify
Check the status of your Gateway. It should show as “Programmed” once Envoy Gateway has reconciled it and created the corresponding Envoy Proxy configuration and service.
kubectl get gateway my-gateway -n default
Expected Output (ADDRESS will be the same as the Envoy Gateway service’s external IP):
NAME CLASS ADDRESS PROGRAMMED AGE
my-gateway envoy-gateway 34.123.45.67 True 30s
Step 5: Create an HTTPRoute Resource
The HTTPRoute resource defines how HTTP traffic arriving at a Gateway should be routed to backend services. This is where application developers or application operators primarily interact with the Gateway API. It allows for advanced routing rules based on hostnames, paths, headers, and more.
In this step, we create an HTTPRoute that attaches to my-gateway, listens for traffic to my-app.example.com, and routes all requests (PathPrefix: /) to our my-app service on port 80. This separation of concerns (Gateway managed by infra vs. HTTPRoute by app dev) is a core benefit of the Gateway API.
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: my-app-route
namespace: default
spec:
parentRefs:
- name: my-gateway
namespace: default # Important: specify namespace if Gateway is not in the same namespace
hostnames:
- "my-app.example.com"
rules:
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
- name: my-app
port: 80
kubectl apply -f - <<EOF
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: my-app-route
namespace: default
spec:
parentRefs:
- name: my-gateway
namespace: default
hostnames:
- "my-app.example.com"
rules:
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
- name: my-app
port: 80
EOF
Verify
Check the status of your HTTPRoute. It should show as “Accepted” and “Programmed” once it’s successfully attached to the Gateway and the routing rules are active.
kubectl get httproute my-app-route -n default
Expected Output:
NAME HOSTNAMES PARENTREFS AGE STATUS
my-app-route ["my-app.example.com"] ["my-gateway"] 30s Accepted
Step 6: Test the Deployment
Now that everything is configured, it’s time to test if traffic is correctly routed through Envoy Gateway to your application. You’ll need the external IP of your Envoy Gateway LoadBalancer service and a way to resolve the hostname my-app.example.com to that IP. For local testing, you can modify your /etc/hosts file. For production, you would configure your DNS provider.
First, get the external IP of the Gateway:
GATEWAY_IP=$(kubectl get svc -n envoy-gateway-system envoy-gateway -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
echo "Gateway External IP: $GATEWAY_IP"
Expected Output:
Gateway External IP: 34.123.45.67
Next, use curl to send a request, specifying the hostname via the Host header. If you’ve updated your /etc/hosts file to map my-app.example.com to $GATEWAY_IP, you can simply use curl http://my-app.example.com.
curl -H "Host: my-app.example.com" http://$GATEWAY_IP
Verify
You should receive the default Nginx welcome page as output, indicating that the request was successfully routed through Envoy Gateway to your my-app service.
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
Production Considerations
Deploying Envoy Gateway in production requires more than just basic installation. Consider these crucial aspects to ensure reliability, security, and scalability:
- TLS Configuration: For any production workload, TLS encryption is non-negotiable. Envoy Gateway supports TLS termination on the Gateway resource. You can use Kubernetes Secrets to store certificates, often provisioned by cert-manager.
# Example Gateway with HTTPS listener apiVersion: gateway.networking.k8s.io/v1 kind: Gateway metadata: name: my-secure-gateway namespace: default spec: gatewayClassName: envoy-gateway listeners: - name: https protocol: HTTPS port: 443 tls: mode: Terminate certificateRefs: - kind: Secret name: my-tls-secret # Secret containing 'tls.crt' and 'tls.key' allowedRoutes: namespaces: from: All - Custom Domains and DNS: Ensure your domain’s A/CNAME records point to the external IP of your Envoy Gateway service. Automate this process if possible, especially in cloud environments, using external DNS controllers.
- Resource Management: Configure appropriate CPU and memory limits/requests for the Envoy Gateway controller and Envoy proxy pods. Monitor resource usage closely and scale horizontally as needed. For cost optimization, consider tools like Karpenter to manage underlying nodes efficiently.
- Observability: Integrate Envoy Gateway with your existing monitoring and logging stacks. Envoy Proxy provides rich metrics (Prometheus format) and access logs. Use tools like Prometheus, Grafana, and Loki/Fluentd to gain insights. For advanced eBPF-based observability, explore solutions like eBPF Observability with Hubble.
- High Availability: Deploy Envoy Gateway with multiple replicas for the controller and Envoy proxy pods. Ensure the underlying infrastructure (e.g., cloud LoadBalancer) is highly available.
- Security Policies: Implement strict
allowedRoutespolicies on your Gateway resources to control which namespaces can attach routes. Leverage Kubernetes Network Policies to restrict traffic to and from the Envoy Gateway pods. Consult our Network Policies Security Guide for best practices. - GitOps Workflow: Manage all Gateway API resources (Gateway, HTTPRoute, TLSRoute, etc.) using a GitOps approach. Tools like Argo CD or Flux CD can automate the deployment and synchronization of your configurations from a Git repository.
- Rate Limiting and WAF: For advanced traffic control and security, explore integrating with Envoy’s native rate limiting capabilities or deploying a Web Application Firewall (WAF) in front of or alongside Envoy Gateway.
- Canary Deployments and A/B Testing: Leverage Envoy Gateway’s advanced routing capabilities to implement traffic splitting for canary releases or A/B testing.
# Example HTTPRoute for Canary Deployment apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: my-app-canary-route spec: parentRefs: - name: my-gateway hostnames: - "canary.example.com" rules: - backendRefs: - name: my-app-v1 # 90% traffic to stable port: 80 weight: 90 - name: my-app-v2 # 10% traffic to canary port: 80 weight: 10 - Service Mesh Integration: While Envoy Gateway handles north-south traffic, a service mesh like Istio Ambient Mesh can manage east-west (inter-service) traffic within your cluster, providing advanced features like mTLS, circuit breaking, and more. Envoy Gateway and a service mesh can complement each other, with the Gateway handling inbound traffic and the mesh managing internal service communication.
Troubleshooting
-
Issue: Gateway Stuck in “Pending” State or No External IP
Explanation: This usually means the underlying cloud provider (AWS, GCP, Azure) is failing to provision a LoadBalancer for the
envoy-gatewayservice. This can be due to insufficient permissions, quota limits, or network configuration issues in your cloud environment.Solution:
- Check the events of the
envoy-gatewayservice:kubectl describe svc envoy-gateway -n envoy-gateway-systemLook for errors related to LoadBalancer provisioning.
- Verify your cluster’s cloud provider integration and permissions. For example, on AWS EKS, ensure the IAM role associated with your worker nodes has permissions to create ELBs/NLBs.
- If running on bare-metal or a local cluster, ensure you have a LoadBalancer implementation (e.g., MetalLB) installed and configured.
- Check the events of the
-
Issue: HTTPRoute Status is “Not Accepted” or “Invalid”
Explanation: The Gateway API controller (Envoy Gateway) is unable to process your
HTTPRouteresource. This often happens due to misconfigurations in the YAML, incorrectparentRefs, or issues with backend service references.Solution:
- Examine the
statusfield of theHTTPRoutefor detailed error messages:kubectl get httproute my-app-route -n default -o yamlLook under
status.parentsfor conditions likeAccepted: falseand the associated reasons. - Ensure the
parentRefscorrectly points to an existingGatewayresource by name and namespace. - Verify that the
backendRefs(service name and port) are correct and the service exists in the specified namespace. - Check for conflicting hostnames or path prefixes across multiple
HTTPRouteresources attached to the same Gateway.
- Examine the
-
Issue: “404 Not Found” when accessing the application via Gateway
Explanation: The Gateway is reachable, but it’s not correctly routing traffic to your application. This points to an issue with the
HTTPRouteconfiguration or the backend service.Solution:
- Double-check the
hostnamesin yourHTTPRoute. Ensure theHostheader in yourcurlcommand (or browser request) exactly matches one of the defined hostnames. - Verify the
pathmatching rules (PathPrefix,Exact,RegularExpression). - Confirm the
backendRefsservice name and port are correct and that the service is running and has healthy endpoints.kubectl get endpoints my-app -n defaultThe
ENDPOINTScolumn should show active pod IPs. - Check the Envoy Gateway controller logs for any routing errors:
kubectl logs -f -n envoy-gateway-system deployment/envoy-gateway
- Double-check the
-
Issue: TLS Handshake Errors or Certificate Issues
Explanation: If you’ve configured HTTPS and are encountering errors like “SSL_ERROR_RX_RECORD_TOO_LONG” or certificate warnings, it indicates a problem with your TLS setup on the Gateway.
Solution:
- Ensure the
Secretreferenced intls.certificateRefsof yourGatewayresource exists in the correct namespace and contains validtls.crtandtls.keyentries.kubectl get secret my-tls-secret -n default -o yaml - Verify the certificate and key are in PEM format.
- Confirm that the domain name in your certificate matches the hostname configured in your
HTTPRoute. - Check that the listener on the Gateway is using
protocol: HTTPSandport: 443. - If using cert-manager, check its logs and events for certificate issuance failures.
- Ensure the
-
Issue: High CPU/Memory Usage by Envoy Gateway Pods
Explanation: Excessive resource consumption by the Envoy Gateway controller or Envoy proxy pods can indicate heavy traffic, misconfiguration leading to inefficient routing, or a potential memory leak.
Solution:
- Monitor resource usage using
kubectl top pods -n envoy-gateway-systemor your cluster’s monitoring solution. - Increase resource limits/requests in the Helm chart values if necessary (e.g.,
controller.resources,envoy.resources). - Scale out the Envoy proxy replicas if traffic is high:
envoy.replicas: 2in Helm values. - Review your
HTTPRouteconfigurations for overly complex regex matching or a large number of routes, which can increase Envoy’s configuration load. - Check for continuous configuration updates (e.g., from a constantly changing backend) that might churn Envoy’s configuration.
- Monitor resource usage using
-
Issue: Envoy Proxy Pods Crashing or Restarting Frequently
Explanation: Frequent restarts (CrashLoopBackOff) of Envoy proxy pods indicate a critical issue, often related to invalid Envoy configuration generated by the Envoy Gateway controller or resource constraints.
Solution:
- Check the logs of the crashing Envoy proxy pod:
kubectl logs -f <envoy-proxy-pod-name> -n envoy-gateway-systemLook for errors related to configuration loading or startup.
- Examine the Envoy Gateway controller logs for errors during configuration generation.
- Ensure the Envoy proxy pods have sufficient memory and CPU resources. Increase limits if necessary.
- Rollback any recent changes to Gateway API resources (Gateway, HTTPRoute, etc.) that might have introduced an invalid configuration.
- Check the logs of the crashing Envoy proxy pod:
FAQ Section
-
Q: What is the main difference between Gateway API and Ingress?
A: The Gateway API is a more expressive, extensible, and role-oriented API compared to Ingress. Ingress is primarily focused on HTTP routing, often limited in features, and less extensible. Gateway API introduces resources like
GatewayClass,Gateway, and various Route types (HTTPRoute,TLSRoute, etc.) to separate concerns between infrastructure providers, cluster operators, and application developers, offering advanced traffic management features out-of-the-box. For a detailed comparison, see our Gateway API vs Ingress Migration Guide. -
Q: Can I use Envoy Gateway with a service mesh like Istio?
A: Yes, Envoy Gateway can complement a service mesh. Envoy Gateway typically handles “north-south” traffic (traffic entering and exiting the cluster), while a service mesh like Istio manages “east-west” traffic (inter-service communication within the cluster). You can deploy Envoy Gateway at the edge of your cluster and have it route traffic to services that are part of your service mesh. For more on Istio, check out our Istio Ambient Mesh Production Guide.
-
Q: How do I handle advanced routing features like traffic splitting or header-based routing with Envoy Gateway?
A: The Gateway API’s
HTTPRouteresource provides rich capabilities for advanced routing. You can define multipleruleswithmatchesbased on headers, query parameters, or methods. Traffic splitting for canary deployments or A/B testing is achieved usingbackendRefswithweightfields, as shown in the Production Considerations section. -
Q: Is Envoy Gateway suitable for multi-cluster deployments?
A: While Envoy Gateway itself is deployed per cluster, its design aligns well with multi-cluster strategies. You can deploy Envoy Gateway in each cluster and use a global load balancer or DNS-based routing to distribute traffic across your clusters. The Gateway API standard itself is being extended to support multi-cluster concepts, and various tools are emerging to facilitate this.
-
Q: How do I secure my container images and supply chain when using Envoy Gateway?
A: Securing your container supply chain is crucial. This involves using trusted base images, scanning for vulnerabilities, and signing your images. Tools like Sigstore can provide cryptographic guarantees about the origin and integrity of your software. You can enforce policies using Kubernetes admission controllers like Kyverno to ensure only signed images are deployed. For more on this, refer to Securing Container Supply Chains with Sigstore and Kyverno.
Cleanup Commands
To remove all resources created during this tutorial:
# Delete the HTTPRoute and Gateway resources
kubectl delete httproute my-app-route -n default
kubectl delete gateway my-gateway -n default
# Delete the sample application
kubectl delete deployment my-app -n default
kubectl delete service my-app -n default
# Uninstall Envoy Gateway via Helm
helm uninstall envoy-gateway -n envoy-gateway-system
kubectl delete namespace envoy-gateway-system
# Uninstall Gateway API CRDs (optional, only if no other Gateway API implementation is in use)
kubectl delete -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.0.0/standard-install.yaml
