在 ambient 模式下通过 Kubernetes Gateway API 暴露服务

在 Istio ambient 模式中,Kubernetes Gateway API 是配置入口流量路由的推荐方式。你可以创建 GatewayHTTPRoute 资源来部署一个 gateway,使 mesh 内部服务可被外部流量访问。

用于 Layer 7 路由的 waypoint proxy

要强制执行 Layer 7(L7)路由策略——包括基于路径的路由和 header 匹配——请在包含目标服务的 namespace 中部署 waypoint proxy。waypoint proxy 负责处理 L7 流量,并应用通过 HTTPRouteGRPCRoute 资源定义的路由规则。

WARNING

在 ambient 模式下,VirtualService 资源的兼容性有限,不应与 Gateway API 配置一起使用。请使用 Kubernetes Gateway API 资源作为 ambient 模式下流量路由的标准方法。

前提条件

  • 已安装 Alauda Service Mesh v2 Operator。
  • IstioIstioCNI 资源已使用 ambient profile 进行配置。
  • 已创建 Ztunnel 资源。
  • 确认 Linux kernel 兼容性
  • 你的 Kubernetes 集群支持外部负载均衡器(即,类型为 LoadBalancer 的 Services)。

操作步骤

  1. 创建一个名为 httpbin 的 namespace:

    kubectl create namespace httpbin
  2. httpbin namespace 添加 istio-discovery=enabled 标签:

    kubectl label namespace httpbin istio-discovery=enabled
  3. 通过应用 dataplane mode 标签,为该 namespace 启用 ambient 模式:

    kubectl label namespace httpbin istio.io/dataplane-mode=ambient
  4. 部署 httpbin 示例服务:

    kubectl apply -n httpbin -f https://raw.githubusercontent.com/istio/istio/refs/heads/master/samples/httpbin/httpbin.yaml
  5. 创建名为 httpbin-waypoint.yaml 的文件以定义 waypoint proxy。此 Gateway 资源使用 istio-waypoint gateway class 来处理该 namespace 中服务的 L7 流量。

    apiVersion: gateway.networking.k8s.io/v1
    kind: Gateway
    metadata:
      name: httpbin-waypoint
      namespace: httpbin
      labels:
        istio.io/waypoint-for: service
    spec:
      gatewayClassName: istio-waypoint
      listeners:
        - name: mesh
          port: 15008
          protocol: HBONE
    1. istio.io/waypoint-for: service 标签表示该 waypoint 会处理服务流量。标签值决定了所处理的流量类型。详情请参见 Waypoint traffic types(Istio 文档)。
    2. 指定 istio-waypoint gateway class,它会部署 waypoint proxy,而不是标准的 ingress gateway。
  6. 应用 waypoint proxy 配置:

    kubectl apply -f httpbin-waypoint.yaml
  7. httpbin 服务添加标签,以便将入口流量引导经过 waypoint proxy:

    kubectl label service httpbin -n httpbin istio.io/ingress-use-waypoint=true
    NOTE

    istio.io/ingress-use-waypoint=true 标签可确保从 ingress gateway 到达的流量会先经过 waypoint proxy,从而在流量到达 httpbin 服务之前执行在 waypoint 上配置的 L7 策略。

  8. 通过为 namespace 添加标签,将该 namespace 中的所有服务关联到 waypoint proxy:

    kubectl label ns httpbin istio.io/use-waypoint=httpbin-waypoint
  9. 创建名为 httpbin-gw.yaml 的文件,定义一个 Kubernetes Gateway 资源。这会配置 gateway proxy 在端口 80 上接受主机名为 httpbin.example.com 的 HTTP 流量。

    apiVersion: gateway.networking.k8s.io/v1
    kind: Gateway
    metadata:
      annotations:
        networking.istio.io/service-type: ClusterIP
      name: httpbin-gateway
      namespace: httpbin
    spec:
      gatewayClassName: istio
      listeners:
        - name: default
          hostname: "httpbin.example.com"
          port: 80
          protocol: HTTP
          allowedRoutes:
            namespaces:
              from: All
    1. 指定 gateway 的 Service 类型;默认值为 LoadBalancer
    2. 指定客户端在访问该端口上的 mesh 服务时使用的虚拟主机名。
  10. 应用 gateway 配置:

    kubectl apply -f httpbin-gw.yaml
  11. 创建名为 httpbin-ingress-hr.yaml 的文件,为 ingress gateway 定义一个 HTTPRoute 资源。此资源指定了流量如何从 gateway proxy 路由到 httpbin 服务。

    apiVersion: gateway.networking.k8s.io/v1
    kind: HTTPRoute
    metadata:
      name: httpbin-ingress
      namespace: httpbin
    spec:
      parentRefs:
        - name: httpbin-gateway
          namespace: httpbin
      hostnames:
        - "httpbin.example.com"
      rules:
        - backendRefs:
            - name: httpbin
              port: 8000
    1. 将此 HTTPRoute 绑定到上一步创建的 Kubernetes Gateway
    2. 将匹配到的流量路由到端口 8000 上的 httpbin 服务。
  12. 应用 ingress HTTPRoute:

    kubectl apply -f httpbin-ingress-hr.yaml
  13. 创建名为 httpbin-waypoint-hr.yaml 的文件,为 waypoint proxy 定义一个 HTTPRoute 资源。此资源配置 waypoint 执行的基于路径的路由规则。

    apiVersion: gateway.networking.k8s.io/v1
    kind: HTTPRoute
    metadata:
      name: httpbin-waypoint-route
      namespace: httpbin
    spec:
      parentRefs:
        - group: ""
          kind: Service
          name: httpbin
          namespace: httpbin
      rules:
        - matches:
            - path:
                type: PathPrefix
                value: /status
            - path:
                type: PathPrefix
                value: /headers
          backendRefs:
            - name: httpbin
              port: 8000
    1. 将此 HTTPRoute 绑定到 httpbin 服务。结合 istio.io/ingress-use-waypoint=true 标签,这会配置由 waypoint proxy 对发往该服务的流量强制执行的 L7 路由规则。
    2. 将匹配到的流量转发到端口 8000 上的 httpbin 服务。
  14. 应用 waypoint HTTPRoute:

    kubectl apply -f httpbin-waypoint-hr.yaml
    NOTE

    在此配置中,由于服务上设置了 istio.io/ingress-use-waypoint=true 标签,来自 ingress gateway 的流量会经过 waypoint proxy。随后,waypoint HTTPRoute 会在流量到达 httpbin 服务之前应用基于路径的路由策略。

  15. 等待 waypoint proxy 就绪:

    kubectl wait --for=condition=programmed gtw httpbin-waypoint -n httpbin

验证

  1. curl 客户端创建一个 namespace:

    kubectl create namespace curl
  2. 部署 curl 客户端:

    kubectl apply -n curl -f https://raw.githubusercontent.com/istio/istio/refs/heads/master/samples/curl/curl.yaml
  3. curl namespace 添加 istio-discovery=enabled 标签:

    kubectl label namespace curl istio-discovery=enabled
  4. curl namespace 启用 ambient 模式:

    kubectl label namespace curl istio.io/dataplane-mode=ambient
  5. curl pod 的名称存储到变量中:

    export CURL_POD=$(kubectl get pods -n curl -l app=curl -o jsonpath='{.items[*].metadata.name}')
    echo "CURL_POD=$CURL_POD"
  6. curl 客户端,通过 ingress gateway Servicehttpbin 应用的 /headers 端点发送请求。将 Host header 设置为 httpbin.example.com,以匹配 Kubernetes GatewayHTTPRoute 资源中指定的主机名:

    kubectl exec $CURL_POD -n curl -- \
      curl -sS -I \
        -H Host:httpbin.example.com \
        httpbin-gateway-istio.httpbin.svc.cluster.local/headers

    响应应返回 HTTP/1.1 200 OK 状态,表示请求已成功处理。

    示例输出

    HTTP/1.1 200 OK
    ...
    server: istio-envoy
    ...
  7. 向 waypoint HTTPRoute 中没有匹配 URI 前缀的端点发送请求:

    kubectl exec $CURL_POD -n curl -- \
      curl -sS -I \
        -H Host:httpbin.example.com \
        httpbin-gateway-istio.httpbin.svc.cluster.local/get

    响应返回 HTTP/1.1 404 Not Found,这是预期行为,因为 /get 路径在 waypoint HTTPRoute 中没有定义对应的前缀匹配。

    示例输出

    HTTP/1.1 404 Not Found
    ...
    server: istio-envoy
    ...
  8. 通过将 Service 类型更改为默认的 LoadBalancer,使 gateway proxy 可从集群外部访问:

    kubectl -n httpbin annotate gtw httpbin-gateway networking.istio.io/service-type-
  9. 使用 gateway Service 的外部主机名或 IP 地址,验证可以从集群外部访问 httpbin 服务。根据你的集群环境设置 INGRESS_HOST 变量。

    a. 设置 INGRESS_HOST 变量:

    export INGRESS_HOST=$(kubectl get gtw httpbin-gateway -n httpbin -o jsonpath='{.status.addresses[0].value}')
    echo "INGRESS_HOST=$INGRESS_HOST"

    b. 设置 INGRESS_PORT 变量:

    export INGRESS_PORT=$(kubectl get gtw httpbin-gateway -n httpbin -o jsonpath='{.spec.listeners[?(@.name=="default")].port}')
    echo "INGRESS_PORT=$INGRESS_PORT"

    c. 使用 gateway 主机向 httpbin 服务发送 curl 请求:

    INFO

    如果 $INGRESS_HOST 是 IPv6 地址,在构造 URL 时请将其放在方括号中。例如:

    curl -sS -g -I -H Host:httpbin.example.com http://[$INGRESS_HOST]:$INGRESS_PORT/headers
    curl -sS -g -I -H Host:httpbin.example.com http://$INGRESS_HOST:$INGRESS_PORT/headers
  10. 确认响应包含 HTTP/1.1 200 OK 状态,这表示请求成功。

    示例输出

    HTTP/1.1 200 OK
    ...
    server: istio-envoy
    ...

清理

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

# Remove the namespaces from the ambient data plane
kubectl label namespace curl istio.io/dataplane-mode-
kubectl label namespace httpbin istio.io/dataplane-mode-
# Remove the namespaces
kubectl delete namespace curl
kubectl delete namespace httpbin