본문 바로가기

컨테이너/쿠버네티스 네트워크

[KANS] 쿠버네티스 네트워크 (12) Gateway API

목표:

1. Gatway API vs API Gateway

2. Gateway API 란? 

3. Gloo Gateway API

Gateway API vs API Gateway

Gateway API vs. API Gateway

One of the first questions that came to my mind when I started exploring the Kubernetes Gateway API was, “How is it different from an API Gateway?” I figured you might have the same question too!😃

While both concepts involve routing and managing traffic, they serve very different purposes.

 

 

  • API 게이트웨이에 대해 누가 물어본다면 저는 과거에 netflix OSS 아키텍처를 이야기 해줍니다. 

 

아마 대부분이 생소하실겁니다.

MSA 아키텍처가 등장하고 쿠버네티스에게 잠식 되기 전에 NETFLIX OSS와 같은 아키텍처들이 유행했었던건 

기사등으로는 접했을수 있겠지만, 실제로 사용해보거나 서비스 해보신 분은 없으실겁니다. 그중에서도 API Gateway는 Netflix OSS의 핵심 컴포넌트 중 하나였습니다.

 

2. API 게이트웨이란 무엇인가요?

API 게이트웨이 는 외부 클라이언트(모바일 앱, 브라우저 또는 외부 API)와 백엔드 마이크로서비스 또는 API 사이에 위치하는 특정 유형의 애플리케이션 수준 서비스 입니다.

주요 목적은 모든 클라이언트 요청에 대한 단일 진입점 역할을 하여 API 트래픽을 관리하고 조율하는 것입니다.

API 게이트웨이에는 간단한 트래픽 라우팅 외에도 인증 , 속도 제한 , 캐싱 , 부하 분산 , 로깅 , 모니터링 과 같은 추가 기능이 포함됩니다 .

API 게이트웨이 에 대한 주요 사항 :

  • API에 초점 : 주로 API 호출과 관련된 트래픽을 처리합니다(애플리케이션 계층 - OSI 모델의 7계층).
  • API 요청 관리 : API 소비자를 위한 단일 진입점 역할을 하며 API 경로에 따라 다양한 백엔드 서비스에 요청을 프록시할 수 있습니다.
  • 추가 기능 : API 게이트웨이에는 보안(인증, 권한 부여), 트래픽 관리(속도 제한, 조절), 캐싱 및 모니터링이 포함되는 경우가 많습니다.
  • Kubernetes에 국한되지 않음 : API 게이트웨이는 모든 환경(클라우드, 온프레미스 또는 하이브리드)에서 사용할 수 있으며 Kubernetes 클러스터에 국한되지 않습니다.

 

물론 쿠버네티스와 호환하여 사용하기도 합니다. svc.cluster.local와 같은 도메인을 coredns 서버를 통해 내부 클러스터간 통신에 범위를 한정해서  API gateway를 클러스터 내부에 배포해 두고 내부 라우팅을 직접 담당하여 사용하고 있습니다.

 

 

아마 이러한 어플리케이션을 사용하고 있는 회사들은 5~7년전에 netflix OSS 아키텍처로 플랫폼을 설계 했던 국내 거대 제조업일겁니다.다른 플랫폼에서 사용하던 어플리케이션을 컨테이너화 해서  사용하는것을 최근에 몇몇 봤습니다.

 

 

Gateway API 란? 

  • 인그레스를 대체하는 기능 (주로 HTTP용으로 설계된 Ingress와 달리 Gateway API는 TCP, UDP, TLS를 포함한 여러 프로토콜을 지원합니다.)
  • 7레이어에서의 HTTP/S 뿐만 아니라 TCP/UDP 지원
  • 기존의 Ingress 에 좀 더 기능을 추가, 역할 분리(role-oriented)

 

구성요소

구성요소

Gateway API has three stable API kinds:

  • GatewayClass: Defines a set of gateways with common configuration and managed by a controller that implements the class.
  • Gateway: Defines an instance of traffic handling infrastructure, such as cloud load balancer.
  • HTTPRoute: Defines HTTP-specific rules for mapping traffic from a Gateway listener to a representation of backend network endpoints. These endpoints are often represented as a Service.

역할의 분리 (role-oriented)

  • 인프라 운영자/Devops 는 GatewayClass,Gateway를 관리 
  • 개발자는 트래픽 라우팅을 관리 (HTTPRoute)- Service

 

Gloo Gateway

  • kind를 통해 쉽게 테스트 가능함
  • Gateway API는 Cilium, istio , Envoy Gatway 등 많은 솔루션에서 제공하지만 가장 편하게 테스트 할수 있음으로 Gloo 사용해봄
  • [Tutorial] Hands-On with the Kubernetes Gateway API and Envoy Proxy : 양이 상당히 매우 많음 😅

실습 1.

 

  • kind cluster 배포
#
cat <<EOT> kind-1node.yaml
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
  extraPortMappings:
  - containerPort: 30000
    hostPort: 30000
  - containerPort: 30001
    hostPort: 30001
  - containerPort: 30002
    hostPort: 30002
EOT

# Install KinD Cluster
kind create cluster --image kindest/node:v1.30.0 --config kind-1node.yaml --name myk8s

# 노드에 기본 툴 설치
docker exec -it myk8s-control-plane sh -c 'apt update && apt install tree psmisc lsof wget bsdmainutils bridge-utils net-tools dnsutils tcpdump ngrep iputils-ping git vim -y'

# 노드/파드 확인
kubectl get nodes -o wide
kubectl get pod -A
# CRDs 설치 및 확인
kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.0.0/standard-install.yaml
kubectl get crd
  • rosetta 비활성화
    • [macOS m시리즈] Docker Desktop : 아래 옵션 Uncheck 해둘 것 → Apply & restart

  • gloo-gateway 헬름 설치
# [신규 터미널] 모니터링
watch -d kubectl get pod,svc,endpointslices,ep -n gloo-system

# Install Gloo Gateway
helm repo add gloo https://storage.googleapis.com/solo-public-helm
helm repo update
helm install -n gloo-system gloo-gateway gloo/gloo \
--create-namespace \
--version 1.17.7 \
--set kubeGateway.enabled=true \
--set gloo.disableLeaderElection=true \
--set discovery.enabled=false

# Confirm that the Gloo control plane has successfully been deployed using this command
kubectl rollout status deployment/gloo -n gloo-system

# 설치 확인
kubectl get crd | grep 'networking.k8s.io'
kubectl get crd | grep -v 'networking.k8s.io'
kubectl get pod,svc,endpointslices -n gloo-system

#
kubectl explain gatewayclasses
kubectl get gatewayclasses
NAME           CONTROLLER             ACCEPTED   AGE
gloo-gateway   solo.io/gloo-gateway   True       21m

kubectl get gatewayclasses -o yaml
apiVersion: v1
items:
- apiVersion: gateway.networking.k8s.io/v1
  kind: GatewayClass
  metadata:
    labels:
      app: gloo
    name: gloo-gateway
  spec:
    controllerName: solo.io/gloo-gateway
...

httpbin 설치 

  1. kubectl rollout 명령어는 애플리케이션 배포와 관련된 상태를 모니터링하고 관리하는 데 사용됩니다.
  2. 배포 상태 확인: kubectl rollout status 명령어로 배포가 성공적으로 이루어졌는지 확인합니다.
  3. 이력 확인 및 롤백: kubectl rollout history와 kubectl rollout undo 명령어로 이전 배포 이력을 확인하거나 문제가 있을 때 이전 버전으로 되돌릴 수 있습니다.
#
watch -d kubectl get pod,svc,endpointslices,ep -n httpbin

# Install Httpbin Application
kubectl apply -f https://raw.githubusercontent.com/solo-io/solo-blog/main/gateway-api-tutorial/01-httpbin-svc.yaml

# 설치 확인
kubectl get deploy,pod,svc,endpointslices,sa -n httpbin
kubectl rollout status deploy/httpbin -n httpbin

# (옵션) NodePort 설정
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Service
metadata:
  labels:
    app: httpbin
    service: httpbin
  name: httpbin
  namespace: httpbin
spec:
  type: NodePort
  ports:
  - name: http
    port: 8000
    targetPort: 80
    nodePort: 30000
  selector:
    app: httpbin
EOF

# (옵션) 로컬 접속 확인
echo "httpbin web - http://localhost:30000"     # macOS 사용자
echo "httpbin web - http://192.168.50.10:30000" # Windows 사용자

Gateway API kinds - Docs

  • GatewayClass: Defines a set of gateways with common configuration and managed by a controller that implements the class.
  • Gateway: Defines an instance of traffic handling infrastructure, such as cloud load balancer.
  • HTTPRoute: Defines HTTP-specific rules for mapping traffic from a Gateway listener to a representation of backend network endpoints. These endpoints are often represented as a Service

# 02-gateway.yaml
kind: Gateway
apiVersion: gateway.networking.k8s.io/v1
metadata:
  name: http
spec:
  gatewayClassName: gloo-gateway
  listeners:
  - protocol: HTTP
    port: 8080
    name: http
    allowedRoutes:
      namespaces:
        from: All

# gateway 리소스 생성
kubectl apply -f https://raw.githubusercontent.com/solo-io/gloo-gateway-use-cases/main/gateway-api-tutorial/02-gateway.yaml

# 확인 : Now we can confirm that the Gateway has been activated
kubectl get gateway -n gloo-system
kubectl get gateway -n gloo-system -o yaml | k neat
apiVersion: v1
items:
- apiVersion: gateway.networking.k8s.io/v1
  kind: Gateway
  metadata:
    name: http
    namespace: gloo-system
  spec:
    gatewayClassName: gloo-gateway
    listeners:
    - allowedRoutes:
        namespaces:
          from: All
      name: http
      port: 8080
      protocol: HTTP
...

# You can also confirm that Gloo Gateway has spun up an Envoy proxy instance in response to the creation of this Gateway object by deploying gloo-proxy-http:
kubectl get deployment gloo-proxy-http -n gloo-system
NAME              READY   UP-TO-DATE   AVAILABLE   AGE
gloo-proxy-http   1/1     1            1           5m22s

# envoy 사용 확인
kubectl get pod -n gloo-system
kubectl describe pod -n gloo-system  |grep Image:
    Image:         quay.io/solo-io/gloo-envoy-wrapper:1.17.7
    Image:          quay.io/solo-io/gloo:1.17.7
    Image:         quay.io/solo-io/gloo-envoy-wrapper:1.17.7


# gloo-proxy-http 서비스는 External-IP는 Pending 상태
kubectl get svc -n gloo-system gloo-proxy-http
NAME              TYPE           CLUSTER-IP    EXTERNAL-IP   PORT(S)          AGE
gloo-proxy-http   LoadBalancer   10.96.71.22   <pending>     8080:31555/TCP   2m4s

# gloo-proxy-http NodePort 30001 설정
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Service
metadata:
  labels:
    app.kubernetes.io/instance: http
    app.kubernetes.io/managed-by: Helm
    app.kubernetes.io/name: gloo-proxy-http
    app.kubernetes.io/version: 1.17.7
    gateway.networking.k8s.io/gateway-name: http
    gloo: kube-gateway
    helm.sh/chart: gloo-gateway-1.17.7
  name: gloo-proxy-http
  namespace: gloo-system
spec:
  ports:
  - name: http
    nodePort: 30001
    port: 8080
  selector:
    app.kubernetes.io/instance: http
    app.kubernetes.io/name: gloo-proxy-http
    gateway.networking.k8s.io/gateway-name: http
  type: LoadBalancer
EOF

kubectl get svc -n gloo-system gloo-proxy-http
  • EXTERNAL-IP : 외부에서 접근하기 위한 IP 주소입니다.
    • 현재 <pending> 상태로, 외부 IP 주소가 아직 할당되지 않았음을 의미합니다. 보통 이 상태는 클라우드 제공자가 외부 IP를 할당 중일 때 나타납니다.
  • gloo-proxy-http  Service는 Gloo Gateway의 HTTP 트래픽을 처리하기 위한 LoadBalancer 타입의 Service입니다.
    • 현재 클러스터 내부 IP는 할당되었지만, 외부 IP는 아직 할당되지 않은 상태입니다. 외부에서 HTTP 트래픽은 
      8080  포트를 통해 접근할 수 있으며, 클러스터 내부에서는 32093 포트를 통해 요청을 수신합니다.
# Port Forward
# We will use a simple port-forward to expose the proxy’s HTTP port for us to use. 
# (Note that gloo-proxy-http is Gloo’s deployment of the Envoy data plane.)
kubectl port-forward deployment/gloo-proxy-http -n gloo-system 8080:8080 &
  • gloo-system 네임스페이스에 있는 http라는 Gateway에 연결되며, api.example.com 호스트의 /get 경로로 들어오는 HTTP 요청을 httpbin 서비스의 8000 포트로 전달합니다. 이는 외부 요청을 내부 서비스로 라우팅하는 데 사용됩니다.
(⎈|kind-myk8s:N/A) root@kind:~# curl -O https://raw.githubusercontent.com/solo-io/gloo-gateway-use-cases/main/gateway-api-tutorial/03-httpbin-route.yaml
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   381  100   381    0     0    813      0 --:--:-- --:--:-- --:--:--   814

(⎈|kind-myk8s:N/A) root@kind:~# cat 03-httpbin-route.yaml
apiVersion: gateway.networking.k8s.io/v1beta1
kind: HTTPRoute
metadata:
  name: httpbin
  namespace: httpbin
  labels:
    example: httpbin-route
spec:
  parentRefs:
    - name: http
      namespace: gloo-system
  hostnames:
    - "api.example.com"
  rules:
  - matches:
    - path:
        type: Exact
        value: /get
    backendRefs:
      - name: httpbin
        port: 8000
        
(⎈|kind-myk8s:N/A) root@kind:~# kubectl apply -f 03-httpbin-route.yaml
httproute.gateway.networking.k8s.io/httpbin created
  • HTTPRoute 리소스를 조회하여 확인
(⎈|kind-myk8s:N/A) root@kind:~# kubectl get httproute -n httpbin
NAME      HOSTNAMES             AGE
httpbin   ["api.example.com"]   20s

(⎈|kind-myk8s:N/A) root@kind:~# kubectl describe httproute -n httpbin
...
Spec:
  Hostnames:
    api.example.com
  Parent Refs:
    Group:      gateway.networking.k8s.io
    Kind:       Gateway
    Name:       http
    Namespace:  gloo-system
  Rules:
    Backend Refs:
      Group:
      Kind:    Service
      Name:    httpbin
      Port:    8000
      Weight:  1
    Matches:
      Path:
        Type:   Exact
        Value:  /get
...
  • 로컬 시스템의 /etc/hosts 파일에 api.example.com이라는 호스트 이름을 127.0.0.1 IP 주소에 매핑하는 내용을 추가합니다.
(⎈|kind-myk8s:N/A) root@kind:~# echo "127.0.0.1 api.example.com" | sudo tee -a /etc/hosts
127.0.0.1 api.example.com
  •  curl을 사용하여 로컬의 HTTP 서버에 요청을 보내고, Gloo Gateway를 통해 httpbin 서비스에 접근하여 /get 엔드포인트에서 JSON 응답을 확인합니다.
  • 포트포워딩을 통해 gateway-proxy SVC를 통해 내부로 인입 할수 있음. 
$ curl -is -H "Host: api.example.com" http://localhost:8080/get
Handling connection for 8080
HTTP/1.1 200 OK
server: envoy
date: Sat, 12 Oct 2024 14:49:09 GMT
content-type: application/json
content-length: 239
access-control-allow-origin: *
access-control-allow-credentials: true
x-envoy-upstream-service-time: 10

{
  "args": {},
  "headers": {
    "Accept": "*/*",
    "Host": "api.example.com",
    "User-Agent": "curl/8.7.1",
    "X-Envoy-Expected-Rq-Timeout-Ms": "15000"
  },
  "origin": "10.244.0.11",
  "u

목표:

이외에도 다음과 같은 기능들을 제공 하는것을 보았을때  Istio의 Gateway와 VirtualService, DestinationRule 을 활용한 다양한 Advanced Routing 기능들을 점차 Gateway API로 마이그레이션 되고 있는것으로 보입니다.

  • [정규식 패턴 매칭] 
  • [업스트림 베어러 토큰을 사용한 변환] 
  • [헤더기반 라우팅을 사용한 다크 런칭]
  • [백분율 기반 라우팅을 사용한 카나리아 릴리스]