Private Service Connect 的综合健康状况

1. 简介

此 Codelab 探讨了 Private Service Connect (PSC) 的复合健康状况,以实现自动区域故障切换。PSC 的复合健康状况是一项网络功能,可提高服务弹性和可用性。

借助综合健康状况,服务提供方可以定义自定义健康状况政策(状态定义了健康或不健康的服务),并自动将这些信号传播给通过 PSC 后端连接到服务的使用方。此功能专门用于支持自动跨区域故障切换。如果区域性提供方服务运行状况不佳,使用方负载平衡器会自动停止将流量路由到该区域,并将流量定向到另一区域中运行状况良好的服务。

与之前的跨区域故障切换方法(例如离群值检测)相比,复合健康状况可提供更准确的故障切换信号,因为它直接基于提供方服务后端(虚拟机实例组或网络端点)的汇总健康状况。提供方可以定义自己的健康状况逻辑,确保只有在服务真正满足必要的健康状况条件时,提供方才会接收流量。

学习内容

  • 复合健康状况的组成部分及其如何协同工作以确定生产者服务的健康状态
  • 使用 gcloud 命令为生产者服务实现 PSC 的复合健康状况
  • 配置跨区域 PSC 使用方访问负载平衡器,以使用提供方综合健康状况政策中的健康信号
  • 测试服务故障场景并验证自动跨区域故障切换

所需条件

  • Google Cloud 项目
  • 授予预定义 roles/compute.admin 角色或广泛的基本角色(例如 roles/admin 或旧版 roles/owner)的 IAM 权限
  • 熟悉 Google Cloud 网络概念并会使用 Google Cloud CLI

2. 概念

PSC 网络

此 Codelab 网络拓扑包含两个有效 Google Cloud 区域中的使用方和提供方 VPC 网络。

使用方侧具有区域级子网,其中包含用于通过跨区域内部应用负载平衡器(具有 PSC 网络端点组 [NEG] 后端)访问提供方服务的客户端虚拟机实例。有两个区域级负载平衡器转发规则,具有区域级 IP 地址,用于全球(跨区域)客户端入站流量。后端服务是全球资源,支持跨不同区域的 NEG。在故障切换场景中,连接到任一区域级前端转发规则的客户端都可以被定向到正常的全球后端。

figure1

图 1. Codelab 网络拓扑

生产者端具有区域级子网,其中包含区域级内部直通式网络负载平衡器,可通过区域级 PSC 服务附件资源公开服务。后端服务包含区域级受管实例组 (MIG),并通过探测 http 请求和验证 200 (OK) 响应来检查健康状况

请参阅有关 Private Service Connect 兼容性的最新文档,了解提供方配置,查看哪些负载平衡器支持 PSC 的复合健康状况。

服务健康状况

在创建负载平衡器期间配置的提供方后端服务健康检查可作为 PSC 功能的复合健康状况的初始信号。健康状况来源资源会使用该信号以及健康状况汇总政策资源中定义的其他限制来确定单个后端服务的健康状态

默认情况下,当同时满足以下两个限制条件时,服务会被视为运行状况良好:

  • 至少有 x% 的后端健康状况良好(默认值为 60
  • 至少有 y 个后端处于健康状态(默认值为 1

复合健康检查会引用所有后端服务的所有健康状况来源,以确定整个区域级提供方服务的总体健康状况。在本实验中,每个区域级提供方服务只有一个后端服务健康状况来源,该来源会汇总到一项复合健康检查中。

figure2

图 2. PSC 资源模型的复合健康状况

综合健康检查资源定义还引用了提供方服务负载平衡器的转发规则。使用方访问负载平衡器后端 PSC NEG 在逻辑上连接到提供方 PSC 服务连接和提供方负载平衡器转发规则。这会将使用方访问负载平衡器与提供方服务综合健康检查状态相关联。然后,区域提供方服务的总体服务健康状况会传播到使用方负载平衡器,以进行适当的后端选择。

3. 项目设置

访问您的项目

此 Codelab 旨在让您使用单个 Google Cloud 项目。配置步骤使用 gcloud 和 Linux shell 命令。

注意:在生产部署中,PSC 使用方资源和提供方服务通常位于不同的项目中。

首先,使用以下命令访问 Google Cloud 云项目命令行:

设置项目 ID

gcloud config set project YOUR_PROJECT_ID_HERE

设置 shell 环境变量

export PROJECT_ID=$(gcloud config list --format="value(core.project)")
export REGION_1="us-west1"
export ZONE_1="us-west1-c"
export REGION_2="us-east1"
export ZONE_2="us-east1-c"
echo ${PROJECT_ID}
echo ${REGION_1}
echo ${ZONE_1}
echo ${REGION_2}
echo ${ZONE_2}

启用 API 服务

gcloud services enable compute.googleapis.com
gcloud services enable dns.googleapis.com

4. 提供方服务

创建共享资源

创建网络

gcloud compute networks create vnet-producer --subnet-mode=custom

创建子网

# create subnet for service workload in region 1
gcloud compute networks subnets create subnet-foo \
  --network=vnet-producer \
  --region=${REGION_1} \
  --range=172.16.1.0/24 \
  --enable-private-ip-google-access

# create subnet for psc nat in region 1
gcloud compute networks subnets create subnet-foo-pscnat \
  --network=vnet-producer \
  --region=${REGION_1} \
  --range=192.168.1.0/29 \
  --purpose=PRIVATE_SERVICE_CONNECT
# create subnet for service workload in region 2
gcloud compute networks subnets create subnet-bar \
  --network=vnet-producer \
  --region=${REGION_2} \
  --range=172.16.2.0/24 \
  --enable-private-ip-google-access

# create subnet for psc nat in region 2
gcloud compute networks subnets create subnet-bar-pscnat \
  --network=vnet-producer \
  --region=${REGION_2} \
  --range=192.168.2.0/29 \
  --purpose=PRIVATE_SERVICE_CONNECT

创建防火墙组件

需要防火墙规则来允许流量进入虚拟机资源(隐式默认防火墙规则是拒绝入站流量并允许出站流量)。政策是部署防火墙规则的首选方式,具体做法是创建网络防火墙政策资源,创建规则并将其添加到政策中,然后将政策与 VPC 网络相关联。

# create fw policy
gcloud compute network-firewall-policies create fw-policy-producer --global
# create fw policy rules
gcloud compute network-firewall-policies rules create 1001 \
  --description="allow iap for ssh" \
  --firewall-policy=fw-policy-producer \
  --global-firewall-policy \
  --action=allow \
  --direction=INGRESS \
  --layer4-configs=tcp:22  \
  --src-ip-ranges=35.235.240.0/20

gcloud compute network-firewall-policies rules create 1002 \
  --description="allow health checks" \
  --firewall-policy=fw-policy-producer \
  --global-firewall-policy \
  --action=allow \
  --direction=INGRESS \
  --layer4-configs=tcp,udp,icmp  \
  --src-ip-ranges=130.211.0.0/22,35.191.0.0/16

gcloud compute network-firewall-policies rules create 1003 \
  --description="allow psc nat clients" \
  --firewall-policy=fw-policy-producer \
  --global-firewall-policy \
  --action=allow \
  --direction=INGRESS \
  --layer4-configs=tcp:80  \
  --src-ip-ranges=192.168.1.0/29,192.168.2.0/29
# associate fw policy to vnet
gcloud compute network-firewall-policies associations create \
  --firewall-policy=fw-policy-producer \
  --network=vnet-producer \
  --name=fw-policy-association-producer \
  --global-firewall-policy

创建 Cloud Router 路由器和 NAT 网关

# create routers for nat in each region
gcloud compute routers create cr-nat-foo \
  --network=vnet-producer \
  --asn=16550 \
  --region=${REGION_1}

gcloud compute routers create cr-nat-bar \
  --network=vnet-producer \
  --asn=16550 \
  --region=${REGION_2}
# create nat gateways in each region
gcloud compute routers nats create natgw-foo \
  --router=cr-nat-foo \
  --region=${REGION_1} \
  --auto-allocate-nat-external-ips \
  --nat-all-subnet-ip-ranges

gcloud compute routers nats create natgw-bar \
  --router=cr-nat-bar \
  --region=${REGION_2} \
  --auto-allocate-nat-external-ips \
  --nat-all-subnet-ip-ranges

创建具有 HTTP 服务器的虚拟机启动配置

cat > vm-server-startup.sh << 'EOF'
#! /bin/bash
apt-get update
apt-get install apache2 -y
vm_hostname="$(curl -H "Metadata-Flavor:Google" \
http://169.254.169.254/computeMetadata/v1/instance/name)"
vm_zone="$(curl -H "Metadata-Flavor:Google" \
http://169.254.169.254/computeMetadata/v1/instance/zone)"
echo "Page served from: $vm_hostname in zone $vm_zone" | \
tee /var/www/html/index.html
systemctl restart apache2
EOF

在区域 1 中设置服务 foo

创建服务计算

# create managed instance group template
gcloud compute instance-templates create mig-template-foo \
  --machine-type=e2-micro \
  --network=vnet-producer \
  --region=${REGION_1} \
  --subnet=subnet-foo \
  --no-address \
  --shielded-secure-boot \
  --metadata-from-file=startup-script=vm-server-startup.sh
# create regional managed instance group
gcloud compute instance-groups managed create mig-foo \
  --region=${REGION_1} \
  --size=2 \
  --template=mig-template-foo \
  --base-instance-name=service-foo

创建服务负载平衡器组件

# create lb health check
gcloud compute health-checks create http hc-foo-http \
  --region=${REGION_1} \
  --port=80 \
  --enable-logging
# create backend service
gcloud compute backend-services create ilb-foo \
  --load-balancing-scheme=INTERNAL \
  --protocol=tcp \
  --region=${REGION_1} \
  --health-checks=hc-foo-http \
  --health-checks-region=${REGION_1}

# add managed instance group to backend service
gcloud compute backend-services add-backend ilb-foo \
  --instance-group=mig-foo \
  --instance-group-region=${REGION_1} \
  --region=${REGION_1}
# create forwarding rule
gcloud compute forwarding-rules create fr-foo \
  --region=${REGION_1} \
  --load-balancing-scheme=INTERNAL \
  --network=vnet-producer \
  --subnet=subnet-foo \
  --address=172.16.1.99 \
  --ip-protocol=TCP \
  --ports=80 \
  --backend-service=ilb-foo \
  --backend-service-region=${REGION_1} \
  --allow-global-access

发布 PSC 服务

# create psc service attachment
gcloud compute service-attachments create psc-sa-foo \
  --region=${REGION_1} \
  --target-service=projects/${PROJECT_ID}/regions/${REGION_1}/forwardingRules/fr-foo \
  --connection-preference=ACCEPT_AUTOMATIC \
  --nat-subnets=subnet-foo-pscnat

在区域 2 中设置服务 bar

创建服务计算

# create managed instance group template
gcloud compute instance-templates create mig-template-bar \
  --machine-type=e2-micro \
  --network=vnet-producer \
  --region=${REGION_2} \
  --subnet=subnet-bar \
  --no-address \
  --shielded-secure-boot \
  --metadata-from-file=startup-script=vm-server-startup.sh
# create regional managed instance group
gcloud compute instance-groups managed create mig-bar \
  --region=${REGION_2} \
  --size=2 \
  --template=mig-template-bar \
  --base-instance-name=service-bar

创建服务负载平衡器组件

# create lb health check
gcloud compute health-checks create http hc-bar-http \
  --region=${REGION_2} \
  --port=80 \
  --enable-logging
# create backend service
gcloud compute backend-services create ilb-bar \
  --load-balancing-scheme=INTERNAL \
  --protocol=tcp \
  --region=${REGION_2} \
  --health-checks=hc-bar-http \
  --health-checks-region=${REGION_2}

# add managed instance group to backend service
gcloud compute backend-services add-backend ilb-bar \
  --instance-group=mig-bar \
  --instance-group-region=${REGION_2} \
  --region=${REGION_2}
# create forwarding rule
gcloud compute forwarding-rules create fr-bar \
  --region=${REGION_2} \
  --load-balancing-scheme=INTERNAL \
  --network=vnet-producer \
  --subnet=subnet-bar \
  --address=172.16.2.99 \
  --ip-protocol=TCP \
  --ports=80 \
  --backend-service=ilb-bar \
  --backend-service-region=${REGION_2} \
  --allow-global-access

发布 PSC 服务

# create psc service attachment
gcloud compute service-attachments create psc-sa-bar \
  --region=${REGION_2} \
  --target-service=projects/${PROJECT_ID}/regions/${REGION_2}/forwardingRules/fr-bar \
  --connection-preference=ACCEPT_AUTOMATIC \
  --nat-subnets=subnet-bar-pscnat

5. 消费者访问方式

设置客户端资源

创建网络组件

# create vpc network
gcloud compute networks create vnet-consumer --subnet-mode=custom
# create client subnet in each region
gcloud compute networks subnets create subnet-client-1 \
  --network=vnet-consumer \
  --region=${REGION_1} \
  --range=10.10.1.0/24 \
  --enable-private-ip-google-access

gcloud compute networks subnets create subnet-client-2 \
  --network=vnet-consumer \
  --region=${REGION_2} \
  --range=10.10.2.0/24 \
  --enable-private-ip-google-access

消费者应用(基于代理)负载平衡器需要代理专用子网。这些子网提供了一个 IP 地址池,基于代理的负载平衡器在向后端发送流量时会使用其中的 IP 地址作为内部源地址。

# create proxy subnet in each region
gcloud compute networks subnets create subnet-proxy-1 \
  --purpose=GLOBAL_MANAGED_PROXY \
  --role=ACTIVE \
  --network=vnet-consumer \
  --region=${REGION_1} \
  --range=10.10.128.0/23

gcloud compute networks subnets create subnet-proxy-2 \
  --purpose=GLOBAL_MANAGED_PROXY \
  --role=ACTIVE \
  --network=vnet-consumer \
  --region=${REGION_2} \
  --range=10.10.130.0/23

创建防火墙组件

# create fw policy
gcloud compute network-firewall-policies create fw-policy-consumer --global
# create fw policy rules
gcloud compute network-firewall-policies rules create 1001 \
  --description="allow iap for ssh" \
  --firewall-policy=fw-policy-consumer \
  --global-firewall-policy \
  --action=allow \
  --direction=INGRESS \
  --layer4-configs=tcp:22  \
  --src-ip-ranges=35.235.240.0/20
# associate fw policy to vnet
gcloud compute network-firewall-policies associations create \
  --firewall-policy=fw-policy-consumer \
  --network=vnet-consumer \
  --name=fw-policy-association-consumer \
  --global-firewall-policy

创建负载均衡器组件

# create psc network endpoint group per region
gcloud compute network-endpoint-groups create neg-foo \
  --network-endpoint-type=private-service-connect \
  --psc-target-service=projects/${PROJECT_ID}/regions/${REGION_1}/serviceAttachments/psc-sa-foo \
  --region=${REGION_1} \
  --network=vnet-consumer \
  --subnet=subnet-client-1

gcloud compute network-endpoint-groups create neg-bar \
  --network-endpoint-type=private-service-connect \
  --psc-target-service=projects/${PROJECT_ID}/regions/${REGION_2}/serviceAttachments/psc-sa-bar \
  --region=${REGION_2} \
  --network=vnet-consumer \
  --subnet=subnet-client-2
# verify psc connections
gcloud compute network-endpoint-groups list --format="value(selfLink, pscData.pscConnectionStatus)"
# create global backend service
gcloud compute backend-services create bes-foobar \
  --load-balancing-scheme=INTERNAL_MANAGED \
  --protocol=HTTP \
  --global
# add negs to backend service
gcloud compute backend-services add-backend bes-foobar \
  --network-endpoint-group=neg-foo \
  --network-endpoint-group-region=${REGION_1} \
  --global

gcloud compute backend-services add-backend bes-foobar \
  --network-endpoint-group=neg-bar \
  --network-endpoint-group-region=${REGION_2} \
  --global
# create global url map
gcloud compute url-maps create ilb-foobar \
  --default-service=bes-foobar \
  --global
# create global target proxy
gcloud compute target-http-proxies create proxy-foobar \
  --url-map=ilb-foobar \
  --global
# create global forwarding rule for region 1
gcloud compute forwarding-rules create fr-foobar-1 \
  --load-balancing-scheme=INTERNAL_MANAGED \
  --network=vnet-consumer \
  --subnet=subnet-client-1 \
  --subnet-region=${REGION_1} \
  --address=10.10.1.99 \
  --ports=80 \
  --target-http-proxy=proxy-foobar \
  --global
# create global forwarding rule for region 2
gcloud compute forwarding-rules create fr-foobar-2 \
  --load-balancing-scheme=INTERNAL_MANAGED \
  --network=vnet-consumer \
  --subnet=subnet-client-2 \
  --subnet-region=${REGION_2} \
  --address=10.10.2.99 \
  --ports=80 \
  --target-http-proxy=proxy-foobar \
  --global

创建 DNS 记录

# create dns zone
gcloud dns managed-zones create zone-foobar \
  --description="private zone for foobar" \
  --dns-name=foobar.com \
  --networks=vnet-consumer \
  --visibility=private
# create geo dns record
gcloud dns record-sets create www.foobar.com \
  --zone=zone-foobar \
  --type=A \
  --ttl=300 \
  --routing-policy-type=GEO \
  --routing-policy-item="location=${REGION_1},rrdatas=10.10.1.99" \
  --routing-policy-item="location=${REGION_2},rrdatas=10.10.2.99"

创建计算资源

# create client vm in region 1
gcloud compute instances create client-1 \
  --machine-type=e2-micro \
  --zone=${ZONE_1} \
  --subnet=subnet-client-1 \
  --no-address \
  --shielded-secure-boot
# create client vm in region 2
gcloud compute instances create client-2 \
  --machine-type=e2-micro \
  --zone=${ZONE_2} \
  --subnet=subnet-client-2 \
  --no-address \
  --shielded-secure-boot

测试服务基准

从区域 1 中的客户端虚拟机

# send request from vm to service using hostname
gcloud compute ssh client-1 --zone=${ZONE_1} --command='
  curl -s -v www.foobar.com'
# send request from vm to load balancer forwarding rule region 1
gcloud compute ssh client-1 --zone=${ZONE_1} --command='
  curl -s 10.10.1.99'
# send request from vm to load balancer forwarding rule region 2
gcloud compute ssh client-1 --zone=${ZONE_1} --command='
  curl -s 10.10.2.99'

可选:尝试从区域 2 中的客户端虚拟机运行相同的测试:gcloud compute ssh client-2 --zone=${ZONE_2}

重点:对于通过 region-x 中的转发规则进入的客户端请求,负载平衡器的正常行为是优先选择同一 region-x 中的后端。如果所有后端资源都运行状况良好,则延迟最低的区域胜出。全局后端将故障切换到具有适当健康信号的其他区域。

但由于实际的提供方服务资源位于提供方 VPC 网络中的提供方负载平衡器后面,因此使用方负载平衡器之前无法获取这些健康信号,也就无法做出此类后端故障切换判断。PSC 健康状况通过将服务健康状况信息从提供方传播到使用方来解决此问题。

6. 健康类资源

PSC 资源的复合健康状况由提供方配置,用于表示区域级服务的总体健康状况。健康状况政策基于服务生产者为维持正常运行的服务等级而定义的适当条件。设置阈值是为了在不再满足提供方定义的条件时通知消费者进行故障切换。

在区域 1 中设置服务健康状况 foo

创建健康状况汇总政策

gcloud compute health-aggregation-policies create foo-health-policy \
  --region=${REGION_1} \
  --healthy-percent-threshold=60 \
  --min-healthy-threshold=1

创建健康状况来源

gcloud compute health-sources create foo-health-source \
  --region=${REGION_1} \
  --source-type=BACKEND_SERVICE \
  --sources=ilb-foo \
  --health-aggregation-policy=foo-health-policy

创建复合健康检查

gcloud compute composite-health-checks create foo-health-composite \
  --region=${REGION_1} \
  --health-sources=foo-health-source \
  --health-destination=projects/${PROJECT_ID}/regions/${REGION_1}/forwardingRules/fr-foo

验证服务 foo 健康状况配置

可以使用 list(和 describe)命令按区域查看健康资源配置

# show health aggregation policies
gcloud compute health-aggregation-policies list --regions=${REGION_1}

# show health sources
gcloud compute health-sources list --regions=${REGION_1}

# show composite health checks
gcloud compute composite-health-checks list --regions=${REGION_1}

在区域 2 中设置服务健康状况 bar

创建健康状况汇总政策

gcloud compute health-aggregation-policies create bar-health-policy \
  --region=${REGION_2} \
  --healthy-percent-threshold=60 \
  --min-healthy-threshold=1

创建健康状况来源

gcloud compute health-sources create bar-health-source \
  --region=${REGION_2} \
  --source-type=BACKEND_SERVICE \
  --sources=ilb-bar \
  --health-aggregation-policy=bar-health-policy

创建复合健康检查

gcloud compute composite-health-checks create bar-health-composite \
  --region=${REGION_2} \
  --health-sources=bar-health-source \
  --health-destination=projects/${PROJECT_ID}/regions/${REGION_2}/forwardingRules/fr-bar

验证服务 bar 健康状况配置

# show health aggregation policies
gcloud compute health-aggregation-policies list --regions=${REGION_2}

# show health sources
gcloud compute health-sources list --regions=${REGION_2}

# show composite health checks
gcloud compute composite-health-checks list --regions=${REGION_2}

配置部分到此结束,接下来是测试。

7. 故障切换测试

服务 foo 区域 1 健康状况不佳的场景

此方案通过停止两个虚拟机实例中的一个上的 Web 服务器,模拟区域 1 中 PSC 提供方服务 foo 的故障。

获取服务器虚拟机的详细信息

# set env var for a foo service vm name
export FOO_FAIL_NAME=$(gcloud compute instance-groups managed list-instances mig-foo \
  --limit=1 \
  --region=${REGION_1} \
  --format="value(name)")
echo ${FOO_FAIL_NAME}
# set env var for a foo service zone
export FOO_FAIL_ZONE=$(gcloud compute instance-groups managed list-instances mig-foo \
  --limit=1 \
  --region=${REGION_1} \
  --format="value(ZONE)")
echo ${FOO_FAIL_ZONE}

停止区域 1 http 服务器

# stop apache http server to fail service
gcloud compute ssh ${FOO_FAIL_NAME} --zone=${FOO_FAIL_ZONE} --command='
  sudo systemctl stop apache2'
# verify service dead
gcloud compute ssh ${FOO_FAIL_NAME} --zone=${FOO_FAIL_ZONE} --command='
  sudo systemctl status apache2 | grep Active:'

验证区域服务是否健康状况不佳

# check health state of backend service
gcloud compute backend-services get-health ilb-foo --region=${REGION_1}

输出应类似于以下内容...

backend: .../regions/us-west1/instanceGroups/mig-foo
status:
  healthStatus:
  -   forwardingRule: .../regions/us-west1/forwardingRules/fr-foo
    forwardingRuleIp: 172.16.1.99
    healthState: UNHEALTHY
    instance: .../zones/us-west1-a/instances/service-foo-<UID_1>
    ipAddress: 172.16.1.2
    port: 80
  -   forwardingRule: .../regions/us-west1/forwardingRules/fr-foo
    forwardingRuleIp: 172.16.1.99
    healthState: HEALTHY
    instance: .../zones/us-west1-b/instances/service-foo-<UID_2>
    ipAddress: 172.16.1.3
    port: 80
  kind: compute#backendServiceGroupHealth
# check health state of health source
gcloud compute health-sources get-health foo-health-source --region=${REGION_1}

输出应类似于以下内容...

healthState: UNHEALTHY
kind: compute#healthSourceHealth
sources:
- backends:
  - endpointCount: 1
    group: .../zones/us-west1-a/instanceGroups/mig-foo
    healthyEndpointCount: 0
  - endpointCount: 0
    group: .../zones/us-west1-c/instanceGroups/mig-foo
    healthyEndpointCount: 0
  - endpointCount: 1
    group: .../zones/us-west1-b/instanceGroups/mig-foo
    healthyEndpointCount: 1
  forwardingRule: .../regions/us-west1/forwardingRules/fr-foo
  source: .../regions/us-west1/backendServices/ilb-foo

测试区域 1 客户端故障切换

# send request to service using hostname
gcloud compute ssh client-1 --zone=${ZONE_1} --command='
  curl -s -v www.foobar.com'
# curl to ilb vip in region 1
gcloud compute ssh client-1 --zone=${ZONE_1} --command='
  curl -s 10.10.1.99'
# curl to ilb vip in region 2
gcloud compute ssh client-1 --zone=${ZONE_1} --command='
  curl -s 10.10.2.99'

PSC 的复合健康状况已更新使用方负载平衡器,并指示其避开区域 1 中运行状况不佳的后端服务。而是将流量定向到区域 2 中运行状况良好的服务 bar

重启区域 1 http 服务器

# start apache http server to return service to healthy
gcloud compute ssh ${FOO_FAIL_NAME} --zone=${FOO_FAIL_ZONE} --command='
  sudo systemctl start apache2'
# verify service running
gcloud compute ssh ${FOO_FAIL_NAME} --zone=${FOO_FAIL_ZONE} --command='
  sudo systemctl status apache2 | grep Active:'
# check health state of health source
gcloud compute health-sources get-health foo-health-source --region=${REGION_1}

输出现在应报告类似于以下内容的 HEALTHY 状态...

healthState: HEALTHY
kind: compute#healthSourceHealth
sources:
- backends:
  - endpointCount: 1
    group: .../zones/us-west1-a/instanceGroups/mig-foo
    healthyEndpointCount: 1
  - endpointCount: 0
    group: .../zones/us-west1-c/instanceGroups/mig-foo
    healthyEndpointCount: 0
  - endpointCount: 1
    group: .../zones/us-west1-b/instanceGroups/mig-foo
    healthyEndpointCount: 1
  forwardingRule: .../regions/us-west1/forwardingRules/fr-foo
  source: .../regions/us-west1/backendServices/ilb-foo

更改健康状况政策

生产者可以根据不同的条件调整服务健康状况政策。健康状况汇总政策资源用于指定在所有不同的健康状况来源(后端服务)中保持健康状态所需的最低阈值。

更新 bar 服务健康状况汇总政策

gcloud compute health-aggregation-policies update bar-health-policy \
  --region=${REGION_2} \
  --description="min 40% threshold" \
  --healthy-percent-threshold=40 \
  --min-healthy-threshold=2
# verify new policy is applied
gcloud compute health-aggregation-policies list --regions=${REGION_2}

生产者健康状况政策变更实现了以下目标:

  1. 将“状况良好判断阈值下限百分比”从 60% 降至 40% - 现在,单个虚拟机实例故障将不会根据 --healthy-percent-threshold 触发运行状况不佳状态(故障状态将为 50%,而只需 40% 即可达到运行状况良好状态)
  2. 将后端的最少健康数量从 1 个增加到 2 个虚拟机实例 - 现在,单个虚拟机实例故障根据 --min-healthy-threshold 触发健康状况不佳状态(故障状态将为 1,但需要 2 才能健康)

服务 bar 区域 2 健康状况不佳的场景

此方案通过停止两个虚拟机实例中的一个上的 Web 服务器,模拟区域 2 中 PSC 提供方服务 bar 的故障。

获取服务器虚拟机的详细信息

# set env var for a bar service vm name
export BAR_FAIL_NAME=$(gcloud compute instance-groups managed list-instances mig-bar \
  --limit=1 \
  --region=${REGION_2} \
  --format="value(name)")
echo ${BAR_FAIL_NAME}
# set env var for a bar service zone
export BAR_FAIL_ZONE=$(gcloud compute instance-groups managed list-instances mig-bar \
  --limit=1 \
  --region=${REGION_2} \
  --format="value(ZONE)")
echo ${BAR_FAIL_ZONE}

停止区域 2 http 服务器

# stop apache http server to fail service
gcloud compute ssh ${BAR_FAIL_NAME} --zone=${BAR_FAIL_ZONE} --command='
  sudo systemctl stop apache2'
# verify service dead
gcloud compute ssh ${BAR_FAIL_NAME} --zone=${BAR_FAIL_ZONE} --command='
  sudo systemctl status apache2 | grep Active:'

验证区域服务是否健康状况不佳

# check health state of backend service
gcloud compute backend-services get-health ilb-bar --region=${REGION_2}

输出应类似于以下内容...

backend: .../regions/us-east1/instanceGroups/mig-bar
status:
  healthStatus:
  -   forwardingRule: .../regions/us-east1/forwardingRules/fr-bar
    forwardingRuleIp: 172.16.2.99
    healthState: UNHEALTHY
    instance: .../zones/us-east1-b/instances/service-bar-<UID_1>
    ipAddress: 172.16.2.3
    port: 80
  -   forwardingRule: .../regions/us-east1/forwardingRules/fr-bar
    forwardingRuleIp: 172.16.2.99
    healthState: HEALTHY
    instance: .../zones/us-east1-d/instances/service-foo-<UID_2>
    ipAddress: 172.16.2.2
    port: 80
  kind: compute#backendServiceGroupHealth
# check health state of health source
gcloud compute health-sources get-health bar-health-source --region=${REGION_2}

输出应类似于以下内容...

healthState: UNHEALTHY
kind: compute#healthSourceHealth
sources:
- backends:
  - endpointCount: 1
    group: .../zones/us-east1-b/instanceGroups/mig-bar
    healthyEndpointCount: 0
  - endpointCount: 1
    group: .../zones/us-east1-d/instanceGroups/mig-bar
    healthyEndpointCount: 1
  - endpointCount: 0
    group: .../zones/us-east1-c/instanceGroups/mig-bar
    healthyEndpointCount: 0
  forwardingRule: .../regions/us-west1/forwardingRules/fr-bar
  source: .../regions/us-west1/backendServices/ilb-bar

测试区域 2 客户端故障切换

# send request to service using hostname
gcloud compute ssh client-2 --zone=${ZONE_2} --command='
  curl -s -v www.foobar.com'
# curl to ilb vip in region 1
gcloud compute ssh client-2 --zone=${ZONE_2} --command='
  curl -s 10.10.1.99'
# curl to ilb vip in region 2
gcloud compute ssh client-2 --zone=${ZONE_2} --command='
  curl -s 10.10.2.99'

PSC 的复合健康状况已更新使用方负载平衡器,并指示其避开区域 2 中运行状况不佳的后端服务。而是将流量定向到区域 1 中运行状况良好的服务 foo

如果使用方负载平衡器发现所有提供方服务都运行状况不佳,则负载平衡器无法故障切换到运行状况良好的实例。预期行为是负载平衡器将流量分配给所有运行状况不佳的后端(故障开放)。

测试部分到此结束,接下来是监控部分。

8. 监控健康状况

默认情况下,系统会记录健康状况变化。提供方项目可以查看健康状况来源和复合健康检查的日志。使用方项目可以查看使用复合健康状况的 PSC NEG 连接到已发布服务的日志。

虽然本实验为简单起见,将使用方和提供方资源部署在同一项目中,但如果部署在不同的项目中,日志将显示这两个角色已分离。

受监控的资源

查看

日志名称

健康状况来源和复合检查

提供方视图

.../logs/compute.googleapis.com%2Fcompositehealth

Private Service Connect NEG

“消费者”视图

.../logs/compute.googleapis.com%2Fservicehealthchecks

提供方日志

生产者日志显示了生产者服务的内部健康汇总

  • HealthSource:各个后端服务的健康状况(例如 mig-barmig-foo 的虚拟机状态)
  • CompositeHealthCheck:已发布服务的汇总区域健康状况,映射到提供方转发规则目标(例如 fr-barfr-foo
# query logs for producer
gcloud logging read \
  'logName="projects/'${PROJECT_ID}'/logs/compute.googleapis.com%2Fcompositehealth"' \
  --project=${PROJECT_ID} \
  --limit=10 \
  --format='table(
    timestamp.date(format="%I:%M:%S %p", tz=LOCAL):label=TIME,
    resource.type.basename():label=TYPE,
    resource.labels.location:label=REGION,
    jsonPayload.healthState:label=STATE,
    jsonPayload.sources[0].backends[].group.basename().join(","):label=BACKENDS,
    jsonPayload.sources[0].backends[].healthyEndpointCount.join(","):label=HEALTHY,
    jsonPayload.sources[0].backends[].endpointCount.join(","):label=TOTAL,
    jsonPayload.healthDestination.basename():label=DESTINATION
  )'

使用方日志

消费者日志显示了消费者资源的传播健康状况

  • NetworkEndpointGroup:连接到已发布服务的 PSC NEG 的传播健康状况状态(例如 neg-barneg-foo

在单独的使用方和提供方设置中,请在消费方项目中使用此日志查询来定位 PSC NEG 的复合健康状况事件...

# query logs for consumer
gcloud logging read \
  "logName=projects/${PROJECT_ID}/logs/compute.googleapis.com%2Fservicehealthchecks
  AND resource.type=\"compute.googleapis.com/NetworkEndpointGroupV2\"" \
  --project="${PROJECT_ID}" \
  --freshness=30m \
  --limit=10 \
  --format="table(
    timestamp.date(format='%I:%M:%S %p', tz=LOCAL):label=TIME,
    resource.labels.location:label=REGION,
    jsonPayload.serviceHealthCheckResult.healthState:label=STATE,
    jsonPayload.serviceHealthCheckResult.previousHealthState:label=PREV_STATE,
    resource.labels.network_endpoint_group_id:label=NEG_ID
  )"

监控部分到此结束,接下来是清理。

9. 清理

# delete health resources
gcloud -q compute composite-health-checks delete foo-health-composite --region=${REGION_1}

gcloud -q compute health-sources delete foo-health-source --region=${REGION_1}

gcloud -q compute health-aggregation-policies delete foo-health-policy --region=${REGION_1}

gcloud -q compute composite-health-checks delete bar-health-composite --region=${REGION_2}

gcloud -q compute health-sources delete bar-health-source --region=${REGION_2}

gcloud -q compute health-aggregation-policies delete bar-health-policy --region=${REGION_2}
# delete consumer compute and load balancer resources
gcloud -q compute instances delete client-2 --zone=${ZONE_2}

gcloud -q compute instances delete client-1 --zone=${ZONE_1}

gcloud -q dns record-sets delete www.foobar.com --type=A --zone=zone-foobar

gcloud -q dns managed-zones delete zone-foobar

gcloud -q compute forwarding-rules delete fr-foobar-2 --global

gcloud -q compute forwarding-rules delete fr-foobar-1 --global

gcloud -q compute target-http-proxies delete proxy-foobar --global

gcloud -q compute url-maps delete ilb-foobar --global

gcloud -q compute backend-services delete bes-foobar --global


# delete consumer network resources
gcloud -q compute network-endpoint-groups delete neg-bar --region=${REGION_2}

gcloud -q compute network-endpoint-groups delete neg-foo --region=${REGION_1}

gcloud -q compute networks subnets delete subnet-proxy-2 --region=${REGION_2}

gcloud -q compute networks subnets delete subnet-proxy-1 --region=${REGION_1}

gcloud -q compute networks subnets delete subnet-client-2 --region=${REGION_2}

gcloud -q compute networks subnets delete subnet-client-1 --region=${REGION_1}

gcloud -q compute network-firewall-policies associations delete \
  --firewall-policy=fw-policy-consumer \
  --name=fw-policy-association-consumer \
  --global-firewall-policy

gcloud -q compute network-firewall-policies delete fw-policy-consumer --global

gcloud -q compute networks delete vnet-consumer
# delete producer load balancer resources
gcloud -q compute service-attachments delete psc-sa-bar --region=${REGION_2}

gcloud -q compute service-attachments delete psc-sa-foo --region=${REGION_1}

gcloud -q compute forwarding-rules delete fr-bar --region=${REGION_2}

gcloud -q compute forwarding-rules delete fr-foo --region=${REGION_1}

gcloud -q compute backend-services delete ilb-bar --region=${REGION_2}

gcloud -q compute backend-services delete ilb-foo --region=${REGION_1}

gcloud -q compute health-checks delete hc-bar-http --region=${REGION_2}

gcloud -q compute health-checks delete hc-foo-http --region=${REGION_1}
# delete producer compute resources
gcloud -q compute instance-groups managed delete mig-bar --region=${REGION_2}

gcloud -q compute instance-groups managed delete mig-foo --region=${REGION_1}

gcloud -q compute instance-templates delete mig-template-bar --global

gcloud -q compute instance-templates delete mig-template-foo --global
# delete producer network resources
gcloud -q compute networks subnets delete subnet-bar-pscnat --region=${REGION_2}

gcloud -q compute networks subnets delete subnet-foo-pscnat --region=${REGION_1}

gcloud -q compute networks subnets delete subnet-bar --region=${REGION_2}

gcloud -q compute networks subnets delete subnet-foo --region=${REGION_1}

gcloud -q compute routers delete cr-nat-bar --region=${REGION_2}

gcloud -q compute routers delete cr-nat-foo --region=${REGION_1}

gcloud -q compute network-firewall-policies associations delete \
  --firewall-policy=fw-policy-producer \
  --name=fw-policy-association-producer \
  --global-firewall-policy

gcloud -q compute network-firewall-policies delete fw-policy-producer --global

gcloud -q compute networks delete vnet-producer
# delete shell variables and script file
unset FOO_FAIL_NAME FOO_FAIL_ZONE BAR_FAIL_NAME BAR_FAIL_ZONE

unset PROJECT_ID REGION_1 ZONE_1 REGION_2 ZONE_2

rm vm-server-startup.sh
#

10. 总结

恭喜!您已成功为 PSC 配置了复合健康状况,并测试了自动区域级故障切换!

欢迎使用此反馈表单提出任何意见、问题或更正。

谢谢!