本文档将通过一个实际示例,引导您部署内部多集群 Gateway,以将 VPC 网络内的流量路由到在两个不同的 GKE 集群中运行的应用。
多集群网关提供了一种强大的方式来管理部署在多个 GKE 集群中的服务的流量。借助 Google 的全球负载均衡基础架构,您可以为应用创建一个统一的入口点,从而简化管理并提高可靠性。在本教程中,您将使用示例 store 应用来模拟以下现实场景:在线购物服务由单独的团队拥有和运营,并且跨共享 GKE 集群舰队进行部署。
准备工作
多集群 Gateway 需要一些环境准备才能部署。在继续操作之前,请按照为多集群 Gateway 准备环境 中的步骤操作:
最后,请先查看 GKE Gateway Controller 的限制和已知问题,然后才可在环境中使用该控制器。
跨区域部署内部多集群网关
您可以部署多集群 Gateway,以在多个区域中的 GKE 集群之间提供内部第 7 层负载均衡。这些网关使用 gke-l7-cross-regional-internal-managed-mc GatewayClass。此 GatewayClass 会预配由 Google Cloud 管理的跨区域内部应用负载平衡器,并启用 VPC 网络中的客户端可以访问的内部 VIP。只需使用网关请求这些区域中的地址,即可通过所选区域中的前端公开这些网关。内部 VIP 可以是单个 IP 地址,也可以是多个区域中的 IP 地址,每个区域中有一个 IP 地址在网关中指定。流量会定向到距离最近且健康状况良好并可处理请求的后端 GKE 集群。
前提条件
通过使用项目 ID 配置
gcloud环境来设置项目和 shell:export PROJECT_ID="YOUR_PROJECT_ID" gcloud config set project ${PROJECT_ID}在不同区域中创建 GKE 集群。
此示例使用了两个集群,即
us-west1中的gke-west-1和us-east1中的gke-east-1。确保已启用 Gateway API (--gateway-api=standard),并且集群已注册到舰队。gcloud container clusters create gke-west-1 \ --location=us-west1-a \ --workload-pool=${PROJECT_ID}.svc.id.goog \ --project=${PROJECT_ID} \ --enable-fleet \ --gateway-api=standard gcloud container clusters create gke-east-1 \ --location=us-east1-c \ --workload-pool=${PROJECT_ID}.svc.id.goog \ --project=${PROJECT_ID} \ --enable-fleet \ --gateway-api=standard重命名上下文,以便更轻松地访问:
gcloud container clusters get-credentials gke-west-1 \ --location=us-west1-a \ --project=${PROJECT_ID} gcloud container clusters get-credentials gke-east-1 \ --location=us-east1-c \ --project=${PROJECT_ID} kubectl config rename-context gke_${PROJECT_ID}_us-west1-a_gke-west-1 gke-west1 kubectl config rename-context gke_${PROJECT_ID}_us-east1-c_gke-east-1 gke-east1启用多集群服务 (MCS) 和多集群 Ingress (MCI/Gateway):
gcloud container fleet multi-cluster-services enable --project=${PROJECT_ID} # Set the config membership to one of your clusters (e.g., gke-west-1) # This cluster will be the source of truth for multi-cluster Gateway and Route resources. gcloud container fleet ingress enable \ --config-membership=projects/${PROJECT_ID}/locations/us-west1/memberships/gke-west-1 \ --project=${PROJECT_ID}配置代理专用子网。 在 GKE 集群所在的每个区域以及负载均衡器将运行的每个区域中,都需要一个代理专用子网。跨区域内部应用负载均衡器要求将此子网的用途设置为
GLOBAL_MANAGED_PROXY。# Proxy-only subnet for us-west1 gcloud compute networks subnets create us-west1-proxy-only-subnet \ --purpose=GLOBAL_MANAGED_PROXY \ --role=ACTIVE \ --region=us-west1 \ --network=default \ --range=10.129.0.0/23 # Choose an appropriate unused CIDR range # Proxy-only subnet for us-east1 gcloud compute networks subnets create us-east1-proxy-only-subnet \ --purpose=GLOBAL_MANAGED_PROXY \ --role=ACTIVE \ --region=us-east1 \ --network=default \ --range=10.130.0.0/23 # Choose an appropriate unused CIDR range如果您未使用默认网络,请将
default替换为您的 VPC 网络名称。确保 CIDR 范围具有唯一性,并且不重叠。将演示应用(例如
store)部署到两个集群。gke-networking-recipes中的示例store.yaml文件会创建一个store命名空间和一个部署。kubectl apply --context gke-west1 -f https://raw.githubusercontent.com/GoogleCloudPlatform/gke-networking-recipes/main/gateway/gke-gateway-controller/multi-cluster-gateway/store.yaml kubectl apply --context gke-east1 -f https://raw.githubusercontent.com/GoogleCloudPlatform/gke-networking-recipes/main/gateway/gke-gateway-controller/multi-cluster-gateway/store.yaml通过在每个集群中创建 Kubernetes
Service资源和ServiceExport资源,从每个集群导出服务,从而使服务可在整个舰队中被发现。 以下示例从每个集群导出通用store服务和特定于区域的服务(store-west-1、store-east-1),所有这些服务都位于store命名空间内。应用于
gke-west1。cat << EOF | kubectl apply --context gke-west1 -f - apiVersion: v1 kind: Service metadata: name: store namespace: store spec: selector: app: store ports: - port: 8080 targetPort: 8080 --- kind: ServiceExport apiVersion: net.gke.io/v1 metadata: name: store namespace: store --- apiVersion: v1 kind: Service metadata: name: store-west-1 # Specific to this cluster namespace: store spec: selector: app: store ports: - port: 8080 targetPort: 8080 --- kind: ServiceExport apiVersion: net.gke.io/v1 metadata: name: store-west-1 # Exporting the region-specific service namespace: store EOF应用于
gke-east1。cat << EOF | kubectl apply --context gke-east1 -f - apiVersion: v1 kind: Service metadata: name: store namespace: store spec: selector: app: store ports: - port: 8080 targetPort: 8080 --- kind: ServiceExport apiVersion: net.gke.io/v1 metadata: name: store namespace: store --- apiVersion: v1 kind: Service metadata: name: store-east-1 # Specific to this cluster namespace: store spec: selector: app: store ports: - port: 8080 targetPort: 8080 --- kind: ServiceExport apiVersion: net.gke.io/v1 metadata: name: store-east-1 # Exporting the region-specific service namespace: store EOF检查 ServiceImports: 验证是否在
store命名空间内的每个集群中都创建了ServiceImport资源。创建这些实例可能需要几分钟时间。bash kubectl get serviceimports --context gke-west1 -n store kubectl get serviceimports --context gke-east1 -n store您应该会看到store、store-west-1和store-east-1列出(或根据传播情况显示相关条目)。
配置内部多区域网关
定义引用 gke-l7-cross-regional-internal-managed-mc GatewayClass 的 Gateway 资源。您需要将此清单应用于指定的配置集群,例如 gke-west-1。
您可以使用 spec.addresses 字段在特定区域中请求临时 IP 地址,也可以使用预先分配的静态 IP 地址。
如需使用临时 IP 地址,请将以下
Gateway清单另存为cross-regional-gateway.yaml:# cross-regional-gateway.yaml kind: Gateway apiVersion: gateway.networking.k8s.io/v1 metadata: name: internal-cross-region-gateway namespace: store # Namespace for the Gateway resource spec: gatewayClassName: gke-l7-cross-regional-internal-managed-mc addresses: # Addresses across regions. Address value is allowed to be empty or matching # the region name. - type: networking.gke.io/ephemeral-ipv4-address/us-west1 value: "us-west1" - type: networking.gke.io/ephemeral-ipv4-address/us-east1 value: "us-east1" listeners: - name: http protocol: HTTP port: 80 allowedRoutes: kinds: - kind: HTTPRoute # Only allow HTTPRoute to attach以下列表定义了上述 YAML 文件中的部分字段:
metadata.namespace:创建 Gateway 资源的命名空间,例如store。spec.gatewayClassName:GatewayClass 的名称。必须为gke-l7-cross-regional-internal-managed-mc。spec.listeners.allowedRoutes.kinds:可附加的 Route 对象的种类,例如HTTPRoute。spec.addresses:type: networking.gke.io/ephemeral-ipv4-address/REGION:请求临时 IP 地址。value:指定地址的区域,例如"us-west1"或"us-east1"。
将清单应用于配置集群,例如
gke-west1:kubectl apply --context gke-west1 -f cross-regional-gateway.yaml
将 HTTPRoute 连接到网关
定义 HTTPRoute 资源以管理流量路由,并将其应用于配置集群。
将以下
HTTPRoute清单保存为store-route.yaml:# store-route.yaml kind: HTTPRoute apiVersion: gateway.networking.k8s.io/v1 metadata: name: store-route namespace: store labels: gateway: cross-regional-internal spec: parentRefs: - name: internal-cross-region-gateway namespace: store # Namespace where the Gateway is deployed hostnames: - "store.example.internal" # Hostname clients will use rules: - matches: # Rule for traffic to /west - path: type: PathPrefix value: /west backendRefs: - group: net.gke.io # Indicates a multi-cluster ServiceImport kind: ServiceImport name: store-west-1 # Targets the ServiceImport for the west cluster port: 8080 - matches: # Rule for traffic to /east - path: type: PathPrefix value: /east backendRefs: - group: net.gke.io kind: ServiceImport name: store-east-1 # Targets the ServiceImport for the east cluster port: 8080 - backendRefs: # Default rule for other paths (e.g., /) - group: net.gke.io kind: ServiceImport name: store # Targets the generic 'store' ServiceImport (any region) port: 8080以下列表定义了上述 YAML 文件中的部分字段:
spec.parentRefs:将此路由附加到store命名空间中的internal-cross-region-gateway。spec.hostnames:表示客户端用于访问服务的主机名。spec.rules:定义路由逻辑。此示例使用基于路径的路由:/west流量路由到store-west-1ServiceImport。/east流量路由到store-east-1ServiceImport。- 所有其他流量(例如
/)都会流向通用storeServiceImport。
backendRefs:group: net.gke.io和kind: ServiceImport定位多集群服务。
将
HTTPRoute清单应用于配置集群:kubectl apply --context gke-west1 -f store-route.yaml
验证网关和路由的状态
检查网关状态:
kubectl get gateway internal-cross-region-gateway -n store -o yaml --context gke-west1查找具有以下条件的条件:
type:已编程and状态:“True”. You should see IP addresses assigned in the状态。地址field, corresponding to the regions you specified (e.g., one forus-west1and one forus-east1)。检查 HTTPRoute 状态:
kubectl get httproute store-route -n store -o yaml --context gke-west1在
status.parents[].conditions中查找具有type: Accepted(或ResolvedRefs)和status: "True"的条件。
确认流量
将 IP 地址分配给网关后,您可以测试来自客户端虚拟机的流量,该虚拟机位于您的 VPC 网络中,并且位于某个区域内,或者位于可以连接到网关 IP 地址的区域内。
检索网关 IP 地址。
以下命令尝试解析 JSON 输出。您可能需要根据确切的结构调整
jsonpath。kubectl get gateway cross-region-gateway -n store --context gke-west1 -o=jsonpath="{.status.addresses[*].value}".此命令的输出应包含 VIP,例如
VIP1_WEST或VIP2_EAST。发送测试请求: 从 VPC 中的客户端虚拟机:
# Assuming VIP_WEST is an IP in us-west1 and VIP_EAST is an IP in us-east1 # Traffic to /west should ideally be served by gke-west-1 curl -H "host: store.example.internal" http://VIP_WEST/west curl -H "host: store.example.internal" http://VIP_EAST/west # Still targets store-west-1 due to path # Traffic to /east should ideally be served by gke-east-1 curl -H "host: store.example.internal" http://VIP_WEST/east # Still targets store-east-1 due to path curl -H "host: store.example.internal" http://VIP_EAST/east # Traffic to / (default) could be served by either cluster curl -H "host: store.example.internal" http://VIP_WEST/ curl -H "host: store.example.internal" http://VIP_EAST/响应应包含
store应用的详细信息,以指明哪个后端 pod 处理了请求,例如cluster_name或zone。
使用静态 IP 地址
您可以使用预先分配的静态内部 IP 地址,而不是临时 IP 地址。
在您要使用的区域中创建静态 IP 地址:
gcloud compute addresses create cross-region-gw-ip-west --region us-west1 --subnet default --project=${PROJECT_ID} gcloud compute addresses create cross-region-gw-ip-east --region us-east1 --subnet default --project=${PROJECT_ID}如果您未使用默认子网,请将
default替换为具有您要分配的 IP 地址的子网的名称。这些子网是常规子网,而非代理专用子网。通过修改
cross-regional-gateway.yaml文件中的spec.addresses部分来更新网关清单:# cross-regional-gateway-static-ip.yaml kind: Gateway apiVersion: gateway.networking.k8s.io/v1 metadata: name: internal-cross-region-gateway # Or a new name if deploying alongside namespace: store spec: gatewayClassName: gke-l7-cross-regional-internal-managed-mc addresses: - type: networking.gke.io/named-address-with-region # Use for named static IP value: "regions/us-west1/addresses/cross-region-gw-ip-west" - type: networking.gke.io/named-address-with-region value: "regions/us-east1/addresses/cross-region-gw-ip-east" listeners: - name: http protocol: HTTP port: 80 allowedRoutes: kinds: - kind: HTTPRoute应用更新后的网关清单。
kubectl apply --context gke-west1 -f cross-regional-gateway.yaml
非默认子网的特殊注意事项
使用非默认子网时,请注意以下事项:
同一 VPC 网络:所有用户创建的资源(例如静态 IP 地址、代理专用子网和 GKE 集群)都必须位于同一 VPC 网络中。
地址子网:为网关创建静态 IP 地址时,系统会从指定区域中的常规子网分配这些地址。
集群子网命名:每个区域都必须有一个子网,其名称与 MCG 配置集群所在的子网相同。
- 例如,如果您的
gke-west-1配置集群位于projects/YOUR_PROJECT/regions/us-west1/subnetworks/my-custom-subnet中,则您要请求地址的区域也必须具有my-custom-subnet子网。如果您请求us-east1和us-centra1区域中的地址,则还必须在这些区域中存在名为my-custom-subnet的子网。
- 例如,如果您的
清理
完成本文档中的练习后,请按照以下步骤移除资源,防止您的账号产生不必要的费用:
删除集群。
如果不需要为其他目的注册集群,请从舰队中取消注册集群。
停用
multiclusterservicediscovery功能:gcloud container fleet multi-cluster-services disable停用 Multi Cluster Ingress:
gcloud container fleet ingress disable停用 API:
gcloud services disable \ multiclusterservicediscovery.googleapis.com \ multiclusteringress.googleapis.com \ trafficdirector.googleapis.com \ --project=PROJECT_ID
问题排查
内部 Gateway 的代理专用子网不存在
如果您的内部 Gateway 上出现以下事件,则该区域不存在代理专用子网。如需解决此问题,请部署代理专用子网。
generic::invalid_argument: error ensuring load balancer: Insert: Invalid value for field 'resource.target': 'regions/us-west1/targetHttpProxies/gkegw-x5vt-default-internal-http-2jzr7e3xclhj'. A reserved and active subnetwork is required in the same region and VPC as the forwarding rule.
没有健康的上行
具体情况:
创建网关但无法访问后端服务(503 响应代码)时,可能会出现以下问题:
no healthy upstream
原因:
此错误消息表示健康检查探测器找不到健康状况良好的后端服务。您的后端服务可能处于健康状况良好状态,但您可能需要自定义健康检查。
临时解决方法:
如需解决此问题,请使用 HealthCheckPolicy 根据应用的要求自定义监控状况检查(例如 /health)。
后续步骤
- 详细了解 Gateway Controller。