使用Gateway API访问服务

Gateway API是Kubernetes中用于对服务网络流量进行建模的一系列资源。它的目标是建立一套表现力强、易扩展、面向角色的服务网络模型。本文介绍如何使用Gateway API访问服务。

前提条件

  • 确保集群为1.24及以上版本。

  • 已安装Gateway API组件。具体操作,请参见管理组件

    说明

    1.24及以上版本的集群已默认安装Gateway API组件。

背景信息

ACK 1.24及以上版本集群默认安装Gateway API组件相关的CRD资源。您可以通过安装支持Gateway API的网关来使用Gateway API的相关特性。关于Gateway API的更多说明,请参见Gateway API

使用流程

流程

准备工作

  1. 获取集群KubeConfig并通过kubectl工具连接集群

  2. 创建测试应用go-httpbin。

    1. 使用以下内容,创建httpbin.yaml

      apiVersion: apps/v1
      kind: Deployment
      metadata:
        name: go-httpbin
        namespace: default
      spec:
        replicas: 1
        selector:
          matchLabels:
            app: go-httpbin
        template:
          metadata:
            labels:
              app: go-httpbin
              version: v1
          spec:
            containers:
              - image: specialyang/go-httpbin:v3
                args:
                  - "--port=8090"
                  - "--version=v1"
                imagePullPolicy: Always
                name: go-httpbin
                ports:
                  - containerPort: 8090
      ---
      apiVersion: v1
      kind: Service
      metadata:
        name: go-httpbin
        namespace: default
      spec:
        ports:
          - port: 80
            targetPort: 8090
            protocol: TCP
        selector:
          app: go-httpbin
    2. 执行以下命令,创建go-httpbin应用。

      kubectl apply -f httpbin.yaml
  3. 安装Kong Kubernetes Ingress Controller。

    ACK中未提供支持Gateway API的网关组件,本文以kubernetes-ingress-controller网关为例。

    1. 执行以下命令,安装Kong Kubernetes Ingress Controller。

      说明

      Kong Kubernetes Ingress Controller会使用LoadBalancer类型的kong-proxy Service向外暴露服务,创建的CLB实例会产生额外的费用。关于CLB实例的计费说明,请参见CLB计费概述

      kubectl create -f https://raw.githubusercontent.com/Kong/kubernetes-ingress-controller/v2.8.0/deploy/single/all-in-one-dbless.yaml

      创建完成的资源将会放置在kong命名空间下。

    2. 验证Kong Kubernetes Ingress Controller是否安装成功。

      1. 执行以下命令,查看Service的LoadBalancer IP。

        kubectl get svc -n kong kong-proxy

        预期输出:

        NAME         TYPE           CLUSTER-IP      EXTERNAL-IP    PORT(S)                      AGE
        kong-proxy   LoadBalancer   172.16.19.238   47.14.**.**  80:31611/TCP,443:30936/TCP     10s

        在返回结果中获取EXTERNAL IP

      2. 执行以下命令,访问Kong Kubernetes Ingress Controller。

        curl http://<EXTERNAL-IP>

        预期输出:

        {"message":"no Route matched with those values"}

      访问Kong Kubernetes Ingress Controller时,返回{"message":"no Route matched with those values"},表明安装Kong Kubernetes Ingress Controller成功。

  4. 创建GatewayClass和Gateway。

    1. 使用以下内容,创建gateway.yaml

      apiVersion: gateway.networking.k8s.io/v1beta1
      kind: GatewayClass
      metadata:
        name: kong
        annotations:
          konghq.com/gatewayclass-unmanaged: 'true'
      spec:
        controllerName: konghq.com/kic-gateway-controller
      ---
      apiVersion: gateway.networking.k8s.io/v1beta1
      kind: Gateway
      metadata:
        name: kong
      spec:
        gatewayClassName: kong
        listeners:
        - name: proxy
          port: 80
          protocol: HTTP
        - name: proxy-ssl
          port: 443
          protocol: HTTPS
    2. 执行以下命令,创建GatewayClass和Gateway。

      kubectl apply -f gateway.yaml
    3. 执行以下命令,查看Gateway外部端点。

      kubectl get gateway kong

      预期输出:

      NAME   CLASS   ADDRESS        PROGRAMMED   AGE
      kong   kong    47.14.**.**              68s

      返回以上结果,表明创建GatewayClass和Gateway成功。

使用HTTPRoute

以下介绍如何使用HTTPRoute,

功能一:创建前缀匹配路由

使用HTTPRoute的前缀匹配路由能力,使仅前缀正确的请求路由到应用。

  1. 使用以下内容,创建demo-route.yaml

    apiVersion: gateway.networking.k8s.io/v1beta1
    kind: HTTPRoute
    metadata:
      name: demo-route
    spec:
      parentRefs: # 引用Gateway资源。
        - group: gateway.networking.k8s.io
          kind: Gateway
          name: kong
      hostnames:
        - example.com # host设置为example.com
      rules:
        - matches: # 匹配规则为前缀匹配路径。
            - path:
                type: PathPrefix
                value: /
          backendRefs: # 后端为类型为Service,名称go-httpbin,端口80。
            - kind: Service
              name: go-httpbin
              port: 80
  2. 执行以下命令,创建HTTPRoute资源。

    kubectl apply -f demo-route.yaml
  3. 执行以下命令,访问go-httpbin应用。

    curl http://example.com/version --resolve example.com:80:<EXTERNAL-IP>

    预期输出:

    version:v1

    返回以上结果,表明访问go-httpbin应用成功,创建前缀匹配路由成功。

功能二:创建权重路由

使用HTTPRoute的权重路由能力,使流量按照权重比例路由到应用。

  1. 创建测试应用new-nginx和old-nginx。

    1. 使用以下内容,创建nginx.yaml

      apiVersion: apps/v1
      kind: Deployment
      metadata:
        name: old-nginx
      spec:
        replicas: 1
        selector:
          matchLabels:
            run: old-nginx
        template:
          metadata:
            labels:
              run: old-nginx
          spec:
            containers:
            - image: registry.cn-hangzhou.aliyuncs.com/acs-sample/old-nginx
              imagePullPolicy: Always
              name: old-nginx
              ports:
              - containerPort: 80
                protocol: TCP
            restartPolicy: Always
      ---
      apiVersion: v1
      kind: Service
      metadata:
        name: old-nginx
      spec:
        ports:
        - port: 80
          protocol: TCP
          targetPort: 80
        selector:
          run: old-nginx
        sessionAffinity: None
        type: NodePort
      ---
      apiVersion: apps/v1
      kind: Deployment
      metadata:
        name: new-nginx
      spec:
        replicas: 1
        selector:
          matchLabels:
            run: new-nginx
        template:
          metadata:
            labels:
              run: new-nginx
          spec:
            containers:
            - image: registry.cn-hangzhou.aliyuncs.com/acs-sample/new-nginx
              imagePullPolicy: Always
              name: new-nginx
              ports:
              - containerPort: 80
                protocol: TCP
            restartPolicy: Always
      ---
      apiVersion: v1
      kind: Service
      metadata:
        name: new-nginx
      spec:
        ports:
        - port: 80
          protocol: TCP
          targetPort: 80
        selector:
          run: new-nginx
        sessionAffinity: None
        type: NodePort
    2. 执行以下命令,创建new-nginx和old-nginx。

      kubectl apply -f nginx.yaml
  2. 创建HTTPRoute资源。

    1. 执行以下命令,创建demo-weight.yaml

      apiVersion: gateway.networking.k8s.io/v1beta1
      kind: HTTPRoute
      metadata:
        name: demo-weight
      spec:
        parentRefs: # 引用Gateway资源。
          - group: gateway.networking.k8s.io
            kind: Gateway
            name: kong
        hostnames:
          - weight.example.com # host设置为weight.example.com
        rules:
          - matches: # 匹配规则为前缀匹配路径。
              - path:
                  type: PathPrefix
                  value: /
            backendRefs:
              # 设置后端以及对应权重,权重不为百分比形式,无需等于100。
              - kind: Service
                name: old-nginx
                port: 80
                weight: 1 # 设置old-nginx的权重为1。
              - kind: Service
                name: new-nginx
                port: 80
                weight: 1 # 设置new-nginx的权重为1。

      weight:权重比例,例如本文设置old-nginx的weight1,new-nginx的weight1,表明流量按照1∶1的比例路由到old-nginx和new-nginx。

    2. 执行以下命令,创建HTTPRoute资源。

      kubectl apply -f demo-weight.yaml
  3. 多次执行以下命令,访问new-nginx和old-nginx应用。

    curl http://weight.example.com/ --resolve weight.example.com:80:<EXTERNAL-IP>

    预期输出:

    old
    new
    old
    new
    old
    new

    可以看到流量按照1∶1的比例路由到new-nginx和old-nginx两个应用中,表明创建权重路由成功。

功能三:修改请求头

使用HTTPRoute的filter能力,可以在请求或者回复阶段对请求头进行额外处理。本文以给发送到后端的请求添加请求头为例。关于filter能力的更多介绍,请参见HTTPRoute

  1. 创建HTTPRoute资源。

    1. 执行以下命令,创建demo-filter.yaml

      apiVersion: gateway.networking.k8s.io/v1beta1
      kind: HTTPRoute
      metadata:
        name: demo-filter
      spec:
        parentRefs: # 引用Gateway资源。
          - group: gateway.networking.k8s.io
            kind: Gateway
            name: kong
        hostnames:
          - filter.example.com # host设置为filter.example.com。
        rules:
          - matches: # 匹配规则为前缀匹配路径。
              - path:
                  type: PathPrefix
                  value: /
            filters:
              - type: RequestHeaderModifier # 添加请求头my-header: foo。
                requestHeaderModifier:
                  add:
                    - name: my-header
                      value: foo
            backendRefs: # 后端为类型为Service,名称go-httpbin,端口80。
              - kind: Service
                name: go-httpbin
                port: 80
    2. 执行以下命令,创建HTTPRoute资源。

      kubectl apply -f demo-filter.yaml
  2. 执行以下命令,访问go-httpbin应用。

    curl http://filter.example.com/ --resolve filter.example.com:80:<EXTERNAL-IP>

    预期输出:

    headers: {
        // ...
        "My-Header": [
          "foo"
        ],
        // ...
    }

    可以看到访问go-httpbin应用时,返回结果中包含My-Header:foo请求头,表明修改请求头成功。

配置TLS证书

  1. 执行以下命令,通过OpenSSL创建自签名证书。

    openssl req -subj '/CN=example.com' -new -newkey rsa:2048 -sha256 \
      -days 365 -nodes -x509 -keyout server.key -out server.crt \
      -addext "subjectAltName = DNS:example.com" \
      -addext "keyUsage = digitalSignature" \
      -addext "extendedKeyUsage = serverAuth" 2> /dev/null;
      openssl x509 -in server.crt -subject -noout

    生成的证书和私钥位于当前目录的server.crtserver.key文件中。

  2. 执行以下命令,使用server.crtserver.key文件创建TLS Secret。

    kubectl create secret tls example.com --key server.key --cert server.crt

    预期输出:

    secret/example.com created
  3. 将证书配置到Gateway。

    1. 执行以下命令,创建gateway1.yaml

      apiVersion: gateway.networking.k8s.io/v1beta1
      kind: Gateway
      metadata:
        name: kong
      spec:
        gatewayClassName: kong
        listeners:
        - name: proxy
          port: 80
          protocol: HTTP
        - name: proxy-ssl
          port: 443
          protocol: HTTPS
          tls: # 配置TLS。
            mode: Terminate
            certificateRefs: # 引用所创建的secret。
              - kind: Secret
                name: example.com
    2. 执行以下命令,将证书配置到Gateway。

      kubectl apply -f gateway1.yaml
  4. 执行以下命令,验证配置TLS证书是否成功。

    openssl s_client -servername example.com -connect <EXTERNAL-IP>:443

    返回结果中包含CN = example.com,表明配置TLS证书成功。

相关文档