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

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

用于第七层路由的 waypoint 代理

为了执行第七层(L7)路由策略——包括基于路径的路由和头部匹配——请在包含目标服务的命名空间中部署 waypoint 代理。waypoint 代理负责处理 L7 流量并应用通过 HTTPRouteGRPCRoute 资源定义的路由规则。

WARNING

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

前提条件

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

操作步骤

  1. 创建名为 httpbin 的命名空间:

    kubectl create namespace httpbin
  2. httpbin 命名空间添加标签 istio-discovery=enabled

    kubectl label namespace httpbin istio-discovery=enabled
  3. 通过应用数据平面模式标签启用该命名空间的 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 代理。该 Gateway 资源使用 istio-waypoint 网关类来处理命名空间内服务的 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 网关类,部署 waypoint 代理而非标准入口网关。
  6. 应用 waypoint 代理配置:

    kubectl apply -f httpbin-waypoint.yaml
  7. httpbin 服务添加标签,使入口流量通过 waypoint 代理:

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

    istio.io/ingress-use-waypoint=true 标签确保来自入口网关的流量经过 waypoint 代理,使得在 waypoint 上配置的 L7 策略在流量到达 httpbin 服务前生效。

  8. 通过为命名空间添加标签,将该命名空间内所有服务关联到 waypoint 代理:

    kubectl label ns httpbin istio.io/use-waypoint=httpbin-waypoint
  9. 创建名为 httpbin-gw.yaml 的文件,定义 Kubernetes Gateway 资源。该配置使网关代理在端口 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. 指定网关的 Service 类型;默认为 LoadBalancer
    2. 指定客户端访问该端口时使用的虚拟主机名。
  10. 应用网关配置:

    kubectl apply -f httpbin-gw.yaml
  11. 创建名为 httpbin-ingress-hr.yaml 的文件,定义入口网关的 HTTPRoute 资源。该资源指定流量如何从网关代理路由到 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. 应用入口 HTTPRoute:

    kubectl apply -f httpbin-ingress-hr.yaml
  13. 创建名为 httpbin-waypoint-hr.yaml 的文件,定义 waypoint 代理的 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 代理对目标服务流量执行的 L7 路由规则。
    2. 将匹配的流量转发到端口 8000 上的 httpbin 服务。
  14. 应用 waypoint HTTPRoute:

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

    在此配置中,来自入口网关的流量因服务上的 istio.io/ingress-use-waypoint=true 标签而流经 waypoint 代理。waypoint 的 HTTPRoute 随后应用基于路径的路由策略,之后流量才到达 httpbin 服务。

  15. 等待 waypoint 代理就绪:

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

验证

  1. 创建一个用于 curl 客户端的命名空间:

    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 命名空间添加标签 istio-discovery=enabled

    kubectl label namespace curl istio-discovery=enabled
  4. 启用 curl 命名空间的 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 客户端通过入口网关的 Servicehttpbin 应用的 /headers 端点发送请求。设置 Host 头为 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,将网关代理暴露给集群外部流量:

    kubectl -n httpbin annotate gtw httpbin-gateway networking.istio.io/service-type-
  9. 使用网关 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. 使用网关主机发送 curl 请求到 httpbin 服务:

    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
    ...

清理

删除本操作步骤中创建的资源:

# 从 ambient 数据平面移除命名空间标签
kubectl label namespace curl istio.io/dataplane-mode-
kubectl label namespace httpbin istio.io/dataplane-mode-
# 删除命名空间
kubectl delete namespace curl
kubectl delete namespace httpbin