Native Gateway API policies
Learn how policy inheritance and overrides work for Kubernetes Gateway API-native policies in a route delegation setup.
About policy inheritance
Kubernetes Gateway API policies that can be defined on an HTTPRoute, such as timeouts and retries, are inherited as follows:
- Policies that are defined on a parent HTTPRoute are automatically inherited by all child or grandchild HTTPRoutes.
- If the child or grandchild HTTPRoute defines a policy, this policy takes precedence and overrides the policy that is set on the parent.
Configuration overview
In this guide you walk through a route delegation example where a child HTTPRoute inherits or overrides policies that are set on a parent HTTPRoute.
The following image illustrates the route delegation hierarchy and policy inheritance:
parent
HTTPRoute:
- The
parent
HTTPRoute resource delegates traffic as follows:- Requests to
/anything/team1
are delegated to the child HTTPRoute resourcechild-team1
in namespaceteam1
. A timeout policy of 10s is defined on this route. - Requests to
/anything/team2
are delegated to the child HTTPRoute resourcechild-team2
in namespaceteam2
. A timeout policy of 20s is defined on this route.
- Requests to
child-team1
HTTPRoute:
- The child HTTPRoute resource
child-team1
matches incoming traffic for the/anything/team1/foo
prefix path and routes that traffic to the httpbin app in theteam1
namespace. - The
child-team1
resource does not define any custom timeout policies. Because of that, the timeout policy that is set on the parent is automatically inherited and enforced.
child-team2
HTTPRoute:
- The child HTTPRoute resource
child-team2
delegates traffic on the/anything/team2/bar
path to a grandchild HTTPRoute resource in theteam2
namespace. - The
child-team2
resource defines a custom timeout policy. Because of that, the timeout policy on the parent is ignored and only the timeout policy on thechild-team2
resource is enforced.
Before you begin
-
Follow the Get started guide to install kgateway.
-
Create a Gateway resource and configure an HTTP listener. The following Gateway can serve HTTPRoute resources from all namespaces.
kubectl apply -f- <<EOF kind: Gateway apiVersion: gateway.networking.k8s.io/v1 metadata: name: http namespace: kgateway-system spec: gatewayClassName: kgateway listeners: - protocol: HTTP port: 8080 name: http allowedRoutes: namespaces: from: All EOF
-
Get the external address of the gateway and save it in an environment variable.
export INGRESS_GW_ADDRESS=$(kubectl get svc -n kgateway-system http -o jsonpath="{.status.loadBalancer.ingress[0]['hostname','ip']}") echo $INGRESS_GW_ADDRESS
kubectl port-forward deployment/http -n kgateway-system 8080:8080
-
Create the namespaces for
team1
andteam2
.kubectl create namespace team1 kubectl create namespace team2
-
Deploy the httpbin app into both namespaces.
kubectl -n team1 apply -f https://raw.githubusercontent.com/kgateway-dev/kgateway.dev/main/assets/docs/examples/httpbin.yaml kubectl -n team2 apply -f https://raw.githubusercontent.com/kgateway-dev/kgateway.dev/main/assets/docs/examples/httpbin.yaml
-
Verify that the httpbin apps are up and running.
kubectl get pods -n team1 kubectl get pods -n team2
Example output:
NAME READY STATUS RESTARTS AGE httpbin-f46cc8b9b-bzl9z 3/3 Running 0 7s NAME READY STATUS RESTARTS AGE httpbin-f46cc8b9b-nhtmg 3/3 Running 0 6s
Setup
-
Create the parent HTTPRoute resource that matches incoming traffic on the
delegation.example
domain. The HTTPRoute resource specifies two routes and defines a timeout policy for each of the routes:/anything/team1
: The routing decision is delegated to achild-team1
HTTPRoute resource in theteam1
namespace. A timeout policy of 10s is defined on this route./anything/team2
: The routing decision is delegated to achild-team2
HTTPRoute resource in theteam2
namespace. A timeout policy of 20s is defined on this route.
kubectl apply -f- <<EOF apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: parent namespace: kgateway-system spec: parentRefs: - name: http hostnames: - "delegation.example" rules: - matches: - path: type: PathPrefix value: /anything/team1 backendRefs: - group: gateway.networking.k8s.io kind: HTTPRoute name: "*" namespace: team1 timeouts: request: 10s - matches: - path: type: PathPrefix value: /anything/team2 backendRefs: - group: gateway.networking.k8s.io kind: HTTPRoute name: "*" namespace: team2 timeouts: request: 20s EOF
-
Create the
child-team1
HTTPRoute resource in theteam1
namespace that matches traffic on the/anything/team1/foo
prefix and routes traffic to the httpbin app in theteam1
namespace. The child HTTPRoute resource does not define any timeout policies. Because of that, the HTTPRoute inherits the timeout setting of theparent
.kubectl apply -f- <<EOF apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: child-team1 namespace: team1 spec: rules: - matches: - path: type: PathPrefix value: /anything/team1/foo backendRefs: - name: httpbin port: 8000 EOF
-
Create the
child-team2
HTTPRoute resource in theteam2
namespace that specifies a custom timeout policy and matches traffic on the/anything/team2/bar/
prefix. The custom timeout policy overrides the timeout policy that is set on theparent
.kubectl apply -f- <<EOF apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: child-team2 namespace: team2 spec: parentRefs: - name: parent namespace: kgateway-system group: gateway.networking.k8s.io kind: HTTPRoute rules: - matches: - path: type: PathPrefix value: /anything/team2/bar backendRefs: - name: httpbin port: 8000 timeouts: request: 30s EOF
-
Send a request to the
delegation.example
domain along the/anything/team1/foo
path. Verify that you get back a 200 HTTP response code and that theX-Envoy-Expected-Rq-Timeout-Ms
header is set to 10000 milliseconds (10s) as defined on theparent
HTTPRoute.curl -i http://$INGRESS_GW_ADDRESS:8080/anything/team1/foo \ -H "host: delegation.example:8080"
curl -i localhost:8080/anything/team1/foo \ -H "host: delegation.example"
Example output:
HTTP/1.1 200 OK access-control-allow-credentials: true access-control-allow-origin: * content-type: application/json; encoding=utf-8 content-length: 509 x-envoy-upstream-service-time: 0 server: envoy { "args": {}, "headers": { "Accept": [ "*/*" ], "Host": [ "delegation.example:8080" ], "User-Agent": [ "curl/8.7.1" ], "X-Envoy-Expected-Rq-Timeout-Ms": [ "10000" ], "X-Forwarded-Proto": [ "http" ], "X-Request-Id": [ "65927858-2c6b-42ae-9278-8ff9d8bba3f8" ] }, "origin": "10.0.64.27:49526", "url": "http://delegation.example:8080/anything/team1/foo", "data": "", "files": null, "form": null, "json": null }
-
Send a request to the
delegation.example
domain along the/anything/team2/bar
path. Verify that you get back a 200 HTTP response code and that theX-Envoy-Expected-Rq-Timeout-Ms
header is set to 30000 milliseconds (30s) as defined on thechild-team2
HTTPRoute. The timeout setting of 20s that was defined on theparent
was not applied and overridden by the timeout setting of 30s on thechild-team2
HTTPRoute.curl -i http://$INGRESS_GW_ADDRESS:8080/anything/team2/bar \ -H "host: delegation.example:8080"
curl -i localhost:8080/anything/team2/bar \ -H "host: delegation.example:8080"
Example output:
HTTP/1.1 200 OK access-control-allow-credentials: true access-control-allow-origin: * content-type: application/json; encoding=utf-8 content-length: 509 x-envoy-upstream-service-time: 1 server: envoy { "args": {}, "headers": { "Accept": [ "*/*" ], "Host": [ "delegation.example:8080" ], "User-Agent": [ "curl/8.7.1" ], "X-Envoy-Expected-Rq-Timeout-Ms": [ "30000" ], "X-Forwarded-Proto": [ "http" ], "X-Request-Id": [ "d645dc37-5326-4b69-8c2c-4060e12ca4ff" ] }, "origin": "10.0.64.27:53026", "url": "http://delegation.example:8080/anything/team2/bar", "data": "", "files": null, "form": null, "json": null }
Cleanup
You can remove the resources that you created in this guide.kubectl delete gateway http -n kgateway-system
kubectl delete httproute parent -n kgateway-system
kubectl delete httproute child-team1 -n team1
kubectl delete httproute child-team2 -n team2
kubectl delete -n team1 -f https://raw.githubusercontent.com/kgateway-dev/kgateway.dev/v2.0.x/assets/docs/examples/httpbin.yaml
kubectl delete -n team2 -f https://raw.githubusercontent.com/kgateway-dev/kgateway.dev/v2.0.x/assets/docs/examples/httpbin.yaml
kubectl delete namespaces team1 team2