Skip to content
Published on

Kubernetes Gateway API와 GRPCRoute 완벽 가이드: 서비스 메시부터 트래픽 라우팅까지

Authors
  • Name
    Twitter

Gateway API란?

Kubernetes Gateway API는 기존 Ingress 리소스의 한계를 넘어선 차세대 네트워킹 API입니다. 역할 기반의 리소스 모델(GatewayClass, Gateway, Route)을 통해 인프라 운영자와 애플리케이션 개발자의 관심사를 명확히 분리합니다.

왜 Gateway API인가?

기존 Ingress의 문제점:

  • 단일 리소스에 모든 설정이 집중
  • 구현체마다 다른 어노테이션
  • gRPC, TCP, UDP 등 HTTP 외 프로토콜 미지원
  • 역할 분리 불가

Gateway API는 이를 해결합니다:

# 1. 인프라팀이 관리하는 GatewayClass
apiVersion: gateway.networking.k8s.io/v1
kind: GatewayClass
metadata:
  name: istio
spec:
  controllerName: istio.io/gateway-controller
---
# 2. 플랫폼팀이 관리하는 Gateway
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: production-gateway
  namespace: infra
spec:
  gatewayClassName: istio
  listeners:
    - name: grpc
      protocol: HTTPS
      port: 443
      tls:
        mode: Terminate
        certificateRefs:
          - name: wildcard-cert
    - name: http
      protocol: HTTP
      port: 80

GRPCRoute 심층 분석

GRPCRoute는 Gateway API v1 (GA)에 포함된 gRPC 전용 라우팅 리소스입니다. HTTPRoute와 달리 gRPC의 서비스/메서드 기반 매칭을 네이티브로 지원합니다.

기본 구조

apiVersion: gateway.networking.k8s.io/v1
kind: GRPCRoute
metadata:
  name: user-service-route
  namespace: app
spec:
  parentRefs:
    - name: production-gateway
      namespace: infra
      sectionName: grpc
  hostnames:
    - 'api.example.com'
  rules:
    - matches:
        - method:
            service: 'user.v1.UserService'
            method: 'GetUser'
      backendRefs:
        - name: user-service
          port: 50051
    - matches:
        - method:
            service: 'user.v1.UserService'
            method: 'CreateUser'
      backendRefs:
        - name: user-write-service
          port: 50051

헤더 기반 라우팅

특정 헤더 값에 따라 다른 백엔드로 라우팅할 수 있습니다:

apiVersion: gateway.networking.k8s.io/v1
kind: GRPCRoute
metadata:
  name: ab-test-route
spec:
  parentRefs:
    - name: production-gateway
      namespace: infra
  rules:
    - matches:
        - method:
            service: 'recommendation.v1.RecommendationService'
          headers:
            - name: x-experiment-group
              value: 'treatment-a'
      backendRefs:
        - name: recommendation-v2
          port: 50051
    - matches:
        - method:
            service: 'recommendation.v1.RecommendationService'
      backendRefs:
        - name: recommendation-v1
          port: 50051

트래픽 스플리팅 (카나리 배포)

GRPCRoute의 backendRefs에 weight를 지정하면 트래픽을 비율로 분배할 수 있습니다:

apiVersion: gateway.networking.k8s.io/v1
kind: GRPCRoute
metadata:
  name: canary-route
spec:
  parentRefs:
    - name: production-gateway
      namespace: infra
  rules:
    - matches:
        - method:
            service: 'order.v1.OrderService'
      backendRefs:
        - name: order-service-stable
          port: 50051
          weight: 90
        - name: order-service-canary
          port: 50051
          weight: 10

GAMMA: 서비스 메시 통합

GAMMA(Gateway API for Mesh Management and Administration)는 Gateway API를 서비스 메시로 확장하는 이니셔티브입니다.

GAMMA의 핵심: Service를 parentRef로

기존 Gateway API에서 Route의 parentRefs는 Gateway를 가리킵니다. GAMMA에서는 Service 자체를 parentRef로 지정하여 서비스 간 통신(East-West)을 제어합니다:

apiVersion: gateway.networking.k8s.io/v1
kind: GRPCRoute
metadata:
  name: payment-mesh-route
spec:
  parentRefs:
    - group: ''
      kind: Service
      name: payment-service
      port: 50051
  rules:
    - matches:
        - method:
            service: 'payment.v1.PaymentService'
            method: 'ProcessPayment'
      filters:
        - type: RequestHeaderModifier
          requestHeaderModifier:
            add:
              - name: x-request-priority
                value: 'high'
      backendRefs:
        - name: payment-service
          port: 50051

Istio에서 GAMMA 활성화

# Istio 1.22+ 에서 GAMMA 지원
istioctl install --set profile=ambient

# Gateway API CRD 설치
kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.2.0/experimental-install.yaml

실전 핸즈온: gRPC 마이크로서비스 라우팅

1단계: gRPC 서비스 배포

apiVersion: apps/v1
kind: Deployment
metadata:
  name: user-service-v1
  namespace: app
spec:
  replicas: 3
  selector:
    matchLabels:
      app: user-service
      version: v1
  template:
    metadata:
      labels:
        app: user-service
        version: v1
    spec:
      containers:
        - name: user-service
          image: myregistry/user-service:v1.0
          ports:
            - containerPort: 50051
              name: grpc
          resources:
            requests:
              cpu: 100m
              memory: 128Mi
            limits:
              cpu: 500m
              memory: 256Mi
          livenessProbe:
            grpc:
              port: 50051
            initialDelaySeconds: 10
          readinessProbe:
            grpc:
              port: 50051
            initialDelaySeconds: 5
---
apiVersion: v1
kind: Service
metadata:
  name: user-service
  namespace: app
spec:
  selector:
    app: user-service
  ports:
    - name: grpc
      port: 50051
      targetPort: 50051
      appProtocol: kubernetes.io/grpc

2단계: Gateway 설정

apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: grpc-gateway
  namespace: infra
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
  gatewayClassName: istio
  listeners:
    - name: grpc-tls
      protocol: HTTPS
      port: 443
      hostname: '*.api.example.com'
      tls:
        mode: Terminate
        certificateRefs:
          - name: api-tls-cert
      allowedRoutes:
        namespaces:
          from: Selector
          selector:
            matchLabels:
              gateway-access: 'true'
        kinds:
          - kind: GRPCRoute

3단계: GRPCRoute로 라우팅 규칙 정의

apiVersion: gateway.networking.k8s.io/v1
kind: GRPCRoute
metadata:
  name: user-grpc-route
  namespace: app
spec:
  parentRefs:
    - name: grpc-gateway
      namespace: infra
      sectionName: grpc-tls
  hostnames:
    - 'user.api.example.com'
  rules:
    - matches:
        - method:
            service: 'user.v1.UserService'
            method: 'GetUser'
        - method:
            service: 'user.v1.UserService'
            method: 'ListUsers'
      backendRefs:
        - name: user-service-reader
          port: 50051
    - matches:
        - method:
            service: 'user.v1.UserService'
            method: 'CreateUser'
        - method:
            service: 'user.v1.UserService'
            method: 'UpdateUser'
        - method:
            service: 'user.v1.UserService'
            method: 'DeleteUser'
      backendRefs:
        - name: user-service-writer
          port: 50051

4단계: 테스트

# grpcurl로 테스트
grpcurl -d '{"user_id": "123"}' \
  -H "x-request-id: test-001" \
  user.api.example.com:443 \
  user.v1.UserService/GetUser

# 카나리 배포 확인 (여러 번 호출하여 비율 확인)
for i in $(seq 1 100); do
  grpcurl -d '{"user_id": "123"}' \
    user.api.example.com:443 \
    user.v1.UserService/GetUser 2>&1 | grep "server_version"
done | sort | uniq -c

ReferenceGrant: 크로스 네임스페이스 접근 제어

다른 네임스페이스의 백엔드를 참조하려면 ReferenceGrant가 필요합니다:

apiVersion: gateway.networking.k8s.io/v1beta1
kind: ReferenceGrant
metadata:
  name: allow-app-to-backend
  namespace: backend
spec:
  from:
    - group: gateway.networking.k8s.io
      kind: GRPCRoute
      namespace: app
  to:
    - group: ''
      kind: Service

모니터링과 디버깅

Gateway API 상태 확인

# Gateway 상태 확인
kubectl get gateway -A
kubectl describe gateway grpc-gateway -n infra

# GRPCRoute 상태 확인
kubectl get grpcroute -A
kubectl describe grpcroute user-grpc-route -n app

# Istio 라우팅 규칙 확인
istioctl proxy-config route deploy/istio-ingressgateway -n istio-system -o json

Prometheus 메트릭

apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
  name: grpc-gateway-alerts
spec:
  groups:
    - name: grpc-gateway
      rules:
        - alert: GRPCHighErrorRate
          expr: |
            sum(rate(grpc_server_handled_total{grpc_code!="OK"}[5m])) by (grpc_service)
            /
            sum(rate(grpc_server_handled_total[5m])) by (grpc_service)
            > 0.05
          for: 5m
          labels:
            severity: warning

프로덕션 체크리스트

Gateway API를 프로덕션에 도입할 때 확인 사항:

  • GatewayClass 구현체 선택 (Istio, Envoy Gateway, Cilium 등)
  • TLS 인증서 자동화 (cert-manager 연동)
  • ReferenceGrant 정책 수립
  • 모니터링 (Gateway 상태, 라우팅 메트릭)
  • 레이트 리미팅 설정 (BackendTrafficPolicy)
  • 타임아웃 및 리트라이 정책
  • gRPC 헬스체크 설정
  • 점진적 마이그레이션 계획

📝 확인 퀴즈 (5문제)

Q1. Gateway API에서 역할 분리를 위한 세 가지 핵심 리소스는?

GatewayClass, Gateway, Route (HTTPRoute/GRPCRoute 등)

Q2. GAMMA 이니셔티브에서 GRPCRoute의 parentRefs가 가리키는 것은?

Gateway 대신 Service 자체를 parentRef로 지정하여 East-West(서비스 간) 트래픽을 제어합니다.

Q3. GRPCRoute에서 카나리 배포를 구현하려면 어떤 필드를 사용하나요?

backendRefs의 weight 필드를 사용하여 트래픽 비율을 분배합니다.

Q4. 다른 네임스페이스의 Service를 backendRef로 참조하려면 어떤 리소스가 필요한가요?

ReferenceGrant 리소스가 대상 네임스페이스에 생성되어야 합니다.

Q5. GRPCRoute에서 특정 gRPC 메서드를 매칭하려면 어떤 필드를 사용하나요?

rules.matches.method 필드에 service와 method를 지정합니다.