通过 Kubernetes Gateway API 暴露服务

您可以使用 Kubernetes Gateway API 创建 GatewayHTTPRoute 资源来部署网关。这些资源配置网关,使网格内的服务可以被外部流量访问。然后,您可以将网关的 Service 类型更改为 LoadBalancer,以便将其暴露给集群外部的流量。

前提条件

  • 已安装 Alauda Service Mesh v2 Operator。
  • 已部署 Istio 控制平面。
  • 请确认Linux 内核兼容性

操作步骤

  1. 使用以下命令创建一个名为 httpbin 的新命名空间:

    kubectl create namespace httpbin
  2. 使用以下命令部署 httpbin 示例服务:

    kubectl apply -n httpbin -f https://raw.githubusercontent.com/istio/istio/refs/heads/master/samples/httpbin/httpbin.yaml
  3. 创建一个名为 httpbin-k8s-gw.yaml 的文件,定义一个 Kubernetes Gateway 资源。该资源将配置网关代理,暴露端口 80(HTTP)供 httpbin.example.com 主机使用。

    自动部署

    默认情况下,每个 Gateway 会自动创建一个 ServiceDeployment。它们的名称格式为 <Gateway 名称>-<GatewayClass 名称>istio-waypoint GatewayClass 除外,该类不添加后缀)。如果 Gateway 发生更改(例如添加新端口),这些配置会自动更新。

    示例网关资源文件

    apiVersion: gateway.networking.k8s.io/v1
    kind: Gateway
    metadata:
      annotations:
        networking.istio.io/service-type: ClusterIP
      labels:
        istio.io/rev: default
      name: httpbin-gateway
      namespace: httpbin
    spec:
      gatewayClassName: istio
      listeners:
        - name: http
          hostname: "httpbin.example.com"
          port: 80
          protocol: HTTP
          allowedRoutes:
            namespaces:
              from: All
    1. 指定网关的 Service 类型;默认为 LoadBalancer
    2. 指定 Istio 版本名称;默认为 default
    3. 指定网关名称。
    4. 指定网关所在命名空间。
    5. 指定客户端访问该端口时使用的虚拟主机名。
  4. 使用以下命令应用该 YAML 文件:

    kubectl apply -f httpbin-k8s-gw.yaml
  5. 创建一个名为 httpbin-hr.yaml 的 YAML 文件,定义一个 HTTPRoute 资源。该资源指定从网关代理到 httpbin 服务的流量路由规则。

    示例 HTTPRoute 文件

    apiVersion: gateway.networking.k8s.io/v1
    kind: HTTPRoute
    metadata:
      name: httpbin
      namespace: httpbin
    spec:
      parentRefs:
      - name: httpbin-gateway
        namespace: httpbin
      rules:
      - matches:
        - path:
            type: PathPrefix
            value: /status
        - path:
            type: PathPrefix
            value: /headers
        backendRefs:
        - name: httpbin
          port: 8000
    1. 通过将网关名称添加到网关列表,将 HTTPRoute 资源关联到之前创建的 Kubernetes Gateway
    2. 通过定义包含 httpbin 服务名称和端口的 backendRefs 条目,将匹配的流量定向到 httpbin 服务。
  6. 使用以下命令应用该 YAML 文件:

    kubectl apply -f httpbin-hr.yaml
  7. 运行以下命令,确认 Gateway API 服务已准备就绪并分配了地址:

    kubectl wait --for=condition=programmed gtw httpbin-gateway -n httpbin
  8. 可选:将网关部署到 Infra Nodes

    点击展开
    前提条件

    Alauda Container Platform 4.2.0 或更高版本,或将 Gateway API CRDs 升级到最新版本。

    a. 在计划部署 Gateway 的同一命名空间中创建名为 asm-kube-gateway-options 的 ConfigMap:

    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: asm-kube-gateway-options
      namespace: httpbin
    data:
      deployment: |
        spec:
          template:
            spec:
              nodeSelector:
                node-role.kubernetes.io/infra: ""
              tolerations:
                - effect: NoSchedule
                  key: node-role.kubernetes.io/infra
                  value: reserved
                  operator: Equal
    1. 指定 ConfigMap 名称。
    2. 指定 ConfigMap 命名空间,与网关相同。
    3. 设置节点选择器和容忍度,将网关 Pod 调度到 Infra 节点。

    b. 在 Gateway 资源中通过添加 infrastructure.parametersRef 字段引用该 ConfigMap:

    apiVersion: gateway.networking.k8s.io/v1
    kind: Gateway
    metadata:
      name: httpbin-gateway
      namespace: httpbin
    spec:
      # 在 Gateway CR 中添加以下基础设施配置
      infrastructure:
        parametersRef:
          group: ""
          kind: ConfigMap
          name: asm-kube-gateway-options
      # ... 其余 Gateway 配置
    1. 指定网关名称。
    2. 指定网关命名空间。

验证

  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 客户端发送请求到 httpbin 应用的 /headers 端点,访问入口网关的 Service。将 Host 头设置为 httpbin.example.com,以匹配 Kubernetes GatewayHTTPROUTE 资源中指定的主机。运行以下 curl 命令:

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

    响应应显示 200 OK HTTP 状态,表示请求成功。

    示例输出

    HTTP/1.1 200 OK
    server: istio-envoy
    ...
  5. 发送一个请求到 httpbin HTTPROUTE 中没有匹配 URI 前缀的端点,运行以下命令:

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

    响应将是 404 Not Found 状态。这是预期行为,因为 /get 端点在 httpbin HTTPROUTE 资源中没有定义匹配的 URI 前缀。

    示例输出

    HTTP/1.1 404 Not Found
    server: istio-envoy
    ...
  6. 通过将其 Service 类型设置为默认的 LoadBalancer,将网关代理暴露给外部流量。运行以下命令:

    kubectl -n httpbin annotate gtw httpbin-gateway networking.istio.io/service-type-
  7. 使用网关 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=="http")].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
  8. 验证响应显示 HTTP/1.1 200 OK 状态,确认请求成功。