Gateway API是Kubernetes官方项目,是下一代Kubernetes路由和负载均衡API,支持通过Gateway API配置流量规则。本文介绍如何通过ALB使用Gateway API来暴露服务至集群外部。
背景信息
Gateway API是Kubernetes中用于对服务网络流量进行建模的一系列资源。目标是建立一套表现力强、易扩展、面向角色的服务网络模型。
ALB Ingress Controller在v2.17.0版本后提供了对Gateway API的支持,您可以安装ALB Ingress Controller来通过ALB使用Gateway API暴露服务。
前提条件
已创建ACS集群,且集群版本在1.31及以上。
已在集群中安装ALB Ingress Controller,且版本在2.17及以上。
已在集群中安装Gateway API,且版本在1.3.0及以上。
集群VPC下已创建两个支持ALB产品的虚拟交换机。
环境确认
若您的集群满足前提条件,集群中会自动创建出名为alb
的GatewayClass资源。您可以通过以下方式进行确认。
控制台
登录容器计算服务控制台,在左侧导航栏选择集群列表。
在集群列表页面,单击目标集群名称,然后在左侧导航栏,选择工作负载 > 自定义资源。
单击gateway.networking.k8s.io,查看v1下的GatewayClass。
kubectl
kubectl get gatewayclass
预期输出:
NAME CONTROLLER ACCEPTED AGE
alb gateways.alibabacloud.com/alb/v1 True 1m
部署示例应用
创建httpbin.yaml。
apiVersion: apps/v1 kind: Deployment metadata: name: go-httpbin namespace: default spec: replicas: 1 selector: matchLabels: app: go-httpbin template: metadata: labels: app: go-httpbin version: v1 spec: containers: - image: registry.cn-hangzhou.aliyuncs.com/mse/go-httpbin args: - "--port=8090" - "--version=v1" imagePullPolicy: Always name: go-httpbin ports: - containerPort: 8090 --- apiVersion: v1 kind: Service metadata: name: go-httpbin namespace: default spec: type: ClusterIP ports: - port: 80 targetPort: 8090 protocol: TCP selector: app: go-httpbin
部署应用。
kubectl apply -f httpbin.yaml
部署Gateway和路由
创建gateway.yaml。
apiVersion: gateway.networking.k8s.io/v1 kind: Gateway metadata: name: alb namespace: default spec: gatewayClassName: alb listeners: - name: http protocol: HTTP port: 80 hostname: "*.ingress.top" allowedRoutes: namespaces: from: Same --- apiVersion: gateway.networking.k8s.io/v1beta1 kind: HTTPRoute metadata: name: demo-route spec: parentRefs: # 引用Gateway资源 - group: gateway.networking.k8s.io kind: Gateway name: alb hostnames: - demo.ingress.top # host设置为demo.domain.ingress.top rules: - matches: # 匹配规则为前缀匹配路径 - path: type: PathPrefix value: / backendRefs: # 后端为类型为Service,名称go-httpbin,端口80 - kind: Service name: go-httpbin port: 80
部署Gateway和路由规则。
kubectl apply -f gateway.yaml
等待约2分钟后,确认Gateway创建状态。
kubectl get gateway alb
预期输出:
NAME CLASS ADDRESS PROGRAMMED AGE alb alb alb-0mwhq4ck6xxxxxxxxx.cn-hangzhou.alb.aliyuncsslb.com True 2m12s
可以看到,Gateway创建成功。
确认路由创建状态。
kubectl describe httproute demo-route|grep Status -A 20
预期输出:
Status: Parents: Conditions: Last Transition Time: 2025-05-23T08:21:25Z Message: Route is accepted. Observed Generation: 1 Reason: Accepted Status: True Type: Accepted Last Transition Time: 2025-05-23T08:21:25Z Message: Route is resolved. Observed Generation: 1 Reason: ResolvedRefs Status: True Type: ResolvedRefs Controller Name: gateways.alibabacloud.com/alb/v1 Parent Ref: Group: gateway.networking.k8s.io Kind: Gateway Name: alb
测试访问应用。
获取Gateway地址。
export ALB_DOMAIN=$(kubectl get gateway alb -n default -o jsonpath='{.status.addresses[?(@.type=="Hostname")].value}')
访问应用。
curl -H "Host: demo.ingress.top" http://${ALB_DOMAIN}/version
预期输出:
version: v1 hostname: go-httpbin-547xxxxxf6-xxxxx
场景演示
场景一:使用filter修改请求头
通过HTTPRoute中的filter能力,可以在请求或者回复阶段进行额外的处理。以下演示如何使用filter来为发送到后端的请求添加请求头。
创建httproute-filter.yaml。
apiVersion: gateway.networking.k8s.io/v1beta1 kind: HTTPRoute metadata: name: demo-filter spec: parentRefs: # 引用Gateway资源 - group: gateway.networking.k8s.io kind: Gateway name: alb hostnames: - filter.ingress.top # host设置为filter.ingress.top rules: - matches: # 匹配规则为前缀匹配路径 - path: type: PathPrefix value: / filters: - type: RequestHeaderModifier # 添加请求头my-header: foo requestHeaderModifier: add: - name: my-header value: foo backendRefs: # 后端为类型为Service,名称go-httpbin,端口80 - kind: Service name: go-httpbin port: 80
此文件将创建一个名为
demo-filter
的HTTPRoute资源。部署后访问应用go-httpbin时,配置域名为filter.ingress.top
,请求将自动添加请求头my-header : foo
。部署路由规则。
kubectl apply -f httproute-filter.yaml
访问应用。
curl -H "Host: filter.ingress.top" http://${ALB_DOMAIN}/header
预期输出:
headers: { "Accept": [ "*/*" ], "Connection": [ "close" ], "Host": [ "filter.ingress.top" ], "My-Header": [ "foo" ], "Path": [ "/header" ], "Protocol": [ "HTTP/1.1" ], "Remoteip": [ "118.xx.xx.91" ], "URL": [ "/header" ], "User-Agent": [ "curl/8.9.1" ] } query param: , hostname: go-httpbin-547xxxxxf6-xxxxx
场景二:按照权重对流量进行切分
通过设置后端多个服务的权重,您可以对请求按照流量进行切分。
创建nginx.yaml。
上述文件将部署两个nginx应用。其中,
old-nginx
服务会返回old
字符串,new-nginx
服务会返回new
字符串。部署的资源将会放置在default
命名空间下。创建httproute-weight.yaml。
apiVersion: gateway.networking.k8s.io/v1beta1 kind: HTTPRoute metadata: name: demo-weight spec: parentRefs: # 引用Gateway资源 - group: gateway.networking.k8s.io kind: Gateway name: alb hostnames: - weight.ingress.top # host设置为weight.ingress.top rules: - matches: # 匹配规则为前缀匹配路径 - path: type: PathPrefix value: / backendRefs: # 设置后端以及对应权重,权重不为百分比形式,无需等于100 - kind: Service name: old-nginx port: 80 weight: 100 # 设置old-nginx的权重为100 - kind: Service name: new-nginx port: 80 weight: 100 # 设置new-nginx的权重为100
此路由规则中设置了
old-nginx
服务和new-nginx
服务的权重相同,因此访问应用时new-nginx
和old-nginx
两个服务的流量应该是1:1。部署应用和路由规则。
kubectl apply -f nginx.yaml kubectl apply -f httproute-weight.yaml
访问10次应用。
for i in {1..10}; do curl -H "Host: weight.ingress.top" http://${ALB_DOMAIN}/; done
预期输出:
old new new old new old old new new old
可以看到,
new-nginx
和old-nginx
两个服务的流量是1:1。
相关操作
为应用配置证书
您可以在Gateway资源上为应用配置TLS证书。
创建域名为
ingress.tap
的自签名证书。openssl req -subj '/CN=ingress.top' -new -newkey rsa:2048 -sha256 \ -days 365 -nodes -x509 -keyout server.key -out server.crt \ -addext "subjectAltName = DNS:ingress.top" \ -addext "keyUsage = digitalSignature" \ -addext "extendedKeyUsage = serverAuth" 2> /dev/null; openssl x509 -in server.crt -subject -noout
创建TLS Secret。
kubectl create secret tls ingress.top --key server.key --cert server.crt
创建gateway-tls.yaml用于更新Gateway。
apiVersion: gateway.networking.k8s.io/v1 kind: Gateway metadata: name: alb namespace: default spec: gatewayClassName: alb listeners: - name: http protocol: HTTP port: 80 hostname: "*.ingress.top" allowedRoutes: namespaces: from: Same - name: https protocol: HTTPS port: 443 hostname: "*.ingress.top" allowedRoutes: namespaces: from: Same tls: # 配置TLS mode: Terminate certificateRefs: # 引用所创建的secret - kind: Secret name: ingress.top
更新Gateway。
gateway.gateway.networking.k8s.io/alb configured
等待Gateway的Programmed状态为True后,验证证书配置。
openssl s_client -servername ingress.top -connect ${ALB_DOMAIN}:443
预期输出:
CONNECTED(00000003) depth=0 CN = ingress.top verify error:num=18:self-signed certificate verify return:1 depth=0 CN = ingress.top verify return:1 --- Certificate chain 0 s:CN = ingress.top i:CN = ingress.top a:PKEY: rsaEncryption, 2048 (bit); sigalg: RSA-SHA256 v:NotBefore: Jun 24 10:49:39 2025 GMT; NotAfter: Jun 24 10:49:39 2026 GMT --- Server certificate -----BEGIN CERTIFICATE----- ... ... ... -----END CERTIFICATE----- subject=CN = ingress.top issuer=CN = ingress.top --- No client certificate CA names sent Peer signing digest: SHA256 Peer signature type: RSA-PSS Server Temp Key: X25519, 253 bits --- SSL handshake has read 1506 bytes and written 410 bytes Verification error: self-signed certificate --- New, TLSv1.2, Cipher is ECDHE-RSA-AES128-GCM-SHA256 Server public key is 2048 bit Secure Renegotiation IS supported Compression: NONE Expansion: NONE No ALPN negotiated SSL-Session: Protocol : TLSv1.2 Cipher : ECDHE-RSA-AES128-GCM-SHA256 Session-ID: xxxxxxxxxxxxxxxxxxxxxxxxx Session-ID-ctx: Master-Key: xxxxxxxxxxxxxxxxxxxxxxxxxxx PSK identity: None PSK identity hint: None SRP username: None TLS session ticket lifetime hint: 300 (seconds) TLS session ticket: ... ... ... Start Time: 1750820008 Timeout : 7200 (sec) Verify return code: 18 (self-signed certificate) Extended master secret: yes ---
出现类似以上输出内容,表明证书已经生效。
说明您可以执行
curl -H "Host: demo.ingress.top" -k https://${ALB_DOMAIN}/version
来访问应用,预期输出与测试访问应用相同。