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

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

前提条件

  • 已安装 Alauda Service Mesh v2 Operator。
  • 已部署 Istio 控制平面。
  • 确认 Linux kernel 兼容性
  • 您的 Kubernetes 集群支持外部负载均衡器(即,类型为 LoadBalancer 的 Service)。

操作步骤

  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 资源。此文件将配置网关代理,为 httpbin.example.com 主机暴露 80 端口(HTTP)。

    自动部署

    默认情况下,每个 Gateway 都会自动创建一个 ServiceDeployment。这些资源的名称将为 <Gateway name>-<GatewayClass name>istio-waypoint GatewayClass 除外,它不会附加后缀)。如果 Gateway 发生变更(例如添加了新端口),这些配置也会自动更新。

    示例 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 Service 的流量路由规则。

    示例 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. 通过将网关名称添加到 gateways 列表,将 HTTPROUTE 资源关联到前面创建的 Kubernetes Gateway
    2. 通过定义一个 backendRefs 条目将匹配的流量定向到 httpbin Service,该条目包含 httpbin Service 的名称和端口。
  6. 执行以下命令应用 YAML 文件:

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

    kubectl wait --for=condition=programmed gtw httpbin-gateway -n httpbin
  8. 可选:将网关部署到 基础设施节点

    单击展开
    前提条件

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

    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. 设置 node selector 和 tolerations,使网关 Pod 调度到基础设施节点上。

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

    apiVersion: gateway.networking.k8s.io/v1
    kind: Gateway
    metadata:
      name: httpbin-gateway
      namespace: httpbin
    spec:
      # Add the following infrastructure configuration to your Gateway CR
      infrastructure:
        parametersRef:
          group: ""
          kind: ConfigMap
          name: asm-kube-gateway-options
      # ... rest of your Gateway configuration
    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 客户端,通过 ingress gateway Servicehttpbin 应用的 /headers 端点发送请求。将 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)前缀的端点发送 curl 请求:

    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. 使用网关主机,通过以下命令向 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
  8. 验证响应显示 HTTP/1.1 200 OK 状态,这表明请求成功。

清理

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

kubectl delete namespace curl
kubectl delete namespace httpbin