️ Add chapter on Gateway API

This commit is contained in:
Jérôme Petazzoni
2025-10-22 16:48:49 +02:00
parent 487968dee5
commit adbd10506a
5 changed files with 528 additions and 1 deletions

523
slides/k8s/gateway-api.md Normal file
View File

@@ -0,0 +1,523 @@
# The Gateway API
- Over time, Kubernetes has introduced multiple ways to expose containers
- In the first versions of Kubernetes, we would use a `Service` of type `LoadBalancer`
- HTTP services often need extra features, though:
- content-based routing (route requests with URI, HTTP headers...)
- TLS termination
- middlewares (e.g. authentication)
- etc.
- This led to the introduction of the `Ingress` resource
---
## History of Ingress
- Kubernetes 1.8 (September 2017) introduced `Ingress` (v1beta1)
- Kubernetes 1.19 (August 2020) graduated `Ingress` to GA (v1)
- Ingress supports:
- content-based routing with URI or HTTP `Host:` header
- TLS termination (with neat integration with e.g. cert-manager)
- Ingress doesn't support:
- content-based routing with other headers (e.g. cookies)
- middlewares
- traffic split for e.g. canary deployments
---
## Everyone needed something better
- Virtually *every* ingress controller added proprietary extensions:
- `nginx.ingress.kubernetes.io/configuration-snippet` annotation
- Traefik has CRDs like `IngressRoute`, `TraefikService`, `Middleware`...
- HAProxy has CRDs like `Backend`, `TCP`...
- etc.
- Ingress was too specific to L7 (HTTP) traffic
- We needed a totally new set of APIs and resources!
---
## Gateway API in a nutshell
- Handle HTTP, GRPC, TCP, TLS, UDP routes
(note: as of October 2025, only HTTP and GRPC routes are in GA)
- Finer-grained permission model
(e.g. define which namespaces can use a specific "gateway"; more on that later)
- Standardize more "core" features than Ingress
(header-based routing, traffic weighing, rewrite requests and responses...)
- Pave the way for further extension thanks to different feature sets
(`Core` vs `Extended` vs `Implementation-specific`)
- Can also be used for service meshes
---
## Gateway API personas
- Ingress informally had two personas:
- cluster administrator (installs and manages the Ingress Controller)
- application developer (creates Ingress resources)
- Gateway [formally defines three personas][gateway-personas]:
- infrastructure provider
<br/>
(~network admin; potentially works within managed providers)
- cluster operator
<br/>
(~Kubernetes admin; potentially manages multiple clusters)
- application developer
[gateway-personas]: https://gateway-api.sigs.k8s.io/concepts/roles-and-personas/
---
class: pic
## Gateway API resources
![Diagram showing GatewayClass, Gateway, HTTPRoute, Service](https://gateway-api.sigs.k8s.io/images/resource-model.png)
---
## Gateway API resources
- `Service` = our good old Kubernetes service
- `HTTPRoute` = describes which requests should go to which `Service`
(similar to the `Ingress` resource)
- `Gateway` = how traffic enters the system
(could correspond to e.g. a `LoadBalancer` `Service`)
- `GatewayClass` = represents different types of `Gateways`
(many gateway controllers will offer only one)
---
## `HTTPRoute` anatomy
- `spec.parentRefs` = where requests come from
- typically a single `Gateway`
- could be multiple `Gateway` resources
- can also be a `Service` (for cluster mesh uses)
- `spec.hostnames` = which hosts (HTTP `Host:` header) this applies to
- `spec.rules[].matches` = which requests this applies to (match paths, headers...)
- `spec.rules[].filters` = optional transformations (change headers, rewrite URI...)
- `spec.rules[].backendRefs` = where requests go to
---
## Minimal `HTTPRoute`
```yaml
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: xyz
spec:
parentRefs:
- group: gateway.networking.k8s.io
kind: Gateway
name: my-gateway
namespace: my-gateway-namespace
hostnames: [ xyz.example.com ]
rules:
- backendRefs:
- name: xyz
port: 80
```
---
## Gateway API in action
- Let's deploy Traefik in Gateway API mode!
- We'll use the [official Helm chart for Traefik][traefik-chart]
- We'll need to set a few values
- `providers.kubernetesGateway.enabled=true`
*enable Gateway API provisioning*
- `gateway.listeners.web.namespacePolicy.from=All`
*allow `HTTPRoutes` in all namespaces to refer to the default `Gateway`*
[traefik-chart]: https://artifacthub.io/packages/helm/traefik/traefik
---
## `LoadBalancer` vs `hostPort`
- If we're using a managed Kubernetes cluster, we'll use the default mode:
- Traefik runs with a `Deployment`
- Traefik `Service` has type `LoadBalancer`
- we connect to the `LoadBalancer` public IP address
- If we don't have a CCM (or `LoadBalancer` `Service`), we'll do things differently:
- Traefik runs with a `DaemonSet`
- Traefik `Service` has type `ClusterIP` (not strictly necessary but cleaner)
- we connect to any node's public IP address
---
## Installing Traefik (with `LoadBalancer`)
Install the Helm chart:
```bash
helm upgrade --install --namespace traefik --create-namespace \
--repo https://traefik.github.io/charts traefik traefik \
--version 37.1.2 \
--set providers.kubernetesGateway.enabled=true \
--set gateway.listeners.web.namespacePolicy.from=All \
#
```
We'll connect by using the public IP address of the load balancer:
```bash
kubectl get services --namespace traefik
```
---
## Installing Traefik (with `hostPort`)
Install the Helm chart:
```bash
helm upgrade --install --namespace traefik --create-namespace \
--repo https://traefik.github.io/charts traefik traefik \
--version 37.1.2 \
--set deployment.kind=DaemonSet \
--set ports.web.hostPort=80 \
--set ports.websecure.hostPort=443 \
--set service.type=ClusterIP \
--set providers.kubernetesGateway.enabled=true \
--set gateway.listeners.web.namespacePolicy.from=All \
#
```
We'll connect by using the public IP address of any node of the cluster.
---
class: extra-details
## Taints and tolerations
- By default, Traefik Pods will respect node taints
- If some nodes have taints (e.g. control plane nodes) we might need tolerations
(if we want to run Traefik on all nodes)
- Adding the corresponding tolerations is left as an exercise for the reader!
---
class: extra-details
## Rolling updates with `hostPort`
- It is not possible to have two pods on the same node using the same `hostPort`
- Therefore, it is important to pay attention to the `DaemonSet` rolling update parameters
- If `maxUnavailable` is non-zero:
- old pods will be shutdown first
- new pods will start without a problem
- there will be a short interruption of service
- If `maxSurge` is non-zero:
- new pods will be created but won't be able to start (since the `hostPort` is taken)
- old pods will remain running and the rolling update will not proceed
---
## Testing our Gateway controller
- Send a test request to Traefik
(e.g. with `curl http://<ipaddress>`)
- For now we should get a `404 not found`
(as there are no routes configured)
---
## A basic HTTP route
- Create a basic HTTP container and expose it with a Service; e.g.:
```bash
kubectl create deployment blue --image jpetazzo/color --port 80
kubectl expose deployment blue
```
---
## A basic HTTP route
- Create an `HTTPRoute` with the following YAML:
```yaml
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: blue
spec:
parentRefs:
- group: gateway.networking.k8s.io
kind: Gateway
name: traefik-gateway
namespace: traefik
rules:
- backendRefs:
- name: blue
port: 80
```
- Our `curl` command should now show a response from the `blue` pod
---
class: extra-details
## Traefik dashboard
- By default, Traefik exposes a dashboard
(on a different port than the one used for "normal" traffic)
- To access it:
```bash
kubectl port-forward --namespace traefik daemonset/traefik 1234:8080
```
(replace `daemonset` with `deployment` if necessary)
- Then connect to http://localhost:1234/dashboard/ (pay attention to the final `/`!)
---
## `Core` vs `Extended` vs `Implementation-specific`
- All Gateway controllers must support `Core` features
- Some optional features are in the `Extended` set:
- they may or may not supported
- but at least, their specification is part of the API definition
- Gateway controllers can also have `Implementation-specific` features
(=proprietary extensions)
- In the following slides, we'll tag features with `Core` or `Extended`
---
## `HTTPRoute.spec.rules[].matches`
Some fields are part of the `Core` set; some are part of the `Extended` set.
```yaml
match:
path: # Core
value: /hello
type: PathPrefix # default value; can also be "Exact"
headers: # Core
- name: x-custom-header
value: foo
queryparams: # Extended
- type: Exact # can also have implementation-specific values, e.g. Regex
name: product
value: pizza
method: GET # Extended
```
---
## `HTTPRoute.spec.rules[].filters.*HeaderModifier`
`RequestHeaderModifier` is `Core`
`ResponseHeaderModifier` is `Extended`
```yaml
type: RequestHeaderModifier # or ResponseHeaderModifier
requestHeaderModifier: # or responseHeaderModifier
set: # replace an existing header
- name: x-my-header
value: hello
add: # appends to an existing header
- name: x-my-header # (adding a comma if it's already set)
value: hello
remove:
- x-my-header
```
---
## `HTTPRoute.spec.rules[].filters.RequestRedirect`
```yaml
type: RequestRedirect
requestRedirect:
scheme: https # http or https
hostname: newxyz.example.com
path: /new
port: 8080
statusCode: 302 # default=302; can be 301 302 303 307 308
```
All fields are optional. Empty fields mean "leave as is".
Note that while `RequestRedirect` is `Core`, some options are `Extended`!
(See the [API specification for details][http-request-redirect].)
[http-request-redirect]: https://gateway-api.sigs.k8s.io/reference/spec/#httprequestredirectfilter
---
## `HTTPRoute.spec.rules[].filters.URLRewrite`
```yaml
type: URLRewrite
urlRewrite:
hostname: newxyz.example.com
path: /new
```
`hostname` will rewrite the HTTP `Host:` header.
This is an `Extended` feature.
It conflicts with `HTTPRequestRedirect`.
---
## `HTTPRoute.spec.rules[].filters.RequestMirror`
This is an `Extended` feature. It sends a copy of all (or a fraction) of requests to another backend. Responses from the mirrored backend are ignored.
```yaml
type: RequestMirror
requestMirror:
percent: 10
fraction:
numerator: 1
denominator: 10
backendRef:
group: "" # default
kind: Service # default
name: log-some-requests
namespace: my-observability-namespace # defaults to same namespace
port: 80
hostname: newxyz.example.com
```
Specify `percent` or `fraction`, not both. If neither is specified, all requests get mirrored.
---
## Other routes
- `GRPCRoute` can use GRPC services and methods to route requests
*this is useful if you're using GRPC; otherwise you can ignore it!*
- `TLSRoute` can use SNI header to route requests (without decrypting traffic)
*this is useful to host multiple TLS services on a single address with end-to-end encryption*
- `TCPRoute` can route TCP connections
*this is useful to colocate multiple protocols on the same address, e.g. HTTP+HTTPS+SSH*
- `UDPRoute` can route UDP packets
*ditto, e.g. for DNS/UDP, DNS/TCP, DNS/HTTPS*
---
## `gateway.spec.listeners.allowedRoutes`
- With `Ingress`, any `Ingress` resource can "catch" traffic
- This could be a problem e.g. if a dev/staging environment accidentally (or maliciously) creates an `Ingress` with a production hostname
- Gateway API introduces guardrails
- A `Gateway` can indicate if it can be referred by routes:
- from all namespaces (like with `Ingress`)
- only from the same namespace
- only from specific namespaces matching a selector
- That's why we specified `gateway.listeners.web.namespacePolicy.from=All` when deploying Traefik
???
:EN:- The Gateway API
:FR:- La Gateway API

View File

@@ -64,8 +64,9 @@ content:
- k8s/crd.md
- #6
- k8s/ingress-tls.md
- k8s/ingress-advanced.md
#- k8s/ingress-advanced.md
#- k8s/ingress-canary.md
- k8s/gateway-api.md
- k8s/cert-manager.md
- k8s/cainjector.md
- k8s/eck.md

View File

@@ -66,6 +66,7 @@ content:
- k8s/rollout.md
- k8s/healthchecks.md
- k8s/ingress.md
#- k8s/gateway-api.md
#- k8s/volumes.md
- k8s/configuration.md
- k8s/secrets.md

View File

@@ -86,6 +86,7 @@ content:
- k8s/ingress-advanced.md
#- k8s/ingress-canary.md
- k8s/ingress-tls.md
- k8s/gateway-api.md
- k8s/cert-manager.md
- k8s/cainjector.md
- k8s/kustomize.md

View File

@@ -84,6 +84,7 @@ content:
#- k8s/ingress-advanced.md
#- k8s/ingress-canary.md
#- k8s/ingress-tls.md
#- k8s/gateway-api.md
- k8s/kustomize.md
- k8s/helm-intro.md
- k8s/helm-chart-format.md