使用 Istio API 通过网关路由出口流量

本节介绍如何使用 Istio API,通过使用 gateway injection 安装的网关路由出站 HTTP 流量。

NOTE

对于基于 sidecar 的部署,请使用此方法。在 ambient 模式下,请改用 Kubernetes Gateway API 配置出口路由。

前提条件

操作步骤

  1. 执行以下命令创建名为 curl 的命名空间:

    kubectl create namespace curl
    kubectl label namespace curl pod-security.kubernetes.io/enforce=restricted --overwrite
  2. 为该命名空间启用 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.30.4   47h
    2. 使用 revision 名称为命名空间添加标签,以启用 sidecar injection:

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

    kubectl apply -n curl -f https://raw.githubusercontent.com/alauda-mesh/istio/refs/heads/istio-1.30/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 文件,将流量从网格指向外部服务。以下示例为特定 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 配置已成功应用。运行以下命令,向上一步中指定的主机发送 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 文件,建立出口 Gateway,并将流量从网格路由到为外部服务定义的主机。

    示例配置

    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 经由出口网关到外部主机的流量流向。

    示例配置

    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. 运行以下命令,确认请求已通过网关路由:

    启用访问日志

    访问日志必须处于启用状态,此验证步骤才能正常运行。您可以创建以下 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