Kubernetes Gateway API
In addition to its own traffic management API, Istio supports the Kubernetes Gateway API and intends to make it the default API for traffic management in the future. This document describes the differences between the Istio and Kubernetes APIs and provides a simple example that shows you how to configure Istio to expose a service outside the service mesh cluster using the Gateway API. Note that these APIs are an actively developed evolution of the Kubernetes Service and Ingress APIs.
Setup
The Gateway APIs do not come installed by default on most Kubernetes clusters. Install the Gateway API CRDs if they are not present:
$ kubectl get crd gateways.gateway.networking.k8s.io &> /dev/null || \ { kubectl kustomize "github.com/kubernetes-sigs/gateway-api/config/crd?ref=v1.2.1" | kubectl apply -f -; }
Install Istio using the
minimal
profile:$ istioctl install --set profile=minimal -y
Differences from Istio APIs
The Gateway APIs share a lot of similarities to the Istio APIs such as Gateway and VirtualService.
The main resource shares the same name, Gateway
, and the resources serve similar goals.
The new Gateway APIs aim to take the learnings from various Kubernetes ingress implementations, including Istio, to build a standardized vendor neutral API. These APIs generally serve the same purposes as Istio Gateway and VirtualService, with a few key differences:
- In Istio APIs, a
Gateway
configures an existing gateway Deployment/Service that has been deployed. In the Gateway APIs, theGateway
resource both configures and deploys a gateway. See Deployment Methods for more information. - In the Istio
VirtualService
, all protocols are configured within a single resource. In the Gateway APIs, each protocol type has its own resource, such asHTTPRoute
andTCPRoute
. - While the Gateway APIs offer a lot of rich routing functionality, it does not yet cover 100% of Istio’s feature set. Work is ongoing to extend the API to cover these use cases, as well as utilizing the APIs extensibility to better expose Istio functionality.
Configuring a Gateway
See the Gateway API documentation for information about the APIs.
In this example, we will deploy a simple application and expose it externally using a Gateway
.
First, deploy the
httpbin
test application:$ kubectl apply -f @samples/httpbin/httpbin.yaml@
Deploy the Gateway API configuration including a single exposed route (i.e.,
/get
):$ kubectl create namespace istio-ingress $ kubectl apply -f - <<EOF apiVersion: gateway.networking.k8s.io/v1 kind: Gateway metadata: name: gateway namespace: istio-ingress spec: gatewayClassName: istio listeners: - name: default hostname: "*.example.com" port: 80 protocol: HTTP allowedRoutes: namespaces: from: All --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: http namespace: default spec: parentRefs: - name: gateway namespace: istio-ingress hostnames: ["httpbin.example.com"] rules: - matches: - path: type: PathPrefix value: /get backendRefs: - name: httpbin port: 8000 EOF
Set the Ingress Host environment variable:
$ kubectl wait -n istio-ingress --for=condition=programmed gateways.gateway.networking.k8s.io gateway $ export INGRESS_HOST=$(kubectl get gateways.gateway.networking.k8s.io gateway -n istio-ingress -ojsonpath='{.status.addresses[0].value}')
Access the
httpbin
service using curl:$ curl -s -I -HHost:httpbin.example.com "http://$INGRESS_HOST/get" ... HTTP/1.1 200 OK ... server: istio-envoy ...
Note the use of the
-H
flag to set the Host HTTP header to “httpbin.example.com”. This is needed because theHTTPRoute
is configured to handle “httpbin.example.com”, but in your test environment you have no DNS binding for that host and are simply sending your request to the ingress IP.Access any other URL that has not been explicitly exposed. You should see an HTTP 404 error:
$ curl -s -I -HHost:httpbin.example.com "http://$INGRESS_HOST/headers" HTTP/1.1 404 Not Found ...
Update the route rule to also expose
/headers
and to add a header to the request:$ kubectl apply -f - <<EOF apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: http namespace: default spec: parentRefs: - name: gateway namespace: istio-ingress hostnames: ["httpbin.example.com"] rules: - matches: - path: type: PathPrefix value: /get - path: type: PathPrefix value: /headers filters: - type: RequestHeaderModifier requestHeaderModifier: add: - name: my-added-header value: added-value backendRefs: - name: httpbin port: 8000 EOF
Access
/headers
again and notice headerMy-Added-Header
has been added to the request:$ curl -s -HHost:httpbin.example.com "http://$INGRESS_HOST/headers" | jq '.headers["My-Added-Header"][0]' ... "added-value" ...
Deployment methods
In the example above, you did not need to install an ingress gateway Deployment
prior to configuring a Gateway.
In the default configuration, a gateway Deployment
and Service
is automatically provisioned based on the Gateway
configuration.
For advanced use cases, manual deployment is still allowed.
Automated deployment
By default, each Gateway
will automatically provision a Service
and Deployment
.
These will be named <Gateway name>-<GatewayClass name>
(with the exception of the istio-waypoint
GatewayClass
, which does not append a suffix).
These configurations will be updated automatically if the Gateway
changes (for example, if a new port is added).
These resources can be customized by using the infrastructure
field:
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: gateway
spec:
infrastructure:
annotations:
some-key: some-value
labels:
key: value
parametersRef:
group: ""
kind: ConfigMap
name: gw-options
gatewayClassName: istio
Key-value pairs under labels
and annotations
will be copied onto the generated resources.
The parametersRef
can be used to fully customize the generated resources.
This must reference a ConfigMap
in the same namespace as the Gateway
.
An example configuration:
apiVersion: v1
kind: ConfigMap
metadata:
name: gw-options
data:
horizontalPodAutoscaler: |
spec:
minReplicas: 2
maxReplicas: 2
deployment: |
metadata:
annotations:
additional-annotation: some-value
spec:
replicas: 4
template:
spec:
containers:
- name: istio-proxy
resources:
requests:
cpu: 1234m
service: |
spec:
ports:
- "\$patch": delete
port: 15021
These configurations will be overlaid on top of the generated resources using a Strategic Merge Patch strategy. The following keys are valid:
service
deployment
serviceAccount
horizontalPodAutoscaler
podDisruptionBudget
GatewayClass defaults
Defaults for all Gateway
s can be configured for each GatewayClass
.
This is done by a ConfigMap
with the label gateway.istio.io/defaults-for-class: <gateway class name>
.
This ConfigMap
must be in the root namespace (typically, istio-system
).
Only one ConfigMap
per GatewayClass
is allowed.
This ConfigMap
takes the same format as the ConfigMap
for a Gateway
.
Customization may be present on both a GatewayClass
and a Gateway
.
If both are present, the Gateway
customization applies after the GatewayClass
customization.
This ConfigMap
can also be created at installation time. For example:
kind: IstioOperator
spec:
values:
gatewayClasses:
istio:
deployment:
spec:
replicas: 2
Resource attachment and scaling
Resources can be attached to a Gateway
to customize it.
However, most Kubernetes resources do not currently support attaching directly to a Gateway
, but they can be attached to the corresponding generated Deployment
and Service
instead.
This is easily done because the resources are generated with well-known labels (gateway.networking.k8s.io/gateway-name: <gateway name>
) and names:
- Gateway:
<gateway name>-<gateway class name>
- Waypoint:
<gateway name>
For example, to deploy a Gateway
with a HorizontalPodAutoscaler
and PodDisruptionBudget
:
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: gateway
spec:
gatewayClassName: istio
listeners:
- name: default
hostname: "*.example.com"
port: 80
protocol: HTTP
allowedRoutes:
namespaces:
from: All
---
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: gateway
spec:
# Match the generated Deployment by reference
# Note: Do not use `kind: Gateway`.
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: gateway-istio
minReplicas: 2
maxReplicas: 5
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 50
---
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: gateway
spec:
minAvailable: 1
selector:
# Match the generated Deployment by label
matchLabels:
gateway.networking.k8s.io/gateway-name: gateway
Manual deployment
If you do not want to have an automated deployment, a Deployment
and Service
can be configured manually.
When this option is done, you will need to manually link the Gateway
to the Service
, as well as keep their port configuration in sync.
In order to support Policy Attachment, e.g. when you’re using the targetRef
field on an AuthorizationPolicy, you will also need to reference the name of your Gateway
by adding the following label to your gateway pod: gateway.networking.k8s.io/gateway-name: <gateway name>
.
To link a Gateway
to a Service
, configure the addresses
field to point to a single Hostname
.
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: gateway
spec:
addresses:
- value: ingress.istio-gateways.svc.cluster.local
type: Hostname
...
Mesh Traffic
The Gateway API can also be used to configure mesh traffic.
This is done by configuring the parentRef
to point to a service, instead of a gateway.
For example, to add a header on all calls to an in-cluster Service
named example
:
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: mesh
spec:
parentRefs:
- group: ""
kind: Service
name: example
rules:
- filters:
- type: RequestHeaderModifier
requestHeaderModifier:
add:
- name: my-added-header
value: added-value
backendRefs:
- name: example
port: 80
More details and examples can be found in other traffic management tasks.
Cleanup
Remove the
httpbin
sample and gateway:$ kubectl delete -f @samples/httpbin/httpbin.yaml@ $ kubectl delete httproute http $ kubectl delete gateways.gateway.networking.k8s.io gateway -n istio-ingress $ kubectl delete ns istio-ingress
Uninstall Istio:
$ istioctl uninstall -y --purge $ kubectl delete ns istio-system
Remove the Gateway API CRDs if they are no longer needed:
$ kubectl kustomize "github.com/kubernetes-sigs/gateway-api/config/crd?ref=v1.2.1" | kubectl delete -f -