본문 바로가기
DevOps/Istio

istio와 envoy proxy 세부적으로 파악해보기

by 비어원 2025. 2. 20.
728x90

istio를 다루다보면 envoy proxy에 대한 내용도 이해해야 하고, EnvoyFilter를 사용하여 라우팅룰을 조금 더 자유롭게 구성하기 위해서 envoy proxy에 대한 내용을 잘 알아야 한다. 특히 EnvoyFilter의 필드는 envoy proxy에 대한 스펙을 다루기 때문이다.

 

그래서 이번 시간에는 istio와 envoy proxy와의 관계와 istio를 다루기 위해 필요한 envoy proxy의 기초 지식에 대해 알아보는 시간을 가지도록 하겠다.

envoy proxy란?

envoy는 대규모 현대 서비스 지향 아키텍처를 위해 설계된 L7 proxy 및 통신 버스이다. Envoy는 다음과 같은 철학을 가지고 개발하였다.

네트워크는 애플리케이션에 투명해야 하며, 네트워크 또는 애플리케이션에서 문제가 발생하면 문제의 근원을 쉽게 파악할 수 있어야 한다.


Envoy는 다음과 같이 여러가지 고급 기능을 제공하여 네트워크와 애플리케이션을 투명하게 하려고 한다. istio에서 제공한다고 하는 기능들은 모두 envoy proxy에서 왔다고 보면 된다.

  • L3/L4 네트워크 프록시
  • HTTP 기반 L7 프록시
  • HTTP/1.1 ~ HTTP/2 (HTTP/3) 및 gRPC 지원
  • 서비스 디스커버리 및 로드밸런싱
  • 헬스체크
  • observability
  • Circuit breaking
  • Rate limit
  • 동적 구성 (xDS)

 

Terminology

 

Envoy 에서 사용하는 용어는 다음과 같으며 envoy proxy의 구성에서도 마찬가지로 해당 용어를 사용한다.

  • Cluster: Envoy가 요청을 포워딩하는 엔드포인트 집합을 갖춘 논리적 서비스
  • Endpoints: 논리적 서비스를 구현하는 네트워크 노드, 클러스터로 그룹화 되어있다
  • Downstream: Envoy에 연결하는 엔티티이며 로컬 애플리케이션 도는 네트워크 노드가 될 수 있다. 사이드카가 아닌 모델에서 이는 외부 클라이언트이다.
  • Upstream: Envoy가 서비스에 대한 요청을 전달할 때 연결하는 엔드포인트이다. 이는 로컬 애플리케이션 또는 네트워크 노드가 될 수 있으며 사이드카가 아닌 모델에서 이는 외부 백엔드에 해당한다.
  • Filter: 요청 처리의 일부 측면을 제공하는 연결 또는 요청 처리 파이프라인 모듈
  • Filter chain: 체이닝된 일련의 필터
  • Listener: IP/Port를 바인딩하는 책임이 있는 envoy 모듈, 새로운 TCP 연결을 수락하고 요청 처리의 다운스트림 측면을 조율하는 역할을 한다.

 

Request flow

Envoy는 이벤트 기반 쓰레드 모델이다. 메인 스레드는 서버 라이프사이클, 구성 처리, 통계 등을 담당하고 일부의 워커 쓰레드는 요청을 처리한다. 모든 쓰레드는 이벤트 루프를 중심으로 작동하며 모든 다운스트림 TCP 연결은 해당 연결의 수명 동안 정확히 하나의 워커 쓰레드에 의해 처리된다. 각 워커 쓰레드는 업스트림 엔드포인트에 대한 자체 TCP 연결 풀을 유지한다.

 

워커 쓰레드는 상태를 거의 공유하지 않으며 병렬적인 방식으로 작동힌다. 이 쓰레드 모델을 사용하면 매우 많은 코어 수가 있는 CPU로 확장할 수 있다.

 

 

만약 envoy의 구성이 다음과 같다고 하자.

static_resources:
  listeners:
  # 443 포트에 바인딩 되어있는 하나의 Listener
  - name: listener_https
    address:
      socket_address:
        protocol: TCP
        address: 0.0.0.0
        port_value: 443
    # listener filter에 TLS inspector만 존재한다.
    listener_filters:
    - name: "envoy.filters.listener.tls_inspector"
      typed_config:
        "@type": type.googleapis.com/envoy.extensions.filters.listener.tls_inspector.v3.TlsInspector

	# 해당 리스너에 acme.com의 SNI와 일치하는 filter chain이 하나 있다.
    filter_chains:
    - filter_chain_match:
        # TLS Inspector filter에 의해 추출되는 SNI와 일치함.
        server_names: ["acme.com"]
        
      # TLS 처리 (TLS transport socket)
      transport_socket:
        name: envoy.transport_sockets.tls
        typed_config:
          "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext
          common_tls_context:
            tls_certificates:
            - certificate_chain: {filename: "certs/servercert.pem"}
              private_key: {filename: "certs/serverkey.pem"}

      # Network Filter가 들어갈 자리 
      filters:
      # 여기에는 HTTP connection manager 만 존재.
      - 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
          use_remote_address: true
          http2_protocol_options:
            max_concurrent_streams: 100
          # Access log 구성
          access_log:
          - name: envoy.access_loggers.file
            typed_config:
              "@type": type.googleapis.com/envoy.extensions.access_loggers.file.v3.FileAccessLog
              path: "/var/log/envoy/access.log"
          # Route 구성
          route_config:
            name: local_route
            virtual_hosts:
            - name: local_service
              domains: ["acme.com"]
              routes:
              - match:
                  path: "/foo"
                route:
                  cluster: some_service
          # HTTP filter chain (지금은 Router filter만 존재).
          http_filters:
          - name: envoy.filters.http.router
            typed_config:
              "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
  clusters:
  - name: some_service
    # Upstream TLS configuration.
    transport_socket:
      name: envoy.transport_sockets.tls
      typed_config:
        "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext
    load_assignment:
      cluster_name: some_service
      # Static endpoint assignment.
      endpoints:
      - lb_endpoints:
        - endpoint:
            address:
              socket_address:
                address: 10.1.2.10
                port_value: 10002
        - endpoint:
            address:
              socket_address:
                address: 10.1.2.11
                port_value: 10002
    typed_extension_protocol_options:
      envoy.extensions.upstreams.http.v3.HttpProtocolOptions:
        "@type": type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions
        explicit_http_config:
          http2_protocol_options:
            max_concurrent_streams: 100
  - name: some_statsd_sink
  # The rest of the configuration for statsd sink cluster.
# statsd sink.
stats_sinks:
- name: envoy.stat_sinks.statsd
  typed_config:
    "@type": type.googleapis.com/envoy.config.metrics.v3.StatsdSink
    tcp_cluster_name: some_statsd_sink

 

위의 구성을 envoy proxy에 적용했을 때 HTTP를 처리하는 envoy proxy로 들어오는 하나의 요청에 대해 워커 쓰레드에서 어떤 과정으로 요청이 흐르는지에 대해 보여준다. 

 

 

  1. 워커 쓰레드에서 구동 중인 envoy listener에 의해 다운스트림의 TCP 연결이 수락된다.
  2. Listener filter chain이 생성되고 구동한다. 여기서는 SNI 및 기타 TLS 이전 정보를 제공할 수 있다. 성공하면 listener는 network filter chain을 일치시킨다. 각 리스너는 목적지 IP CIDR, SNI, ALPN, source port 등의 조합과 일치하는 여러 개의 필터 체인을 가질 수 있다. TLS transport socket이 이 필터 체인과 연결되어 있다.
  3. 네트워크를 읽으면 TLS transport socket은 데이터를 복호화하여 추가 처리를 위해 복호화된 데이터 스트림으로 변환한다.
  4. network filter chain이 생성되고 실행된다. HTTP에 가장 중요한 필터는 HTTP connection filter로 체인의 마지막 네트워크 필터이다.
  5. HTTP connection manager의 HTTP/2 codec은 TLS 연결에서 복호화된 데이터 스트림을 여러 개의 독립적인 스트림으로 프레임 해제하고 디멀티플렉싱 한다. 각 스트림은 단일 요청과 응답을 처리한다.
  6. 각 HTTP 스트림에 대해 다운스트림 HTTP filter chain이 생성되고 구동된다. 요청은 처음에 CustomFilter를 통해 통과하는데 여기서 요청을 읽고 수정할 수 있다. 가장 중요한 HTTP filter는 router filter이며, 여기서는 HTTP filter chain 끝에 위치한다. router filter에서 decodeHeader 가 호출되면 라우트가 선택되고 클러스터가 선택된다. 스트림에서 요청 헤더는 클러스터의 업스트림 엔드포인트로 전달된다. router filter는 이를 위해 일치하는 클러스터에 대한 cluster manager로부터 HTTP connection pool을 얻는다.
  7. 엔드포인트를 찾기 위해 클러스터 특정 로드밸런싱이 수행된다. 새로운 스트림을 허용할지 판단하기 위해 클러스터의 서킷 브레이커를 확인한다. 엔드포인트의 커넥션 풀이 비어있거나 용량이 부족한 경우 엔드포인트에 대한 새로운 연결이 생성된다.
  8. 각 스트림에 대해 업스트림 HTTP filter chain이 생성되고 실행된다. 기본적으로 여기에는 적절한 코덱으로 데이터를 보내는 CodecFilter 만이 포함된다. 하지만 클러스터가 Upstream HTTP filter chain을 구성하면 filter chain이 생성되고 실행된다. 여기에는 재시도 및 쉐도잉된 요청에 대한 별도의 filter chain을 만들고 실행하는 것이 포함된다.
  9. 업스트림 엔드포인트 연결의 HTTP/2 코덱은 단일 TCP 연결을 통해 해당 업스트림으로 전송되는 다른 스트림과 요청 스트림을 멀티플렉싱하고 프레임화 한다.
  10. 업스트림 엔드포인트 연결의 TLS transport socket은 바이트를 암호화하여 업스트림 연결을 위한 TCP 소켓에 쓴다.
  11. 헤더와 선택적 바디 및 트레일러를 구성하는 요청은 업스트림으로 프록시되고 응답이 다운스트림으로 프록시된다. 응답은 codec filter에서 시작하여 업스트림 HTTP filter를 통과한 다음 router filter를 통과하고 Custom filter를 통과한 후 다운스트림으로 전송되기 전에 요청과 반대 순서로 HTTP filter를 통과한다.
  12. 독립적인 half-close가 활성화되는 경우 요청과 응답이 모두 완료된 후 스트림이 해제된다. 그리고 응답은 성공 (2XX) 를 내려준다. 그렇지 않으면 응답이 완료되면 스트림이 해제되고 요청이 아직 완료되지 않앗떠라고 마찬가지이다. 요청 후 처리가 통계를 업데이트하고 엑세스 로그를 남기고 추적 스팬을 마무리한다.

 

istio는 Envoy proxy 중앙 관리

istio는 애플리케이션 부분과 네트워크 부분을 투명하게 관리하기 위해 사용되는 서비스 메쉬 오픈소스로, istio 소개 글에서 설명하였듯이 컨트롤 플레인과 데이터 플레인으로 나뉜다.

 

 

데이터 플레인은 서비스 메쉬 안에 들어있는 애플리케이션에 envoy proxy가 사이드카로 들어있는 형태로 구성되어 있고, 그 외에는 메쉬 안으로 들어오는 트래픽을 받는 ingressgateway 와 메쉬 밖으로 나가는 트래픽을 처리하는 egressgateway 가 존재한다. ingressgatewayegressgateway 는 모두 envoy proxy의 일종이다.

 

컨트롤 플레인은 istiod 로 존재하며 사이드카 또는 ingress/egressgateway의 envoy proxy 의 구성을 중앙 관리한다. 쿠버네티스 관리자가 GatewayVirtualService 등의 istio 커스텀 리소스를 추가/변경/삭제 하면 istiod가 변경사항을 감지하여 적절한 envoy-proxy 의 구성을 변경한다.

 

그렇다면 istiod는 istio 커스텀 리소스의 변경사항을 감지하여 어떤 방식으로 envoy-proxy의 설정을 변경할까?

 

xDS

Envoy는 파일 시스템을 통하거나 관리 서버에 쿼리를 보내서 동적 리소스를 검색할 수 있다. 이러한 검색 서비스와 API를 통틀어서 xDS (eXtensible Discovery Services) 이라고 한다. 리소스는 구독을 통해 요청되고, 감시할 파일 시스템 경로를 지정하거나 gRPC 스트림을 사용하거나 REST-JSON URL을 폴링하는 형식으로 동적 리소스를 확인한다.

 

 

istio에서는 리소스 관리 서비스는 istiod 이며 istiod에서는 VirtualService, Gateway 등의 istio 커스텀 리소스의 변경사항을 감지한 후 변경사항이 발생했다면 해당 커스텀 리소스를 envoy의 구성으로 변환한 다음 istiod를 구독한 envoy proxy 중에 구성의 타깃이 되는 envoy proxy에 xDS로 동적 구성을 PUSH한다.

 

그리고 envoy-proxy (사이드카 및 게이트웨이) 는 파드(컨테이너)가 뜨는 시점에 istiod를 구독하기 위해 커넥션을 맺는다. 구독이 완료되어야 istiod에서 server-side PUSH 를 할 수 있기 때문이다.

 

xDS의 종류는 여러가지가 있다.

  • LDS (Listener)
  • RDS (Route)
  • CDS (Cluster)
  • EDS (Endpoint)
  • SDS (Secret)
  • ADS (Aggregate) 등

 

로그 뜯어보기

로그를 통해 istio 커스텀 리소스를 추가/변경/삭제하면 어떤 일이 발생하는지 확인해보자.

 

istiod

먼저 모든 커스텀 리소스를 삭제하고 모든 istio 컴포넌트를 재구동한 상태에서 istiod의 로그를 확인해보자.

2025-02-18T14:54:44.322674Z    info    FLAG: --caCertFile=""
2025-02-18T14:54:44.322860Z    info    FLAG: --clusterAliases="[]"
...

2025-02-18T14:54:44.352388Z    info    Loaded MeshNetworks config from Kubernetes API server.
2025-02-18T14:54:44.352404Z    info    mesh networks configuration updated to: {

}
2025-02-18T14:54:44.353703Z    info    Loaded MeshConfig config from Kubernetes API server.
2025-02-18T14:54:44.354199Z    info    mesh configuration updated to: {
    "proxyListenPort": 15001,
    "proxyInboundListenPort": 15006,
    ...
}

2025-02-18T14:54:44.361014Z    info    initializing mesh networks from mesh config watcher
2025-02-18T14:54:44.361095Z    info    mesh configuration: {
    "proxyListenPort": 15001,
    "proxyInboundListenPort": 15006,
    ...
}
...

2025-02-18T14:54:44.363408Z    info    initializing mesh handlers
2025-02-18T14:54:44.363688Z    info    model    reloading network gateways
2025-02-18T14:54:44.363973Z    info    creating CA and initializing public key
2025-02-18T14:54:44.364084Z    info    Using istiod file format for signing ca files
2025-02-18T14:54:44.364140Z    info    Use self-signed certificate as the CA certificate
2025-02-18T14:54:44.366090Z    info    pkica    Load signing key and cert from existing secret istio-system/istio-ca-secret
2025-02-18T14:54:44.366560Z    info    pkica    Using existing public key: -----BEGIN CERTIFICATE-----
MIIC/TCCAeWgAwIBAgIRALvmlLV2nf4b7lBT0y1XoY0wDQYJKoZIhvcNAQELBQAw
...

-----END CERTIFICATE-----

2025-02-18T14:54:44.366697Z    info    pkica    Set secret name for self-signed CA cert rotator to istio-ca-secret
2025-02-18T14:54:44.366791Z    info    rootcertrotator    Set up back off time 32m3s to start rotator.
2025-02-18T14:54:44.366848Z    info    initializing controllers
2025-02-18T14:54:44.366891Z    info    rootcertrotator    Jitter is enabled, wait 32m3s before starting root cert rotator.
2025-02-18T14:54:44.367562Z    info    Adding Kubernetes registry adapter
2025-02-18T14:54:44.367709Z    info    Discover server subject alt names: [istio-pilot.istio-system.svc istiod-1-23-4.istio-system.svc istiod-remote.istio-system.svc istiod.istio-system.svc]
2025-02-18T14:54:44.367839Z    info    initializing Istiod DNS certificates host: istiod-1-23-4.istio-system.svc, custom host:
2025-02-18T14:54:44.603751Z    info    Generating istiod-signed cert for [istio-pilot.istio-system.svc istiod-1-23-4.istio-system.svc istiod-remote.istio-system.svc istiod.istio-system.svc]:
 -----BEGIN CERTIFICATE-----
 ...

-----END CERTIFICATE-----

2025-02-18T14:54:44.603797Z    info    Using istiod file format for signing ca files
2025-02-18T14:54:44.603804Z    info    Use roots from istio-ca-secret
2025-02-18T14:54:44.603982Z    info    x509 cert - Issuer: "O=cluster.local", Subject: "", SN: 315c7d66cc8771ffb550c0165b1336e9, NotBefore: "2025-02-18T14:52:44Z", NotAfter: "2035-02-16T14:54:44Z"
2025-02-18T14:54:44.603988Z    info    Istiod certificates are reloaded
  • 첫 로그를 보면 기본으로 설정된 FLAGS를 출력하고 설정한 meshConfig를 불러와서 istiod의 구성을 설정한다.
  • 그 다음에는 istiod와 mesh간 gRPC 통신을 위해 인증서를 가져온다. istio-system/istio-ca-secret 시크릿에 인증서 정보가 있다.

 

2025-02-18T14:54:44.604115Z    info    spiffe    Added 1 certs to trust domain cluster.local in peer cert verifier
2025-02-18T14:54:44.604126Z    info    initializing secure discovery service
2025-02-18T14:54:44.604183Z    info    initializing secure webhook server for istiod webhooks
2025-02-18T14:54:44.610317Z    info    initializing sidecar injector
2025-02-18T14:54:44.632181Z    info    initializing config validator
2025-02-18T14:54:44.632255Z    info    initializing registry event handlers
2025-02-18T14:54:44.632340Z    info    starting discovery service
2025-02-18T14:54:44.632416Z    info    initializing CA server with IstioD CA
2025-02-18T14:54:44.633692Z    info    Starting Istiod Server with primary cluster Kubernetes
2025-02-18T14:54:44.633869Z    info    ControlZ available at 127.0.0.1:9876
2025-02-18T14:54:44.634446Z    info    kube    Initializing Kubernetes service registry "Kubernetes"
2025-02-18T14:54:44.634722Z    info    status    Starting status manager
2025-02-18T14:54:44.634862Z    info    Starting validation controller
2025-02-18T14:54:44.634958Z    info    Starting ADS server
2025-02-18T14:54:44.635054Z    info    starting CA server
2025-02-18T14:54:44.635108Z    info    klog    attempting to acquire leader lease istio-system/istio-leader...
2025-02-18T14:54:44.635272Z    info    Istiod CA has started
2025-02-18T14:54:44.635358Z    info    cluster "Kubernetes" kube client started
2025-02-18T14:54:44.634784Z    info    Starting multicluster remote secrets controller
2025-02-18T14:54:44.635587Z    info    klog    attempting to acquire leader lease istio-system/istio-gateway-status-leader...
2025-02-18T14:54:44.635795Z    info    controllers    starting    controller=healthcheck
2025-02-18T14:54:44.635953Z    info    klog    attempting to acquire leader lease istio-system/istio-gateway-deployment-1-23-4...
2025-02-18T14:54:44.636594Z    info    controllers    starting    controller=auto-register existing connections
2025-02-18T14:54:44.636718Z    info    controllers    starting    controller=unregister_workloadentry
2025-02-18T14:54:44.637213Z    info    kube    Starting Pilot K8S CRD controller    controller=crd-controller
2025-02-18T14:54:44.637246Z    info    kube    controller "gateway.networking.k8s.io/v1/GRPCRoute" is syncing...    controller=crd-controller
2025-02-18T14:54:44.639479Z    info    kube    controller "gateway.networking.k8s.io/v1beta1/GatewayClass" is syncing...    controller=crd-controller
2025-02-18T14:54:44.648217Z    info    kube    controller "gateway.networking.k8s.io/v1beta1/ReferenceGrant" is syncing...    controller=crd-controller
2025-02-18T14:54:44.654714Z    info    multicluster remote secrets controller cache synced in 19.92704ms
2025-02-18T14:54:44.654734Z    info    controllers    starting    controller=multicluster secret
2025-02-18T14:54:44.657167Z    info    controllers    starting    controller=validation
2025-02-18T14:54:44.657389Z    info    controllers    starting    controller=ingress
2025-02-18T14:54:44.658358Z    info    controllers    starting    controller=default revision
2025-02-18T14:54:44.658382Z    info    kube    controller "extensions.istio.io/v1alpha1/WasmPlugin" is syncing...    controller=crd-controller
2025-02-18T14:54:44.658552Z    info    controllers    starting    controller=default revision
2025-02-18T14:54:44.658572Z    info    controllers    starting    controller=default revision
2025-02-18T14:54:44.667388Z    info    controllers    starting    controller=webhook patcher
2025-02-18T14:54:44.676250Z    info    controllers    starting    controller=crd watcher
2025-02-18T14:54:44.676391Z    info    controllers    starting    controller=configmap istio-sidecar-injector-1-23-4
2025-02-18T14:54:44.676481Z    info    authorizationpolicies.security.istio.io is now ready, building client
2025-02-18T14:54:44.676699Z    info    destinationrules.networking.istio.io is now ready, building client
2025-02-18T14:54:44.676806Z    info    envoyfilters.networking.istio.io is now ready, building client
2025-02-18T14:54:44.676904Z    info    gateways.networking.istio.io is now ready, building client
2025-02-18T14:54:44.676966Z    info    peerauthentications.security.istio.io is now ready, building client
2025-02-18T14:54:44.677026Z    info    proxyconfigs.networking.istio.io is now ready, building client
2025-02-18T14:54:44.677122Z    info    requestauthentications.security.istio.io is now ready, building client
2025-02-18T14:54:44.677213Z    info    serviceentries.networking.istio.io is now ready, building client
2025-02-18T14:54:44.677316Z    info    sidecars.networking.istio.io is now ready, building client
2025-02-18T14:54:44.677412Z    info    telemetries.telemetry.istio.io is now ready, building client
2025-02-18T14:54:44.677487Z    info    virtualservices.networking.istio.io is now ready, building client
2025-02-18T14:54:44.677607Z    info    wasmplugins.extensions.istio.io is now ready, building client
2025-02-18T14:54:44.677685Z    info    workloadentries.networking.istio.io is now ready, building client
2025-02-18T14:54:44.677750Z    info    workloadgroups.networking.istio.io is now ready, building client
2025-02-18T14:54:44.676310Z    info    kube    controller "networking.istio.io/v1alpha3/Gateway" is syncing...    controller=crd-controller
2025-02-18T14:54:44.710448Z    info    kube    kube controller for Kubernetes synced after 73.949042ms
2025-02-18T14:54:44.710492Z    info    kube    Pilot K8S CRD controller synced in 73.277254ms    controller=crd-controller
  • 이 이후에는 istiod에 필요한 컴포넌트들을 시작시킨다.

 

2025-02-18T14:54:44.710910Z    info    model    Full push, new service argocd/argocd-applicationset-controller.argocd.svc.cluster.local
2025-02-18T14:54:44.710947Z    info    model    Full push, new service argocd/argocd-dex-server.argocd.svc.cluster.local
2025-02-18T14:54:44.710998Z    info    model    Full push, new service argocd/argocd-redis.argocd.svc.cluster.local
2025-02-18T14:54:44.711020Z    info    model    Full push, new service argocd/argocd-repo-server.argocd.svc.cluster.local
2025-02-18T14:54:44.711088Z    info    model    Full push, new service argocd/argocd-server.argocd.svc.cluster.local
2025-02-18T14:54:44.711166Z    info    model    Full push, new service bookinfo/details.bookinfo.svc.cluster.local
2025-02-18T14:54:44.711191Z    info    model    Full push, new service bookinfo/productpage.bookinfo.svc.cluster.local
2025-02-18T14:54:44.711275Z    info    model    Full push, new service bookinfo/ratings.bookinfo.svc.cluster.local
2025-02-18T14:54:44.711325Z    info    model    Full push, new service bookinfo/reviews.bookinfo.svc.cluster.local
2025-02-18T14:54:44.711419Z    info    model    Full push, new service default/kubernetes.default.svc.cluster.local
2025-02-18T14:54:44.711451Z    info    model    Full push, new service istio-system/egressgateway.istio-system.svc.cluster.local
2025-02-18T14:54:44.711549Z    info    model    Full push, new service istio-system/ingressgateway.istio-system.svc.cluster.local
2025-02-18T14:54:44.711578Z    info    model    Full push, new service istio-system/istiod-1-23-4.istio-system.svc.cluster.local
2025-02-18T14:54:44.711649Z    info    model    Full push, new service kube-system/kube-dns.kube-system.svc.cluster.local
2025-02-18T14:54:44.711752Z    info    model    Full push, new service kube-system/metrics-server.kube-system.svc.cluster.local
2025-02-18T14:54:44.711781Z    info    model    Full push, new service metallb-system/webhook-service.metallb-system.svc.cluster.local
2025-02-18T14:54:44.711817Z    info    model    Full push, new service middleware/mysql-hs.middleware.svc.cluster.local
2025-02-18T14:54:44.711861Z    info    model    Full push, new service middleware/mysql.middleware.svc.cluster.local
2025-02-18T14:54:44.711912Z    info    model    Full push, new service todo/todo-api.todo.svc.cluster.local
2025-02-18T14:54:44.779286Z    info    Waiting for caches to be synced
  • 그 다음에 Kubernetes Service 리소스를 읽어들여서 클러스터와 같은 envoy 구성으로 변환한다.

 

2025-02-18T14:54:46.130502Z    info    ads    XDS: Incremental Pushing ConnectedEndpoints:0 Version:2025-02-18T14:54:44Z/1
2025-02-18T14:54:46.202290Z    info    delta    ADS: new delta connection for node:ingressgateway-66765874f6-jjdlg.istio-system-1
2025-02-18T14:54:46.210432Z    info    delta    CDS: PUSH request for node:ingressgateway-66765874f6-jjdlg.istio-system resources:33 removed:0 size:37.4kB cached:0/32 filtered:0
2025-02-18T14:54:46.211947Z    info    delta    EDS: PUSH request for node:ingressgateway-66765874f6-jjdlg.istio-system resources:32 removed:0 size:6.8kB empty:0 cached:0/32 filtered:0
2025-02-18T14:54:46.212811Z    info    delta    LDS: PUSH request for node:ingressgateway-66765874f6-jjdlg.istio-system resources:0 removed:0 size:0B
2025-02-18T14:54:46.220763Z    info    delta    SDS: PUSH request for node:ingressgateway-66765874f6-jjdlg.istio-system resources:1 removed:0 size:2.9kB cached:0/1 filtered:0
2025-02-18T14:54:46.221558Z    warn    buildGatewayRoutes: no gateways for router ingressgateway-66765874f6-jjdlg.istio-system
2025-02-18T14:54:46.222146Z    warn    buildGatewayRoutes: no gateways for router ingressgateway-66765874f6-jjdlg.istio-system
2025-02-18T14:54:46.222264Z    info    delta    RDS: PUSH request for node:ingressgateway-66765874f6-jjdlg.istio-system resources:2 removed:0 size:53B cached:0/0 filtered:0
  • 그 다음에는 envoy 구성을 타깃 envoy proxy로 보내는 작업이 이루어진다. 여기서는 xDS API를 사용한다. (server-side PUSH)

 

ingressgateway (envoy-proxy)

 

일단 아무 istio 커스텀 리소스가 반영되어있지 않다면 어떠한 라우팅룰과 관련된 설정이 없을 것이다. 초기 상태에서 ingressgateway 파드의 envoy proxy 구성을 살펴보자.

 

다음 명령어를 통해 파드 내 envoy proxy의 구성을 확인할 수 있다.

$ istioctl proxy-config all ingressgateway-557bff5b5f-cg2lc -o yaml > initial.yaml
  • proxy-config 명령어에서는 특정 구성만을 확인하는 것도 가능하고, all 로 선택한 경우 모든 구성을 확인해볼 수 있다. 구성의 종류로는 bootstrap, cluster, ecds, endpoint, listener, route, secret 등이 있다.
  • -o yaml 옵션을 사용하면 구성을 yaml 형태로 받을 수 있다.

 

 

파일을 보면 크게 7가지 부분으로 나뉜다. 여기서 BootstrapConfig를 제외하고 하나씩 살펴보자.

 

ClusterConfig

 

ClusterConfig를 보면 여러개의 cluster 배열이 선언되어 있는데, 최상단의 BlackHoleCluster 를 제외하고는 모두 쿠버네티스 내에 있는 서비스가 등록 되어있는 것을 확인할 수 있다. 즉 istiod는 쿠버네티스의 서비스 변경사항을 감지한 후 변경사항이 발생하면 관련된 envoy 구성으로 만든 다음 EDS를 통해 메쉬 내 envoy-proxy 로 동적 구성을 적용시킨다.

  • metadata.filter_metadata.istio.services 부분에서 host, name, namespace는 각각 서비스 FQDN, 서비스 이름, 서비스 네임스페이스로 매핑된다.
  • name의 부분이 클러스터의 이름인데 클러스터 이름은 outbound|${PORT}|${Service_FQDN}으로 결정된다.
  • type 부분을 보면 EDS 라고 되어있는데 EDS에 의해 추가된 것으로 볼 수 있다.

 

 

EndpointsConfig

 

EndpointsConfig는 각 ClusterConfig에 등록된 Cluster의 엔드포인트가 선언되어 있다. 하나의 endpoint_config 안에는 클러스터(서비스)에서 디스커버리되는 엔드포인트 ip/port 주소들이 들어있다.

 

ListenerConfig

 

ListenerConfig에는 리스너의 정보가 들어있는데, 여기서는 envoy-proxy에 오픈되어있는 포트별로 리스너 구성정보가 담겨있다.

  • 첫 번째로 볼 것은 address 항목인데 여기서는 IP주소와 포트번호에 대한 정보가 들어있다.
  • 두 번째로 볼 것은 filter_chains 항목인데 여기서 처음 등장하는 체인은 NetworkFilterChain의 HTTP connection filter 이다. 이전의 envoy 필터 구조 그림을 보면 NetworkFilterChain의 맨 끝에 HTTP connection filter 가 있는 것을 확인할 수 있다.
  • HTTP connection filter 부분을 보면 http_filters 라는 항목이 있는데 이 부분부터는 HTTPFilterChain 이며, 여기서도 마찬가지로 Router filter를 사용하고 있다.
  • router_config 부분을 보면 알 수 있듯이 기본적으로 ingressgateway의 15090 포트는 메트릭 수집용 포트이고, 15021 포트는 헬스체크용으로 사용하고 있다. 초기에는 이 외의 listener는 없다. Gateway, VirtualService 등의 리소스가 추가되면 생성이 될 것이다.

 

RoutesConfig

 

RoutesConfig에서는 라우팅룰에 대한 정보를 담고있는 것 같다. 아직은 ListenerConfig와 별 다른 것은 없어보인다.

 

SecretConfig

 

SecretConfig는 envoy proxy에서 사용할 인증서에 대한 정보를 담고있다.

 

 

리소스 추가

 

아무 istio 커스텀 리소스가 없을 때 최초로 ingressgateway를 대상으로 GatewayVirtualService를 추가하면 구성이 어떻게 달라질까? 한번 다음과 같이 Gateway, VirtualService 를 생성한 후 ingressgateway의 proxy-config를 다시 분석해보자.

 

먼저 다음과 같이 Gateway 만 추가해보자. 그 후 어떤 설정이 변경되었는지 살펴보자.

apiVersion: networking.istio.io/v1
kind: Gateway
metadata:
  name: beer1-com
  namespace: istio-system
spec:
  selector:
    istio: ingressgateway
  servers:
  - port:
      number: 80
      name: http
      protocol: HTTP
    hosts:
    - "*.beer1.com"
  - port:
      number: 443
      name: https
      protocol: HTTPS
    hosts:
    - bookinfo.beer1.com
    tls:
      mode: SIMPLE
      credentialName: bookinfo # 인증서 시크릿은 별도로 준비해야 한다.

 

ListenerConfig

 

Gateway 설정에서는 80, 443 포트에 대한 규칙이 생겼기 때문에 ListenerConfig에는 80, 443 포트에 관련된 구성이 추가되었다.

 

RouteConfig

 

RouteConfig에는 다음과 같이 80, 443 포트에 대한 route_config가 추가되었는데 여기서는 둘다 blackhole으로 되어있다. 이렇게 되어있으면 무조건 503에러를 리턴하는 것 같다.

 

 

SecretConfig

 

Gateway에서 TLS 인증서 설정을 했기 때문에 ingressgateway에서는 TLS 처리를 위해 인증서 설정이 필요하다. 그래서 Gateway가 추가되면 해당하는 gateway의 파드의 SecretConfig에 인증서 정보가 추가된다.

 

 

 

 

이 이후에 다음과 같이 VirtualService 도 추가하면 어떻게 되는지 확인해보자.

apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
  name: bookinfo-ingress
  namespace: istio-system
spec:
  hosts:
  - bookinfo.beer1.com
  gateways:
  - beer1-com
  http:
  - route:
    - destination:
        host: productpage.bookinfo.svc.cluster.local
        port: 
          number: 9080

 

RouteConfig

 

예상했겠지만 VirtualService는 L7 라우팅룰을 선언하는 부분이기 때문에 VirtualService 를 변경하면 RouteConfig가 변경된다.

  • 여기서는 bookinfo.beer1.com 호스트로 80포트에 요청이 오는 경우 / 경로 하위로 올 때 productpage.booinfo.svc.cluster.local:9080 으로 포워딩 시켜준다.

 

 

 

 

마무리

이번 시간에는 Envoy proxy의 구조와 xDS에 대해 간단히 알아보았고 istiod가 istio 커스텀 리소스를 감지하여 어떤 방식으로 istio dataplane (gateway, sidecar)의 구성을 변경하는지 알아보았다. 그리고 실제로 어떻게 구성이 바뀌는지도 istioctl을 통해 두 눈으로 확인해 보았다. 

 

istio에서 EnvoyProxy를 다루려면 envoy의 구조와 구성파일의 구조에 대해 대략적으로 알아야 제대로 사용할 수 있기 때문에 이렇게 자세하게 구성을 뜯어보는것도 어느정도 istio를 다루는 데 도움이 될 것이라고 생각한다.

 

 

728x90

댓글