Tìm Hiểu Về Kubernetes Gateway API Với Kong Ingress Controller

Khám phá cách sử dụng Kubernetes Gateway API với Kong Ingress Controller. Hướng dẫn cấu hình HTTPRoute, GatewayClass, quản lý traffic và routing nâng cao.

Tìm Hiểu Về Kubernetes Gateway API Với Kong Ingress Controller

Kubernetes đã trở thành tiêu chuẩn cho việc điều phối các ứng dụng container nhờ khả năng quản lý tự động và khai báo rõ ràng. Trước đây, đối tượng Ingress thường được sử dụng để xử lý lưu lượng truy cập từ bên ngoài vào các microservices bên trong cluster.

Tuy nhiên, Ingress có một số hạn chế nhất định: nó chủ yếu quản lý lưu lượng L7 (HTTP/HTTPS), giới hạn việc định tuyến trong cùng một namespace và thiếu các tính năng nâng cao như khớp (match) theo header hay query string.

Để giải quyết những hạn chế này, Gateway API đã ra đời. Nó cung cấp một bộ API Proxy linh hoạt hơn, hỗ trợ nhiều giao thức vượt ngoài HTTP và mô hình hóa chi tiết các thành phần hạ tầng. Đặc biệt, Gateway API phân chia rõ ràng vai trò và trách nhiệm (roles & personas) cho các team khác nhau trong hệ thống (như team hạ tầng, team vận hành cluster, team phát triển ứng dụng).

Trong bài viết này, TechCoBan sẽ cùng bạn tìm hiểu về Gateway API tiêu chuẩn và cách sử dụng Kong Ingress Controller (KIC) để khám phá sức mạnh mà Gateway API mang lại.


1. Cài đặt Gateway API CRD

Gateway API yêu cầu cài đặt thủ công một số Custom Resource Definitions (CRD). Chúng ta sẽ cài đặt các CRD tiêu chuẩn, bao gồm Package v1:

  • Gateway
  • GatewayClass
  • HTTPRoute

Chạy lệnh sau để cài đặt:

kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.0.0/standard-install.yaml

2. Infrastructure Ops (Vận hành hạ tầng)

Sau khi cài đặt CRD, bước tiếp theo là định nghĩa đối tượng GatewayClass. Đối tượng này mô tả các loại (loại hình) Gateway instances khác nhau. Thực chất, GatewayClass định nghĩa cách bạn muốn triển khai các instance Gateway với các cấu hình riêng biệt.

Ví dụ: Các nhà cung cấp hạ tầng có thể cung cấp GatewayClass nội bộ (internal) và bên ngoài (external). Gateway nội bộ có thể hỗ trợ stream listening, trong khi gateway bên ngoài chỉ hỗ trợ proxy listening.

Tạo GatewayClass

Hãy tạo một GatewayClass tên là kong-demo trong cluster và thiết lập controllerNamekonghq.com/kic-gateway-controller. Đây là giá trị mặc định để Kong Ingress Controller nhận diện và quản lý các tài nguyên gắn với GatewayClass này.

apiVersion: gateway.networking.k8s.io/v1
kind: GatewayClass
metadata:
  name: kong-demo
  annotations:
    konghq.com/gatewayclass-unmanaged: 'true'
spec:
  controllerName: konghq.com/kic-gateway-controller

3. Cluster Operations (Vận hành Cluster)

Các đối tượng Gateway được dùng để tự động tạo ra các gateway instances dựa trên GatewayClass mà nó tham chiếu và các listeners được định nghĩa. Tuy nhiên, do Kong Gateway Operator vẫn đang trong giai đoạn thử nghiệm (tech preview), chúng ta sẽ tự triển khai Kong một cách thủ công.

Triển khai Kong Ingress Controller bằng Helm

Sử dụng Helm để cài đặt Kong. Đầu tiên, thêm repo của Kong và cập nhật:

helm repo add kong https://charts.konghq.com
helm repo update

Kiểm tra để chắc chắn phiên bản chart kong/ingress0.10.2 trở lên:

helm search repo kong/ingress -o json | jq .[].version

Cài đặt Kong Ingress Controller với tên release là my-kong:

helm upgrade -i my-kong kong/ingress -n kong \
  --set gateway.image.tag=3.5 \
  --set gateway.env.router_flavor=expressions \
  --set gateway.admin.enabled=true \
  --set gateway.admin.http.enabled=true \
  --set controller.ingressController.installCRDs=false \
  --create-namespace

Lưu ý: Nếu bạn dùng MetalLB và nó không tự động gán LoadBalancer IP, bạn có thể gán IP mong muốn (ví dụ: 192.168.18.150) vào Service proxy của Kong:

kubectl -n kong annotate service my-kong-gateway-proxy \
  metallb.universe.tf/loadBalancerIPs=192.168.18.150

Tạo đối tượng Gateway

Vì chúng ta đang triển khai Kong thủ công, hãy đảm bảo rằng listener trên đối tượng Gateway khớp với Service Proxy của Kong.

Bạn có thể cấu hình Gateway dùng chung cho toàn bộ cluster (cho phép nhiều namespace sử dụng). Trong ví dụ dưới đây, chúng ta tạo Gateway tên kong-gw-demo ở namespace kong và cho phép các namespace có nhãn (label) shared-gateway-access: "true" được phép sử dụng Gateway này.

apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: kong-gw-demo
  namespace: kong
spec:
  gatewayClassName: kong-demo
  listeners:
    - name: proxy
      port: 80
      protocol: HTTP
      allowedRoutes:
        namespaces:
          from: Selector
          selector:
            matchLabels:
              shared-gateway-access: "true"

Mẹo: Bạn cũng có thể dùng matchExpressions để chỉ định đích danh tên của các namespaces được phép.

Triển khai ứng dụng Demo

Tiếp theo, hãy triển khai hai ứng dụng đơn giản (httpbinnginx) để thử nghiệm:

Ứng dụng httpbin:

kubectl create namespace httpbin
kubectl label namespace httpbin shared-gateway-access=true
kubectl -n httpbin create deployment httpbin --image=mccutchen/go-httpbin
kubectl -n httpbin expose deployment httpbin --name httpbin-svc --port 8080

Ứng dụng nginx:

kubectl create namespace nginx
kubectl label namespace nginx shared-gateway-access=true
kubectl -n nginx create deployment nginx --image=nginx:alpine
kubectl -n nginx expose deployment nginx --name nginx-svc --port 80

4. Cấu hình HTTPRoute

HTTPRoute là thành phần quan trọng dùng để định nghĩa:

  1. Conditions (matches): Điều kiện để khớp với request.
  2. Process (filters): Xử lý request (ví dụ: sửa đổi header, chuyển hướng).
  3. Forward (backendRefs): Chuyển tiếp request đến Service backend.

A. HTTPRouteMatch (Các tiêu chí Match Request)

1. Match theo Path (Đường dẫn)

Tương tự Ingress, path hỗ trợ Exact (chính xác), PathPrefix (tiền tố) và RegularExpression (Biểu thức chính quy).

Exact Match:

apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: nginx-route
  namespace: nginx
  annotations:
    konghq.com/strip-path: 'true'
spec:
  parentRefs:
    - group: gateway.networking.k8s.io
      kind: Gateway
      name: kong-gw-demo
      namespace: kong
  rules:
    - matches:
      - path:
          type: Exact
          value: /nginx
      backendRefs:
      - name: nginx-svc
        kind: Service
        port: 80

PathPrefix Match:

apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: httpbin-route
  namespace: httpbin
  annotations:
    konghq.com/strip-path: 'true'
spec:
  parentRefs:
    - group: gateway.networking.k8s.io
      kind: Gateway
      name: kong-gw-demo
      namespace: kong
  rules:
    - matches:
      - path:
          type: PathPrefix
          value: /test
      backendRefs:
      - name: httpbin-svc
        kind: Service
        port: 8080

RegularExpression (Regex):

apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: httpbin-regex-route
  namespace: httpbin
  annotations:
    konghq.com/strip-path: 'true'
spec:
  parentRefs:
    - group: gateway.networking.k8s.io
      kind: Gateway
      name: kong-gw-demo
      namespace: kong
  rules:
    - matches:
      - path:
          type: RegularExpression
          value: /api/v(1|2)
      backendRefs:
      - name: httpbin-svc
        kind: Service
        port: 8080

2. Match theo HTTP Header

Giờ đây, bạn có thể match trực tiếp theo Header trên HTTPRoute mà không cần dùng đến annotations.

Exact Header Match:

apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: httpbin-route
  namespace: httpbin
spec:
  parentRefs:
    - group: gateway.networking.k8s.io
      kind: Gateway
      name: kong-gw-demo
      namespace: kong
  rules:
    - matches:
      - path:
          type: PathPrefix
          value: /test
        headers:
        - name: "x-version"
          type: Exact
          value: "2"
      backendRefs:
      - name: httpbin-svc
        kind: Service
        port: 8080

3. Match theo Query Parameters

Khi cấu hình router_flavor=expressions ở Kong, bạn có thể match request dựa theo query string của URL.

apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: httpbin-route
  namespace: httpbin
spec:
  parentRefs:
    - group: gateway.networking.k8s.io
      kind: Gateway
      name: kong-gw-demo
      namespace: kong
  rules:
    - matches:
      - path:
          type: PathPrefix
          value: /test
        queryParams:
        - type: Exact
          name: version
          value: "2"
      backendRefs:
      - name: httpbin-svc
        kind: Service
        port: 8080

4. Match theo HTTP Method

Bạn cũng có thể chỉ định HTTPRoute chỉ nhận các phương thức cụ thể như GET hoặc POST.

apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: httpbin-route
  namespace: httpbin
spec:
  parentRefs:
    - group: gateway.networking.k8s.io
      kind: Gateway
      name: kong-gw-demo
      namespace: kong
  rules:
    - matches:
      - path:
          type: PathPrefix
          value: /test
        method: "POST"
      - path:
          type: PathPrefix
          value: /test
        method: "GET"
      backendRefs:
      - name: httpbin-svc
        kind: Service
        port: 8080

5. Match theo Hostname

Bạn có thể xác định hostnames cụ thể ở cấp độ HTTPRoute. Nếu Gateway listener không giới hạn hostname, nó sẽ chấp nhận tất cả. Tuy nhiên, nếu Listener trên Gateway quy định hostname (ví dụ: *.li.k8s), thì HTTPRoute chỉ hoạt động nếu hostname của nó khớp với điều kiện trên Gateway.

apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: httpbin-route
  namespace: httpbin
spec:
  hostnames:
  - proxy.li.k8s
  parentRefs:
    - group: gateway.networking.k8s.io
      kind: Gateway
      name: kong-gw-demo
      namespace: kong
  rules:
    - matches:
      - path:
          type: PathPrefix
          value: /test
      backendRefs:
      - name: httpbin-svc
        kind: Service
        port: 8080

B. HTTPRouteFilter (Xử lý Request / Response)

HTTPRouteFilter giúp can thiệp vào vòng đời của request.

1. RequestHeaderModifier

Cho phép set (ghi đè), add (thêm), hoặc remove (xóa) header của Request trước khi gửi đến Backend.

        filters:
        - type: RequestHeaderModifier
          requestHeaderModifier:
            add:
              - name: x-test-id
                value: fomm
            set: 
              - name: User-Agent
                value: fomm-local
            remove: ["Accept"]

2. ResponseHeaderModifier

Hoạt động tương tự đối với Response trả về từ Backend.

        filters:
        - type: ResponseHeaderModifier
          responseHeaderModifier:
            add:
              - name: x-test-id
                value: fomm
            set: 
              - name: User-Agent
                value: fomm-local
            remove: ["Access-Control-Allow-Origin"]

3. RequestRedirect

Cho phép chặn yêu cầu và Redirect thẳng đến một địa chỉ khác (sẽ bỏ qua backendRefs).

      filters:
      - type: RequestRedirect
        requestRedirect:
          scheme: http
          hostname: httpbin.org
          path:
            type: ReplaceFullPath
            replaceFullPath: /anything/paprika
          statusCode: 301
          port: 80

C. ExtensionRef (Tích hợp Kong Plugin)

ExtensionRef giúp tận dụng sức mạnh của nhà cung cấp (ở đây là Kong) bằng cách gán trực tiếp KongPlugin lên HTTPRoute.

apiVersion: configuration.konghq.com/v1
kind: KongPlugin
metadata:
  name: key-auth-example
  namespace: httpbin
plugin: key-auth
config:
  key_names:
  - apikey
---
# ... (Phần cấu hình HTTPRoute)
      filters:
        - type: ExtensionRef
          extensionRef:
            group: configuration.konghq.com
            kind: KongPlugin
            name: key-auth-example

5. BackendRefs nâng cao

Cross-namespace routing (Định tuyến khác Namespace)

Ingress truyền thống không cho phép route traffic đến Service ở một namespace khác. Với Gateway API, điều này hoàn toàn có thể thông qua ReferenceGrant.

Ví dụ, HTTPRoute ở namespace kong muốn trỏ đến httpbin-svc ở namespace httpbin:

Bước 1: HTTPRoute ở namespace kong trỏ đến httpbin-svc (namespace: httpbin). Bước 2: Cấp quyền bằng ReferenceGrant ở namespace httpbin:

apiVersion: gateway.networking.k8s.io/v1beta1
kind: ReferenceGrant
metadata:
  name: httpbin-grant-kong
  namespace: httpbin
spec:
  from:
  - group: gateway.networking.k8s.io
    kind: HTTPRoute
    namespace: kong
  to:
  - group: ""
    kind: Service

Weighted routing (Chia tỷ lệ truy cập / Traffic Splitting)

Rất hữu ích cho Canary Deployment. Dưới đây là cách chia 90% traffic vào httpbin và 10% vào nginx:

    backendRefs:
    - name: httpbin-svc
      namespace: httpbin
      kind: Service
      port: 8080
      weight: 90
    - name: nginx-svc
      namespace: nginx
      kind: Service
      port: 80
      weight: 10

Tổng kết

Kubernetes Gateway API là tương lai của việc quản lý lưu lượng K8s và nên bắt đầu khám phá tiêu chuẩn mới này. Sự kết hợp giữa Gateway API và Kong Ingress Controller mang lại một hệ thống định tuyến cực kỳ mạnh mẽ, rõ ràng, phân quyền tốt và dễ dàng mở rộng.

Vẫn còn rất nhiều tính năng thú vị để khám phá như TLS termination, tích hợp cert-manager và L4 routing. Hẹn gặp lại các bạn ở các bài viết tiếp theo của TechCoBan!

Bình luận

Bài viết liên quan