본문 바로가기
기타/기타

[proxy] Envoy 이해하기 - 실습 (Listener, Cluster, Route, Filter의 개념)

by 사바라다 2025. 4. 5.
반응형

개요

안녕하세요. 이전 포스팅 Envoy 이해하기 - 기본 이론편에서 마지막에 envoy.yaml 파일의 기본 구성을 함께 확인해 보았었습니다. 그때는 잠깐 언급만 하고 넘어가는 수준이었는데요. 오늘은 제대로 한번 해당 파일을 함께 보고 Envoy의 구성을 알아보도록 하겠습니다.

Envoy 구성

Envoy의 기본적인 아키텍처와 구성요소는 아래와 같습니다.

  • Listener
    • Envoy가 수신 대기할 IP와 포트를 정의
  • Filter
    • filter_chain이란 어떠한 조건으로 요청을 처리할 것인지 정의
    • 예를 들어 L4 계층 기반으로 라우팅할지 L7 계층 기반으로 라우팅할지 등의 상위 레벨의 설정
  • Router
    • 실제 라우팅의 조건 및 라우팅할 서비스 등을 지정
    • L7 이라면 URL 경로, Header 기반 라우팅 설정이 가능
    • L4 라면 IP 기반으로 설정
  • Cluster
    • 백엔드 서비스의 연결 정보와 로드 밸런싱 정책

도식표로 나타내면 아래와 같은 흐름을 가집니다.

Local 에서 실행해보기

아래 파일을 먼저 실행해서 테스트해보고 내용을 확인해보도록 하겠습니다. 해당 envoy의 버전은 1.29.latest 버전입니다.

static_resources:
  listeners:
    - name: listener_0
      address:
        socket_address: { address: 0.0.0.0, port_value: 10000 }
      filter_chains:
        - filters:
            - name: envoy.filters.network.http_connection_manager
              typed_config:
                "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
                stat_prefix: ingress_http
                route_config:
                  name: local_route
                  virtual_hosts:
                    - name: local_service
                      domains: ["*"]
                      routes:
                        - match: { prefix: "/" }
                          route: { cluster: backend_service }
                http_filters:
                  - name: envoy.filters.http.router
                    "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
  clusters:
    - name: backend_service
      connect_timeout: 0.25s
      type: logical_dns
      lb_policy: round_robin
      load_assignment:
        cluster_name: backend_service
        endpoints:
          - lb_endpoints:
              - endpoint:
                  address:
                    socket_address:
                      address: backend
                      port_value: 8080

테스트

위 구성에 대해서 먼저 테스트를 해보도록하겠습니다. 먼저 envoy를 실행 후 api를 호출해보도록 하겠습니다. envoy의 실행은 docker를 통해서 하셔도 되며, local에서 직접 실행하셔도 좋습니다. 저는 docker를 통해서 실행하도록 하겠습니다. docker-compose 파일은 아래와 같습니다.

version: '3'
services:
  envoy:
    image: envoyproxy/envoy:v1.29-latest
    volumes:
      - ./envoy.yaml:/etc/envoy/envoy.yaml
    ports:
      - "10000:10000"
      - "9901:9901"
    depends_on:
      - backend

  backend:
    build: ./backend
    ports:
      - "8080:8080"

실제로 envoy listener Port에 API를 호출해보도록 하겠습니다.
실행하면 결과는 아래와 같습니다.

  01-basic-proxy curl -X GET http://localhost:10000 -i
HTTP/1.1 200 OK
x-powered-by: Express
content-type: text/html; charset=utf-8
content-length: 19
etag: W/"13-fPIWo1EVMLABSBGW9/pl2LXKw10"
date: Sun, 30 Mar 2025 14:23:21 GMT
x-envoy-upstream-service-time: 2
server: envoy

Hello from backend!%

정상적으로 Backend의 Response를 잘 가져온것을 확인할 수 있었습니다.

Envoy 파일 뜯어보기

테스트했을 때 이제 잘 나오는 것도 보았으니, 이제 실제 설정 파일을 보면서 Envoy가 어떻게 구성되어 있는지 파악해보도록 하겠습니다.

Listener

listeners:
- name: listener_0
  address:
    socket_address:
     address: 0.0.0.0
     port_value: 10000

Envoy에서 Listener는 말 그대로 외부 요청을 수신하는 진입점입니다. 위 설정은 Envoy가 0.0.0.0:10000, 즉 모든 IP에서 들어오는 10000번 포트의 요청을 받는다는 의미입니다.

각 property를 보면 아래와 같습니다.

  • name: 이 Listener에 붙이는 내부 이름입니다. 통계나 로그에 활용됩니다.
  • address.socket_address: 네트워크 바인딩 설정
    • address: 0.0.0.0 → 모든 네트워크 인터페이스(IP)에서 요청을 받겠다는 의미
    • port_value: 10000 → 실제 요청을 받을 포트

즉, 사용자가 브라우저에서 http://localhost:10000으로 접근하면 가장 먼저 이 Listener가 요청을 받아들이고, 이후 정의된 필터 체인과 라우팅 설정을 따라 백엔드로 요청을 전달하게 됩니다.

Filter

Filter는 문법상 filter_chains으로 구성됩니다. 그리고 이 부분은 실질적으로 "어떤 요청을 어떻게 처리할지"를 정의하는 곳입니다.

filter_chains:
  - filters:
    - name: envoy.filters.network.http_connection_manager
      typed_config:
        "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
  • filter_chains : 요청이 들어왔을 때 어떤 처리를 할 것인지를 체인 형태로 정의
    • name: 여기서는 http_connection_manager 필터 하나만 등록되어 있는데, 이게 바로 HTTP 요청을 처리하는 핵심 필터
      • http_connection_manager는 L7 라우팅과 필터를 제공해주는 컴포넌티입니다.
      • 내부적으로 여러 기능을 포함하고 있고, 그 중 하나가 아래의 route_config입니다.
    • typed_config : 어떠한 구조를 사용할 것인지 정의합니다.
      • 위에서는 v3.HttpConnectionManager 형태 사용. 이는 이미 proto로 정의되어 있는 것을 선언해주는 역할입니다. Link

Router

router는 요청을 수신한 후, 정의된 규칙에 따라 적절한 클러스터(백엔드)전달(proxy) 하는 역할을 합니다.

route_config:
  name: local_route
  virtual_hosts:
  - name: backend_service
    domains: ["*"]
    routes:
    - match: { prefix: "/" }
      route: { cluster: backend }
    http_filters:
          - name: envoy.filters.http.router
            typed_config:
              "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
  • route_config : http_connection_manager 내부에 정의되며, Envoy의 라우팅 규칙을 담당
    • name: router_config의 이름
    • virtual_hosts: 하나의 Envoy 인스턴스가 여러 도메인의 요청을 처리할 수 있게 하는 구조
      • domain : ["*"]는 모든 도메인에서 오는 요청을 이 규칙에 따라 처리한다는 의미. (Host` 헤더 기반으로 요청을 구분)
      • routes: 실제 요청 경로에 따라 어떤 클러스터로 보낼지를 정의

위 설정은 "도메인에 상관없이, 모든 경로의 요청을 backend로 보낸다"를 뜻합니다.

Cluster

이 블록은 Envoy가 실제로 요청을 전달할 대상(백엔드 서비스) 를 정의하는 부분입니다.

clusters:
  - name: backend
    connect_timeout: 0.25s
    type: LOGICAL_DNS
    load_assignment:
      cluster_name: backend
      endpoints:
      - lb_endpoints:
        - endpoint:
            address:
              socket_address:
                address: backend
                port_value: 8080
  • name: backend → 클러스터 이름
    • 앞서 route_config에서 cluster: backend 라고 지정했기 때문에 해당 요청이 여기에 정의된 클러스터로 들어오게 됩니다.
    • connection_timeout: 0.25s → 백엔드에 연결 시도할 때의 타임아웃 시간
    • type: LOGICAL_DNS → 이 클러스터는 DNS 이름을 통해 백엔드 위치를 파악한다는 의미
    • load_assignment → 이 부분은 클러스터 안에 있는 실제 서버(엔드포인트)를 지정하는 영역
      • endpoint: 요청이 실제로 도달하는 목적지 (IP:Port)
      • lb_endpoints로드밸런싱 대상들을 나타냅니다.
      • 여기서는 backend:8080 하나만 정의되어 있지만, 여러 개를 넣으면 라운드로빈 등 로드밸런싱 전략이 적용

전체 흐름 다시 정리

  1. 사용자가 localhost:10000에 요청을 보냅니다.
  2. Listener가 요청을 받아 filter_chain을 적용합니다.
  3. HTTP Connection Manager가 요청을 파싱하고,
  4. 설정된 라우팅 규칙에 따라 cluster: backend로 전달합니다.
  5. cluster.backendbackend:8080이라는 DNS 이름으로 백엔드 컨테이너에 연결됩니다.

마무리

오늘은 이렇게 실제로 Local에서 Envoy를 띄어보고 테스트를 해보는 시간을 가져보았습니다.

오늘 테스트한 코드는 github 에 업로드해 두었으므로 코드가 궁금하신 분들은 Link 참고 부탁드립니다.

감사합니다.

참조

[1] https://www.youtube.com/watch?v=40gKzHQWgP0

[2] https://www.youtube.com/watch?v=E-UpGmj6B9M

[3] https://github.com/envoyproxy/envoy/blob/35d358ed87692f4a1731ce81b120b9b159db1092/api/envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.proto#L40

반응형

댓글