传统实现k8s 的集群外访问的方法
当我们部署了一个web app 到k8s的pods里, 如果要实现从外部访问, 除了要创建1个clusterip 作为loadbarlancer 外, 还需要创建1个ingress 实现从外部访问 该clusterip.
但是ingress 的 创建相对繁琐, 以nginx-ingress为例, 首先要安装1个 ingress controller, 再基于此controller setup 1个ingress 对象。。。
体验并不好
什么是k8s 的gateway api?
Kubernetes Gateway API 是一个用于管理集群入口流量的高级 API。它旨在替代 Ingress API,并提供更强大、更灵活、更具扩展性的功能。
Gateway API 由 Kubernetes SIG-NETWORK 社区开发和维护。
最早版本: Gateway API 的第一个版本是 v1alpha1,于 2021 年发布。
较新版本: 目前,Gateway API 的最新版本是 v1beta1 和 v1。v1beta1 版本在 Kubernetes v1.23+ 中可用,而 v1 版本在 Kubernetes v1.28+ 中可用。
gateway api 相比于 ingress 有哪些优缺点?
如何使用 Gateway API:
安装 Gateway API CRD: 首先需要在 Kubernetes 集群中安装 Gateway API 的 Custom Resource Definitions (CRD)。
部署 Gateway Controller: Gateway Controller 负责监听 Gateway 资源,并根据配置进行流量路由。常用的 Gateway Controller 包括 Contour、Istio 和 Kong。
创建 Gateway 资源: 创建 Gateway 资源来定义监听的端口和协议。
创建 Route 资源: 创建 HTTPRoute 或 TCPRoute 等资源来定义流量路由规则。
配置 Backend: 将流量路由到后端服务。
gateway api 相比于 ingress 有哪些优缺点?
gateway api 相比于 ingress 有哪些优缺点?
Gateway API 的优点:
角色分离: Gateway API 允许集群管理员、应用开发者和服务提供商分别管理 Gateway 资源、HTTPRoute/TCPRoute 等路由资源以及后端服务,实现了更清晰的职责划分。
协议支持: 除了 HTTP(S) 之外,Gateway API 还支持 TCP、UDP 和 TLS 等协议,适用范围更广。
高级流量管理: Gateway API 提供了更丰富的流量管理功能,例如流量分割、流量镜像、请求头修改等,可以满足更复杂的业务需求。
可扩展性: Gateway API 允许自定义 GatewayClass 和 Route 类型,可以根据实际需求进行扩展。
更强的表达能力: Gateway API 使用 CRD (Custom Resource Definitions) 扩展了 Kubernetes API,允许更细粒度的配置和更强大的功能。
Gateway API 的缺点:
复杂性: Gateway API 的配置和管理比 Ingress 更加复杂,需要更多的学习成本。
生态系统: 相比于 Ingress,Gateway API 的生态系统还不够完善,支持的 Controller 较少。
成熟度: Gateway API 还是相对较新的 API,可能存在一些未知的 Bug 或问题。
GKE的gateway api
可见gateway api的首次安装甚至更复杂, 但是GKE 已经在平台Level 帮我们完全了所有繁琐的前置工作, 我们只需要直接使用就好
GKE Gateway API 支持
GKE 提供了对 Gateway API 的支持,方便你在 GKE 集群中使用 Gateway API 来管理入口流量。
GKE Gateway Controller
GKE 提供了自己的 Gateway Controller,称为 gke-l7-global-external-managed。你可以在 Gateway 资源中使用 gatewayClassName: gke-l7-global-external-managed 来指定使用 GKE 提供的 Gateway Controller。这个 Controller 实现了 Gateway API 规范,并与 GKE 的负载均衡器集成。
接下我会用1个实际例子部署和使用GKE 的gateway api.
首先我们部署两个python的web app 到GKE
py-api-svc:
https://github.com/nvd11/py-api-svc.git
root path 是/pyapi
py-webhook-svc:
https://github.com/nvd11/py-webhook-svc.git
root path 是/webhook
我们还要配置两个clusterip 作为 它们的Load balancer
部署过程省略。。。
检查部署后的资源
bash
gateman@MoreFine-S500: github$ kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
dns-test 1/1 Running 0 86m 192.171.18.9 gke-my-cluster2-node-pool1-01eff82c-1r5b <none> <none>
py-api-svc-77585759d7-6dcfs 1/1 Running 0 76m 192.171.17.13 gke-my-cluster2-node-pool1-8bb426f2-3nqn <none> 1/1
py-api-svc-77585759d7-9mdt7 1/1 Running 0 76m 192.171.16.13 gke-my-cluster2-node-pool1-6a83612b-mj40 <none> 1/1
py-api-svc-77585759d7-lf9wh 1/1 Running 0 76m 192.171.18.11 gke-my-cluster2-node-pool1-01eff82c-1r5b <none> 1/1
py-webhook-svc-78bd8646bd-9mnqv 1/1 Running 0 48s 192.171.16.15 gke-my-cluster2-node-pool1-6a83612b-mj40 <none> 1/1
py-webhook-svc-78bd8646bd-chwh9 1/1 Running 0 40s 192.171.17.15 gke-my-cluster2-node-pool1-8bb426f2-3nqn <none> 1/1
py-webhook-svc-78bd8646bd-p77k9 1/1 Running 0 54s 192.171.18.13 gke-my-cluster2-node-pool1-01eff82c-1r5b <none> 1/1
gateman@MoreFine-S500: github$ kubectl get svc -o wide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
clusterip-py-api-svc ClusterIP 192.172.26.174 <none> 8000/TCP 10h app=py-api-svc
clusterip-py-webhook-svc ClusterIP 192.172.21.174 <none> 8000/TCP 72m app=py-webhook-svc
kubernetes ClusterIP 192.172.16.1 <none> 443/TCP 47h <none>
在dns-test 容器里测试两个clusterip
bash
gateman@MoreFine-S500: github$ kubectl exec -it dns-test -- /bin/sh
/home # curl clusterip-py-api-svc:8000/pyapi/
{"message":"Hello, py-api-svc!"}/home #
/home # curl clusterip-py-webhook-svc:8000/webhook/
{"message":"Hello, webhook service!"}/home #
两个web svc 都部署好了, 接下来配置gateway
为GKE cluster enable gateway api
默认下是没有enabled的。
命令
bash
gcloud container clusters update my-cluster2 --region europe-west2 --gateway-api=standard
确认结果:
bash
(.venv) gateman@MoreFine-S500: py-webhook-svc$ kubectl get crds | grep gateway.networking.k8s.io
gatewayclasses.gateway.networking.k8s.io 2025-10-04T10:34:22Z
gateways.gateway.networking.k8s.io 2025-10-04T10:34:21Z
httproutes.gateway.networking.k8s.io 2025-10-04T10:34:22Z
referencegrants.gateway.networking.k8s.io 2025-10-04T10:34:24Z
编写一个gateway 的yaml
gateway.yaml
yaml
apiVersion: gateway.networking.k8s.io/v1beta1
kind: Gateway
metadata:
name: py-api-gateway
spec:
gatewayClassName: gke-l7-global-external-managed
listeners:
- name: http
protocol: HTTP
port: 80
allowedRoutes:
namespaces:
from: Same
---
apiVersion: gateway.networking.k8s.io/v1beta1
kind: HTTPRoute
metadata:
name: py-api-route
spec:
parentRefs:
- name: py-api-gateway
hostnames:
- "jpgcp.shop"
rules:
- matches:
- path:
type: PathPrefix
value: /pyapi
filters:
- type: URLRewrite
urlRewrite:
path:
type: ReplacePrefixMatch
replacePrefixMatch: /
backendRefs:
- name: clusterip-py-api-svc
port: 8000
- matches:
- path:
type: PathPrefix
value: /webhook
filters:
- type: URLRewrite
urlRewrite:
path:
type: ReplacePrefixMatch
replacePrefixMatch: /
backendRefs:
- name: clusterip-py-webhook-svc
port: 8000
注意这里定义了两个资源, 一个是gateway本身,另一个是其http route。
其中httproute 中根据不同的url path 转发到不同的后端svc, 这也是gateway的核心功能。
值得注意是hostname , 如果不只是为了内部测试, 建议先从go爸爸买一个dns.
部署后检查gateway资源
当执行kubectl apply 后
我们检查下创建出来的Gateway对象, 正常需要大概一分钟才会被完全初始化和分配ip
bash
gateman@MoreFine-S500: github$ kubectl describe gateway py-api-gateway
Name: py-api-gateway
Namespace: default
Labels: <none>
Annotations: networking.gke.io/addresses: /projects/912156613264/global/addresses/gkegw1-bu0s-default-py-api-gateway-jfly4jdo622c
networking.gke.io/backend-services:
/projects/912156613264/global/backendServices/gkegw1-bu0s-default-clusterip-py-api-svc-8000-iwtsiatbjn23, /projects/912156613264/global/ba...
networking.gke.io/firewalls: /projects/912156613264/global/firewalls/gkegw1-bu0s-l7-tf-vpc0-global
networking.gke.io/forwarding-rules: /projects/912156613264/global/forwardingRules/gkegw1-bu0s-default-py-api-gateway-e6c3tpani22a
networking.gke.io/health-checks:
/projects/912156613264/global/healthChecks/gkegw1-bu0s-default-clusterip-py-api-svc-8000-iwtsiatbjn23, /projects/912156613264/global/healt...
networking.gke.io/last-reconcile-time: 2025-10-04T16:03:47Z
networking.gke.io/lb-route-extensions:
networking.gke.io/lb-traffic-extensions:
networking.gke.io/ssl-certificates:
networking.gke.io/target-http-proxies: /projects/912156613264/global/targetHttpProxies/gkegw1-bu0s-default-py-api-gateway-rrnx141i3brm
networking.gke.io/target-https-proxies:
networking.gke.io/url-maps: /projects/912156613264/global/urlMaps/gkegw1-bu0s-default-py-api-gateway-rrnx141i3brm
networking.gke.io/wasm-plugin-versions:
networking.gke.io/wasm-plugins:
API Version: gateway.networking.k8s.io/v1
Kind: Gateway
Metadata:
Creation Timestamp: 2025-10-04T10:45:50Z
Finalizers:
gateway.finalizer.networking.gke.io
Generation: 1
Resource Version: 1759593827931391023
UID: 4567f1b0-0c3c-414e-b407-28b9d29c06fa
Spec:
Gateway Class Name: gke-l7-global-external-managed
Listeners:
Allowed Routes:
Namespaces:
From: Same
Name: http
Port: 80
Protocol: HTTP
Status:
Addresses:
Type: IPAddress
Value: 34.111.35.228
Conditions:
Last Transition Time: 2025-10-04T10:46:40Z
Message: The OSS Gateway API has deprecated this condition, do not depend on it.
Observed Generation: 1
Reason: Scheduled
Status: True
Type: Scheduled
Last Transition Time: 2025-10-04T10:46:40Z
Message:
Observed Generation: 1
Reason: Accepted
Status: True
Type: Accepted
Last Transition Time: 2025-10-04T16:03:47Z
Message:
Observed Generation: 1
Reason: Programmed
Status: True
Type: Programmed
Last Transition Time: 2025-10-04T16:03:47Z
Message: The OSS Gateway API has altered the "Ready" condition semantics and reserved it for future use. GKE Gateway will stop emitting it in a future update, use "Programmed" instead.
Observed Generation: 1
Reason: Ready
Status: True
Type: Ready
Last Transition Time: 2025-10-04T16:03:47Z
Message:
Observed Generation: 1
Reason: Healthy
Status: True
Type: networking.gke.io/GatewayHealthy
Listeners:
Attached Routes: 1
Conditions:
Last Transition Time: 2025-10-04T10:46:40Z
Message:
Observed Generation: 1
Reason: ResolvedRefs
Status: True
Type: ResolvedRefs
Last Transition Time: 2025-10-04T10:46:40Z
Message:
Observed Generation: 1
Reason: Accepted
Status: True
Type: Accepted
Last Transition Time: 2025-10-04T16:03:47Z
Message:
Observed Generation: 1
Reason: Programmed
Status: True
Type: Programmed
Last Transition Time: 2025-10-04T16:03:47Z
Message: The OSS Gateway API has altered the "Ready" condition semantics and reserved it for future use. GKE Gateway will stop emitting it in a future update, use "Programmed" instead.
Observed Generation: 1
Reason: Ready
Status: True
Type: Ready
Name: http
Supported Kinds:
Group: gateway.networking.k8s.io
Kind: HTTPRoute
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal SYNC 41m (x118 over 5h18m) sc-gateway-controller default/py-api-gateway
Normal SYNC 3s (x114 over 5h15m) sc-gateway-controller SYNC on default/py-api-gateway was a success
获得ip地址34.111.35.228 后, 直至使用ip地址访问是无效的,
yaml
hostnames:
- "jpgcp.shop"
httproute的hostname配置指定了只能通过hostname 访问
所以我们还需要在域名提供商那里把jpgcp.shop 跟ip 34.111.35.228 map上

测试gateway
bash
gateman@MoreFine-S500: github$ curl http://jpgcp.shop/pyapi/
{"message":"Hello, py-api-svc!"}gateman@MoreFine-S500: github$
gateman@MoreFine-S500: github$ curl http://jpgcp.shop/webhook/
{"message":"Hello, webhook service!"}gateman@MoreFine-S500: github$
完美