通过 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.26.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. 通过定义指定 hostportdestination,将匹配的流量路由到之前部署的 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 客户端向 ingress 网关 Service/headers 端点发送请求。将 Host 头设置为 httpbin.example.com,以匹配 Istio GatewayVirtualService 中指定的主机。执行以下 curl 命令:

    kubectl exec $CURL_POD -n curl -- \
      curl -s -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 -s -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}')

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

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

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

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