Envoy Gateway 핵심 개념: Gateway, Listener, Proxy, 그리고 Route 계열 완전 해설

13 min read

Gateway API를 처음 보면 많은 사람이 이런 느낌을 받습니다. "용어 수가 엄청 많은 건 아닌데, 이름 비슷한 등장인물만 가득한 출연진 표를 보는 느낌이다. 누가 주인공이고 누가 조연인지 모르겠다." 이 글은 바로 그 혼란을 잘라내기 위해 존재합니다. 그리고 그 과정에서 자주 쓰는 route 타입들도 함께 정리합니다.

전체 아키텍처

공식 Envoy Gateway 개념 문서는 시스템을 세 계층으로 나눕니다:

  • User Configuration: 여러분이 작성하는 Gateway API 리소스와 Envoy Gateway 확장 CRD
  • Envoy Gateway Controller: 리소스를 읽고, 검증하고, 설정으로 번역
  • Envoy Proxy: 실제로 트래픽을 처리하는 데이터 플레인

즉, 여러분이 보통 수정하는 것은 Envoy Proxy 자체가 아닙니다. 여러분은 "원하는 상태를 선언"하고 있는 겁니다. Envoy Gateway는 그 선언을 Envoy Proxy가 실행할 수 있는 설정으로 바꿔 줍니다. 그래서 프록시 설정을 직접 쓰는 것보다 훨씬 다루기 편합니다.

핵심 역할들

지금은 이것만 기억해 두면 됩니다:

  • GatewayClass: "이 클러스터에서 어떤 Gateway 구현체를 쓸지" 정의
  • Gateway: "ingress가 어디에 있고 어떤 프로토콜을 말하는지" 정의
  • Listener: 특정 port/protocol/hostname ingress 슬롯 정의
  • Route: "어떤 요청을 어떤 Service로 보낼지" 정의
  • Envoy Proxy: 실제로 트래픽을 받고 전달하는 Gateway Proxy

쉽게 풀어 말하면:

  • GatewayClass는 사양서
  • Gateway는 건물의 정문
  • Listener는 프런트 데스크
  • Route는 건물 내부의 안내 표지판
  • Envoy Proxy는 출입 통제와 안내를 맡는 보안 시스템

이들 중 하나라도 빠지면 트래픽은 원하는 목적지까지 가지 못합니다.

전체 그림이 보이는 최소 YAML

이해 가능한 가장 작은 예시는 이렇습니다:

apiVersion: gateway.networking.k8s.io/v1
kind: GatewayClass
metadata:
  name: eg
spec:
  controllerName: gateway.envoyproxy.io/gatewayclass-controller
---
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: eg
spec:
  gatewayClassName: eg
  listeners:
    - name: http
      protocol: HTTP
      port: 80
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: backend
spec:
  parentRefs:
    - name: eg
  hostnames:
    - "www.example.com"
  rules:
    - backendRefs:
        - name: backend
          port: 3000

이걸 체인으로 보면 로직은 다음과 같습니다:

  1. GatewayClassEnvoy Gateway 컨트롤러가 담당한다고 선언
  2. Gateway가 포트 80에서 하나의 HTTP ingress를 선언
  3. HTTPRoutewww.example.com 요청을 backend:3000으로 보내라고 정의
  4. Envoy Gateway가 이 전체를 Envoy Proxy용 설정으로 번역

각 필드 이해하기

GatewayClass

이것은 클러스터 수준의 ingress 타입 정의입니다. 보통 가장 중요한 필드는 다음입니다:

spec:
  controllerName: gateway.envoyproxy.io/gatewayclass-controller

뜻은 아주 단순합니다: "이 GatewayClass는 Envoy Gateway 컨트롤러가 관리한다."

controllerName이 맞지 않으면, 잘못된 회사에 택배를 보낸 것과 같습니다. 아무도 수거하러 오지 않죠.

Gateway

이것은 "ingress가 어떤 모습인지"를 정의합니다. 가장 자주 참고하는 필드는 listeners입니다:

listeners:
  - name: http
    protocol: HTTP
    port: 80

의미는 다음과 같습니다:

  • http라는 이름의 listener를 연다
  • HTTP 트래픽을 받는다
  • 외부 포트 80에서 리슨한다

HTTPS를 쓰려면 일반적으로 protocol: HTTPS인 listener를 하나 더 추가하고 TLS 설정을 붙입니다.

Gateway가 주로 관리하는 것:

  • 외부 포트와 프로토콜
  • listener별 hostname
  • TLS termination 위치
  • 어떤 네임스페이스의 route가 attach할 수 있는지

Gateway는 플랫폼 계층의 관심사에 더 가깝고, 소유권도 보통 플랫폼 팀에 있습니다.

Listener

이건 초보자가 가장 자주 놓치는 역할이지만, 실제로는 매우 중요합니다.

listener는 Gateway 바깥으로 노출된 ingress 슬롯입니다. 다음을 정의합니다:

  • name
  • port
  • protocol
  • hostname
  • tls
  • allowedRoutes

예시:

listeners:
  - name: https
    protocol: HTTPS
    port: 443
    hostname: api.example.com

이 말은 곧:

  • 이 슬롯 이름은 https
  • HTTPS를 받는다
  • 포트 443에서 리슨한다
  • api.example.com 전용이다

만약 listener가 여러 개라면, 예를 들어:

  • 포트 80용 http
  • 포트 443용 https
  • 포트 50051용 grpc

같은 Gateway 안에서 여러 ingress 슬롯을 여는 셈이고, 각각 다른 route가 붙을 수 있습니다.

Envoy Proxy

많은 사람이 YAML에만 집중하고 Envoy Proxy가 실제 라이브 트래픽을 처리한다는 점을 잊습니다.

역할은 다음과 같습니다:

  • 클라이언트 요청 수신
  • Envoy Gateway가 푸시한 설정과 매칭
  • 적절한 백엔드로 트래픽 전달
  • TLS, header, timeout, retry 등 데이터 플레인 동작 처리

즉 Envoy Gateway는 "컨트롤 플레인", Envoy Proxy는 "데이터 플레인 / Gateway Proxy"라고 생각하면 됩니다.

Route 계열

Route는 단순히 HTTPRoute만을 뜻하지 않습니다. 이 계열 전체가 Gateway API 설계의 핵심입니다.

HTTPRoute

여러분이 가장 자주 작성하고 수정하게 될 타입입니다. 핵심 필드 세 가지:

spec:
  parentRefs:
    - name: eg
  hostnames:
    - "www.example.com"
  rules:
    - backendRefs:
        - name: backend
          port: 3000
  • parentRefs: 어느 Gateway에 attach할지
  • hostnames: 어떤 Host header가 이 규칙을 트리거하는지
  • backendRefs: 매칭된 요청을 어디로 보낼지

가장 흔한 오해는 Gateway에 세밀한 라우팅을 적는다고 생각하는 것입니다. 실제로 "트래픽을 어떻게 나눌지"를 결정하는 것은 HTTPRoute입니다.

GRPCRoute

gRPC를 다룬다면, 억지로 HTTPRoute에 밀어 넣는 것보다 GRPCRoute가 더 자연스럽습니다.

다음 기준으로 매칭할 수 있습니다:

  • gRPC hostname
  • gRPC service
  • gRPC method
  • headers

예시:

matches:
  - method:
      service: com.example.User
      method: Login

이 의미 체계는 gRPC와 자연스럽게 맞아떨어집니다. 단순히 URL path를 보는 게 아니라, gRPC service/method 모델에 직접 매칭하는 것이니까요.

공식 문서도 말하듯, GRPCRouteHTTPRoute가 같은 listener를 공유하고 hostname이 충돌하면 구현체는 한쪽을 거부해야 합니다. 쉽게 말해 HTTP와 gRPC가 같은 hostname을 두고 싸우게 두지 말라는 뜻입니다.

TCPRoute

TCPRoute는 raw TCP 트래픽을 처리합니다. HTTPRoute와 달리 path나 header 같은 L7 의미를 이해하지 못합니다. L4 포워딩에 더 가깝습니다.

적합한 시나리오:

  • 비 HTTP 프로토콜 서비스
  • 순수 TCP 서비스
  • listener 포트만 기준으로 서로 다른 백엔드에 연결을 보내는 경우

커스텀 프로토콜을 쓰는 데이터베이스나 독자 TCP 프로토콜은 전형적인 TCPRoute 사용 사례입니다.

TLSRoute

TLSRoute는 TLS 트래픽을 처리하며, 특히 TLS passthrough 시나리오에서 자주 등장합니다.

핵심 개념:

  • Gateway가 반드시 TLS를 종료하는 것은 아니다
  • TLS 핸드셰이크의 SNI hostname만 보고 라우팅할 수 있다
  • 암호화된 트래픽은 백엔드까지 그대로 유지된다

이것은 end-to-end 암호화가 필요한 경우, 혹은 Gateway에서 TLS를 종료하고 싶지 않은 경우에 중요합니다.

Route 타입은 어떻게 고를까

요구사항 이걸 사용
웹사이트, REST API, 일반 웹 트래픽 HTTPRoute
gRPC service/method 라우팅 GRPCRoute
raw TCP 트래픽 TCPRoute
TLS passthrough / SNI 기반 라우팅 TLSRoute

이 표가 중요한 이유는 많은 사람이 본능적으로 모든 것에 HTTPRoute를 쓰기 때문입니다. 하지만 실제 대상이 gRPC나 TCP라면, HTTPRoute에 억지로 끼워 넣을수록 YAML만 점점 어색해집니다.

Ingress보다 Route가 더 이해하기 쉬운 이유

기존 Ingress 설정은 너무 많은 책임을 하나의 리소스에 욱여넣는 경우가 많았고, 그 결과 몇 가지 지속적인 문제를 낳았습니다:

  • 플랫폼 설정과 앱 라우팅이 한데 섞임
  • 고급 기능이 가독성 나쁜 annotation으로 표현됨
  • 비 HTTP 프로토콜에 대한 표현력이 제한적임

Gateway API는 책임을 분리하는 방식을 택합니다:

  • 플랫폼 팀은 GatewayClass / Gateway 관리
  • 앱 팀은 각자 HTTPRoute 관리

이 분리는 여러 사람이 협업할 때 특히 잘 맞습니다. 단순히 path 하나 바꾸려고 ingress 전체를 건드릴 필요가 없고, 팀끼리 서로 밟는 일도 크게 줄어듭니다.

이제 status를 보기 시작하세요

spec뿐 아니라, 점차 status를 확인하는 습관을 들이세요. 특히 HTTPRouteGateway에서 중요합니다:

kubectl get gateway eg -o yaml
kubectl get httproute backend -o yaml

처음에는 이것만 확인해도 좋습니다:

  • route가 Accepted 되었는가
  • gateway listener가 Ready 인가
  • address가 정상 할당되었는가

시험으로 치면 제출만 확인하지 말고 채점과 합격 여부까지 봐야 합니다.

한 줄 요약

GatewayClass, Gateway, Listener, Route, Envoy Proxy를 각각 "누가 관리하는지, ingress가 어떻게 열리는지, 각 슬롯이 어떻게 연결되는지, 트래픽이 어떻게 나뉘는지, 누가 실제로 실행하는지"로 이해하면 핵심 개념의 80%는 이미 잡은 셈입니다.

💡 초보자는 종종 곧바로 CRD 세부 필드로 뛰어듭니다. 서두르지 마세요. 먼저 각 역할을 정리하면 YAML이 더 이상 매번 낯선 사람처럼 느껴지지 않습니다.

다음 단계

이제 개념이 잡혔으니, 다음 글에서는 가장 흔한 HTTP 라우팅 시나리오인 host, path, header, 트래픽 분할을 살펴봅니다: 👉 실전 HTTP 라우팅