通过ACK Gateway with Inference Extension访问服务

Gateway APIKubernetes官方项目,是下一代Kubernetes路由和负载均衡API,支持通过Gateway API配置流量规则。本文介绍ACK Gateway with Inference Extension支持的一些Gateway API基础能力配置方法。

背景信息

ACK Gateway with Inference Extension组件基于Envoy Gateway项目构建,支持完整的Gateway API基础能力及开源Envoy Gateway扩展资源。

Envoy Gateway架构包括:

  • 控制面:由Envoy Gateway组件构成,主要负责监听集群中的流量规则,动态创建和管理Envoy代理实例,并实时更新其转发规则,但不直接参与业务流量的转发。

  • 数据面:由实际运行的Envoy Proxy实例组成,负责处理和转发业务流量,确保高效和可靠的通信。

前提条件

准备工作

  1. 创建测试应用backendbackend-2。

    说明

    应用backend-2只需要将backendYAMLbackend都替换为backend-2即可,此处不再赘述。

    apiVersion: v1
    kind: ServiceAccount
    metadata:
      name: backend
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: backend
      labels:
        app: backend
        service: backend
    spec:
      ports:
        - name: http
          port: 3000
          targetPort: 3000
      selector:
        app: backend
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: backend
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: backend
          version: v1
      template:
        metadata:
          labels:
            app: backend
            version: v1
        spec:
          serviceAccountName: backend
          containers:
            - image: registry-cn-hangzhou.ack.aliyuncs.com/ack-demo/envoygateway-echo-basic:v20231214-v1.0.0-140-gf544a46e
              imagePullPolicy: IfNotPresent
              name: backend
              ports:
                - containerPort: 3000
              env:
                - name: POD_NAME
                  valueFrom:
                    fieldRef:
                      fieldPath: metadata.name
                - name: NAMESPACE
                  valueFrom:
                    fieldRef:
                      fieldPath: metadata.namespace
  2. 创建GatewayClass,声明controllerNamegateway.envoyproxy.io/gatewayclass-controller

    apiVersion: gateway.networking.k8s.io/v1
    kind: GatewayClass
    metadata:
      name: eg
    spec:
      controllerName: gateway.envoyproxy.io/gatewayclass-controller
  3. 创建Gateway资源。

    apiVersion: gateway.networking.k8s.io/v1
    kind: Gateway
    metadata:
      name: eg
    spec:
      gatewayClassName: eg
      listeners:
        - name: http
          protocol: HTTP
          port: 80

    ACK Gateway with Inference Extension组件控制面会根据当前Gateway资源创建出EnvoyProxy Deployment以及对应的LB类型的Service,并在指定端口开启监听。关于LB实例的计费标准,请参见负载均衡计费说明

    您也可以自定义EnvoyProxyDeployment规格以及Service参数,或者开启网关HPA

  4. 获取网关地址。

    export GATEWAY_HOST=$(kubectl get gateway/eg -o jsonpath='{.status.addresses[0].value}')

基于路径前缀匹配的HTTP路由

以下示例配置HTTPRoute匹配/get前缀,并进行测试验证。

  1. 创建HTTPRoute资源。

    apiVersion: gateway.networking.k8s.io/v1
    kind: HTTPRoute
    metadata:
      name: backend
    spec:
      parentRefs:
        - name: eg
      hostnames:
        - "www.example.com"
      rules:
        - backendRefs:
            - group: ""
              kind: Service
              name: backend
              port: 3000
              weight: 1
          matches:
            - path:
                type: PathPrefix
                value: /get
  2. 测试访问。

    curl -H "Host: www.example.com" http://$GATEWAY_HOST/get

    预期输出:

    {
     "path": "/get",
     "host": "www.example.com",
     "method": "GET",
     "proto": "HTTP/1.1",
     "headers": {
      "Accept": [
       "*/*"
      ],
      "User-Agent": [
       "curl/8.9.1"
      ],
      "X-Envoy-External-Address": [
       "115.XX.XXX.55"
      ],
      "X-Forwarded-For": [
       "115.XX.XXX.55"
      ],
      "X-Forwarded-Proto": [
       "http"
      ],
      "X-Request-Id": [
       "953b2f8f-26d3-4ba9-93ba-a482b197b1ff"
      ]
     },
     "namespace": "default",
     "ingress": "",
     "service": "",
     "pod": "backend-5bff7XXXXX-XXXXX"
     }

添加请求Header

以下将更新HTTPRoute配置,为路由的请求添加Header。

  1. 更新HTTPRoute资源。

    apiVersion: gateway.networking.k8s.io/v1
    kind: HTTPRoute
    metadata:
      name: backend
    spec:
      parentRefs:
        - name: eg
      hostnames:
        - "www.example.com"
      rules:
      - matches:
        - path:
            type: PathPrefix
            value: /get
        backendRefs:
        - group: ""
          kind: Service
          name: backend
          port: 3000
          weight: 1
        filters:
        - type: RequestHeaderModifier
          requestHeaderModifier:
            add:
            - name: "added-header"
              value: "foo"
  2. 测试访问。

    curl -H "Host: www.example.com" http://$GATEWAY_HOST/get

    预期输出:

    {
     "path": "/get",
     "host": "www.example.com",
     "method": "GET",
     "proto": "HTTP/1.1",
     "headers": {
      "Accept": [
       "*/*"
      ],
      "Added-Header": [
       "foo"
      ],
      "User-Agent": [
       "curl/8.9.1"
      ],
      "X-Envoy-External-Address": [
       "115.XX.XXX.55"
      ],
      "X-Forwarded-For": [
       "115.XX.XXX.55"
      ],
      "X-Forwarded-Proto": [
       "http"
      ],
      "X-Request-Id": [
       "d37f19e5-25c1-45cf-90e5-51453e7ae3ed"
      ]
     },
     "namespace": "default",
     "ingress": "",
     "service": "",
     "pod": "backend-5bff7XXXXX-XXXXX"
    }%  

    由于当前应用的作用就是将请求内容作为响应直接输出,因此可以在响应中看到,为请求添加Header的操作已经完成。

按比例分发请求

以下将再次更新HTTPRoute配置,增加backend-2的路由规则,并为backendbackend-2服务配置权重。

说明

Gateway API并不要求所有backendRef的权重之和为100。单个服务比例计算规则为:。所有请求的流量将按照此规则的比例进行分配。

  1. 更新HTTPRoute资源。

    apiVersion: gateway.networking.k8s.io/v1
    kind: HTTPRoute
    metadata:
      name: backend
    spec:
      parentRefs:
        - name: eg
      hostnames:
        - "www.example.com"
      rules:
      - matches:
        - path:
            type: PathPrefix
            value: /get
        backendRefs:
        - group: ""
          kind: Service
          name: backend
          port: 3000
          weight: 8
        - group: ""
          kind: Service
          name: backend-2
          port: 3000
          weight: 2
  2. 测试连续访问20次,查看两个服务的比例。

    说明

    以下命令增加了额外处理,使输出仅显示backendbackend-2

    for i in $(seq 1 20); do curl -sS -H "Host: www.example.com" http://$GATEWAY_HOST/get |grep backend; done | \
        sed -E 's/".*"(backend(-2)?)-[0-9a-zA-Z]*-.*/\1/'

    预期输出:

     backend-2
     backend
     backend
     backend
     backend
     backend
     backend
     backend
     backend
     backend
     backend
     backend-2
     backend-2
     backend
     backend
     backend-2
     backend
     backend
     backend
     backend

    可以看到,两个服务的流量比例大致为80%和20%。

处理TLS流量

以下内容将更新Gateway资源,配置证书并添加TLS监听,来验证对TLS流量处理的支持。

  1. 生成证书,并创建Secret。

    openssl req -x509 -sha256 -nodes -days 365 -newkey rsa:2048 -subj '/O=example Inc./CN=example.com' -keyout example.com.key -out example.com.crt
    openssl req -out www.example.com.csr -newkey rsa:2048 -nodes -keyout www.example.com.key -subj "/CN=www.example.com/O=example organization"
    openssl x509 -req -days 365 -CA example.com.crt -CAkey example.com.key -set_serial 0 -in www.example.com.csr -out www.example.com.crt
    kubectl create secret tls example-cert --key=www.example.com.key --cert=www.example.com.crt
  2. 更新Gateway资源,添加TLS监听,并且使用上一步配置的证书。

    kubectl patch gateway eg --type=json --patch '
      - op: add
        path: /spec/listeners/-
        value:
          name: https
          protocol: HTTPS
          port: 443
          tls:
            mode: Terminate
            certificateRefs:
            - kind: Secret
              group: ""
              name: example-cert
      '
  3. 查看更改是否生效。

    kubectl get gateway/eg -o yaml | grep spec: -A 20

    预期输出:

    spec:
      gatewayClassName: eg
      listeners:
      - allowedRoutes:
          namespaces:
            from: Same
        name: http
        port: 80
        protocol: HTTP
      - allowedRoutes:
          namespaces:
            from: Same
        name: https
        port: 443
        protocol: HTTPS
        tls:
          certificateRefs:
          - group: ""
            kind: Secret
            name: example-cert
          mode: Terminate
    status:

    可以看到,更改已经生效。

  4. 测试访问。

    curl -H Host:www.example.com --resolve "www.example.com:443:${GATEWAY_HOST}" \
    --cacert example.com.crt https://www.example.com/get

    预期输出:

    {
     "path": "/get",
     "host": "www.example.com",
     "method": "GET",
     "proto": "HTTP/1.1",
     "headers": {
      "Accept": [
       "*/*"
      ],
      "User-Agent": [
       "curl/8.9.1"
      ],
      "X-Envoy-External-Address": [
       "115.XX.XXX.55"
      ],
      "X-Forwarded-For": [
       "115.XX.XXX.55"
      ],
      "X-Forwarded-Proto": [
       "https"
      ],
      "X-Request-Id": [
       "ac539756-3826-474b-be2f-5e57fdd49dac"
      ]
     },
     "namespace": "default",
     "ingress": "",
     "service": "",
     "pod": "backend-5bff7XXXXX-XXXXX"
    }