Kubernetes

Operator로 배포하는 Gateway API 형태의 Kong API Gateway

mokpolar 2024. 10. 9. 16:20
반응형

안녕하세요?

 

Kong API Gateway를 Ingress가 아니라 Gateway API 형태로 설치해 보고 간단하게 테스트해 본 얘기를 해보겠습니다.
그리고 Kong API Gateway는 Operator 패턴으로 배포하였습니다.

 

설치하기 쉽게 가이드 형태로 작성해보겠습니다.

 

TL; DR

구조를 그려봤는데, 아래와 같은 형태가 되는 것 같습니다.

Gateway API에 대해서

Ingress는 frozen

Ingress는 frozen 되었습니다.


Ingress | Kubernetes 를 보면

 

동결되었고 Gateway API에 새로운 기능이 추가된다고 나와 있습니다.
이제는 Gateway API | Kubernetes문서를 봐야 되네요.

 

Gateway API는 뭔가요?

 

Gateway API를 쉽게 표현하면 기존의 Ingress에 기능을 더 추가하고, 역할 분리(role-oriented)가 된 것이라고 할 수 있습니다.

주요 기능은 아래와 같습니다.

 

  1. 개선된 리소스 모델
    : API는 GatewayClass, Gateway 및 Route(HTTPRoute, TCPRoute 등)와 같은 새로운 사용자 정의 리소스를 도입하여 라우팅 규칙을 정의하는 보다 세부적이고 표현력 있는 방법을 제공합니다.
  2. 프로토콜 독립적
    : 주로 HTTP용으로 설계된 Ingress와 달리 Gateway API는 TCP, UDP, TLS를 포함한 여러 프로토콜을 지원합니다.
  3. 강화된 보안
    : TLS 구성 및 보다 세부적인 액세스 제어에 대한 기본 제공 지원.
  4. 교차 네임스페이스 지원
    : 서로 다른 네임스페이스의 서비스로 트래픽을 라우팅하여 보다 유연한 아키텍처를 구축할 수 있는 기능을 제공합니다.
  5. 확장성
    : API는 사용자 정의 리소스 및 정책으로 쉽게 확장할 수 있도록 설계되었습니다.
  6. 역할 지향
    : 클러스터 운영자, 애플리케이션 개발자, 보안 팀 간의 우려를 명확하게 분리합니다.

 

Gateway API의 구성 요소

Gateway API | Kubernetes 문서에 의하면,

  • GatewayClass: 공통 구성 설정을 가진 일련의 게이트웨이를 정의하며, 이 클래스의 구현을 담당하는 컨트롤러에 의해 관리됩니다.
  • Gateway: 클라우드 로드 밸런서와 같은 트래픽 처리 인프라의 인스턴스를 정의합니다.
  • HTTPRoute: Gateway 리스너에서 백엔드 네트워크 엔드포인트의 표현으로 트래픽을 매핑하는 HTTP 전용 규칙을 정의합니다. 이 엔드포인트는 종종 Service로 표현됩니다.

이라고 합니다.

출처 : Gateway API | Kubernetes

 

Gateway API의 역할 분리

 

역할 분리라는 얘기가 앞에 나왔었는데,

출처: https://gateway-api.sigs.k8s.io/

 

위 그림이 그 의미를 가장 잘 표현해주는 것 같습니다.

 

이전에는 개발자가 데브옵스 등 인프라 관리자에게 요청해서 하던 일들을 스스로 할 수 있게 분리한 것 같습니다.

 

문서에서는 아래와 같이 설명하고 있습니다.

  • Infrastructure Provider: 여러 격리된 클러스터가 여러 테넌트를 지원할 수 있도록 인프라를 관리하는 역할을 하며, 예를 들어 클라우드 제공자가 이에 해당합니다.
  • Cluster Operator: 클러스터를 관리하며, 주로 정책, 네트워크 접근, 애플리케이션 권한 등에 관련된 사항을 다룹니다.
  • Application Developer: 클러스터에서 실행되는 애플리케이션을 관리하며, 주로 애플리케이션 수준의 구성 및 Service 구성을 담당합니다.

 

Gateway API로된 Kong API Gateway 를 Operator로 배포

Kong Gateway Operator 배포

Kong Gateway Operator | Kong Docs 문서를 참조해서 배포를 해보겠습니다.

 

Kong 의 설정을 DB에 저장하는 형태로 배포도 하지만 Kubernetes 상에서는 DB-less 형태로 배포를 권장하는 것 같습니다.
참고 : https://docs.konghq.com/gateway/latest/install/kubernetes/

 

이름이 조금 헷갈립니다.
Gateway Operator가 떠있다가 Kong gateway CR을 배포하면 라우팅을 구성해주는 형태입니다.

 

아래는 Gateway Operator의 helm value입니다.
보기 쉽게 주석들을 한글화해두었습니다.

 

kgo_values.yaml

image:
  repository: docker.io/kong/gateway-operator
  # 버전 태그 1.3으로 변경
  tag: 1.3

kubeRBACProxy:
  # 컨트롤러의 추가 파드 컨테이너
  image: gcr.io/kubebuilder/kube-rbac-proxy
  tag: v0.8.0
  # 이 섹션을 사용하여 kube-rbac-proxy의 요청 및 한계를 사용자 지정
  resources:
    limits:
      cpu: 500m
      memory: 128Mi
    requests:
      cpu: 5m
      memory: 64Mi

# gateway-operator 차트 리소스에 대한 네임스페이스 재정의. 기본적으로 차트는 릴리스 네임스페이스에 리소스를 생성.

replicaCount: 1

serviceAccount:
  # 서비스 계정을 생성할지 여부 지정
  create: true
  # 사용할 서비스 계정의 이름
  # 설정하지 않으면 생성이 true인 경우 fullname 템플릿을 사용하여 이름이 생성됨
  name: controller-manager

test:
  enabled: false

# 이 섹션을 사용하여 생성된 각 Kubernetes 객체에 추가할 레이블을 구성
extraLabels: {}

# KGO 파드에 추가할 레이블
podLabels: {}

# KIC의 CRD 설치
# 이 지점에서 kong ingress controller crd 설치 
kic-crds:
  enabled: true

# Gateway API 표준 CRD 설치
# 이 지점에서 kong gateway api crd 설치 
gwapi-standard-crds:
  enabled: true

# Gateway API 실험적 CRD 설치
gwapi-experimental-crds:
  enabled: false

# gateway-operator livenessProbe 사용자 지정
livenessProbe:
  httpGet:
    path: /healthz
    port: 8081
  initialDelaySeconds: 15
  periodSeconds: 20

# gateway-operator readinessProbe 사용자 지정
readinessProbe:
  httpGet:
    path: /readyz
    port: 8081
  initialDelaySeconds: 5
  periodSeconds: 10

# 이 섹션을 사용하여 gateway-operator의 요청 및 한계를 사용자 지정
resources:
  limits:
    cpu: 500m
    memory: 256Mi
  requests:
    cpu: 10m
    memory: 128Mi

배포해보겠습니다.

kubectl create ns mokpolar
helm upgrade --install kgo kong/gateway-operator -n mokpolar --values kgo_values.yaml

 

다 배포된 모습을 그려보면 이런 형태인 것 같습니다.

 

Gateway Configuration

Kong Gateway Configuration에는 control plane, data plane에 대한 설정(LoadBalancer, Proxy 등) 이 들어갑니다.
AWS 를 기준으로 익숙한 annotation을 넣어서 NLB로 만들어봅니다.

 

여기 들어간 설정들대로 control plane, data plane이 생성됩니다.

위 도식에서 보듯이 트래픽을 실제로 받는 부분은 Dataplane pod가 됩니다.

kind: GatewayConfiguration
apiVersion: gateway-operator.konghq.com/v1beta1
metadata:
  name: mokpolar-kong
  namespace: mokpolar
spec:
  dataPlaneOptions:
    network:
      services:
        ingress:
          annotations:
            service.beta.kubernetes.io/aws-load-balancer-type: external
            service.beta.kubernetes.io/aws-load-balancer-scheme: internet-facing
            service.beta.kubernetes.io/aws-load-balancer-nlb-target-type: instance
            service.beta.kubernetes.io/aws-load-balancer-security-groups: "your-security-group"
            service.beta.kubernetes.io/aws-load-balancer-manage-backend-security-group-rules: "true"
    deployment:
      podTemplateSpec:
        metadata:
          annotations:
            dataplane-pod-annotation: example
        spec:
          containers:
          - name: proxy
            image: kong:3.7.1
            readinessProbe:
              initialDelaySeconds: 1
              periodSeconds: 1
  controlPlaneOptions:
    deployment:
      podTemplateSpec:
        spec:
          containers:
          - name: controller
            image: kong/kubernetes-ingress-controller:3.2.0
            env:
            - name: CONTROLLER_LOG_LEVEL
              value: debug

 

Gateway Class, Gateway, HTTPRoute

GatewayConfiguration에 선언된 LB 등 설정을 기반으로 protocol, path 등을 정의합니다.

 

  • GatewayClass

GatewayClass에는 어떤 Controller를 사용하는지에 대한 내용이 들어갑니다.
이 경우, Kong gateway operator를 사용합니다.

 

그리고 GatewayConfiguration으로 설정들을 위에서 선언했기 때문에 이 내용을 넣습니다.

kind: GatewayClass
apiVersion: gateway.networking.k8s.io/v1beta1
metadata:
  name: mokpolar-kong
spec:
  controllerName: konghq.com/gateway-operator
  parametersRef:
    group: gateway-operator.konghq.com
    kind: GatewayConfiguration
    name: mokpolar-kong
    namespace: mokpolar

 

  • Gateway

Gateway에서는 protocol, port 등을 정의하여 listener를 선언합니다.
어떤 GatewayClass를 사용하는지가 들어가야합니다.

kind: Gateway
apiVersion: gateway.networking.k8s.io/v1beta1
metadata:
  name: mokpolar-kong
  namespace: mokpolar
spec:
  gatewayClassName: mokpolar-kong
  listeners:
  - name: http
    protocol: HTTP
    port: 80

 

  • HTTPRoute

role base로 나뉘어진 구조 상 개발자들이 만들면 되는 HTTPRoute 입니다.
어떤 Gateway를 사용하는지 나타주고, routing rule을 선언합니다.

 

아래에서는 PathPrefix type으로 vector에 매치된 트래픽이
vector 라는 이름의 Kubernetes ClusterIP Service의 8889번 포트로 가도록 되어있습니다.

 

이런 형태로 개발자들이 본인들이 배포하는 서비스에 외부에서부터 접근하는 경로를 만들 수 있습니다.

kind: HTTPRoute
apiVersion: gateway.networking.k8s.io/v1beta1
metadata:
  name: mokpolar-routes
  namespace: mokpolar
spec:
  parentRefs:
    - group: gateway.networking.k8s.io
      kind: Gateway
      name: mokpolar-kong
      namespace: mokpolar
  rules:
    - matches:
        - path:
            type: PathPrefix
            value: /vector
      backendRefs:
        - name: vector
          port: 8889

 

지금쯤이면 AWS NLB가 생성되어 있을 겁니다. 호출 테스트를 해봅니다.

export PROXY_IP=$(kubectl get gateway {your_namespace}_kong -n {your_namespace} -o jsonpath='{.status.addresses[0].value}')
curl -X POST $PROXY_IP/vector -d '{your_data}'

Plugin

Kong의 플러그인은 Lua 로 개발하여 .lua 파일을 custom으로 직접 탑재할 수 있습니다.
EBS 등에 집어넣어서 GatewayConfiguration에 마운트 정보를 넣는 형태로 사용해도 됩니다.

 

그리고 기성품을 사용하려면 https://docs.konghq.com/hub/ kong plugin hub에 바로 탑재할 수 있는 plugin들도 많으니 그대로 사용해도 좋습니다.

 

간단하게 key-auth plugin을 테스트한 내용을 보여드리겠습니다.
아래와 같이 plugin, consumer를 배포해서 key를 추가합니다.

apiVersion: configuration.konghq.com/v1
kind: KongPlugin
metadata:
  name: key-auth-plugin
  namespace: mokpolar
plugin: key-auth
config:
  key_names:
    - apikey
  anonymous: anonymous
  hide_credentials: true
---
apiVersion: configuration.konghq.com/v1
kind: KongConsumer
metadata:
  name: consumer-2
  namespace: mokpolar
  annotations:
    kubernetes.io/ingress.class: kong
username: consumer-2
credentials:
  - consumer-2-key-auth
  • client에서 호출시 key가 없는 경우
curl -X POST http://{host}/vector \
-d '{"mokpolar-test": "mokpolar", "test": "mokpolar-test10"}'
{
  "message":"An unexpected error occurred",
  "request_id":"..."
}%

이 경우 Kong data plane에는 이런 로그가 남습니다.

2024/07/27 08:56:18 [error] 1332#0: *255668 [kong] init.lua:409 [key-auth] /usr/local/share/lua/5.1/kong/plugins/key-auth/handler.lua:53: either credential or consumer must be provided, client: ..., server: kong, request: "POST /vector HTTP/1.1", host: "....elb.us-east-1.amazonaws.com", request_id: "..."
100.120.13.9 - - [27/Jul/2024:08:56:18 +0000] "POST /vector HTTP/1.1" 500 97 "-" "curl/8.6.0" kong_request_id: "..."

 

  • client에서 호출시 이상한 key가 있는 경우
curl -X POST http://{host}/vector \
-H "apikey: dddconsumer-2-password" \
-d '{"mokpolar-test": "mokpolar", "test": "mokpolar-test10"}'
{
  "message":"An unexpected error occurred",
  "request_id":"acecd32e99ca046f440b9e04c7971d5b"
}%

 

Kong의 성능

Kong Performance Benchmark를 보면 아래와 같이 안내하고 있습니다.
Kong Performance Benchmark 문서를 참고 바랍니다.

 

route를 추가할 때 RPS 감소가 크지 않고 auth plugin 추가시 RPS가 다소 줄어드는 것 같습니다.

 

Kong의 대시보드

kong의 대시보드는 enterprise기능이므로 konga 라는 오픈소스 대시보드를 따로 배포해야 합니다.
아래와 같이 생겼습니다.

Reference

반응형