apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: public
namespace: infra
spec:
gatewayClassName: eg
listeners:
- name: https
protocol: HTTPS
port: 443
hostname: "*.example.com"
tls:
mode: Terminate
certificateRefs:
- kind: Secret
name: wildcard-example-com
namespace: certs
allowedRoutes:
namespaces:
from: Selector
selector:
matchLabels:
gateway-access: public
---
apiVersion: gateway.networking.k8s.io/v1beta1
kind: ReferenceGrant
metadata:
name: allow-infra-gateways
namespace: certs
spec:
from:
- group: gateway.networking.k8s.io
kind: Gateway
namespace: infra
to:
- group: ""
kind: Secret
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: orders
namespace: shop
spec:
parentRefs:
- name: public
namespace: infra
sectionName: https
hostnames: ["shop.example.com"]
rules:
- matches:
- path:
type: PathPrefix
value: /api
backendRefs:
- name: orders-v1
port: 8080
weight: 90
- name: orders-v2
port: 8080
weight: 10
---
apiVersion: v1
kind: Namespace
metadata:
name: shop
labels:
gateway-access: public
---
apiVersion: v1
kind: Service
metadata:
name: orders-v1
namespace: shop
spec:
selector:
app: orders
version: v1
ports:
- port: 8080
---
apiVersion: v1
kind: Service
metadata:
name: orders-v2
namespace: shop
spec:
selector:
app: orders
version: v2
ports:
- port: 8080Kubernetes graph
Gateway API: GatewayClass, Gateway and HTTPRoute with a canary split
How Gateway API splits ownership between the platform team and app teams: GatewayClass, a shared Gateway, a ReferenceGrant for a cross-namespace certificate, and an HTTPRoute that sends 10% of traffic to v2.
Gateway API replaces one Ingress object with three, one for each team. The infrastructure provider supplies the GatewayClass, the platform team runs a shared Gateway, and app teams attach HTTPRoutes to it from their own namespaces.
Two different mechanisms control what may cross a namespace. A Gateway's allowedRoutes decides which namespaces may attach routes to it. A ReferenceGrant, written in the namespace being pointed at, allows a reference into that namespace, here a Gateway reading a certificate Secret from certs. This example uses Envoy Gateway, but the objects are the same for Istio, Cilium, NGINX Gateway Fabric and the other implementations.
Interactive graph
Click a resource to see what it does, or follow the setup step by step.
How it works
All 14 resources and what they do
- Client Browser
- Calls
https://shop.example.com/api/orders. - Load balancer Cloud load balancer
- Provisioned by the cloud for the
type: LoadBalancerService that the implementation creates for the Gateway. Its address shows up in the Gateway'sstatus.addresses. - GatewayClass eggateway.networking.k8s.io/v1
- Cluster-scoped. Says which controller implements Gateways of this class, through
controllerName. The controller setsAccepted: Truein its status when it takes the class. - Deployment envoy-gatewayapps/v1
- The Gateway API implementation. It watches GatewayClasses with its
controllerName, then Gateways and Routes, and runs the Envoy proxies that carry the traffic. - Gateway publicgateway.networking.k8s.io/v1
- Owned by the platform team. It opens an HTTPS listener on port 443 for
*.example.com, takes its certificate from thecertsnamespace, and lets routes attach only from namespaces labeledgateway-access: public. - Service envoy-infra-public-…v1
- Created by Envoy Gateway for this Gateway, with a Deployment of Envoy Pods behind it. It is
type: LoadBalancer, so the cloud gives it a public address. Other implementations create similar objects under other names. - ReferenceGrant allow-infra-gatewaysgateway.networking.k8s.io/v1beta1
- Lives in
certs, the namespace being referenced. It allows Gateways ininfrato read Secrets here. Without it, the listener reportsResolvedRefs: Falsewith the reasonRefNotPermitted. - Secret wildcard-example-comv1
- The
*.example.comcertificate, kept in its own namespace so that only a few people can read the private key. cert-manager can issue it with a DNS-01 challenge. - HTTPRoute ordersgateway.networking.k8s.io/v1
- Owned by the app team in
shop. It attaches to thepublicGateway, matchesshop.example.comwith paths under/api, and splits requests 90/10 between two Services by weight. - Namespace shopv1
- Carries the label
gateway-access: public, which is what the Gateway'sallowedRoutesselector checks. Remove the label and every route in the namespace gets detached. - Service orders-v1v1
- Selects the Pods of the current version with
app: orders, version: v1. Gets 90% of the requests. - Service orders-v2v1
- Selects the canary Pods with
app: orders, version: v2. Gets 10% of the requests until you change the weights. - Pod orders-v1-…v1
- Pods of the stable version, from a Deployment named
orders-v1. - Pod orders-v2-…v1
- Pods of the canary version, from a Deployment named
orders-v2. Weights split requests, not Pods, so one Pod can take 10% of the traffic.
Common mistakes
- An HTTPRoute whose
parentRefspoints at a Gateway that doesn't allow its namespace isn't rejected when you apply it. It just never gets traffic. Checkkubectl get httproute orders -n shop -o yamland readstatus.parents[].conditions.Accepted: Falsewith the reasonNotAllowedByListenersmeans the namespace selector didn't match. - A ReferenceGrant goes in the namespace being referenced, not in the one making the reference. Writing it in
infradoes nothing. - Backends in another namespace need a ReferenceGrant too, this time in the Service's namespace with
from: HTTPRoute. hostnameson the route must overlap the listener'shostname. A route forshop.example.orgon a*.example.comlistener is not accepted.- A weight of 0 sends no traffic but keeps the backend in the route, which is handy for preparing a canary before you send it anything.
The manifests you write
Everything above that is marked "You write it", in one file. The rest comes from add-ons and controllers.
Keep going
More graphs
- Deployment, Service and Ingress: how a request reaches your Pods
- PVC, StorageClass and CSI: how a cloud disk ends up in your Pod
- RBAC: how a ServiceAccount gets its permissions
- cert-manager with Let's Encrypt: Certificate, CertificateRequest, Order and Challenge
- A private CA with cert-manager and trust-manager
- Istio traffic management: Gateway, VirtualService, DestinationRule and policies
- Flux dependencies: Git and OCI sources, Kustomizations and HelmReleases
- Argo CD: ApplicationSet, AppProject and the Applications it generates
- Inside an OCI image: tag, index, manifests, config and layers
- OCI artifacts: Helm charts, Flux artifacts and image volumes