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

您可以使用 Kubernetes Gateway API 创建 GatewayHTTPRoute 资源来部署网关。这些资源配置网关,使 mesh 内的服务能够接收来自外部的流量。然后,您可以将网关的 Service 更改为 LoadBalancer,使其能够接收集群外部的流量。

前提条件

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

操作步骤

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

    kubectl create namespace httpbin
    kubectl label namespace httpbin pod-security.kubernetes.io/enforce=restricted --overwrite
  2. 使用以下命令部署 httpbin 示例服务:

    kubectl apply -n httpbin -f https://raw.githubusercontent.com/alauda-mesh/istio/refs/heads/istio-1.30/samples/httpbin/httpbin.yaml
  3. istio gateway class overlay 添加到 Istio 资源,以便将网关 pod 准入 Restricted httpbin 命名空间:

    kubectl patch istio default --type=merge -p '{"spec":{"values":{"gatewayClasses":{"istio":{"deployment":{"spec":{"template":{"spec":{"securityContext":{"seccompProfile":{"type":"RuntimeDefault"}}}}}}}}}}}'

    有关更多信息,请参阅 Pod Security Admission

  4. 创建名为 httpbin-k8s-gw.yaml 的文件,其中定义 Kubernetes Gateway 资源。该资源将配置网关代理,为 httpbin.example.com 主机暴露端口 80(HTTP)。

    自动部署

    默认情况下,每个 Gateway 都会自动配置一个 Service 和一个 Deployment。它们将命名为 <Gateway name>-<GatewayClass name>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 revision 名称;默认为 default
    3. 指定网关名称。
    4. 指定网关命名空间。
    5. 指定客户端通过此端口访问 mesh 服务时使用的虚拟主机名。
  5. 使用以下命令应用 YAML 文件:

    kubectl apply -f httpbin-k8s-gw.yaml
  6. 创建名为 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 Service 名称和端口的 backendRefs 条目,将匹配的流量定向到 httpbin 服务。
  7. 执行以下命令应用 YAML 文件:

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

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

    点击展开
    前提条件

    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. 设置节点选择器和容忍度,以便在基础设施节点上调度网关 pod。

    b. 在 Gateway 资源中添加 infrastructure.parametersRef 字段,以引用 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
    kubectl label namespace curl pod-security.kubernetes.io/enforce=restricted --overwrite
  2. 使用以下命令部署 curl 客户端:

    kubectl apply -n curl -f https://raw.githubusercontent.com/alauda-mesh/istio/refs/heads/istio-1.30/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 客户端通过入口网关 Service,向 httpbin 应用的 /headers endpoint 发送请求。将 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 前缀的 endpoint 发送 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 endpoint 在 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