通过 Istio Gateway 和 VirtualService 资源暴露服务

本指南演示如何使用 Istio 的 GatewayVirtualService 资源来配置通过网关注入部署的网关。这些资源将网关配置为将网格内的服务暴露给外部流量。随后,通过将网关的 Service 类型更改为 LoadBalancer,将网关暴露给集群外部的流量。

前提条件

操作步骤

  1. 通过执行以下命令创建一个名为 httpbin 的新命名空间:

    kubectl create namespace httpbin
  2. 为该命名空间启用 sidecar 注入。如果您的环境使用 InPlace 升级策略,请运行以下命令:

    kubectl label namespace httpbin 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.3   47h
    2. 使用修订名称为命名空间打标签以启用 sidecar 注入:

      kubectl label namespace httpbin istio.io/rev=default
  3. 通过运行以下命令部署 httpbin 示例服务:

    kubectl apply -n httpbin -f https://raw.githubusercontent.com/istio/istio/refs/heads/master/samples/httpbin/httpbin.yaml
  4. 创建一个名为 httpbin-gw.yaml 的文件,包含 Istio Gateway 资源定义。该资源配置网关代理打开端口 80(HTTP),用于主机 httpbin.example.com

    apiVersion: networking.istio.io/v1
    kind: Gateway
    metadata:
      name: httpbin-gateway
      namespace: httpbin
    spec:
      selector:
        istio: <gateway_name>
      servers:
        - port:
            number: 80
            name: http
            protocol: HTTP
          hosts:
            - httpbin.example.com
    1. selector 设置为与网关代理 Deployment 的 Pod 模板中定义的唯一标签匹配。默认情况下,Istio Gateway 配置适用于所有命名空间中匹配的网关 Pod。
    2. hosts 字段中列出客户端可用于访问对应端口网格服务的地址。
  5. 使用以下命令应用该 YAML 文件:

    kubectl apply -f httpbin-gw.yaml
  6. 创建另一个名为 httpbin-vs.yaml 的 YAML 文件,用于定义 VirtualService。该 VirtualService 将定义规则,将流量从网关代理路由到 httpbin 服务。

    apiVersion: networking.istio.io/v1
    kind: VirtualService
    metadata:
      name: httpbin
      namespace: httpbin
    spec:
      hosts:
        - httpbin.example.com
      gateways:
        - httpbin-gateway
      http:
        - match:
            - uri:
                prefix: /status
            - uri:
                prefix: /headers
          route:
            - destination:
                port:
                  number: 8000
                host: httpbin
    1. 定义 hosts,指定 VirtualService 路由规则适用的主机。所指定的 hosts 必须由此 VirtualService 所附加的 Istio Gateway 资源暴露。
    2. 通过将网关名称添加到 gateways 列表,将 VirtualService 附加到上一步的 Istio Gateway 资源。
    3. 通过定义指定 httpbin Servicehostportdestination,将匹配的流量定向到之前部署的 httpbin 服务。
  7. 使用以下命令应用该 YAML 文件:

    kubectl apply -f httpbin-vs.yaml

验证

  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 Pod 的名称存储在变量 CURL_POD 中:

    CURL_POD=$(kubectl get pods -n curl -l app=curl -o jsonpath='{.items[*].metadata.name}')
  4. curl 客户端通过入口网关 Servicehttpbin 应用的 /headers 端点发送请求。将 Host 头设置为 httpbin.example.com,以匹配 Istio GatewayVirtualService 中指定的主机。执行以下 curl 命令:

    kubectl exec $CURL_POD -n curl -- \
      curl -sS -I \
        -H Host:httpbin.example.com \
        <gateway_name>.<gateway_namespace>.svc.cluster.local/headers
  5. 响应应显示 200 OK HTTP 状态,确认请求成功。

    示例输出

    HTTP/1.1 200 OK
    server: istio-envoy
    ...
  6. 发送另一个请求,访问 httpbin VirtualService 中未定义 URI 前缀匹配的端点,运行以下命令:

    kubectl exec $CURL_POD -n curl -- \
      curl -sS -I \
        -H Host:httpbin.example.com \
        <gateway_name>.<gateway_namespace>.svc.cluster.local/get

    响应应为 404 Not Found 状态。这是预期结果,因为 /get 端点在 httpbin VirtualService 中没有定义 URI 前缀匹配。

    示例输出

    HTTP/1.1 404 Not Found
    server: istio-envoy
    ...
  7. 通过将网关的 Service 类型更改为 LoadBalancer,将网关代理暴露给集群外部流量:

    kubectl patch service <gateway_name> -n <gateway_namespace> -p '{"spec": {"type": "LoadBalancer"}}'
  8. 使用网关 Service 的外部主机名或 IP 地址确认 httpbin 服务可从集群外部访问。请确保根据您的集群环境正确设置 INGRESS_HOST 变量。

    a. 使用以下命令设置 INGRESS_HOST 变量:

    INGRESS_HOST=$(kubectl get service <gateway_name> -n <gateway_namespace> -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
    echo "INGRESS_HOST=$INGRESS_HOST"

    在某些环境中,负载均衡器可能通过主机名而非 IP 地址暴露。在这种情况下,入口网关的 EXTERNAL-IP 值不是 IP 地址,而是主机名,上述命令将无法正确设置 INGRESS_HOST 环境变量。请使用以下命令修正 INGRESS_HOST 的值:

    INGRESS_HOST=$(kubectl get service <gateway_name> -n <gateway_namespace> -o jsonpath='{.status.loadBalancer.ingress[0].hostname}')
    echo "INGRESS_HOST=$INGRESS_HOST"

    b. 通过运行以下命令,使用网关主机向 httpbin 服务发送 curl 请求:

    INFO

    如果 $INGRESS_HOST 是 IPv6 地址,构造 URL 时请用方括号括起来。例如:

    curl -sS -g -I -H Host:httpbin.example.com http://[$INGRESS_HOST]/headers
    curl -sS -g -I -H Host:httpbin.example.com http://$INGRESS_HOST/headers
  9. 检查响应是否包含 HTTP/1.1 200 OK 状态,确认请求成功。