为适用于 Azure Kubernetes 服务的 Istio 服务网格加载项部署流出量网关

本文介绍如何为 Azure Kubernetes 服务(AKS)群集的 Istio 服务网格加载项部署出口网关。

概述

Istio 出口网关可用作一个集中式点,用于监视和限制来自网格中的应用程序的出站流量。 借助 Istio 加载项,可以跨不同的命名空间部署多个出口网关,从而设置所选的出口网关拓扑:每个群集的出口网关、每个命名空间、每个工作负荷等。虽然 AKS 管理 Istio 加载项出口网关的预配和生命周期,但必须创建 Istio 自定义资源,以便通过出口网关路由来自网格中的应用程序的流量,并应用策略和遥测收集。

Istio 加载项流出量网关也基于静态流出量网关功能构建并且需要该功能,该功能为 Istio 流出量 Pod 分配固定的源 IP 地址前缀。 可以使用此可预测的出站 IP 范围,用于防火墙规则和其他出站流量过滤机制。 通过在静态出口网关的基础上使用 Istio 出口网关,可以应用 Istio L7、基于标识的策略和基于 IP 的限制,以实现深度防御的出口流量控制。 此外,通过 Istio 流出量网关定向出站流量允许多个工作负载通过静态流出量网关节点池路由流量,而无需直接修改这些应用程序 Pod/部署。

限制和要求

  • 每个群集最多可启用 500 个 Istio 加载项出口网关。
  • Istio 加载项流出量网关名称在每个命名空间中必须是唯一的。
  • Istio 加载项流出量网关名称必须在 1-53 个字符之间,只能由小写字母数字字符、“-”和“.”组成,并且必须以字母数字字符开头和结尾。 名称还应是有效的域名系统(DNS)名称。 用于名称验证的正则表达式为 ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
  • 仅支持在手动部署模型中使用Kubernetes 网关 API来管理与 Istio 加载项的出口流量。
  • 由于 Azure CNI Pod 子网群集当前不支持静态出口网关,因此 Pod 子网群集也不支持 Istio 加载项出口网关。

先决条件

启用 Istio 加载项

本指南假定你已按照文档的说明在 AKS 群集上启用 Istio 加载项。

更新 Azure CLI 版本

必须使用 azure-cli 版本 2.80.0 或更高版本。 运行 az --version 以查找版本 azure-cli ,然后运行 az upgrade 以升级。

启用和配置静态出口网关

按照 静态出口网关文档中 的说明在群集上启用静态出口网关、创建模式 gateway节点池和创建 StaticGatewayConfiguration 资源。

启用 Istio 流出量网关

注释

Istio 加载项流出量网关 Pod 不会计划到 gateway 节点池。 节点 gateway 池用于静态出口流量的基于 IP 的路由,并且不托管工作负荷,包括网关。 如果需要将出口网关 Pod 调度到特定节点上,请使用 azureservicemesh/istio.replica.preferred 节点标签或 AKS 系统节点。 这些 Pod 具有节点亲和性:对于标记为 100 的节点,权重偏好为 azureservicemesh/istio.replica.preferred: true;对于 AKS 系统节点(标记为 50),权重偏好为 kubernetes.azure.com/mode: system。 此配置意味着,如果找不到 azureservicemesh/istio.replica.preferred: true 标签,或者此类节点不可调度,则会改为将 Pod 调度到 AKS 系统节点上。

对于早于 asm-1-30 的修订版本,这些权重则相反:AKS 系统节点为 10050 节点为 azureservicemesh/istio.replica.preferred: true

使用 az aks mesh enable-egress-gateway 在 AKS 群集上启用 Istio 出口网关。 必须指定 Istio 流出量网关的名称以及你在StaticGatewayConfiguration步骤中创建的 的名称。 还可以指定要在其中部署 Istio 出口网关的命名空间,该网关必须与在其中创建的命名空间 StaticGatewayConfiguration 相同。 如果未指定命名空间,则将在 aks-istio-egress 命名空间中预配出口网关。

最佳做法是,在使用该网关配置启用 Istio 流出量网关之前,应等待为 StaticGatewayConfiguration 分配 egressIpPrefix

az aks mesh enable-egress-gateway --resource-group $RESOURCE_GROUP --name $CLUSTER_NAME --istio-egressgateway-name $ISTIO_EGRESS_NAME --istio-egressgateway-namespace $ISTIO_EGRESS_NAMESPACE --gateway-configuration-name $ISTIO_SGC_NAME

验证是否已为流出量网关创建服务。

kubectl get svc $ISTIO_EGRESS_NAME -n $ISTIO_EGRESS_NAMESPACE

应会看到流出量网关的 ClusterIP 服务:

NAME              TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)                    AGE
asm-egress-test   ClusterIP   10.0.128.17   <none>        15021/TCP,80/TCP,443/TCP   6d4h

还可以验证是否已为 Istio 流出量网关创建部署,并且流出量网关 Pod 是否已将 kubernetes.azure.com/static-gateway-configuration 批注设置为 gatewayConfigurationName

ASM_REVISION=$(az aks show -g $RESOURCE_GROUP -n $CLUSTER_NAME | jq '.serviceMeshProfile.istio.revisions[0]' | sed 's/"//g')

kubectl get deployment $ISTIO_EGRESS_NAME-$ASM_REVISION -n $ISTIO_EGRESS_NAMESPACE -o jsonpath={.spec.template.metadata.annotations."kubernetes\.azure\.com\/static-gateway-configuration"}

可以再次运行 az aks mesh enable-egress-gateway 该命令以创建另一个 Istio 出口网关。

注释

当对 Istio 加载项执行次要修订升级时,将针对新的控制平面修订为每个流出量网关创建另一个部署。

通过 Istio 流出量网关路由流量

设置 outboundTrafficPolicy.mode

默认情况下,Istio outboundTrafficPolicy.mode 被设置为 ALLOW_ANY,这意味着 Envoy 将未知服务的请求直接传递处理。 作为安全最佳实践,应将 Istio outboundTrafficPolicy.mode 设置为REGISTRY_ONLY,以便 Istio 代理阻止对未添加到 Istio 服务注册表中的服务的请求。 可以将群集外部的主机使用 ServiceEntry 添加到 Istio 的服务注册表中。

可以使用 Istio 加载项outboundTrafficPolicy.mode 在网格范围内配置 ,或使用挎斗自定义资源来定位特定的命名空间或工作负载。

apiVersion: v1
kind: ConfigMap
metadata:
  name: istio-shared-configmap-asm-1-27
  namespace: aks-istio-system
data:
  mesh: |-
    outboundTrafficPolicy:
      mode: REGISTRY_ONLY

部署示例应用程序

在此示例中,我们将应用程序部署 curl 在与 Istio 加载项出口网关相同的命名空间中。 请记得使用 ISTIO_EGRESS_NAMESPACE 标签标记 istio.io/rev,以便已部署的应用程序 Pod 注入挎斗:

kubectl label namespace $ISTIO_EGRESS_NAMESPACE istio.io/rev=$ASM_REVISION

然后,部署示例应用程序:

kubectl apply -f https://raw.githubusercontent.com/istio/istio/release-1.27/samples/curl/curl.yaml -n $ISTIO_EGRESS_NAMESPACE

应会看到使用注入的挎斗容器运行 curl Pod:

NAME                                       READY   STATUS    RESTARTS   AGE
curl-5b549b49b8-bcgts                      2/2     Running   0          13s

尝试直接从curledition.cnn.com发送请求。

SOURCE_POD=$(kubectl get pod -n $ISTIO_EGRESS_NAMESPACE -l app=curl -o jsonpath={.items..metadata.name})

kubectl exec -n $ISTIO_EGRESS_NAMESPACE "$SOURCE_POD" -c curl -- curl -sSL -o /dev/null -D - http://edition.cnn.com/politics

如果将outboundTrafficPolicy.mode设置为REGISTRY_ONLY,那么curl请求应该会失败,因为你没有为ServiceEntry创建一个edition.cnn.com。 如果outboundTrafficPolicy.modeALLOW_ANY,则请求应成功。

若要将请求从 edition.cnn.com Pod 实际路由至 curl Istio 插件出口网关,需创建ServiceEntry并配置其他 Istio 自定义资源。 按照后续部分之一的说明配置 HTTP 出口网关HTTPS 出口网关源自传输层安全性(TLS)连接的出口网关

在启动以下任一方案之前,请设置以下环境变量:

ISTIO_EGRESS_DEPLOYMENT=$ISTIO_EGRESS_NAME-$ASM_REVISION
EGRESS_GTW_SELECTOR=$(kubectl get deployment $ISTIO_EGRESS_DEPLOYMENT -n $ISTIO_EGRESS_NAMESPACE -o jsonpath={.metadata.labels.istio})

还可以通过 MeshConfigTelemetry API启用 Envoy 访问日志记录。 启用访问日志记录后,可以通过检查 istio-proxy 容器日志来验证流量是否流经出口网关:

kubectl logs -l istio=$EGRESS_GTW_SELECTOR -n $ISTIO_EGRESS_NAMESPACE

配置 HTTP Istio 出口网关

  1. ServiceEntry 创建 edition.cnn.com
kubectl apply -n $ISTIO_EGRESS_NAMESPACE -f - <<EOF
apiVersion: networking.istio.io/v1
kind: ServiceEntry
metadata:
  name: cnn
spec:
  hosts:
  - edition.cnn.com
  ports:
  - number: 80
    name: http-port
    protocol: HTTP
  - number: 443
    name: https
    protocol: HTTPS
  resolution: DNS
EOF
  1. GatewayVirtualServiceDestinationRule创建为出口网关,通过它将 HTTP 流量从curl应用程序路由到edition.cnn.com。 请务必根据流出量网关部署中的 istio 标签选择器相应地设置网关选择器和服务完全限定的域名 (FQDN)。
kubectl apply -n $ISTIO_EGRESS_NAMESPACE -f - <<EOF
apiVersion: networking.istio.io/v1
kind: Gateway
metadata:
  name: istio-egressgateway
spec:
  selector:
    istio: $EGRESS_GTW_SELECTOR
  servers:
  - port:
      number: 80
      name: http
      protocol: HTTP
    hosts:
    - edition.cnn.com
---
apiVersion: networking.istio.io/v1
kind: DestinationRule
metadata:
  name: egressgateway-for-cnn
spec:
  host: $ISTIO_EGRESS_NAME.$ISTIO_EGRESS_NAMESPACE.svc.cluster.local
  subsets:
  - name: cnn
---
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
  name: direct-cnn-through-egress-gateway
spec:
  hosts:
  - edition.cnn.com
  gateways:
  - istio-egressgateway
  - mesh
  http:
  - match:
    - gateways:
      - mesh
      port: 80
    route:
    - destination:
        host: $ISTIO_EGRESS_NAME.$ISTIO_EGRESS_NAMESPACE.svc.cluster.local
        subset: cnn
        port:
          number: 80
      weight: 100
  - match:
    - gateways:
      - istio-egressgateway
      port: 80
    route:
    - destination:
        host: edition.cnn.com
        port:
          number: 80
      weight: 100
EOF
  1. 尝试将 HTTP 请求从 curl Pod 发送到 edition.cnn.com
kubectl exec -n $ISTIO_EGRESS_NAMESPACE "$SOURCE_POD" -c curl -- curl -sSL -o /dev/null -D - http://edition.cnn.com/politics

应会看到 HTTP/2 200 响应。

  1. 清理资源
kubectl delete serviceentry cnn -n $ISTIO_EGRESS_NAMESPACE
kubectl delete gateway istio-egressgateway -n $ISTIO_EGRESS_NAMESPACE
kubectl delete virtualservice direct-cnn-through-egress-gateway -n $ISTIO_EGRESS_NAMESPACE
kubectl delete destinationrule egressgateway-for-cnn -n $ISTIO_EGRESS_NAMESPACE

配置 HTTPS Istio 出口网关

  1. ServiceEntry 创建 HTTPS edition.cnn.com
kubectl apply -n $ISTIO_EGRESS_NAMESPACE -f - <<EOF
apiVersion: networking.istio.io/v1
kind: ServiceEntry
metadata:
  name: cnn
spec:
  hosts:
  - edition.cnn.com
  ports:
  - number: 443
    name: tls
    protocol: TLS
  resolution: DNS
EOF
  1. GatewayVirtualServiceDestinationRule创建为出口网关,通过它将 HTTP 流量从curl应用程序路由到edition.cnn.com。 请务必根据流出量网关部署中的 istio 标签选择器相应地设置网关选择器和服务 FQDN。
kubectl apply -n $ISTIO_EGRESS_NAMESPACE -f - <<EOF
apiVersion: networking.istio.io/v1
kind: Gateway
metadata:
  name: istio-egressgateway
spec:
  selector:
    istio: $EGRESS_GTW_SELECTOR
  servers:
  - port:
      number: 443
      name: tls
      protocol: TLS
    hosts:
    - edition.cnn.com
    tls:
      mode: PASSTHROUGH
---
apiVersion: networking.istio.io/v1
kind: DestinationRule
metadata:
  name: egressgateway-for-cnn
spec:
  host: $ISTIO_EGRESS_NAME.$ISTIO_EGRESS_NAMESPACE.svc.cluster.local
  subsets:
  - name: cnn
---
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
  name: direct-cnn-through-egress-gateway
spec:
  hosts:
  - edition.cnn.com
  gateways:
  - mesh
  - istio-egressgateway
  tls:
  - match:
    - gateways:
      - mesh
      port: 443
      sniHosts:
      - edition.cnn.com
    route:
    - destination:
        host: $ISTIO_EGRESS_NAME.$ISTIO_EGRESS_NAMESPACE.svc.cluster.local
        subset: cnn
        port:
          number: 443
  - match:
    - gateways:
      - istio-egressgateway
      port: 443
      sniHosts:
      - edition.cnn.com
    route:
    - destination:
        host: edition.cnn.com
        port:
          number: 443
      weight: 100
EOF
  1. 尝试从curl发送 HTTPS 请求到edition.cnn.com
kubectl exec "$SOURCE_POD" -n $ISTIO_EGRESS_NAMESPACE -c curl -- curl -sSL -o /dev/null -D - https://edition.cnn.com/politics

应会看到 HTTP/2 200 响应。

  1. 清理资源
kubectl delete serviceentry cnn -n $ISTIO_EGRESS_NAMESPACE
kubectl delete gateway istio-egressgateway -n $ISTIO_EGRESS_NAMESPACE
kubectl delete virtualservice direct-cnn-through-egress-gateway -n $ISTIO_EGRESS_NAMESPACE
kubectl delete destinationrule egressgateway-for-cnn -n $ISTIO_EGRESS_NAMESPACE

配置 Istio 出口网关以执行 TLS 始发功能。

  1. ServiceEntry 创建 edition.cnn.com
kubectl apply -n $ISTIO_EGRESS_NAMESPACE -f - <<EOF
apiVersion: networking.istio.io/v1
kind: ServiceEntry
metadata:
  name: cnn
spec:
  hosts:
  - edition.cnn.com
  ports:
  - number: 80
    name: http
    protocol: HTTP
  - number: 443
    name: https
    protocol: HTTPS
  resolution: DNS
EOF
  1. 创建GatewayVirtualServiceDestinationRule,用于将来自curl应用程序的 HTTP 流量通过出口网关路由至edition.cnn.com,并在出口网关执行 TLS 发起。 请务必根据流出量网关部署中的 istio 标签选择器相应地设置网关选择器和服务 FQDN。
kubectl apply -n $ISTIO_EGRESS_NAMESPACE -f - <<EOF
apiVersion: networking.istio.io/v1
kind: Gateway
metadata:
  name: istio-egressgateway
spec:
  selector:
    istio: $EGRESS_GTW_SELECTOR
  servers:
  - port:
      number: 80
      name: https-port-for-tls-origination
      protocol: HTTPS
    hosts:
    - edition.cnn.com
    tls:
      mode: ISTIO_MUTUAL
---
apiVersion: networking.istio.io/v1
kind: DestinationRule
metadata:
  name: egressgateway-for-cnn
spec:
  host: $ISTIO_EGRESS_NAME.$ISTIO_EGRESS_NAMESPACE.svc.cluster.local
  subsets:
  - name: cnn
    trafficPolicy:
      loadBalancer:
        simple: ROUND_ROBIN
      portLevelSettings:
      - port:
          number: 80
        tls:
          mode: ISTIO_MUTUAL
          sni: edition.cnn.com
---
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
  name: direct-cnn-through-egress-gateway
spec:
  hosts:
  - edition.cnn.com
  gateways:
  - istio-egressgateway
  - mesh
  http:
  - match:
    - gateways:
      - mesh
      port: 80
    route:
    - destination:
        host: $ISTIO_EGRESS_NAME.$ISTIO_EGRESS_NAMESPACE.svc.cluster.local
        subset: cnn
        port:
          number: 80
      weight: 100
  - match:
    - gateways:
      - istio-egressgateway
      port: 80
    route:
    - destination:
        host: edition.cnn.com
        port:
          number: 443
      weight: 100
---
apiVersion: networking.istio.io/v1
kind: DestinationRule
metadata:
  name: originate-tls-for-edition-cnn-com
spec:
  host: edition.cnn.com
  trafficPolicy:
    loadBalancer:
      simple: ROUND_ROBIN
    portLevelSettings:
    - port:
        number: 443
      tls:
        mode: SIMPLE # initiates HTTPS for connections to edition.cnn.com
EOF
  1. 尝试发送请求表单curledition.cnn.com,其中出口网关执行 TLS 起始过程;
kubectl exec "${SOURCE_POD}" -n $ISTIO_EGRESS_NAMESPACE -c curl -- curl -sSL -o /dev/null -D - http://edition.cnn.com/politics

应会看到 200 状态响应。

  1. 清理资源
kubectl delete serviceentry cnn -n $ISTIO_EGRESS_NAMESPACE
kubectl delete gateway istio-egressgateway -n $ISTIO_EGRESS_NAMESPACE
kubectl delete virtualservice direct-cnn-through-egress-gateway -n $ISTIO_EGRESS_NAMESPACE
kubectl delete destinationrule originate-tls-for-edition-cnn-com -n $ISTIO_EGRESS_NAMESPACE
kubectl delete destinationrule egressgateway-for-cnn -n $ISTIO_EGRESS_NAMESPACE

禁用 Istio 流出量网关

运行 az aks mesh disable-egress-gateway 命令以禁用创建的 Istio 加载项流出量网关:

az aks mesh disable-egress-gateway --resource-group $RESOURCE_GROUP --name $CLUSTER_NAME --istio-egressgateway-name $ISTIO_EGRESS_NAME --istio-egressgateway-namespace $ISTIO_EGRESS_NAMESPACE

禁用 Istio 流出量网关后,应能够删除流出量网关正在使用的 StaticGatewayConfiguration、命名空间和 gateway 节点池(如果没有其他 Istio 流出量网关使用它们)。

后续步骤

注释

如果在部署 Istio 出口网关或配置出口流量路由时遇到问题,请参阅 有关排查 Istio 加载项出口网关问题的文章