使用 Istio APIs 通过 gateway 路由 egress 流量

本节说明如何使用 Istio APIs,通过安装了 gateway injection 的 gateway 来路由出站 HTTP 流量。

NOTE

此方法适用于基于 sidecar 的部署。在 ambient mode 中,请改为使用 Kubernetes Gateway API 配置 egress 路由。

前提条件

操作步骤

  1. 通过执行以下命令创建一个名为 curl 的 namespace:

    kubectl create namespace curl
  2. 为该 namespace 启用 sidecar injection。如果你的环境使用 InPlace 升级策略,请运行此命令:

    kubectl label namespace curl istio-injection=enabled
    NOTE

    如果你使用的是 RevisionBased 升级策略,请执行以下命令:

    1. 要查找你的 <revision-name>,请运行以下命令:

      kubectl get istiorevisions.sailoperator.io

      示例输出:

      NAME      NAMESPACE      PROFILE   READY   STATUS    IN USE   VERSION   AGE
      default   istio-system             True    Healthy   True     v1.28.6   47h
    2. 使用 revision 名称为 namespace 添加标签,以启用 sidecar injection:

      kubectl label namespace curl istio.io/rev=default
  3. 通过运行以下命令部署 curl 应用:

    kubectl apply -n curl -f https://raw.githubusercontent.com/istio/istio/refs/heads/master/samples/curl/curl.yaml
  4. 初始化并导出一个包含 curl pod 名称的 CURL_POD 环境变量:

    export CURL_POD=$(kubectl get pod -n curl -l app=curl -o jsonpath='{.items[0].metadata.name}')
    echo "CURL_POD=$CURL_POD"
  5. 创建一个名为 http-se.yaml 的 YAML 文件,用于将流量从 mesh 引导到外部服务。下面的示例为特定 URL 定义了一个 ServiceEntry

    示例配置

    apiVersion: networking.istio.io/v1
    kind: ServiceEntry
    metadata:
      name: egress-se
      namespace: curl
    spec:
      hosts:
        - docs.alauda.io
      ports:
        - number: 80
          name: http-port
          protocol: HTTP
      location: MESH_EXTERNAL
      resolution: DNS
  6. 通过执行以下命令应用该 YAML 文件:

    kubectl apply -f http-se.yaml
  7. 确认 ServiceEntry 配置已成功应用。通过运行以下命令,向上一步中指定的 host 发送 HTTP 请求:

    kubectl exec "$CURL_POD" -n curl -c curl -- curl -sSL -o /dev/null -D - http://docs.alauda.io

    该命令应返回类似 302(重定向)或 200(成功)的 HTTP 状态码,这表示连接正常。

  8. 创建一个名为 http-egress-gw.yaml 的 YAML 文件,用于建立一个 egress Gateway,并将流量从 mesh 路由到为外部服务定义的 host。

    示例配置

    apiVersion: networking.istio.io/v1alpha3
    kind: Gateway
    metadata:
      name: egress-gw
      namespace: <gateway_namespace> # Namespace where the egress gateway is deployed
    spec:
      selector:
        istio: <gateway_name> # Selects the egress-gateway instance to handle this traffic
      servers:
        - port:
            number: 80
            name: http
            protocol: HTTP
          hosts:
            - docs.alauda.io # External service host, not a full URL.
    ---
    apiVersion: networking.istio.io/v1alpha3
    kind: DestinationRule
    metadata:
      name: egress-dr
      namespace: <gateway_namespace> # Namespace where the egress gateway is deployed
    spec:
      host: <gateway_name>.<gateway_namespace>.svc.cluster.local
      subsets:
        - name: alauda-docs
  9. 通过执行以下命令应用该 YAML 文件:

    kubectl apply -f http-egress-gw.yaml
  10. 创建一个名为 http-egress-vs.yaml 的 YAML 文件,用于配置一个 VirtualService,以管理来自应用 sidecar、经过 egress gateway 并到达外部 host 的流量。

    示例配置

    apiVersion: networking.istio.io/v1alpha3
    kind: VirtualService
    metadata:
      name: egress-vs
      namespace: curl # Namespace where the curl pod is running
    spec:
      hosts:
        - docs.alauda.io # External service host, not a full URL.
      gateways:
        - mesh
        - <gateway_namespace>/egress-gw # Egress gateway name defined in the file that you used in the previous step.
      http:
        - match:
            - gateways:
                - mesh
              port: 80
          route:
            - destination:
                host: <gateway_name>.<gateway_namespace>.svc.cluster.local
                subset: alauda-docs
                port:
                  number: 80
              weight: 100
        - match:
            - gateways:
                - <gateway_namespace>/egress-gw # Egress gateway name defined in the file that you used in the previous step.
              port: 80
          route:
            - destination:
                host: docs.alauda.io
                port:
                  number: 80
              weight: 100
  11. 通过运行以下命令应用该 YAML 文件:

    kubectl apply -f http-egress-vs.yaml
  12. 重新向以下 URL 发起 HTTP 请求:

    kubectl exec "$CURL_POD" -n curl -c curl -- curl -sSL -o /dev/null -D - http://docs.alauda.io

    终端输出应类似于以下内容:

    示例输出

    ...
    HTTP/1.1 302 Found
    server: envoy
    ...
    location: <example_url>
    ...
    
    HTTP/2 200
    Content-Type: text/html; charset=utf-8
  13. 通过运行此命令,确认请求已通过 gateway 路由:

    启用访问日志

    此验证步骤要正常工作,必须启用访问日志。你可以通过创建以下 Telemetry 资源来启用它。

    kubectl apply -f - <<EOF
    apiVersion: telemetry.istio.io/v1
    kind: Telemetry
    metadata:
      name: gateway-access-log
      namespace: <gateway_namespace>
    spec:
      selector:
        matchLabels:
          istio: <gateway_name>
      accessLogging:
        - providers:
            - name: envoy
    EOF
    kubectl logs deployment/<gateway_name> -n <gateway_namespace> | tail -1

    你的终端应显示与以下输出类似的信息:

    示例输出

    [2025-09-21T07:45:45.331Z] "GET / HTTP/2" 302 - via_upstream - "-" 0 137 107 105 "10.3.0.56" "curl/8.15.0" "1503bbf4-1571-4d16-9d2b-c9817355284e" "docs.alauda.io" "119.28.207.230:80" outbound|80||docs.alauda.io 10.3.0.41:55194 10.3.0.41:80 10.3.0.56:60876 - -

清理

移除在此操作步骤中创建的资源:

kubectl delete namespace curl