为外部服务配置故障转移

了解如何为网格之外的端点配置区域性负载均衡和故障转移。

2021 年 6 月 4 日 | 作者:Ram Vennam - Solo.io

Istio 的强大 API 可用于解决各种服务网格用例。许多用户了解其强大的入口和东西向功能,但它还提供许多用于出口(出站)流量的功能。这在您的应用程序需要与外部服务进行通信时特别有用 - 例如由云提供商提供的数据库端点。根据您的工作负载运行位置,通常有多个端点可供选择。例如,亚马逊的 DynamoDB 在其各区域提供 多个端点。您通常希望选择最靠近您工作负载的端点以降低延迟,但您可能需要配置自动故障转移到另一个端点,以防情况不如预期。

与在服务网格内部运行的服务类似,您可以配置 Istio 来检测异常值并将流量转移到健康端点,同时对您的应用程序保持完全透明。在本示例中,我们将使用亚马逊 DynamoDB 端点,并选择一个与在 Google Kubernetes Engine (GKE) 集群中运行的工作负载相同或接近的区域。我们还将配置一个故障转移区域。

路由端点
主端点http://dynamodb.us-east-1.amazonaws.com
故障转移http://dynamodb.us-west-1.amazonaws.com

failover

使用 ServiceEntry 定义外部端点

区域性负载均衡 基于 regionzone 工作,这些通常从 Kubernetes 节点上设置的标签中推断。首先,确定您工作负载的位置

$ kubectl describe node | grep failure-domain.beta.kubernetes.io/region
                    failure-domain.beta.kubernetes.io/region=us-east1
                    failure-domain.beta.kubernetes.io/region=us-east1

在本示例中,GKE 集群节点在 us-east1 中运行。

接下来,创建一个 ServiceEntry,它将您要使用的端点聚合在一起。在本示例中,我们选择 mydb.com 作为主机。这是您的应用程序应配置为连接到的地址。将主端点的 locality 设置为与您的工作负载相同的区域

apiVersion: networking.istio.io/v1beta1
kind: ServiceEntry
metadata:
  name: external-svc-dns
spec:
  hosts:
  - mydb.com
  location: MESH_EXTERNAL
  ports:
  - number: 80
    name: http
    protocol: HTTP
  resolution: DNS
  endpoints:
  - address: dynamodb.us-east-1.amazonaws.com
    locality: us-east1
    ports:
      http: 80
  - address: dynamodb.us-west-1.amazonaws.com
    locality: us-west
    ports:
      http: 80

让我们部署一个 sleep 容器作为测试源来发送请求。

压缩
$ kubectl apply -f @samples/sleep/sleep.yaml@

从 sleep 容器尝试访问 http://mydb.com 5 次

$ for i in {1..5}; do kubectl exec deploy/sleep -c sleep -- curl -sS http://mydb.com; echo; sleep 2; done
healthy: dynamodb.us-east-1.amazonaws.com
healthy: dynamodb.us-west-1.amazonaws.com
healthy: dynamodb.us-west-1.amazonaws.com
healthy: dynamodb.us-east-1.amazonaws.com
healthy: dynamodb.us-east-1.amazonaws.com

您会看到 Istio 正在向两个端点发送请求。我们只想将其发送到标记为与我们的节点相同区域的端点。

为此,我们需要配置一个 DestinationRule

使用 DestinationRule 设置故障转移条件

Istio 的 DestinationRule 允许您配置负载均衡、连接池和异常值检测设置。我们可以指定用于识别端点为不健康状态并将其从负载均衡池中移除的条件。

apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
  name: mydynamodb
spec:
  host: mydb.com
  trafficPolicy:
    outlierDetection:
      consecutive5xxErrors: 1
      interval: 15s
      baseEjectionTime: 1m

上面的 DestinationRule 将端点配置为每 15 秒扫描一次,如果任何端点出现 5xx 错误代码,即使只有一次,它也会被标记为不健康状态一分钟。如果该断路器没有触发,流量将路由到与 pod 相同的区域。

如果我们再次运行 curl,我们应该看到流量始终流向 us-east1 端点。

$ for i in {1..5}; do kubectl exec deploy/sleep -c sleep -- curl -sS http://mydb.com; echo; sleep 2; done

healthy: dynamodb.us-east-1.amazonaws.com
healthy: dynamodb.us-east-1.amazonaws.com
healthy: dynamodb.us-east-1.amazonaws.com
healthy: dynamodb.us-east-1.amazonaws.com
healthy: dynamodb.us-east-1.amazonaws.com

模拟故障

接下来,让我们看看如果 us-east 端点宕机会发生什么。为了模拟这种情况,让我们修改 ServiceEntry 并将 us-east 端点设置为无效端口

apiVersion: networking.istio.io/v1beta1
kind: ServiceEntry
metadata:
  name: external-svc-dns
spec:
  hosts:
  - mydb.com
  location: MESH_EXTERNAL
  ports:
  - number: 80
    name: http
    protocol: HTTP
  resolution: DNS
  endpoints:
  - address: dynamodb.us-east-1.amazonaws.com
    locality: us-east1
    ports:
      http: 81 # INVALID - This is purposefully wrong to trigger failover
  - address: dynamodb.us-west-1.amazonaws.com
    locality: us-west
    ports:
      http: 80

再次运行 curl 显示,在无法连接到 us-east 端点后,流量会自动故障转移到我们的 us-west 区域

$ for i in {1..5}; do kubectl exec deploy/sleep -c sleep -- curl -sS http://mydb.com; echo; sleep 2; done
upstream connect error or disconnect/reset before headers. reset reason: connection failure
healthy: dynamodb.us-west-1.amazonaws.com
healthy: dynamodb.us-west-1.amazonaws.com
healthy: dynamodb.us-west-1.amazonaws.com
healthy: dynamodb.us-west-1.amazonaws.com

您可以通过运行以下命令来检查 us-east 端点的异常值状态

$ istioctl pc endpoints <sleep-pod> | grep mydb
ENDPOINT                         STATUS      OUTLIER CHECK     CLUSTER
52.119.226.80:81                 HEALTHY     FAILED            outbound|80||mydb.com
52.94.12.144:80                  HEALTHY     OK                outbound|80||mydb.com

HTTPS 故障转移

为外部 HTTPS 服务配置故障转移同样简单。您的应用程序仍然可以继续使用纯 HTTP,您可以让 Istio 代理对 HTTPS 端点执行 TLS 起始。

apiVersion: networking.istio.io/v1beta1
kind: ServiceEntry
metadata:
  name: external-svc-dns
spec:
  hosts:
  - mydb.com
  ports:
  - number: 80
    name: http-port
    protocol: HTTP
    targetPort: 443
  resolution: DNS
  endpoints:
  - address: dynamodb.us-east-1.amazonaws.com
    locality: us-east1
  - address: dynamodb.us-west-1.amazonaws.com
    locality: us-west

上面的 ServiceEntry 在端口 80 上定义了 mydb.com 服务,并将流量重定向到端口 443 上的真实 DynamoDB 端点。

apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
  name: mydynamodb
spec:
  host: mydb.com
  trafficPolicy:
    tls:
      mode: SIMPLE
    loadBalancer:
      simple: ROUND_ROBIN
      localityLbSetting:
        enabled: true
        failover:
          - from: us-east1
            to: us-west
    outlierDetection:
      consecutive5xxErrors: 1
      interval: 15s
      baseEjectionTime: 1m

DestinationRule 现在执行 TLS 起始并配置异常值检测。该规则还具有 故障转移 字段,您可以在其中指定哪些区域是故障转移目标。当您定义了多个区域时,这很有用。

总结

Istio 的 VirtualServiceDestinationRule API 提供了流量路由、故障恢复和故障注入功能,以便您可以创建弹性应用程序。ServiceEntry API 将这些功能中的许多扩展到不在您的服务网格中的外部服务。

分享此文章