새소식

인기 검색어

Service_Mesh/Istio

[Istio-2주차] Envoy in action (실습)

  • -

Envoy - 실습

도커로 httpbin 서비스와 프록시 구성하기

  • Envoy의 기본적인 프록시 기능과 타임아웃 설정, 그리고 헤더 변화를 하나씩 따라가며 경험한 과정을 정리한다.

1. 실습 환경 준비

  • Envoy는 C++로 작성되어 다양한 플랫폼에서 사용할 수 있다.
  • 실습에 사용할 이미지는 아래와 같다.
docker pull envoyproxy/envoy:v1.19.0
docker pull curlimages/curl
docker pull mccutchen/go-httpbin

이미지가 정상적으로 받아졌는지 docker images 명령어로 확인한다.


2. httpbin 서비스 실행

  • httpbin은 다양한 HTTP 요청을 실험할 때 유용한 테스트용 서비스로, 금번 실습에서는 간단한 httpbin 서비스를 만들어본다.
  • 기본적으로 httpbin은 호출하는 엔드포인트에 따라 호출할 때 사용한 헤더를 반환하거나, HTTP 요청을 지연시키거나, 오류를 발생시키는 등의 서비스를 제공한다.
  • ex) http://httpbin.org/headers 로 이동
    • httpbin 서비스를 시작 → Envoy를 시작 → 모든 트래픽이 httpbin 서비스로 가도록 프록시를 설정할 예정
    • 프록시 설정 후 클라이언트 앱을 시작해 프록시를 호출
  • 예시 이미지
  • 기본 포트는 8080이지만, 이번 실습에서는 8000번 포트로 변경해 실행한다.
docker run -d -e PORT=8000 --name httpbin mccutchen/go-httpbin
docker ps

 

  • 정상적으로 컨테이너가 실행된 후, curl 컨테이너를 이용해 httpbin의 /headers 엔드포인트를 호출해본다.
docker run -it --rm --link httpbin curlimages/curl curl -X GET http://httpbin:8000/headers
  • 요청에 사용된 헤더 정보가 반환되는 것을 확인할 수 있다.

{
  "headers": {
    "Accept": [
      "*/*"
    ],
    "Host": [
      "httpbin:8000"
    ],
    "User-Agent": [
      "curl/8.13.0"
    ]
  }
}

 


3. Envoy 프록시 컨테이너 실행

  • Envoy proxy 를 실행하고 help 를 전달해 플래그와 명령줄 파라미터 중 일부를 확인해 본다.
  • # envoy help document 참조
    docker run -it --rm envoyproxy/envoy:v1.19.0 envoy --help
    ...
       --service-zone <string> # 프록시를 배포할 가용 영역을 지정
         Zone name
    
       --service-node <string> # 프록시에 고유한 이름 부여
         Node name
         
    ...
       -c <string>,  --config-path <string> # 설정 파일을 전달
         Path to configuration file
    • Envoy 실행 : 프록시를 실행하려고 했지만 유효한 설정 파일을 전달하지 않았다.
    # envoy 실행 시도
    docker run -it --rm envoyproxy/envoy:v1.19.0 envoy
    [2021-11-21 21:28:37.347][1][info][main]
    ... [source/server/server.cc:855] exiting
    At least one of --config-path or --config-yaml or Options::configProto() should be non-empty
    위와 같이 --config-path 나 --config-yaml 을 제공해달라는 문구가 발생한다.
  • 확인한 바와 같이 Envoy를 실행하려면 반드시 설정 파일이 필요하다.
  • 아래와 같이, 예제 설정 파일로 해결해본다.
admin:
  address:
    socket_address: { address: 0.0.0.0, port_value: 15000 }

static_resources:
  listeners:
  - name: httpbin-demo
    address:
      socket_address: { address: 0.0.0.0, port_value: 15001 }
    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
          http_filters:
          - name: envoy.filters.http.router
          route_config:
            name: httpbin_local_route
            virtual_hosts:
            - name: httpbin_local_service
              domains: ["*"]
              routes:
              - match: { prefix: "/" }
                route:
                  auto_host_rewrite: true
                  cluster: httpbin_service
  clusters:
    - name: httpbin_service
      connect_timeout: 5s
      type: LOGICAL_DNS
      dns_lookup_family: V4_ONLY
      lb_policy: ROUND_ROBIN
      load_assignment:
        cluster_name: httpbin
        endpoints:
        - lb_endpoints:
          - endpoint:
              address:
                socket_address:
                  address: httpbin
                  port_value: 8000

이 설정은 15001 포트로 들어온 모든 트래픽을 httpbin(8080) 서비스로 라우팅한다.

  • Envoy를 아래와 같이 실행, 로그를 확인한다.
# 설정 예제 파일 확인
cat ch3/simple.yaml

# Terminal 1
docker run --name proxy --link httpbin envoyproxy/envoy:v1.19.0 --config-yaml "$(cat ch3/simple.yaml)"

# Terminal 2
docker logs proxy
[2025-04-12 08:25:15.455][1][info][config] [source/server/listener_manager_impl.cc:834] all dependencies initialized. starting workers
[2025-04-12 08:25:15.456][1][info][main] [source/server/server.cc:804] starting main dispatch loo

 

  • 위와 같이 all dependencies initialized. starting workers 혹은 starting main dispatch loop 로그가 확인된다.
    • 서버가 정상적으로 실행되어 리스닝을 하고 있음을 알 수 있다.

4. 프록시를 통한 요청 및 헤더 확인

  • 이제 curl 컨테이너를 통해 Envoy 프록시를 경유하여 httpbin에 요청을 보낸다.
    • 위의 yaml 파일에서 port를 15001로 설정했기 때문에 15001로 접근해본다.
docker run -it --rm --link proxy curlimages/curl curl -X GET http://proxy:15001/headers
  • 응답 결과

{
  "headers": {
    "Accept": [
      "*/*"
    ],
    "Host": [
      "httpbin"
    ],
    "User-Agent": [
      "curl/8.13.0"
    ],
    "X-Envoy-Expected-Rq-Timeout-Ms": [
      "15000"
    ],
    "X-Forwarded-Proto": [
      "http"
    ],
    "X-Request-Id": [
      "3fd55f78-4b23-4428-adbb-54351c74df20"
    ]
  }
}
  • 프록시에 curl 요청을 하였지만 httpbin 으로 트래픽이 라우팅 된 것을 확인할 수 있다.
  • 응답에는 기존 헤더 외에도 Envoy가 자동으로 추가한 X-Envoy-Expected-Rq-Timeout-MsX-Request-Id 헤더가 포함되어 있다.
    • X-Request-Id: 각 요청마다 고유한 ID가 생성되어, 클러스터에 인입되는 다양한 요청을 식별할 수 있다. 또한 요청에 따른 여러 서비스 간 홉 추적 가능
    • X-Envoy-Expected-Rq-Timeout-Ms: 업스트림 서비스에 타임아웃 정보-힌트를 전달한다. (결과에서는 요청이 15,000ms 후에 타임아웃 될 것으로 기대하는 값임을 의미)
  • 이후 실습을 위해 Envoy 프록시를 삭제한다.
docker rm -f proxy

5. 요청 타임아웃 설정 변경(지연) 실습

  • 설정 파일의 라우팅 규칙에 타임아웃 값을 1초로 변경한다.
# timeout 변경 예시 yaml 적용
docker run -p 15000:15000 --name proxy --link httpbin envoyproxy/envoy:v1.19.0 --config-yaml "$(cat ch3/simple_change_timeout.yaml)"
docker run --name proxy --link httpbin envoyproxy/envoy:v1.19.0 --config-yaml "$(cat ch3/simple_change_timeout.yaml)"
cat ch3/simple_change_timeout.yaml

# 변경 내용
- match: { prefix: "/" }
  route:
    auto_host_rewrite: true
    cluster: httpbin_service
    timeout: 1s
    
   
# 확인
docker ps

 

  • 변경된 설정으로 프록시를 통해 요청 보내기 
docker run -it --rm --link proxy curlimages/curl curl -X GET http://proxy:15001/headers
  • 결과: X-Envoy-Expected-Rq-Timeout-Ms 값이 1000(1초)로 변경된 것을 확인할 수 있다.

{
  "headers": {
    "Accept": [
      "*/*"
    ],
    "Host": [
      "httpbin"
    ],
    "User-Agent": [
      "curl/8.13.0"
    ],
    "X-Envoy-Expected-Rq-Timeout-Ms": [
      "1000" # 1000ms = 1s 변경 확인
    ],
    "X-Forwarded-Proto": [
      "http"
    ],
    "X-Request-Id": [
      "1ec6116b-da79-4886-9ae1-6254b13bb964"
    ]
  }
}

6. 추가 테스트: 지연 응답 시 타임아웃 동작 확인

httpbin의 /delay/{n} 엔드포인트를 활용해 0.5초, 1초, 2초 지연 요청을 각각 보낸다.

# 추가 테스트 : http 로그 레벨 debug로 설정
docker run -it --rm --link proxy curlimages/curl curl -X POST http://proxy:15000/logging
docker run -it --rm --link proxy curlimages/curl curl -X POST http://proxy:15000/logging?http=debug

# 추가 테스트 : Envoy Admin API(TCP 15000) 를 통해 delay 설정
docker run -it --rm --link proxy curlimages/curl curl -X GET http://proxy:15001/delay/0.5
docker run -it --rm --link proxy curlimages/curl curl -X GET http://proxy:15001/delay/1
docker run -it --rm --link proxy curlimages/curl curl -X GET http://proxy:15001/delay/2
  • 0.5초, 1초 요청은 정상 응답된다.

  • 2초 요청은 Envoy에서 타임아웃 처리되어 실패한다. - upstream request timeout

위를 통해 Envoy의 타임아웃 설정이 실제로 동작하는 것을 직접 검증할 수 있다.

 


Envoy - Admin API

 

  • 엔보이의 Admin API를 사용하면 프록시 동작에 대한 통찰력을 향상시킬 수 있고, 메트릭과 설정에 접근할 수 있다.
#
docker run --name proxy --link httpbin envoyproxy/envoy:v1.19.0 --config-yaml "$(cat ch3/simple_change_timeout.yaml)"

# admin API로 Envoy stat 확인 : 응답은 리스너, 클러스터, 서버에 대한 통계 및 메트릭
docker run -it --rm --link proxy curlimages/curl curl -X GET http://proxy:15000/stats

# retry 통계만 확인
docker run -it --rm --link proxy curlimages/curl curl -X GET http://proxy:15000/stats | grep retry
cluster.httpbin_service.circuit_breakers.default.rq_retry_open: 0
cluster.httpbin_service.circuit_breakers.high.rq_retry_open: 0
cluster.httpbin_service.retry_or_shadow_abandoned: 0
cluster.httpbin_service.upstream_rq_retry: 0
cluster.httpbin_service.upstream_rq_retry_backoff_exponential: 0
cluster.httpbin_service.upstream_rq_retry_backoff_ratelimited: 0
cluster.httpbin_service.upstream_rq_retry_limit_exceeded: 0
cluster.httpbin_service.upstream_rq_retry_overflow: 0
cluster.httpbin_service.upstream_rq_retry_success: 0
...

# 다른 엔드포인트 일부 목록들도 확인
docker run -it --rm --link proxy curlimages/curl curl -X GET http://proxy:15000/certs # 머신상의 인증서
docker run -it --rm --link proxy curlimages/curl curl -X GET http://proxy:15000/clusters # 엔보이에 설정한 클러스터
docker run -it --rm --link proxy curlimages/curl curl -X GET http://proxy:15000/config_dump # 엔보이 설정 덤프
docker run -it --rm --link proxy curlimages/curl curl -X GET http://proxy:15000/listeners # 엔보이에 설정한 리스너
docker run -it --rm --link proxy curlimages/curl curl -X POST http://proxy:15000/logging # 로깅 설정 확인 가능
docker run -it --rm --link proxy curlimages/curl curl -X POST http://proxy:15000/logging?http=debug # 로깅 설정 편집 가능
docker run -it --rm --link proxy curlimages/curl curl -X GET http://proxy:15000/stats # 엔보이 통계
docker run -it --rm --link proxy curlimages/curl curl -X GET http://proxy:15000/stats/prometheus # 엔보이 통계(프로메테우스 레코드 형식)

 

예시) retry 통계만 확인

 

Envoy request retries 요청 재시도

 

  • httpbin 요청을 일부러 실패시켜서 envoy가 요청을 자동으로 재시작하는지 살펴보자. (retries)
  • 전과 같이 retry_policy를 사용하도록 설정 파일을 업데이트 한다.
              - match: { prefix: "/" }
                route:
                  auto_host_rewrite: true
                  cluster: httpbin_service
                  retry_policy:
                      retry_on: 5xx  # 5xx 일때 재시도
                      num_retries: 3 # 재시도 횟수

 

  • 실습 진행
# 이전 envoy proxy 삭제
docker rm -f proxy

# retry 예제 적용하여 envoy proxy 실행
cat ch3/simple_retry.yaml
docker run -p 15000:15000 --name proxy --link httpbin envoyproxy/envoy:v1.19.0 --config-yaml "$(cat ch3/simple_retry.yaml)"

# http 로그 레벨 debug 설정
docker run -it --rm --link proxy curlimages/curl curl -X POST http://proxy:15000/logging?http=debug

# /stats/500 경로로 프록시를 호출 : 이 경로로 httphbin 호출하면 오류가 발생
docker run -it --rm --link proxy curlimages/curl curl -X GET http://proxy:15001/status/500

# 호출이 끝났는데 아무런 응답도 보이지 않는다. 엔보이 Admin API에 확인
docker run -it --rm --link proxy curlimages/curl curl -X GET http://proxy:15000/stats | grep retry
...
cluster.httpbin_service.retry.upstream_rq_500: 3
cluster.httpbin_service.retry.upstream_rq_5xx: 3
cluster.httpbin_service.retry.upstream_rq_completed: 3
cluster.httpbin_service.retry_or_shadow_abandoned: 0
cluster.httpbin_service.upstream_rq_retry: 3
...

 

  • 500 에러 주입

  • envoy에서 재시도 호출 확인

 

  • stats 확인
    • cluster.httpbin_service.retry.upstream_rq_500 가 3으로 확인
    • cluster.httpbin_service.upstream_rq_retry 가 3으로 확인
      • cluster.httpbin_service.upstream_rq_retry_limit_exceeded가 1로 확인

Envoy는 업스트림 클러스터 httpbin을 호출할 때 500 에러를 반환받아 요청을 재시도하였음을 알 수 있다.

 

 

Envoy 동적 설정

 

  • 위의 httpbin 예시는 정적 설정 파일을 사용
  • Istio는 xDS 컴포넌트를 이용해서 동적 설정 기능을 사용

동적 설정 예시

bootstrap:
  dynamicResources:
    ldsConfig:
      ads: {} # ADS for listeners 리스너용 ADS
    cdsConfig:
      ads: {} # ADS for clusters 클러스터용 ADS
    adsConfig:
      apiType: GRPC
      grpcServices:
      - envoyGrpc:
          clusterName: xds-grpc # Uses a cluster named xds-grpc 라는 클러스터를 사용
      refreshDelay: 1.000s

  staticResources:
    clusters:
    - name: xds-grpc # Defines the xds-grpc cluster 라는 클러스터를 정의
      type: STRICT_DNS
      connectTimeout: 10.000s
      hosts:
      - socketAddress:
          address: istio-pilot.istio-system
          portValue: 15010
      circuitBreakers: # Reliability and circuit-breaking settings 신뢰성 및 서킷 브레이커 설정
        thresholds:
        - maxConnections: 100000
          maxPendingRequests: 100000
          maxRequests: 100000
        - priority: HIGH
          maxConnections: 100000
          maxPendingRequests: 100000
          maxRequests: 100000
      http2ProtocolOptions: {}

 

# 다음 실습을 위해 Envoy 종료
docker rm -f proxy && docker rm -f httpbin

 

 

 

 

 

Contents

포스팅 주소를 복사했습니다.

이 글이 도움이 되었다면 공감 부탁드립니다.