K8S Gateway

为了从外部能够访问到集群中的服务,k8S 提供了多种方式,从 NodePort 类型的 ServiceLoadBalancer 类型的 Service,到 Ingress,一直在改进,NodePort类型的服务流量从单一节点进来,没法在节点之间负载均衡,进而衍生出LoadBalancer类型的服务,该类型的服务虽然解决了前面存在的问题,但是需要云厂商的支持,况且针对每个Service粒度提供一个公网IP地址,未免有点浪费,进而衍生出 Ingress,支持7层代理,能够通过单一的入口,以及域名和Path匹配等机制将流量转发到不同的后端服务中去。Ingress 虽然解决了LoadBalancer存在的问题,但它在实际的使用场景中又遇到了新的问题:

  1. Ingress 仅支持7层,没法对四层的流量进行转发;
  2. Ingress 在设计的时候只考虑一种用户角色,既整个系统的运维人员和管理员,这种模型在许多拥有多个团队的企业中都不适用,包括应用开发人员、平台运维人员、安全管理员等,他们在协作开发和交付应用的过程中需要控制Ingress配置的不同方面;
  3. Ingress 中使用了很多annotion实现自定义功能,对于不同的 ingress controller 没法做到一致性,例如,这里的 nginx annotions,这些在原本的 Ingress 对象中都是不支持的;

在这些问题的促使下,社区又提出了新的概念:Gateway,明确定义并划分不同角色的职责范围有助于简化管理,对三个主要的 Gateway API 资源(GatewayClassGatewayRoute)进行了标准化。具体来说,基础架构提供商负责为 Kubernetes 集群定义 GatewayClasses,集群运维人员则负责在集群中部署和配置 Gateway(包括策略),而应用开发人员可以自由地将 Route 附加到 Gateway,以对外暴露应用。

安装

Gateway 相关的资源没有在K8S中预置,因为它还在不断发展,在使用之前需要先安装相关的资源,这里分为两个版本:稳定版和实验版,实验版本相比标准稳定版多了 TCPRouteTLSRouteUDPRouteGRPCRoute,根据选用的的 Gateway Controller 的支持程度做选择即可。稳定版执行下下面的命令进行安装:

kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.0.0/standard-install.yaml

实验版本使用下面的命令进行安装:

kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.0.0/experimental-install.yaml

这里选用的 istio 作为Gateway的实现,参考istio的安装指南进行安装。安装成功之后,能看到一个 istioGatewayClass 对象:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
$ kubectl describe gatewayclass -n istio-system istio
Name: istio
Namespace:
Labels: <none>
Annotations: <none>
API Version: gateway.networking.k8s.io/v1
Kind: GatewayClass
Metadata:
Creation Timestamp: 2024-03-01T07:49:53Z
Generation: 1
Resource Version: 731627
UID: b3926b53-612b-4941-acce-d6d7bf0e9f3b
Spec:
Controller Name: istio.io/gateway-controller
Description: The default Istio GatewayClass
Status:
Conditions:
Last Transition Time: 2024-03-01T07:49:53Z
Message: Handled by Istio controller
Observed Generation: 1
Reason: Accepted
Status: True
Type: Accepted
Events: <none>

Gateway

上面的安装步骤完成之后,就可以创建一个Gateway进行使用了,这部分主要是集群运维人员的工作。为了能全面的展示Gateway API,这里使用了https协议,首先创建证书并且上传,使用到的mkcert需要提前安装:

mkcert --cert-file web.local.dev.crt -key-file web.local.dev.key web.local.dev
kubectl create -n nginx-gateway secret tls web.local.dev-crt --cert=web.local.dev.crt --key=web.local.dev.key

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
kubectl apply -f - <<EOF
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: local-gateway
namespace: istio-system
spec:
gatewayClassName: istio
listeners:
- protocol: HTTPS
port: 9443
name: web-gw
hostname: web.local.dev
allowedRoutes:
kinds:
- kind: HTTPRoute
namespaces:
from: Selector
selector:
matchLabels:
shared-gateway-access: "true"
matchExpressions:
- key: kubernetes.io/metadata.name
operator: In
values:
- gateway-test
tls:
mode: Terminate
certificateRefs:
- name: web.local.dev-crt
kind: Secret
group: ""
EOF

Gateway 中的重点概念做下解释:

  • spec.gatewayClassName:指定要使用的 Gateway Controller,这里使用上一节安装的 istio
  • spec.listeners.hostname:网关的名称,如果要使用 HTTPS 协议, 在指定了 spec.listeners.tls 时,该字段必须指定,且附加到该网关的 HTTPRoute 中的 hostnames 字段至少包含这里声明的 hostname
  • spec.listeners.allowedRoutes.namespace:指定允许哪些命名空间的 HTTProute 附加到这个网关中:
    • kinds:允许那种路由添加到这个网关中;
    • from:可以取值 Same,表示只有和网关在相同命名空间的路由才可以添加到这个网关中;All 表示允许所有命名空间的路由添加到这个网关中;Selector 允许选择器选择匹配的命名空间中的路由添加到这个网关中;
    • selector.matchLabels:选择具有 shared-gateway-access: "true" 标记的命名空间;
    • selector.matchLabels:这里允许 gateway-test 这个命名中的路由添加到网关;

执行成功之后,能看到下面的对象,其中 local-gateway-istio service 是整个 local-gateway 的入口,被metalb分配了172.19.106.241地址,它接受到的请求转发给 local-gateway-istio-fb7447f46-g56gm 这个 Pod 进行处理,它负责对路由配置的解释,根据 HTTPRoute 配置的规则将流量转发给对应的后端服务:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
$ kubectl get svc local-gateway-istio -n istio-system -owide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
local-gateway-istio LoadBalancer 10.43.113.75 172.19.106.241 15021:31230/TCP,9443:30992/TCP 20h istio.io/gateway-name=local-gateway
$ kubectl describe svc local-gateway-istio -n istio-system
Name: local-gateway-istio
Namespace: istio-system
Labels: gateway.istio.io/managed=istio.io-gateway-controller
Annotations: metallb.universe.tf/ip-allocated-from-pool: mylocal-net-pool
Selector: istio.io/gateway-name=local-gateway
Type: LoadBalancer
IP Family Policy: SingleStack
IP Families: IPv4
IP: 10.43.113.75
IPs: 10.43.113.75
LoadBalancer Ingress: 172.19.106.241
Port: status-port 15021/TCP
TargetPort: 15021/TCP
NodePort: status-port 31230/TCP
Endpoints: 10.42.0.112:15021
Port: web-gw 9443/TCP
TargetPort: 9443/TCP
NodePort: web-gw 30992/TCP
Endpoints: 10.42.0.112:9443
Session Affinity: None
External Traffic Policy: Cluster
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal ClearAssignment 52s metallb-controller current IP for "istio-system/local-gateway-istio" not allowed by config, will attempt for new IP assignment: ["172.31.46.244"] is not allowed in config
Normal IPAllocated 52s metallb-controller Assigned IP ["172.19.106.241"]
Normal nodeAssigned 41s (x9 over 20h) metallb-speaker announcing from node "f00596107-px" with protocol "layer2"
$ kubectl get gateway local-gateway -n istio-system -owide
NAME CLASS ADDRESS PROGRAMMED AGE
local-gateway istio 172.19.106.241 True 20h
$ kubectl get secret web.local.dev-crt -n istio-system -owide
NAME TYPE DATA AGE
web.local.dev-crt kubernetes.io/tls 2 11m
$ kubectl get pods -n istio-system -owide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
...
local-gateway-istio-fb7447f46-g56gm 1/1 Running 0 13m 10.42.0.112 f00596107-px <none> <none>

功能介绍

前面的配置一般由集群的运维人员进行,现在需要开发人员登场将自己的开发的应用接入到网关中,这样用户就可以从外部进行访问了。

HTTPRoute

使用 kubectl 部署下面的 whoami 服务进行测试:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
kubectl apply -f - <<EOF
apiVersion: v1
kind: Namespace
metadata:
name: gateway-test
labels:
shared-gateway-access: "true"
---
apiVersion: v1
kind: Service
metadata:
name: whoami-svc
namespace: gateway-test
spec:
ports:
- port: 8080
name: http
targetPort: 80
selector:
app: whoami
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: whoami-deploy
namespace: gateway-test
labels:
app: whoami
spec:
replicas: 1
selector:
matchLabels:
app: whoami
template:
metadata:
labels:
app: whoami
spec:
containers:
- name: whoami
image: traefik/whoami
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: whoami-http-route
namespace: gateway-test
spec:
parentRefs:
- name: local-gateway
namespace: istio-system
hostnames:
- "web.local.dev"
rules:
- matches:
- path:
type: PathPrefix
value: /whoami
backendRefs:
- name: whoami-svc
port: 8080
EOF

对上面的一些关键点进行解释:

  1. 命名空间的名称 gateway-test 以及它的标签:shared-gateway-access: "true" 是他被Gateway认可的标识,在创建 Gateway 的时候指定具有这个特征的命名空间中的HTTPRoute才会被接受;
  2. 创建 whoami-svc 用于处理实际的请求,它会将请求转发到具有 app=whoamiPod 进行处理;
  3. 创建 HTTPRoute 路由,使用 istio-system 命名空间中的 local-gateway Gateway 作为网关,匹配Hostweb.local.dev,且以/whoami开始的请求转发给whoami-svc8080端口进行处理;

上面的命令执行成功之后,将能看到下面这些资源信息:

kubectl get svc,pod,deploy,rs,httproute -n gateway-test -owide

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$ kubectl get svc,pod,deploy,rs,httproute -n gateway-test -owide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
service/whoami-svc ClusterIP 10.43.131.190 <none> 8080/TCP 24m app=whoami

NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod/whoami-deploy-6cc79b7f7d-trvtd 1/1 Running 0 24m 10.42.0.115 f00596107-px <none> <none>

NAME READY UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTOR
deployment.apps/whoami-deploy 1/1 1 1 24m whoami traefik/whoami app=whoami

NAME DESIRED CURRENT READY AGE CONTAINERS IMAGES SELECTOR
replicaset.apps/whoami-deploy-6cc79b7f7d 1 1 1 24m whoami traefik/whoami app=whoami,pod-template-hash=6cc79b7f7d

NAME HOSTNAMES AGE
httproute.gateway.networking.k8s.io/whoami-http-route ["web.local.dev"] 24m

使用 curl 命令进行结果验证:

curl -i --resolve web.local.dev:9443:172.19.106.241 https://web.local.dev:9443/whoami

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
$ curl -i --resolve web.local.dev:9443:172.19.106.241 https://web.local.dev:9443/whoami
HTTP/2 200
date: Sat, 02 Mar 2024 07:02:36 GMT
content-length: 1403
content-type: text/plain; charset=utf-8
x-envoy-upstream-service-time: 2
server: istio-envoy

Hostname: whoami-deploy-6cc79b7f7d-trvtd
IP: 127.0.0.1
IP: 10.42.0.115
RemoteAddr: 10.42.0.112:34310
GET /whoami HTTP/1.1
Host: web.local.dev:9443
User-Agent: curl/7.81.0
Accept: */*
X-B3-Sampled: 1
X-B3-Spanid: c6c0d4e855c06fba
X-B3-Traceid: 01bd1b82406ae9bac6c0d4e855c06fba
X-Envoy-Attempt-Count: 1
X-Envoy-Decorator-Operation: whoami-svc.gateway-test.svc.cluster.local:8080/*
X-Envoy-Internal: true
X-Envoy-Peer-Metadata: ChQKDkFQUF9DT05UQUlORVJTEgIaAAoaCgpDTFVTVEVSX0lEEgwaCkt1YmVybmV0ZXMKHQoMSU5TVEFOQ0VfSVBTEg0aCzEwLjQyLjAuMTEyChkKDUlTVElPX1ZFUlNJT04SCBoGMS4yMC4zCscBCgZMQUJFTFMSvAEquQEKKAoVaXN0aW8uaW8vZ2F0ZXdheS1uYW1lEg8aDWxvY2FsLWdhdGV3YXkKOAofc2VydmljZS5pc3Rpby5pby9jYW5vbmljYWwtbmFtZRIVGhNsb2NhbC1nYXRld2F5LWlzdGlvCi8KI3NlcnZpY2UuaXN0aW8uaW8vY2Fub25pY2FsLXJldmlzaW9uEggaBmxhdGVzdAoiChdzaWRlY2FyLmlzdGlvLmlvL2luamVjdBIHGgVmYWxzZQoaCgdNRVNIX0lEEg8aDWNsdXN0ZXIubG9jYWwKLQoETkFNRRIlGiNsb2NhbC1nYXRld2F5LWlzdGlvLWZiNzQ0N2Y0Ni1nNTZnbQobCglOQU1FU1BBQ0USDhoMaXN0aW8tc3lzdGVtClwKBU9XTkVSElMaUWt1YmVybmV0ZXM6Ly9hcGlzL2FwcHMvdjEvbmFtZXNwYWNlcy9pc3Rpby1zeXN0ZW0vZGVwbG95bWVudHMvbG9jYWwtZ2F0ZXdheS1pc3RpbwomCg1XT1JLTE9BRF9OQU1FEhUaE2xvY2FsLWdhdGV3YXktaXN0aW8=
X-Envoy-Peer-Metadata-Id: router~10.42.0.112~local-gateway-istio-fb7447f46-g56gm.istio-system~istio-system.svc.cluster.local
X-Forwarded-For: 10.42.0.1
X-Forwarded-Proto: https
X-Request-Id: 8a0960c0-4626-9a67-9114-61b365b274af

ReferenceGrant

上面的 HTTPRoute 和引用的后端服务在同一个命名空间中,如果不在同一个命名空间,就需要使用 ReferenceGrant 进行显示授权,ReferenceGrant 允许和它在同一个命名空间中的 Service 被其他命名空间中的 HTTPRoute 进行引用,对前面的示例进行改造然后进行演示,首先删除原来命名空间中的资源:

kubectl delete ns --cascade gateway-test

然后重新创建下面的资源:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
kubectl apply -f - <<EOF
apiVersion: v1
kind: Namespace
metadata:
name: gateway-test
labels:
shared-gateway-access: "true"
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: whoami-http-route
namespace: gateway-test
spec:
parentRefs:
- name: local-gateway
namespace: istio-system
hostnames:
- "web.local.dev"
rules:
- matches:
- path:
type: PathPrefix
value: /whoami
backendRefs:
- name: whoami-svc
port: 8080
namespace: gateway-test-svc
---
apiVersion: v1
kind: Namespace
metadata:
name: gateway-test-svc
---
apiVersion: v1
kind: Service
metadata:
name: whoami-svc
namespace: gateway-test-svc
spec:
ports:
- port: 8080
name: http
targetPort: 80
selector:
app: whoami
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: whoami-deploy
namespace: gateway-test-svc
labels:
app: whoami
spec:
replicas: 1
selector:
matchLabels:
app: whoami
template:
metadata:
labels:
app: whoami
spec:
containers:
- name: whoami
image: traefik/whoami
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
---
apiVersion: gateway.networking.k8s.io/v1beta1
kind: ReferenceGrant
metadata:
name: ref-grant-to-svc
namespace: gateway-test-svc
spec:
from:
- group: gateway.networking.k8s.io
kind: HTTPRoute
namespace: gateway-test
to:
- group: ""
kind: Service
EOF

对上面的资源配置做以下解释:

  1. HTTPRoute 依然在 gateway-test 命名空间中,是为了能让 local-gateway 接受此路由,而且它引用的whoami-svc目前被放在了gateway-test-svc中,通过 namespace 显示指定;
  2. 为了能让 gateway-test 中的 HTTPRoute 引用 gateway-test-svcService,使用 ReferenceGrant 显示进行授权;

部署成功之后,使用下面的命令依然能够访问成功:

curl -i --resolve web.local.dev:9443:172.19.106.241 https://web.local.dev:9443/whoami

重定向

使用 HTTPRoute 还可完成重定向和路由重写功能。

协议重定向

HTTP 协议中,经常会将不安全的http访问重定向到https协议,为了测试这个功能,首先对local-gateway进行更新,允许它处理来自http的报文:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
kubectl apply -f - <<EOF
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: local-gateway
namespace: istio-system
spec:
gatewayClassName: istio
listeners:
- protocol: HTTP
port: 9080
name: web-http-gw
hostname: web.local.dev
allowedRoutes:
namespaces:
from: Selector
selector:
matchLabels:
shared-gateway-access: "true"
matchExpressions:
- key: kubernetes.io/metadata.name
operator: In
values:
- gateway-test
- protocol: HTTPS
port: 9443
name: web-https-gw
hostname: web.local.dev
allowedRoutes:
kinds:
- kind: HTTPRoute
namespaces:
from: Selector
selector:
matchLabels:
shared-gateway-access: "true"
matchExpressions:
- key: kubernetes.io/metadata.name
operator: In
values:
- gateway-test
tls:
mode: Terminate
certificateRefs:
- name: web.local.dev-crt
kind: Secret
group: ""
EOF

这个更新让 web.local.dev 可以通过 httphttps 两种协议进行访问。

承接 ReferenceGrant 中的测试案例,这个时候可以使用http协议访问 whoami 服务:

curl -i --resolve web.local.dev:9080:172.19.106.241 http://web.local.dev:9080/whoami

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
$ curl -i --resolve web.local.dev:9080:172.19.106.241 http://web.local.dev:9080/whoami
HTTP/1.1 200 OK
date: Sat, 02 Mar 2024 07:48:14 GMT
content-length: 1406
content-type: text/plain; charset=utf-8
x-envoy-upstream-service-time: 0
server: istio-envoy

Hostname: whoami-deploy-6cc79b7f7d-vjt2m
IP: 127.0.0.1
IP: 10.42.0.117
RemoteAddr: 10.42.0.112:48374
GET /whoami HTTP/1.1
Host: web.local.dev:9080
User-Agent: curl/7.81.0
Accept: */*
X-B3-Sampled: 1
X-B3-Spanid: e1708968da8fe32c
X-B3-Traceid: 715a2daabdb898c2e1708968da8fe32c
X-Envoy-Attempt-Count: 1
X-Envoy-Decorator-Operation: whoami-svc.gateway-test-svc.svc.cluster.local:8080/*
X-Envoy-Internal: true
X-Envoy-Peer-Metadata: ChQKDkFQUF9DT05UQUlORVJTEgIaAAoaCgpDTFVTVEVSX0lEEgwaCkt1YmVybmV0ZXMKHQoMSU5TVEFOQ0VfSVBTEg0aCzEwLjQyLjAuMTEyChkKDUlTVElPX1ZFUlNJT04SCBoGMS4yMC4zCscBCgZMQUJFTFMSvAEquQEKKAoVaXN0aW8uaW8vZ2F0ZXdheS1uYW1lEg8aDWxvY2FsLWdhdGV3YXkKOAofc2VydmljZS5pc3Rpby5pby9jYW5vbmljYWwtbmFtZRIVGhNsb2NhbC1nYXRld2F5LWlzdGlvCi8KI3NlcnZpY2UuaXN0aW8uaW8vY2Fub25pY2FsLXJldmlzaW9uEggaBmxhdGVzdAoiChdzaWRlY2FyLmlzdGlvLmlvL2luamVjdBIHGgVmYWxzZQoaCgdNRVNIX0lEEg8aDWNsdXN0ZXIubG9jYWwKLQoETkFNRRIlGiNsb2NhbC1nYXRld2F5LWlzdGlvLWZiNzQ0N2Y0Ni1nNTZnbQobCglOQU1FU1BBQ0USDhoMaXN0aW8tc3lzdGVtClwKBU9XTkVSElMaUWt1YmVybmV0ZXM6Ly9hcGlzL2FwcHMvdjEvbmFtZXNwYWNlcy9pc3Rpby1zeXN0ZW0vZGVwbG95bWVudHMvbG9jYWwtZ2F0ZXdheS1pc3RpbwomCg1XT1JLTE9BRF9OQU1FEhUaE2xvY2FsLWdhdGV3YXktaXN0aW8=
X-Envoy-Peer-Metadata-Id: router~10.42.0.112~local-gateway-istio-fb7447f46-g56gm.istio-system~istio-system.svc.cluster.local
X-Forwarded-For: 10.42.0.1
X-Forwarded-Proto: http
X-Request-Id: e55ee377-abff-93fd-a3e8-1162549b40ba

如果想将所有的 http 访问全部重定向到 https,需要对 gateway-test 中的HTTPRoute进行更改,使用 sectionName 区分两个路由引用的协议,这样可以单独设置通过http协议访问时的动作:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
kubectl apply -f - <<EOF
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: whoami-http-route
namespace: gateway-test
spec:
parentRefs:
- name: local-gateway
namespace: istio-system
sectionName: web-http-gw
hostnames:
- "web.local.dev"
rules:
- filters:
- type: RequestRedirect
requestRedirect:
scheme: https
port: 9443
statusCode: 301
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: whoami-https-route
namespace: gateway-test
spec:
parentRefs:
- name: local-gateway
namespace: istio-system
sectionName: web-https-gw
hostnames:
- "web.local.dev"
rules:
- matches:
- path:
type: PathPrefix
value: /whoami
backendRefs:
- name: whoami-svc
port: 8080
namespace: gateway-test-svc
EOF

执行上面的操作之后,再次通过 http 协议进行访问,会发现已经重定向了:

1
2
3
4
5
6
$ curl -i --resolve web.local.dev:9080:172.19.106.241 http://web.local.dev:9080/whoami
HTTP/1.1 301 Moved Permanently
location: https://web.local.dev:9443/whoami
date: Sat, 02 Mar 2024 08:01:29 GMT
server: istio-envoy
content-length: 0
路径重定向

路径重定向使用 HTTP 路径修饰符来替换整个路径或路径前缀,如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
kubectl apply -f - <<EOF
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: whoami-https-route
namespace: gateway-test
spec:
parentRefs:
- name: local-gateway
namespace: istio-system
sectionName: web-https-gw
hostnames:
- "web.local.dev"
rules:
- matches:
- path:
type: PathPrefix
value: /whoami
backendRefs:
- name: whoami-svc
port: 8080
namespace: gateway-test-svc
- matches:
- path:
type: PathPrefix
value: /who
filters:
- type: RequestRedirect
requestRedirect:
path:
type: ReplacePrefixMatch
replacePrefixMatch: /whoami
statusCode: 302
- matches:
- path:
type: PathPrefix
value: /whoam
filters:
- type: RequestRedirect
requestRedirect:
path:
type: ReplaceFullPath
replaceFullPath: /whoami
statusCode: 302
EOF

然后当访问以 /whamo 开头的请求时都会被全部重定向到 /whoami

1
2
3
4
5
6
7
8
9
10
$ curl -i --resolve web.local.dev:9443:172.19.106.241 https://web.local.dev:9443/whoam
HTTP/2 302
location: https://web.local.dev:9443/whoami
date: Sat, 02 Mar 2024 08:20:07 GMT
server: istio-envoy
$ curl -i --resolve web.local.dev:9443:172.19.106.241 https://web.local.dev:9443/whoam/xxx
HTTP/2 302
location: https://web.local.dev:9443/whoami
date: Sat, 02 Mar 2024 08:34:27 GMT
server: istio-envoy

当访问以 /who 开头的请求时,仅仅 /who 会被完全替换为 /whoami

1
2
3
4
5
6
7
8
9
10
11
$ curl -i --resolve web.local.dev:9443:172.19.106.241 https://web.local.dev:9443/who/xxx
HTTP/2 302
location: https://web.local.dev:9443/whoami/xxx
date: Sat, 02 Mar 2024 08:35:48 GMT
server: istio-envoy

$ curl -i --resolve web.local.dev:9443:172.19.106.241 https://web.local.dev:9443/who
HTTP/2 302
location: https://web.local.dev:9443/whoami
date: Sat, 02 Mar 2024 08:35:52 GMT
server: istio-envoy

HTTP 头修改

通过 HTTPRoute 中的 RequestHeaderModifier 可以添加、修改或者删除请求头,例如下面的HTTPRoute中将对以/whoami开头的请求添加request-with-correct-path: true 这样的请求头:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
kubectl apply -f - <<EOF
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: whoami-https-route
namespace: gateway-test
spec:
parentRefs:
- name: local-gateway
namespace: istio-system
sectionName: web-https-gw
hostnames:
- "web.local.dev"
rules:
- matches:
- path:
type: PathPrefix
value: /whoami
backendRefs:
- name: whoami-svc
port: 8080
namespace: gateway-test-svc
filters:
- type: RequestHeaderModifier
requestHeaderModifier:
add:
- name: request-with-correct-path
value: "true"
- matches:
- path:
type: PathPrefix
value: /who
filters:
- type: RequestRedirect
requestRedirect:
path:
type: ReplacePrefixMatch
replacePrefixMatch: /whoami
statusCode: 302
- matches:
- path:
type: PathPrefix
value: /whoam
filters:
- type: RequestRedirect
requestRedirect:
path:
type: ReplaceFullPath
replaceFullPath: /whoami
statusCode: 302
EOF

当在请求的时候,会返回如下的结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
$ curl -i --resolve web.local.dev:9443:172.19.106.241 https://web.local.dev:9443/whoami
HTTP/2 200
date: Sat, 02 Mar 2024 08:53:55 GMT
content-length: 1440
content-type: text/plain; charset=utf-8
x-envoy-upstream-service-time: 1
server: istio-envoy

Hostname: whoami-deploy-6cc79b7f7d-vjt2m
IP: 127.0.0.1
IP: 10.42.0.117
RemoteAddr: 10.42.0.112:57130
GET /whoami HTTP/1.1
Host: web.local.dev:9443
User-Agent: curl/7.81.0
Accept: */*
Request-With-Correct-Path: true
...

参考链接

  1. https://www.nginx-cn.net/blog/5-things-to-know-about-nginx-kubernetes-gateway/