Gateway API是Kubernetes官方项目,是下一代Kubernetes路由和负载均衡API,支持通过Gateway API配置流量规则。本文介绍ACK Gateway with Inference Extension支持的一些Gateway API基础能力配置方法。
背景信息
ACK Gateway with Inference Extension组件基于Envoy Gateway项目构建,支持完整的Gateway API基础能力及开源Envoy Gateway扩展资源。
Envoy Gateway架构包括:
控制面:由Envoy Gateway组件构成,主要负责监听集群中的流量规则,动态创建和管理Envoy代理实例,并实时更新其转发规则,但不直接参与业务流量的转发。
数据面:由实际运行的Envoy Proxy实例组成,负责处理和转发业务流量,确保高效和可靠的通信。
前提条件
准备工作
创建测试应用backend和backend-2。
说明应用backend-2只需要将backend的YAML中
backend
都替换为backend-2
即可,此处不再赘述。apiVersion: v1 kind: ServiceAccount metadata: name: backend --- apiVersion: v1 kind: Service metadata: name: backend labels: app: backend service: backend spec: ports: - name: http port: 3000 targetPort: 3000 selector: app: backend --- apiVersion: apps/v1 kind: Deployment metadata: name: backend spec: replicas: 1 selector: matchLabels: app: backend version: v1 template: metadata: labels: app: backend version: v1 spec: serviceAccountName: backend containers: - image: registry-cn-hangzhou.ack.aliyuncs.com/ack-demo/envoygateway-echo-basic:v20231214-v1.0.0-140-gf544a46e imagePullPolicy: IfNotPresent name: backend ports: - containerPort: 3000 env: - name: POD_NAME valueFrom: fieldRef: fieldPath: metadata.name - name: NAMESPACE valueFrom: fieldRef: fieldPath: metadata.namespace
创建GatewayClass,声明
controllerName
为gateway.envoyproxy.io/gatewayclass-controller
。apiVersion: gateway.networking.k8s.io/v1 kind: GatewayClass metadata: name: eg spec: controllerName: gateway.envoyproxy.io/gatewayclass-controller
创建Gateway资源。
apiVersion: gateway.networking.k8s.io/v1 kind: Gateway metadata: name: eg spec: gatewayClassName: eg listeners: - name: http protocol: HTTP port: 80
ACK Gateway with Inference Extension组件控制面会根据当前Gateway资源创建出EnvoyProxy Deployment以及对应的LB类型的Service,并在指定端口开启监听。关于LB实例的计费标准,请参见负载均衡计费说明。
您也可以自定义EnvoyProxy的Deployment规格以及Service参数,或者开启网关HPA。
获取网关地址。
export GATEWAY_HOST=$(kubectl get gateway/eg -o jsonpath='{.status.addresses[0].value}')
基于路径前缀匹配的HTTP路由
以下示例配置HTTPRoute
匹配/get
前缀,并进行测试验证。
创建HTTPRoute资源。
apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: backend spec: parentRefs: - name: eg hostnames: - "www.example.com" rules: - backendRefs: - group: "" kind: Service name: backend port: 3000 weight: 1 matches: - path: type: PathPrefix value: /get
测试访问。
curl -H "Host: www.example.com" http://$GATEWAY_HOST/get
预期输出:
{ "path": "/get", "host": "www.example.com", "method": "GET", "proto": "HTTP/1.1", "headers": { "Accept": [ "*/*" ], "User-Agent": [ "curl/8.9.1" ], "X-Envoy-External-Address": [ "115.XX.XXX.55" ], "X-Forwarded-For": [ "115.XX.XXX.55" ], "X-Forwarded-Proto": [ "http" ], "X-Request-Id": [ "953b2f8f-26d3-4ba9-93ba-a482b197b1ff" ] }, "namespace": "default", "ingress": "", "service": "", "pod": "backend-5bff7XXXXX-XXXXX" }
添加请求Header
以下将更新HTTPRoute
配置,为路由的请求添加Header。
更新HTTPRoute资源。
apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: backend spec: parentRefs: - name: eg hostnames: - "www.example.com" rules: - matches: - path: type: PathPrefix value: /get backendRefs: - group: "" kind: Service name: backend port: 3000 weight: 1 filters: - type: RequestHeaderModifier requestHeaderModifier: add: - name: "added-header" value: "foo"
测试访问。
curl -H "Host: www.example.com" http://$GATEWAY_HOST/get
预期输出:
{ "path": "/get", "host": "www.example.com", "method": "GET", "proto": "HTTP/1.1", "headers": { "Accept": [ "*/*" ], "Added-Header": [ "foo" ], "User-Agent": [ "curl/8.9.1" ], "X-Envoy-External-Address": [ "115.XX.XXX.55" ], "X-Forwarded-For": [ "115.XX.XXX.55" ], "X-Forwarded-Proto": [ "http" ], "X-Request-Id": [ "d37f19e5-25c1-45cf-90e5-51453e7ae3ed" ] }, "namespace": "default", "ingress": "", "service": "", "pod": "backend-5bff7XXXXX-XXXXX" }%
由于当前应用的作用就是将请求内容作为响应直接输出,因此可以在响应中看到,为请求添加Header的操作已经完成。
按比例分发请求
以下将再次更新HTTPRoute
配置,增加backend-2的路由规则,并为backend和backend-2服务配置权重。
Gateway API并不要求所有backendRef
的权重之和为100。单个服务比例计算规则为:
更新HTTPRoute资源。
apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: backend spec: parentRefs: - name: eg hostnames: - "www.example.com" rules: - matches: - path: type: PathPrefix value: /get backendRefs: - group: "" kind: Service name: backend port: 3000 weight: 8 - group: "" kind: Service name: backend-2 port: 3000 weight: 2
测试连续访问20次,查看两个服务的比例。
说明以下命令增加了额外处理,使输出仅显示
backend
和backend-2
。for i in $(seq 1 20); do curl -sS -H "Host: www.example.com" http://$GATEWAY_HOST/get |grep backend; done | \ sed -E 's/".*"(backend(-2)?)-[0-9a-zA-Z]*-.*/\1/'
预期输出:
backend-2 backend backend backend backend backend backend backend backend backend backend backend-2 backend-2 backend backend backend-2 backend backend backend backend
可以看到,两个服务的流量比例大致为80%和20%。
处理TLS流量
以下内容将更新Gateway资源,配置证书并添加TLS监听,来验证对TLS流量处理的支持。
生成证书,并创建Secret。
openssl req -x509 -sha256 -nodes -days 365 -newkey rsa:2048 -subj '/O=example Inc./CN=example.com' -keyout example.com.key -out example.com.crt openssl req -out www.example.com.csr -newkey rsa:2048 -nodes -keyout www.example.com.key -subj "/CN=www.example.com/O=example organization" openssl x509 -req -days 365 -CA example.com.crt -CAkey example.com.key -set_serial 0 -in www.example.com.csr -out www.example.com.crt kubectl create secret tls example-cert --key=www.example.com.key --cert=www.example.com.crt
更新Gateway资源,添加TLS监听,并且使用上一步配置的证书。
kubectl patch gateway eg --type=json --patch ' - op: add path: /spec/listeners/- value: name: https protocol: HTTPS port: 443 tls: mode: Terminate certificateRefs: - kind: Secret group: "" name: example-cert '
查看更改是否生效。
kubectl get gateway/eg -o yaml | grep spec: -A 20
预期输出:
spec: gatewayClassName: eg listeners: - allowedRoutes: namespaces: from: Same name: http port: 80 protocol: HTTP - allowedRoutes: namespaces: from: Same name: https port: 443 protocol: HTTPS tls: certificateRefs: - group: "" kind: Secret name: example-cert mode: Terminate status:
可以看到,更改已经生效。
测试访问。
curl -H Host:www.example.com --resolve "www.example.com:443:${GATEWAY_HOST}" \ --cacert example.com.crt https://www.example.com/get
预期输出:
{ "path": "/get", "host": "www.example.com", "method": "GET", "proto": "HTTP/1.1", "headers": { "Accept": [ "*/*" ], "User-Agent": [ "curl/8.9.1" ], "X-Envoy-External-Address": [ "115.XX.XXX.55" ], "X-Forwarded-For": [ "115.XX.XXX.55" ], "X-Forwarded-Proto": [ "https" ], "X-Request-Id": [ "ac539756-3826-474b-be2f-5e57fdd49dac" ] }, "namespace": "default", "ingress": "", "service": "", "pod": "backend-5bff7XXXXX-XXXXX" }