“`html
Introduction
The Kubernetes Gateway API is rapidly emerging as the successor to Ingress, offering a more expressive, extensible, and role-oriented approach to managing traffic into your Kubernetes clusters. Unlike Ingress, which focuses primarily on HTTP routing, Gateway API provides a robust framework for advanced traffic management, including L4/L7 routing, load balancing, policy attachment, and multi-tenant support. This paradigm shift empowers platform teams to define infrastructure and expose services with greater control, while application developers can self-serve their routing needs.
However, deploying and managing a Gateway API implementation in production requires careful consideration. While the API defines the “what,” an implementation like Envoy Gateway provides the “how.” Envoy Gateway leverages the battle-tested Envoy Proxy to deliver a high-performance, scalable, and feature-rich data plane for Gateway API. This guide will walk you through deploying Envoy Gateway for production, covering everything from initial setup to advanced traffic management and crucial production considerations.
By the end of this comprehensive guide, you’ll have a solid understanding of how to leverage Envoy Gateway to implement the Kubernetes Gateway API, enabling sophisticated traffic routing, policy enforcement, and a clear separation of concerns between infrastructure providers and application developers. We’ll dive deep into practical examples, ensuring you can confidently deploy and manage this powerful combination in your production environment. For those transitioning from Ingress, our Kubernetes Gateway API vs Ingress: The Complete Migration Guide offers an excellent starting point.
TL;DR: Deploying Envoy Gateway
The Kubernetes Gateway API with Envoy Gateway provides a powerful, role-oriented approach to traffic management. This guide covers its production deployment, from installation to advanced features and crucial considerations.
Key Commands:
# Install Envoy Gateway
helm install envoy-gateway \
oci://ghcr.io/envoyproxy/gateway-helm/envoy-gateway \
--version v1.0.0 \
-n envoy-gateway-system --create-namespace
# Deploy a sample application
kubectl apply -f https://raw.githubusercontent.com/kubernetes/website/main/content/en/examples/service/access/hello-world-deployment.yaml
kubectl apply -f https://raw.githubusercontent.com/kubernetes/website/main/content/en/examples/service/access/hello-world-service.yaml
# Create a Gateway
cat <
Prerequisites
To follow this guide, you'll need:
- A running Kubernetes cluster (v1.26+ recommended).
kubectlinstalled and configured to connect to your cluster.- Helm installed (v3.8.0+).
- Basic understanding of Kubernetes concepts (Pods, Services, Deployments).
- Familiarity with networking concepts (HTTP, DNS, load balancing).
Step-by-Step Guide: Envoy Gateway Production Deployment
1. Install Envoy Gateway
The first step is to install Envoy Gateway into your Kubernetes cluster. We'll use Helm, the package manager for Kubernetes, for a streamlined installation process. Envoy Gateway will deploy the necessary control plane components and an Envoy data plane proxy.
Envoy Gateway creates its own namespace, `envoy-gateway-system`, for its control plane components. The data plane (Envoy proxy instances) is typically deployed in the same namespace by default, but can be configured to run elsewhere. It's crucial to pin the Helm chart version for production deployments to ensure reproducibility and stability. Always refer to the official Envoy Gateway documentation for the latest stable version.
# Add the Envoy Gateway Helm repository (optional, if not already added)
# helm repo add envoy-gateway https://envoyproxy.github.io/gateway-helm
# Install Envoy Gateway using OCI registry
helm install envoy-gateway \
oci://ghcr.io/envoyproxy/gateway-helm/envoy-gateway \
--version v1.0.0 \
-n envoy-gateway-system --create-namespace
Verify:
You should see several pods running in the `envoy-gateway-system` namespace, including the Envoy Gateway controller and the Envoy proxy data plane.
kubectl get pods -n envoy-gateway-system
NAME READY STATUS RESTARTS AGE
envoy-gateway-5c7d88b48c-abcde 1/1 Running 0 2m
envoy-56f78997c-fghij 1/1 Running 0 2m
2. Deploy a Sample Application
Before we can route traffic, we need a target application. We'll deploy a simple "hello-world" application that will serve as our backend service. This application consists of a Deployment and a Service.
This step demonstrates the core concept of routing traffic to a Kubernetes Service. The Gateway API, through Envoy Gateway, will manage the external exposure and routing logic, while the Service handles internal load balancing to the application Pods.
kubectl apply -f https://raw.githubusercontent.com/kubernetes/website/main/content/en/examples/service/access/hello-world-deployment.yaml
kubectl apply -f https://raw.githubusercontent.com/kubernetes/website/main/content/en/examples/service/access/hello-world-service.yaml
Verify:
Ensure the `hello-world` deployment and service are running in the `default` namespace.
kubectl get deployments,services hello-world
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/hello-world 1/1 1 1 1m
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/hello-world ClusterIP 10.96.123.123 <none> 80/TCP 1m
3. Create a Gateway Resource
The `Gateway` resource is the entry point for traffic into your cluster. It defines where traffic will be received (e.g., port 80, port 443) and which `GatewayClass` (in our case, `envoy-gateway`) will fulfill its capabilities. Think of the Gateway as the virtual load balancer or proxy that will be provisioned by Envoy Gateway.
The `listeners` section specifies the ports and protocols the Gateway will listen on. `allowedRoutes` is a powerful security feature that restricts which namespaces can attach `HTTPRoute` or other route resources to this Gateway. For production, you might restrict this to specific application namespaces or a dedicated ingress namespace.
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 # For demonstration, allowing all 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
EOF
Verify:
The Gateway resource should transition to a `Ready` status, and Envoy Gateway will provision an external load balancer (if on a cloud provider) or expose a NodePort/HostPort.
kubectl get gateway my-gateway -o yaml
You'll observe status conditions indicating readiness, and importantly, an `address` field in the status, which provides the external IP or hostname.
...
status:
addresses:
- type: IPAddress
value: 34.123.45.67 # This will be your external IP
conditions:
- lastTransitionTime: "2023-10-27T10:00:00Z"
message: Gateway is accepted by the controller
observedGeneration: 1
reason: Accepted
status: "True"
type: Accepted
- lastTransitionTime: "2023-10-27T10:00:00Z"
message: Listener Ready
observedGeneration: 1
reason: Ready
status: "True"
type: Ready
- lastTransitionTime: "2023-10-27T10:00:00Z"
message: All listeners are configured.
observedGeneration: 1
reason: ListenersReady
status: "True"
type: Programmed
...
4. Create an HTTPRoute Resource
The `HTTPRoute` resource defines how HTTP traffic is routed from a `Gateway` to backend services. It specifies hostnames, path matches, and the backend services to which traffic should be forwarded. This is where application teams typically define their routing rules.
The `parentRefs` field links this `HTTPRoute` to our `my-gateway`. `hostnames` defines the domain names this route applies to, and `rules` contain the matching criteria (e.g., path prefix) and backend references. This separation of concerns between Gateway and Route is a key advantage of the Gateway API.
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: http-route-example
namespace: default
spec:
parentRefs:
- name: my-gateway
hostnames:
- "example.com" # Replace with a domain you control or use for testing
rules:
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
- name: hello-world
port: 80
kubectl apply -f - <<EOF
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: http-route-example
namespace: default
spec:
parentRefs:
- name: my-gateway
hostnames:
- "example.com"
rules:
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
- name: hello-world
port: 80
EOF
Verify:
Check the status of your `HTTPRoute`. It should show that it's successfully attached to the `Gateway`.
kubectl get httproute http-route-example -o yaml
...
status:
parents:
- conditions:
- lastTransitionTime: "2023-10-27T10:05:00Z"
message: Route is accepted by the Gateway.
observedGeneration: 1
reason: Accepted
status: "True"
type: Accepted
- lastTransitionTime: "2023-10-27T10:05:00Z"
message: All rules have been successfully programmed.
observedGeneration: 1
reason: Programmed
status: "True"
type: Programmed
controllerName: gateway.envoyproxy.io/gatewayclass-controller
parentRef:
group: gateway.networking.k8s.io
kind: Gateway
name: my-gateway
namespace: default
...
5. Test Traffic Routing
Now that the Gateway and HTTPRoute are configured, retrieve the external IP address of your Gateway and test the routing. You'll need to either configure your local `hosts` file or use a tool like `curl` with the `Host` header to simulate the `example.com` hostname.
This step confirms that Envoy Gateway is correctly receiving external traffic and routing it to your backend application based on the `HTTPRoute` rules.
# Get the external IP of the Gateway
GATEWAY_IP=$(kubectl get gateway my-gateway -o jsonpath='{.status.addresses[0].value}')
echo "Gateway IP: $GATEWAY_IP"
# Test the route using curl with the Host header
curl -H "Host: example.com" http://$GATEWAY_IP
Verify:
You should receive the "Hello, world!" response from your sample application.
Hello, world!
Hostname: hello-world-5d66c5c76-xyzab
6. Advanced Traffic Management (HTTPRoute Filters)
The Gateway API isn't just about simple routing; it supports powerful traffic management features through `filters`. Let's demonstrate adding a request header modification.
HTTPRoute filters allow modifying requests and responses, injecting headers, performing URL rewrites, and much more. Envoy Gateway translates these filters into Envoy proxy configurations, enabling advanced traffic manipulation without direct Envoy configuration. This is crucial for A/B testing, Canary deployments, or even just adding tracing headers.
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: http-route-example-with-filter
namespace: default
spec:
parentRefs:
- name: my-gateway
hostnames:
- "example.com"
rules:
- matches:
- path:
type: PathPrefix
value: /
filters:
- type: RequestHeaderModifier
requestHeaderModifier:
add:
- name: X-Kubezilla-Header
value: "EnvoyGateway-Test"
backendRefs:
- name: hello-world
port: 80
kubectl apply -f - <<EOF
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: http-route-example-with-filter
namespace: default
spec:
parentRefs:
- name: my-gateway
hostnames:
- "example.com"
rules:
- matches:
- path:
type: PathPrefix
value: /
filters:
- type: RequestHeaderModifier
requestHeaderModifier:
add:
- name: X-Kubezilla-Header
value: "EnvoyGateway-Test"
backendRefs:
- name: hello-world
port: 80
EOF
Verify:
To verify this, we need to inspect the headers received by the `hello-world` application. A simple way is to exec into the `hello-world` pod and check its logs or use a more advanced debug container. For simplicity, let's assume `hello-world` echoes headers, or we can use `tcpdump` inside the pod (if installed). For a more robust test, you'd deploy a custom application that logs all incoming headers.
Alternatively, if you have access to the Envoy proxy logs, you could inspect them, though that's more involved.
# Assuming hello-world application logs headers (if it were designed to do so)
# For this example, we'll just re-run the curl and trust the configuration.
# If your hello-world app can show headers, you'd see X-Kubezilla-Header.
GATEWAY_IP=$(kubectl get gateway my-gateway -o jsonpath='{.status.addresses[0].value}')
curl -H "Host: example.com" http://$GATEWAY_IP
Hello, world!
Hostname: hello-world-5d66c5c76-xyzab
# If the app logged headers, you'd see X-Kubezilla-Header: EnvoyGateway-Test
7. HTTPS and TLS Configuration
Securing traffic with HTTPS is a critical production requirement. Envoy Gateway integrates seamlessly with Kubernetes Secrets for TLS certificates.
This involves creating a `Secret` containing your TLS certificate and private key, and then referencing it in the `Gateway`'s listener configuration. This enables end-to-end encryption from the client to the Gateway. For more advanced certificate management, consider integrating with cert-manager.
# Create a self-signed certificate for demonstration purposes
# In production, use a proper CA-signed certificate.
openssl req -x509 -newkey rsa:4096 -keyout tls.key -out tls.crt -days 365 -nodes \
-subj "/CN=example.com" -addext "subjectAltName = DNS:example.com"
# Create a Kubernetes Secret from the certificate and key
kubectl create secret tls example-com-tls \
--key=tls.key \
--cert=tls.crt \
-n default
# Update the Gateway to listen on HTTPS (port 443)
cat <
Verify:
After the Gateway updates, test HTTPS access.
GATEWAY_IP=$(kubectl get gateway my-gateway -o jsonpath='{.status.addresses[0].value}')
curl -k -H "Host: example.com" https://$GATEWAY_IP
The `-k` flag is necessary because we're using a self-signed certificate. In a production scenario with a trusted certificate, you would omit this flag.
Hello, world!
Hostname: hello-world-5d66c5c76-xyzab
Production Considerations
Deploying Envoy Gateway in production demands attention to several key areas beyond basic setup.
1. High Availability: Ensure your Envoy Gateway control plane and data plane (Envoy proxy pods) are deployed with sufficient replicas across multiple availability zones. Configure Pod Disruption Budgets (PDBs) to maintain availability during voluntary disruptions.
2. Resource Management: Define appropriate CPU and memory requests and limits for Envoy Gateway pods and the Envoy proxy pods. Monitor resource usage closely and scale horizontally as needed. Consider using Karpenter Cost Optimization for efficient node provisioning if your cluster autoscales.
3. Observability:
- Metrics: Envoy Gateway exposes Prometheus metrics. Integrate these with your monitoring stack (e.g., Prometheus, Grafana) to track traffic, errors, latency, and resource utilization. Envoy itself provides a wealth of metrics.
- Logging: Configure structured logging for Envoy Gateway and Envoy proxy. Centralize logs with a system like Fluentd/Loki or Elastic Stack.
- Tracing: Envoy supports distributed tracing (e.g., Jaeger, Zipkin). Ensure your application and Envoy Gateway are configured to propagate trace headers.
- For deeper network observability, consider solutions leveraging eBPF Observability with Hubble, especially if you're using Cilium.
4. Security:
- Network Policies: Implement Kubernetes Network Policies to restrict traffic flow to and from Envoy Gateway pods, ensuring only necessary communication paths are open.
- RBAC: Configure fine-grained RBAC for users and service accounts interacting with Gateway API resources. Limit who can create/modify `GatewayClass`, `Gateway`, and `HTTPRoute` resources.
- TLS: Always use trusted, CA-signed certificates for production HTTPS listeners. Automate certificate management with cert-manager.
- WAF/DDoS Protection: For advanced threat protection, consider placing a cloud WAF (Web Application Firewall) or DDoS protection service (e.g., Cloudflare, AWS WAF, Azure Front Door) in front of your Envoy Gateway.
- Supply Chain Security: For critical infrastructure components like Envoy Gateway, consider integrating Sigstore and Kyverno to verify image authenticity and enforce policies.
5. Backup and Restore: While Gateway API resources are stored in etcd, ensure you have a robust backup strategy for your Kubernetes cluster.
6. Disaster Recovery: Plan for disaster recovery. This might involve multi-cluster deployments or strategies for quickly restoring services in another region.
7. Version Control & CI/CD: Manage all Gateway API configurations (Gateway, HTTPRoute, etc.) in Git and integrate them into your CI/CD pipelines. Automate deployments and updates.
8. Traffic Management Policies: Leverage advanced Gateway API features like `TrafficSplit`, `Timeout`, `Retry`, and `RateLimit` policies for fine-grained control over application traffic.
9. Multi-Tenancy: The Gateway API's role-based model inherently supports multi-tenancy. Carefully design your `Gateway` and `HTTPRoute` permissions using `allowedRoutes` and Kubernetes RBAC to ensure tenants can only manage their own traffic.
10. Alternatives/Coexistence: If you're running a service mesh like Istio, you might consider how Envoy Gateway interacts. Istio's Ambient Mesh (Istio Ambient Mesh Guide) offers a sidecar-less approach that could complement or overlap with Gateway API.
Troubleshooting
Here are common issues encountered when deploying Envoy Gateway and their solutions:
1. Gateway Status remains "Pending" or "NotReady"
- Issue: The `Gateway` resource's status shows `Pending` or `NotReady` for an extended period.
- Solution:
- Check the `Gateway` resource's conditions for specific error messages:
kubectl get gateway my-gateway -o yaml - Inspect the logs of the `envoy-gateway` controller pod:
kubectl logs -n envoy-gateway-system -l app.kubernetes.io/name=envoy-gateway - Ensure your cluster has a load balancer provisioner (if on a cloud provider) or that NodePort/HostPort is correctly configured if running on-premises.
- Verify the `GatewayClass` `envoy-gateway` exists and is correctly configured:
kubectl get gatewayclass envoy-gateway -o yaml
- Check the `Gateway` resource's conditions for specific error messages:
2. HTTPRoute Status remains "NotAccepted" or "NotProgrammed"
- Issue: The `HTTPRoute` resource's status indicates it's not accepted or programmed.
- Solution:
- Check the `HTTPRoute` status conditions for `Accepted` and `Programmed` types:
kubectl get httproute http-route-example -o yaml - Ensure the `parentRefs` in the `HTTPRoute` correctly point to an existing and ready `Gateway` in the same or an allowed namespace.
- Verify the `Gateway`'s `allowedRoutes` configuration permits routes from the `HTTPRoute`'s namespace.
- Check the `envoy-gateway` controller logs for errors related to route processing.
- Check the `HTTPRoute` status conditions for `Accepted` and `Programmed` types:
3. Traffic Not Reaching Backend (404/503 Errors)
- Issue: Requests to the Gateway IP result in 404 Not Found or 503 Service Unavailable.
- Solution:
- Hostname Mismatch: Ensure the `Host` header in your `curl` request matches the `hostnames` defined in your `HTTPRoute`.
- Path Mismatch: Verify the `path` match in your `HTTPRoute` (e.g., `PathPrefix`, `Exact`) aligns with the requested URL path.
- Backend Service Unreachable:
- Check if your backend `Service` exists and is correctly named in `backendRefs`.
- Verify that your `Service` has healthy endpoints (pods are running and ready).
kubectl get endpoints hello-world - Ensure no Kubernetes Network Policies are blocking traffic between the Envoy proxy pods and your backend application pods.
- Envoy Proxy Logs: Examine the logs of the Envoy proxy pods (e.g., `envoy-56f78997c-fghij` from step 1 output) for routing errors.
kubectl logs -n envoy-gateway-system -l app.kubernetes.io/name=envoy
4. TLS Handshake Errors (HTTPS)
- Issue: When accessing the HTTPS listener, you get TLS handshake failures.
- Solution:
- Secret Existence: Ensure the TLS `Secret` referenced in the `Gateway`'s `certificateRefs` exists in the correct namespace.
kubectl get secret example-com-tls -n default - Secret Format: Verify the `tls.crt` and `tls.key` keys within the `Secret` contain valid certificate and private key data.
- Hostname Mismatch: Ensure the `CN` (Common Name) or `subjectAltName` in your certificate matches the hostname you are using in your `HTTPRoute` and `curl` request.
- Self-Signed Certs: Remember to use `curl -k` for self-signed certificates.
- Secret Existence: Ensure the TLS `Secret` referenced in the `Gateway`'s `certificateRefs` exists in the correct namespace.
5. Envoy Gateway Controller Crashlooping
- Issue: The `envoy-gateway` controller pod repeatedly crashes and restarts.
- Solution:
- Logs: Immediately check the logs of the crashing pod:
kubectl logs -n envoy-gateway-system -l app.kubernetes.io/name=envoy-gateway --previous - Resource Constraints: The controller might be running out of memory or CPU. Increase the resource requests/limits in the Helm chart values.
- Configuration Errors: A malformed `GatewayClass` or `EnvoyGateway` (custom resource) configuration could cause crashes. Review any custom configurations.
- Version Compatibility: Ensure your Kubernetes cluster version is compatible with the Envoy Gateway version you installed.
- Logs: Immediately check the logs of the crashing pod:
6. External IP Not Provisioned (Cloud Providers)
- Issue: The `Gateway` status `addresses` field remains empty on a cloud provider.
- Solution:
- Cloud Controller Manager: Ensure your Kubernetes cluster has a working cloud controller manager that can provision `LoadBalancer` type services.
- Cloud Provider Quotas: Check if you've hit any load balancer quotas in your cloud provider account.
- Permissions: The Kubernetes service account used by the cloud controller manager might lack permissions to create load balancers.
- Service Type: Verify that the `Service` created by Envoy Gateway (usually named `envoy-gateway-envoy`) is of type `LoadBalancer`.
kubectl get svc -n envoy-gateway-system envoy-gateway-envoy
FAQ Section
1. What is the difference between Ingress and Gateway API?
The Kubernetes Gateway API vs Ingress: The Complete Migration Guide provides a deep dive, but in summary: Ingress is a simpler API for HTTP routing, often limited in features and extensibility. Gateway API is a more expressive, role-oriented API that supports L4/L7 routing, advanced traffic management (weights, retries, timeouts), policy attachment, and multi-tenancy. It separates infrastructure concerns (GatewayClass, Gateway) from application concerns (HTTPRoute, TCPRoute, etc.), leading to better governance and scalability.
2. Can I use Envoy Gateway with my existing Ingress resources?
Envoy Gateway is an implementation of the Gateway API, not Ingress. It will not process existing Ingress resources. You would need to migrate your Ingress configurations to Gateway API resources (like `HTTPRoute`, `TCPRoute`). While they can coexist in the same cluster, they operate independently.
3. How do I handle multiple hostnames or domains with Envoy Gateway?
You can define multiple hostnames within a single `HTTPRoute` or create separate `HTTPRoute` resources for different hostnames. The `Gateway` resource will listen on common ports (e.g., 80, 443), and the `HTTPRoute`s will then match incoming requests based on their `Host` header. For example:
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: multi-host-route
spec:
parentRefs:
- name: my-gateway
hostnames:
- "app1.example.com"
- "app2.example.com"
rules:
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
- name: my-app-service
port: 80
4. How do I perform blue/green or canary deployments using Envoy Gateway?
Envoy Gateway, through `HTTPRoute` and `BackendRef` weights, supports advanced traffic splitting for blue/green and canary deployments. You can define multiple `backendRefs` for a single route with different weights:
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: canary-route
spec:
parentRefs:
- name: my-gateway
hostnames:
- "example.com"
rules:
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
- name: my-app-v1
port: 80
weight: 90
- name: my-app-v2-canary
port: 80
weight: 10
<