2주차 - 엔보이, 게이트웨이

개요

엔보이 간단 실습

초기 세팅

services:
  httpbin:
    container_name: httpbin
    image: mccutchen/go-httpbin
    environment:
      PORT: "8080"
    restart: unless-stopped
    networks:
      - envoy-net
  netshoot:
    container_name: netshoot
    image: nicolaka/netshoot
    restart: unless-stopped
    networks:
      - envoy-net
    command: sh -c "sleep 60d"
  envoy:
    container_name: envoy
    image: envoyproxy/envoy:v1.33.2
    restart: unless-stopped
    networks:
      - envoy-net
networks:
   envoy-net:
    driver: bridge

간단하게 도커 컴포즈 파일을 만들어서 테스트를 진행한다.

alias dc="docker compose"
alias dcn="docker compose exec -ti netshoot"
alias dce="docker compose exec -ti envoy"
alias dch="docker compose exec -ti httpbin"

간단하게 명령어를 치기 위해 별칭도 세팅했다.

dc up -d

전부 실행!
image.png
성공적으로 실행되고 있다.

dce -h

image.png
엔보이 명령어를 쳐보면, 설정 파일을 어떤 식으로 전달하면 되는지 정보가 나온다.
image.png
참고로 엔보이 도커 파일을 보면, /etc/envoy에서 기본 파일을 이용해 실행되는 것을 알 수 있다.

admin:
  address:
    socket_address:
      protocol: TCP
      address: 0.0.0.0
      port_value: 9901
static_resources:
  listeners:
  - name: listener_0
    address:
      socket_address:
        protocol: TCP
        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
          scheme_header_transformation:
            scheme_to_overwrite: https
          stat_prefix: ingress_http
          route_config:
            name: local_route
            virtual_hosts:
            - name: local_service
              domains: ["*"]
              routes:
              - match:
                  prefix: "/"
                route:
                  host_rewrite_literal: www.envoyproxy.io
                  cluster: service_envoyproxy_io
          http_filters:
          - name: envoy.filters.http.router
            typed_config:
              "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
  clusters:
  - name: service_envoyproxy_io
    connect_timeout: 30s
    type: LOGICAL_DNS
    # Comment out the following line to test on v6 networks
    dns_lookup_family: V4_ONLY
    lb_policy: ROUND_ROBIN
    load_assignment:
      cluster_name: service_envoyproxy_io
      endpoints:
      - lb_endpoints:
        - endpoint:
            address:
              socket_address:
                address: www.envoyproxy.io
                port_value: 443
    transport_socket:
      name: envoy.transport_sockets.tls
      typed_config:
        "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext
        sni: www.envoyproxy.io

이게 바로 엔보이의 기본 설정 파일로, 9901 포트로 관리자 페이지, 10000포트로 리스너 세팅이 돼있다.
모든 호스트에 대해 www.envoyproxy.io로 이름을 바꾸고 service_envoyproxy_io 클러스터로 트래픽을 라우팅한다.
클러스터 부분을 보면 엔드포인트로 위 주소로 그대로 요청을 전달하도록 돼있다.
image.png
단순히 처음에 envoy에 트래픽을 날리면 이게 어디에서 나오는 건가 했는데, 실제 엔보이 공식 문서에서 받아오는 거였다.

ip a s | grep  $(docker network ls | grep envoy | awk '{print $1}')

image.png
얼마나 뜯어볼 지는 모르겠지만, 와이어샤크로 패킷을 볼 수 있도록 인터페이스 이름도 확인해둔다.
image.png
패킷을 떠보면, 의도치 않게 엔보이가 ec2로 띄워져있다는 것도 알 수 있다..
아무튼 넷슛에서 엔보이로 요청을 보내자 엔보이가 라우팅을 하고 데이터를 반환했다는 것을 알 수 있다.

기본 세팅

services:
  httpbin:
    container_name: httpbin
    image: mccutchen/go-httpbin
    environment:
      PORT: "8000"
    ports:
    - "8000:8000"
    restart: unless-stopped
    networks:
      - envoy-net
  netshoot:
    container_name: netshoot
    image: nicolaka/netshoot
    restart: unless-stopped
    networks:
      - envoy-net
    command: sh -c "sleep 60d"
    stop_grace_period: 1s
  envoy:
    container_name: envoy
    image: envoyproxy/envoy:v1.33.2
    restart: unless-stopped
    networks:
      - envoy-net
    configs:
      - simple.yaml
    command: envoy -c /simple.yaml
    ports:
    - "15000:15000"
    - "15001:15001"
networks:
   envoy-net:
    driver: bridge
configs:
  simple.yaml:
    file: ./simple.yaml

이제 본격적으로 실습을 진행한다.
configs 필드로 특정 파일을 컨테이너에 전달해주었다.
실질적으로 볼륨 마운팅과 크게 다르진 않은데, 볼륨 마운팅처럼 필드를 길게 쓸 필요는 없기도 하고 원하는 파일만 쉽게 명시할 수 있을 것 같아서 사용했다.

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
          route_config:
            name: httpbin_local_route
            virtual_hosts:
            - name: httpbin_local_service
              domains: ["*"]
              routes:
              - match: { prefix: "/" }
                route:
                  auto_host_rewrite: true
                  cluster: httpbin_service
          http_filters:
          - name: envoy.filters.http.router
            typed_config:
              "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
  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

엔보이의 설정 파일은 이렇게 세팅했다.
1.33 최신 버전의 엔보이는 라우팅을 할 시 http_filters 필드에 typed config를 명확하게 작성해줘야 한다.
image.png
기본적으로 httpbin 컨테이너를 호출하면 이렇게 응답이 돌아온다.
image.png
이번에는 엔보이를 거쳐서 데이터를 받아오도록 해본다.
보다시피 추가적인 헤더들이 더 들어간 것이 보인다.
image.png
위에서 본 것과 같이 데이터를 추고 받는 플로우를 볼 수 있다.
image.png
엔보이는 요청을 보낼 때 위와 같이 헤더에 다양한 값을 추가해서 보내며, 이 상태에서 httpbin은 받은 헤더를 그대로 리턴하기 때문에 그대로 그 헤더값들을 받아볼 수 있는 것이다.
image.png
리퀘스트 타임아웃 예상 기간이 15초로 설정돼있는데, 아예 1초로 줄여보자.
정적 파일을 통한 설정이므로, 컨테이너를 재시작해주어야 한다.

dc restart envoy

image.png
변경값이 성공적으로 반영됐다.

dcn curl envoy:15001/delay/1.5

image.png
실제 설정 상에서도 엔보이는 1.5가 지나면 업스트림에 문제가 있다며 그대로 응답해버린다.
image.png
1.5초가 지나자 엔보이가 먼저 업스트림 측에 FIN으로 tcp 연결을 끊으면서 넷슛에 504 게이트웨이 타임아웃 에러를 보낸 것을 볼 수 있다.
httpbin은 갑자기 연결 끊기니 499둥절하는 사이에 엔보이는 RST, 즉 tcp 연결을 리셋하라고 혼내는 상황..

image.png
간단하게 메트릭도 확인해보자.
위 설정에서 admin 페이지에 대한 포트를 열어놨기에 localhost 15000포트로 접근이 가능하다.
image.png
한가지 재밌는 걸 찾았는데, active html 형식으로 보겠다고 하면 이렇게 도식도 같이 출력된다.
image.png
또 동적으로 페이지가 변화하는데, 패킷으로 보니까 그냥 스크립트에 주기적으로 서버를 호출하도록 코드가 짜여져 있나보다.

curl localhost:15000/stats/prometheus

이렇게 하면 프로메테우스 형식으로도 볼 수 있다.
여기에서 더 다양한 엔드포인트들을 찾을 수 있으니 참고하자.[1]

파일 시스템 기반의 동적 설정

마지막으로는 xDS api를 파일시스템으로 설정하여 간단하게 동적 설정을 진행하는 실습을 해본다.

마운팅된 파일 이용 - 실패

node:
  id: id_1
  cluster: test

dynamic_resources:
  cds_config:
    path_config_source:
      path: /cds.yaml
  lds_config:
    path_config_source:
      path: /lds.yaml

admin:
  address:
    socket_address:
      address: 0.0.0.0
      port_value: 15000

먼저 엔보이 설정 파일에는 이렇게 dynamic_resources 필드를 작성하고, 설정을 넣을 xds를 기입한다.
grpc나 rest를 기반으로 한다면 하위 필드를 다르게 작성해줘야 한다.

resources:
- "@type": type.googleapis.com/envoy.config.listener.v3.Listener
  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
          typed_config:
            "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.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
                retry_policy:
                    retry_on: 5xx
                    num_retries: 3

lds 파일은 이렇게 작성해줬다.

resources:
- "@type": type.googleapis.com/envoy.config.cluster.v3.Cluster
  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

cds 파일은 이렇게 작성했는데, 이전 실습에서 진행한 세팅과 완벽히 일치한다.

    command: envoy -c /dynamic.yaml
    # command: envoy -c /simple.yaml
    configs:
      - simple.yaml
      - dynamic.yaml
      - lds.yaml
      - cds.yaml

마지막으로 도커 컴포즈 파일에서 이렇게 config 파일들을 컨테이너에 넣도록 세팅해주면 된다.
image.png
이 상태로 실행해도 기본 동작이 제대로 이뤄진다.

dc logs envoy

image.png
엔보이의 로그를 뜯어보면, 위와 같이 cds, lds 에 대해 설정 파일을 업데이트했다는 정보가 나온다.
image.png
이제 아까와 같이 타임아웃 시간을 세팅해본다.
image.png
내 예상과 다르게 설정이 동적으로 적용되지 않았는데, 상황을 보니 리스너에 대한 드레이닝이 발생하고 있는 듯했다.
image.png
어드민 페이지로 들어가 현재 상태를 확인해보면 마찬가지로 draining이 뜨는 것을 확인할 수 있다.
글을 찾다보니 컨테이너 환경이라면 inotify의 문제가 있을 수도 있다는 것 같아 변경 시간을 확인해봤으나 변경은 제대로 반영되고 있었다.
image.png
혹시나 내가 변경하려는 필드에만 뭐가 특별한가 싶어서 아예 리스너 포트를 변경해보려고 시도 중..
한가지 마음에 걸린 지점은, 컨테이너 내부에서 파일을 수정할 수 없었다는 것이다.
아무래도 파일이 마운팅되는 방식으로 컨테이너에 반영되니 지속적으로 열린 상태가 컨테이너 내부에서 유지되고 있는 것 같았다.

이미지 레이어로 파일 전달 - 성공

FROM envoyproxy/envoy:v1.33.2
COPY --chmod=777 ./lds.yaml /lds.yaml

이게 답이라면 해법은 간단하다.
이미지 레이어를 하나 더 쌓아서 파일을 넣어주면 끝이다.

  envoy:
    container_name: envoy
    build:
        context: .
    restart: unless-stopped
    networks:
      - envoy-net
    command: envoy -c /dynamic.yaml
    configs:
      - simple.yaml
      - dynamic.yaml
    ports:
    - "15000:15000"
    volumes:
      - ./cds.yaml:/cds.yaml

이에 따라 도커 컴포즈 설정도 현재 디렉토리를 컨텍스트로 하여 이미지를 빌드하도록 조금 수정을 가해주었다.

dce sed -i s/15001/15002/ /lds.yaml

image.png
이번에는 제대로 수정이 되는 것이 확인된다.
image.png
또한 로그로도 lds가 설정이 한번 더 일어난 것이 제대로 추적된다.
image.png
이젠 변경한 포트로 요청을 날려야 값이 반환되는 것을 확인할 수 있다!

엔보이를 직접 파보면서, 엔보이가 많은 기능을 통일된 설정 방식으로 제공한다는 것을 알게 되어서 놀란 한편, 그만큼 설정하는 방법이 너무 복잡해서 굉장히 놀랐다..
이 기반을 알아두면 이스티오를 설정할 때 사용되는 각종 개념을 이해하는데 도움은 될 것이라 생각한다.
다만 이스티오를 공부하는 입장에서는 이스티오를 이해하기 위한 수준으로만 엔보이를 파는 게 좋겠다는 생각이 들었다.

이스티오 설정 다시보기

이전 실습 환경과 동일하게 다시 구성한다.
kind, istioctl을 이용해 클러스터를 구성한다.
자세한 세팅법은 1W - 서비스 메시와 이스티오에 나와있다.

proxy status

istioctl ps

image.png
이제 프록시 스테이터스 명령어를 쳤을 때 나오는 값들이 무엇인지 조금씩 이해할 수 있다.
먼저 클러스터는 엔보이 설정에 명시된 클러스터 이름을 나타낸다.
각종 설정은 istiod와 통신을 통해 설정을 가져가 동기화를 하게 되기 때문에 각 XDS에는 SYNCED라고 표시된다.

keti productpage-v1-d49bb79b4-wx7h2 -c istio-proxy -- ps aux

image.png
프록시가 주입된 아무 컨테이너나 잡아 내부를 들여다보면, pilot agent가 실행되어 각종 설정을 진행하고 이후 엔보이가 envoy-rev.json 파일을 통해 실행되는 것을 확인할 수 있다.

keti productpage-v1-d49bb79b4-wx7h2 -c istio-proxy -- ls /etc/istio/proxy -al

image.png
이 중에서 json 파일을 들여다보자.

{
  "application_log_config": {
    "log_format": { "text_format": "%Y-%m-%dT%T.%fZ\t%l\tenvoy %n %g:%#\t%v\tthread=%t" }
  },
  "node": {
    "id": "sidecar~10.10.0.19~productpage-v1-d49bb79b4-wx7h2.default~default.svc.cluster.local",
    "cluster": "productpage.default",
    "locality": { },
  },
  "dynamic_resources": {
    "lds_config": { "ads": {}, },
    "cds_config": { "ads": {}, },
    "ads_config": {
      "api_type": "DELTA_GRPC",
      "set_node_on_first_message_only": true,
      "transport_api_version": "V3",
      "grpc_services": [ { "envoy_grpc": { "cluster_name": "xds-grpc" } } ]
    }
  },
  "static_resources": {
    "clusters": [
      {
        "name": "prometheus_stats",
        "alt_stat_name": "prometheus_stats;",
        "load_assignment": {
          "cluster_name": "prometheus_stats",
          "endpoints": [{
            "lb_endpoints": [{
              "endpoint": {
                "address":{ "socket_address": { "protocol": "TCP", "address": "127.0.0.1", "port_value": 15000 } }
              }
            }]
          }]
        }
      },
      {
        "name": "agent",
        "alt_stat_name": "agent;",
        "load_assignment": {
          "cluster_name": "agent",
          "endpoints": [{
            "lb_endpoints": [{
              "endpoint": {
                "address":{ "socket_address": { "protocol": "TCP", "address": "127.0.0.1", "port_value": 15020 } }
              }
            }]
          }]
        }
      },
      {
        "name": "xds-grpc",
        "alt_stat_name": "xds-grpc;",
        "type" : "STATIC",
        "connect_timeout": "1s",
        "lb_policy": "ROUND_ROBIN",
        "load_assignment": {
          "cluster_name": "xds-grpc",
          "endpoints": [{
            "lb_endpoints": [{ "endpoint": { "address":{ "pipe": { "path": "./etc/istio/proxy/XDS" } } } }]
          }]
        },
      }
    ],
    "listeners":[
      {
        "name": "0.0.0.0_15021",
        "address": { "socket_address": { "protocol": "TCP", "address": "0.0.0.0", "port_value": 15021 } },
        "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",
                  "route_config": {
                    "virtual_hosts": [
                      {
                        "name": "backend",
                        "domains": [ "*" ],
                        "routes": [ { "match": { "prefix": "/healthz/ready" }, "route": { "cluster": "agent" } } ]
                      }
                    ]
                  },
                  "http_filters": [{
                    "name": "envoy.filters.http.router",
                    "typed_config": {
                      "@type": "type.googleapis.com/envoy.extensions.filters.http.router.v3.Router"
                    }
                  }]
                }
              }
            ]
          }
        ]
      }
    ]
  }
}

설정 파일이 너무 길어서 조금씩 잘라내서 옮겨담았다.
image.png
일단 동적 설정 부분을 보면 ADS 형식으로 설정을 하는데, 이때 클러스터는 xds-grpc이다.
image.png
클러스터 설정 부분을 들여다보면 해당 클러스터를 찾을 수 있고, 엔드포인트는 XDS 소켓파일로 설정된 것을 확인할 수 있다.
image.png
에이전트를 향한 리스너 설정이 돼있는 것도 확인된다.

keti productpage-v1-d49bb79b4-wx7h2 -c istio-proxy -- ss -tnp

image.png
이 에이전트는 pilot agent를 말하는 것인데, /heathz/ready 경로일 때 보내는 것으로 보아 프록시의 헬스체크 상태를 컨트롤 플레인에 보고하기 위한 통로로 사용되는 것으로 추측된다.

proxy config

image.png
설정 파일을 간단하게 확인하여 컨트롤 플레인에서 열어둔 소켓을 통해 설정 정보가 동기화된다고 추측해볼 수 있다.
그럼 이스티오에서의 설정이 어떤 식으로 프록시에 들어갔는지 살펴보자.

 istioctl pc bootstrap productpage-v1-d49bb79b4-wx7h2 

bootstrap 설정을 보면 위에서 본 것과 비슷한 설정을 볼 수 있는데, 엄청 길기도 하고 위에서도 봤으니 생략..

istioctl pc cluster productpage-v1-d49bb79b4-wx7h2

image.png
클러스터 설정을 본다.
여기에서는 클러스터 서비스 레지스트리 정보를 총체적으로 확인할 수 있다.
한편으로 클러스터는 단순히 들어온 트래픽을 보내는 대상으로서의 업스트림만 호스트만을 뜻하지 않고, 엔보이 자체적으로 어떤 정보나 보내는 창구를 포함하기 때문에, 위에서 봤던 agent나 xds-grpc 등의 클러스터도 확인할 수 있다.

istioctl pc endpoint productpage-v1-d49bb79b4-wx7h2

image.png
엔드포인트를 보면 클러스터에 속한 대상들에 대한 조금 더 구체적인 정보를 볼 수 있다.

istioctl pc listener productpage-v1-d49bb79b4-wx7h2

image.png
리스너 쪽 설정을 보면 여러 서비스들의 리스너 정보까지도 표시된다.
사실 이 부분이 조금 의외였는데, 클러스터야 서비스 메시 속에서 어디로 트래픽을 보내야 하는지에 대한 정보를 담기 때문에 당연히 여러 서비스가 출력돼야 한다고 생각했다.
그런데 리스너 쪽에서도 다른 서비스들에 대한 정보가 출력되고 있다는 게 조금 이상하게 느껴졌다.
다른 서비스가 받아야 할 트래픽에 대해서는 주소가 0.0.0.0이고 패스스루를 하도록 돼있는 것 같은데, 다른 서비스로 가야할 트래픽이 어쩌다 이 서비스로 들어오더라도 제대로된 클러스터로 보낼 수 있게 하기 위함인 걸까?

istioctl pc route productpage-v1-d49bb79b4-wx7h2

image.png
라우팅 정보도 확인해보면 어떤 가상호스트가 어떤 도메인을 가지고 있는지도 나온다.
virtual service 리소스를 만들지 않아 관련 정보는 보이지 않고 있다.

istioctl pc secret productpage-v1-d49bb79b4-wx7h2

image.png
마지막으로 인증서 관련 정보를 본다.
SDS api를 자세히 까보진 않았기 때문에 엔보이랑 비교해서 명쾌하게 볼 수 있을 만한 지점은 없는 것 같다.

게이트웨이

apiVersion: networking.istio.io/v1
kind: Gateway
metadata:
  name: bookinfo-gateway
spec:
  selector:
    istio: ingressgateway
  servers:
    - port:
        number: 8080
        name: http
        protocol: HTTP
      hosts:
        - "*"

이전에 했던 방식과 다르지 않게 그냥 게이트웨이를 만들어본다.

kubectl stern -n istio-system -l app=istiod

image.png
그럼 게이트웨이 리소스가 생김에 따라 인그레스 게이트웨이 쪽에 설정 api를 날리는 것이 확인된다.

istioctl pc route -n istio-system istio-ingressgateway-6567675ffd-h5447

image.png
라우팅 정보를 보면 서버로 설정한 포트의 name과 number을 이용해 라우팅 필터 이름이 정해졌고, 뒷단에 추가 리소스 설정이 없어 404로 연결된다는 것을 확인할 수 있다.

apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
  name: bookinfo
spec:
  hosts:
    - "*"
  gateways:
    - bookinfo-gateway
  http:
    - match:
        - uri:
            exact: /productpage
        - uri:
            prefix: /static
        - uri:
            exact: /login
        - uri:
            exact: /logout
        - uri:
            prefix: /api/v1/products
      route:
        - destination:
            host: productpage
            port:
              number: 9080

image.png
virtual service를 만들자 다시 한번 인그레스 게이트웨이 쪽에 일련의 설정이 들어간다.
image.png
라우팅 정보를 보면 이제 virtual service를 향하도록 제대로 반영된 것이 확인된다.
image.png
엔드포인트로 보이는 정보를 보면, 대상으로는 서비스 리소스를 추적하는 것으로 보인다.
image.png
그러나 엔드포인트로서는 파드의 ip를 들고 있다.

image.png
통신을 해보면 제대로 트래픽이 전달되는 것이 확인된다.

apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
  name: bookinfo
spec:
  hosts:
    - "bookinfo.com"
  gateways:
    - bookinfo-gateway
  http:
    - match:
        - uri:
            exact: /productpage
        - uri:
            prefix: /static
        - uri:
            exact: /login
        - uri:
            exact: /logout
        - uri:
            prefix: /api/v1/products
      route:
        - destination:
            host: productpage
            port:
              number: 9080

virtualservice에서 호스트 이름을 바꿔본다.
image.png
이제는 bookinfo.com을 호스트로 설정하고 들어오는 요청만 제대로 수행되는 것을 확인할 수 있다.

apiVersion: networking.istio.io/v1
kind: Gateway
metadata:
  name: bookinfo-gateway
spec:
  selector:
    istio: ingressgateway
  servers:
    - port:
        number: 8080
        name: http
        protocol: HTTP
      hosts:
        - "bookinfo.com"

tls 통신

tls에 대해서는 게이트웨이에서 어떤 식으로 tls를 다룰 수 있는지만 간략하게 보고자 한다.
이를 위해 두 가지 세팅을 할 것이다.
하나는 mtls, 다른 하나는 passthrough이다.
패스스루의 경우 tls를 처리하는 어플리케이션이 필요한데, 이건 책의 예제로 빠르게 테스트할 수 있겠다 싶어 책의 예제를 사용했다.
image.png
책에는 미리 실습에 활용할 수 있는 다양한 인증서를 준비해뒀기에 유용하게 사용할 수 있겠다 싶었다.

kubectl create -n istio-system secret \
generic webapp-credential-mtls --from-file=tls.key=\
../book-source-code-master/ch4/certs/3_application/private/webapp.istioinaction.io.key.pem \
--from-file=tls.crt=\
../book-source-code-master/ch4/certs/3_application/certs/webapp.istioinaction.io.cert.pem \
--from-file=ca.crt=\
../book-source-code-master/ch4/certs/2_intermediate/certs/ca-chain.cert.pem

먼저 이스티오의 네임스페이스에 사용할 시크릿을 등록한다.
구체적으로는 인그레스 게이트웨이가 위치한 네임스페이스에 배치하는 것이다.

apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  name: bookinfo-gateway
spec:
  selector:
    istio: ingressgateway
  servers:
    - port:
        number: 8080
        name: http
        protocol: HTTP
      hosts:
        - "webapp.istioinaction.io"
    - port:
        number: 8443
        name: https
        protocol: HTTPS
      tls:
        mode: SIMPLE 
        credentialName: webapp-credential-mtls 
      hosts:
        - "webapp.istioinaction.io"

주어진 인증서는 webapp.istioinaction.io 도메인에 대한 것이므로 호스트도 적절하게 변경해줘야 한다.
virtualSerivce도 바꿔줘야 한다!
image.png
컨트롤 플레인 로그를 보면 tls 시크릿 값을 넣어줌으로 인해 SDS api가 발동된 것이 확인된다.
image.png
또한 인그레스 게이트웨이에 설정이 들어가서 시크릿 정보가 프록시 설정에도 출력된다.

image.png
단순하게만 curl을 날리면 아무런 소용이 없다.
에러 때문에 조금 헷갈리는데, 현재 문제를 구체적으로 확인하려면 이스티오를 이용하면 된다.
image.png
리스너 설정을 보면 MATCH의 기준이 SNI가 된 것을 볼 수 있다.
이것은 TLS 통신에 있어 첫번째 과정인 ClientHello 값의 SNI 필드를 기준으로 매칭을 하겠다는 것이다.
그러나 위에서 Host 헤더를 설정하는 방식은 HTTP 헤더를 세팅하는 것이므로 TLS 통신 이후에나 전달된다.

DOMAIN="webapp.istioinaction.io"
curl https://$DOMAIN:30005/productpage \
	-H "Host: $DOMAIN" \
	--resolve $DOMAIN:30005:127.0.0.1 -k 

해결 방법은 간단한데, 그냥 curl 요청을 날릴 때 적절한 호스트 이름을 넣어주고 --resolve 옵션으로 해당 도메인에 대해 직접 리졸브를 해주면 된다.
이렇게 하면 curl이 날아갈 때 해당 주소에 대해 별도의 DNS 질의를 하지 않고 바로 해당 IP 주소로 요청을 날리게 된다.
image.png
요청이 성공적으로 수행됐다.

이 실습을 통해 알 수 있는 것은 TLS 통신 시 이스티오에서 호스트 이름을 어떻게 해석하는지에 대한 것이다.
엔보이의 세팅을 공부하면서 리스너 필터 체인과 네트워크 필터 체인 사이 TLS Socket 관련 층이 여기에서도 작용한 것이다.

패스스루 모드도 같이 설정하기

cat ../book-source-code-master/ch4/sni/simple-tls-service-1.yaml | sed s/istioinaction/default/ | kaf -

이제 패스스루 모드도 같이 세팅해보는데, 위에서 말한 바와 같이 이건 그냥 빠르게 진행하기 위해 책의 예제를 사용했다.
처음에 default 네임스페이스 쓴 김에 계속 사용 중인데, 위 파일이 오묘하게 한 리소스만 다른 네임스페이스에 설정이 돼있어 부득이하게 해당 값을 바꾸어 적용했다.

apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  name: bookinfo-gateway
spec:
  selector:
    istio: ingressgateway
  servers:
    - port:
        number: 8080
        name: http
        protocol: HTTP
      hosts:
        - "webapp.istioinaction.io"
    - port:
        number: 8443
        name: https
        protocol: HTTPS
      tls:
        mode: SIMPLE
        credentialName: webapp-credential-mtls
      hosts:
        - "webapp.istioinaction.io"
    - port:
        number: 8443
        name: tcp-sni
        protocol: TLS
      hosts:
        - "simple-sni-1.istioinaction.io"
      tls:
        mode: PASSTHROUGH

게이트웨이에는 패스스루를 진행할 호스트도 같이 설정에 넣어준다.
같은 포트를 쓰기 때문에 문제가 생기지 않을까 싶기도 하지만, 호스트 이름이 다르기에 이스티오(구체적으로는 엔보이)에서는 이를 구분지을 수 있다.

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: vs-psthr
spec:
  hosts:
    - "simple-sni-1.istioinaction.io"
  gateways:
    - bookinfo-gateway
  tls:
    - match: 
        - port: 8443
          sniHosts:
            - simple-sni-1.istioinaction.io
      route:
        - destination:
            host: simple-tls-service-1
            port:
              number: 80

다음으로 해당 호스트로 들어온 요청이 어디로 라우팅돼야 하는지 지정해주면 끝이다.
설정이 상당히 다른 것을 볼 수 있는데, 여태까지는 tls 터미네이션이 일어나고나서 http 트래픽만 클러스터 내부로 들어오게 돼있었다.
그러나 패스스루를 하게 되면 tls 암호문이 그대로 클러스터로 들어오게 되고, 이를 기반으로 설정을 해줘야만 한다.
이번에는 설정 상에서도 완전히 sniHosts라고 명시하는 것이 보인다.

DOMAIN="simple-sni-1.istioinaction.io"
curl https://$DOMAIN:30005/productpage \
	-H "Host: $DOMAIN" \
	--resolve $DOMAIN:30005:127.0.0.1 -k 

image.png
세팅만 제대로 해줬다면, 결국 방법은 다르지 않다.
(출력물이 이쁜 걸 보니 새삼 왜 bookinfo로 실습했나 싶네)
image.png
게이트웨이쪽 리스너 설정을 보면 이번에는 목적지가 조금 다르다.
엔보이에서 Route는 HTTP 관련 설정을 거친 후에야 적용되기에 패스스루로 제대로 HTTP 데이터라는 것을 확인할 수도 없는 게이트웨이 입장에서 해당 트래픽은 그저 클러스터로 인식되는 업스트림으로 표시할 수밖에 없다.
(SNI 필드를 확인하니 최소한 TLS 프로토콜을 사용하고 있다는 것은 알 수 있을 것이다.)

게이트웨이 워크로드 주입

마지막으로 해볼 실습은 게이트웨이 주입이다.

  components:
    ingressGateways:
    - name: istio-ingressgateway
      enabled: true
    - name: my-user-gateway
      namespace: istioinaction
      enabled: true
      label:
        istio: my-user-gateway

게이트웨이 워크로드는 이스티오 관리 양식 파일에서 쉽게 세팅해서 적용할 수 있다.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-user-gateway-injected
spec:
  selector:
    matchLabels:
      ingress: my-user-gateway-injected
  template:
    metadata:
      annotations:
        sidecar.istio.io/inject: "true"
        inject.istio.io/templates: gateway
      labels:
        ingress: my-user-gateway-injected
    spec:
      containers:
        - name: istio-proxy
          image: auto

그런데 이런 식으로 어노테이션만 달아주면, 직접 해당 워크로드를 만드는 것도 가능하다.
주의점이 몇 가지 있다.
일단 어노테이션으로 inject.istio.io/templates: gateway라는 식으로 주입될 프록시가 게이트웨이 임을 명시해야한다.
컨테이너 이름과 이미지는 위와 같이 고정해야 한다.
이미지를 아무거나 세팅해도 되는 줄 알고 바꿔봤는데 제대로 동작하지 않았다.
Mutating Admission Webhook에서 이미지 이름까지 체크하며 프록시를 주입하는 것으로 보인다.
image.png
해당 워크로드를 사용하는 게이트웨이 리소스를 만들고 난 후 상태를 보면 위에서 봤던 게이트웨이 워크로드와 똑같이 동작하는 것을 확인할 수 있다.

게이트웨이 최적화

image.png
위에서도 봤지만, 각 프록시에서 추적하는 클러스터가 뭐가 있는지 확인해보면 이렇게 서비스 레지스트리에 등록된 모든 서비스들이 보인다.
지금 간단하게 실습하는데도 이렇게 많은 서비스들이 보이는데, 실제 운용환경에서도 이렇게 모든 서비스가 추적된다면 프록시는 상당한 메모리 리소스를 소모하게 되며 비효율적으로 자원을 날려먹게 된다.
일반 프록시들의 경우 Sidecar라는 리소스를 이용해 서비스 레지스트리에 등록된 모든 클러스터를 가져오지 않고 필요한 서비스만 테이블에 업데이트되도록 세팅할 수 있다고 한다.
(이후 주차에서 보게 될 것 같아서 더 파보진 않았다.)

그러나 게이트웨이 리소스의 경우 Sidecar 리소스를 이용해 관리할 수 없다.

  components:
    pilot:
      k8s:
        env:
          - name: PILOT_FILTER_GATEWAY_CLUSTER_CONFIG
            value: "true"

그렇기 때문에 사용할 수 있는 방법이 바로 이스티오 컨트롤 플레인 설정이다.
이스티오 관리 양식에서 파일럿에 게이트웨이의 클러스터 설정을 적절하게 필터링하도록 환경변수를 세팅하면 게이트웨이에서 추적할 필요 없는 클러스터에 대해 게이트웨이가 추적하는 것을 막을 수 있다.
image.png
위 설정을 넣고 업데이트하자 곧바로 게이트웨이의 클러스터가 상당히 줄어든 것을 확인할 수 있다.
위 게이트웨이가 트래픽을 보내야 할 서비스만 명확하게 추적되고 있다!
환경 변수 설정 정보는 여기에서 찾아볼 수 있다.[2]
image.png
참고로 이 pilot agent는 이전에 데이터플레인에 주입된 사이드카 컨테이너의 기본 프로세스이기도 하다.

스터디

이스티오 데이터플레인

엔보이는 고급 로드밸런싱
쿠버는 기본 랜덤이 사실 아니다.
least request 기반.
아무튼 다양한 것을 제공

메트릭
cx는 connection 약자
근데 트레이싱 관련 헤더는 어플에서 제공은 해야 한다.

지금 이스티오는 b3가 기반이 아니다?
오텔 기반일 가능성. - 이거 제대로 확인 모했는데 이번에 다시 봐야겠다.

엔보이 확장.
프로토콜에서 필터 바이트 처리 엔진.

static_resources:
  listeners: # (1) 리스너 정의
  - name: httpbin-demo
    address:
      socket_address: { address: 0.0.0.0, port_value: 15001 }
    filter_chains:
    - filters:
      - name:  envoy.filters.network.http_connection_manager # (2) HTTP 필터
        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: # (3) 라우팅 규칙
            name: httpbin_local_route
            virtual_hosts:
            - name: httpbin_local_service
              domains: ["*"] # (4) 와일드카드 가상 호스트
              routes:
              - match: { prefix: "/" }
                route:
                  auto_host_rewrite: true
                  cluster: httpbin_service # (5) 클러스터로 라우팅
  clusters:
    - name: httpbin_service # (6) 업스트림 클러스터
      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

grpc 기반. - 이게 무슨 말일까?
hcm이 필터
15001으로 오면 받는다고 설정됨.

동적 설정을 할 때는 XDS api https://www.anyflow.net/sw-engineer/istio-internals-by-xds

이스티오에서의 거의 모든 세팅은 ads로 이뤄짐.

dynamic_resources:
  lds_config: # Configuration for listeners (LDS) 리스너용 설정
    api_config_source:
      api_type: GRPC
      grpc_services:
        - envoy_grpc: # Go to this cluster for the listener API. 이 클러스터로 이동해 리스너 API를 확인하자
            cluster_name: xds_cluster

clusters: 
- name: xds_cluster # gRPC cluster that implements LDS. LDS를 구현하는 gRPC 클러스터
  connect_timeout: 0.25s
  type: STATIC
  lb_policy: ROUND_ROBIN
  http2_protocol_options: {}
  hosts: [{ socket_address: {
    address: 127.0.0.3, port_value: 5678 }}]

설정할 때는 이걸 전달한다.

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: {}

이스티오에서 부트스트랩하는 설정.
이건 pilot에 들어가있다고 함.

docker pull envoyproxy/envoy:v1.19.0
docker pull curlimages/curl
docker pull mccutchen/go-httpbin

httpbin은 그나마 최근거로 함.

docker run -d -e PORT=8000 --name httpbin mccutchen/go-httpbin 
docker ps

docker run -it --rm --link httpbin curlimages/curl curl -X GET http://httpbin:8000/headers


docker run -it --rm envoyproxy/envoy:v1.19.0 envoy --help

image.png
설정 파일을 간단하게 확인할 수 있다.

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

docker run --rm --name proxy -p 15000:15000 --link httpbin envoyproxy/envoy:v1.19.0 --config-yaml "$(cat envoy-simple.yaml)"
docker run -it --rm --link proxy curlimages/curl curl -X GET http://proxy:15001/headers

image.png
알아서 엔보이가 몇가지 헤더를 추가해줬다.
X가 붙은 헤더들은 엔보이가 추가한 것이다.

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: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

동적 설정을 하는 방식.
어드민 페이지에 로깅 관련 설정을 넣는다.

아래 delay는 httbin쪽 에늗포인트이다.

image.png
어드민 api 페이지.
참고로 여기 있는 건 다 엔드포인트로도 노출이 돼있다.
그래서 api로 동적 설정이 가능한 것.

이전 주차에서 우리는 재시도 로직을 이스티오 리소스로 설정햇다.

              - match: { prefix: "/" }
                route:
                  auto_host_rewrite: true
                  cluster: httpbin_service
                  retry_policy:
                      retry_on: 5xx  # 5xx 일때 재시도
                      num_retries: 3 # 재시도 횟수

근데 실제로는 엔보이에 이런 설정 파일을 주입하는 방식으로 동작하는 것이다.
나는 안 끄고 전부 동적으로 설정해보겠다.

여기까지가 엔보이 기초 실습
엔보이는 퀵스타트 문서 보고 하면매우 좋다.
좀더 발전한 실습이 sandbox에 있다.
도전과제 3번, 솔로 아카데미가 또 좋다.
https://academy.solo.io/learn/courses/7/get-started-with-envoy-proxy

근데, 결국 앱 설정 없이는 트레이스가 연결이 안되나봄?
엔보이가 응답 아직 전달 안한 걸로 체크는 안 해주나.
생가갷보니 이건 말이 안 되는 게, 어떤 요청 응답하기 이전에 발생한 모든 요청이 관련된다고 볼 수 없기 대문.

이제 이스티오에서 사용하는 방식

이스티오 게이트웨이

가상 호스팅

kubectl label namespace default istio-injection=enabled

이번에 proxy status 좀 제대로 파보자.
image.png

istioctl proxy-config secret deploy/istio-ingressgateway.istio-system

image.png
인증서 세팅이 나온다.

kubectl exec -n istio-system deploy/istio-ingressgateway -- ps aux

image.png
프로세스를 보면, 파일럿 에이전트가 먼저 실행된다.
이 에이전트가 실제로 주입되고, 이 놈이 엔보이를 실행시킨다.

유저가 조금 재밌게 생겼는데, istio proxy는 1337 uid를 가지고 있다.
이걸 기반으로 엔보이에 세팅 요청과 다른 요청을 구분짓게 된다.
iptables를 보면 조금 더 구체적으로 볼 수 있다.

게이트웨이 리소스 파악

apiVersion: networking.istio.io/v1
kind: Gateway
metadata:
  name: coolstore-gateway #(1) 게이트웨이 이름
spec:
  selector:
    istio: ingressgateway #(2) 어느 게이트웨이 구현체인가?
  servers:
  - port:
      number: 80          #(3) 노출할 포트 
      name: http
      protocol: HTTP
    hosts:
    - "webapp.istioinaction.io" #(4) 이 포트의 호스트
kubectl stern -n istio-system -l app=istio-gateway
istioctl ps

이제 rds 동기화가 됐다.

istioctl pc route deploy/istio-ingressgateway.istio-system

image.png
이렇게 라우팅 세팅 상태를 확인할 수 있다.
뒷단의 가상서비스를 세팅하지 않아 404로 표시되고 잇다.

virtual service 리소스 탐구
딥다이브는 3주차.

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: webapp-vs-from-gw     #1 VirtualService 이름
spec:
  hosts:
  - "webapp.istioinaction.io" #2 비교할 가상 호스트네임(또는 호스트네임들)
  gateways:
  - coolstore-gateway         #3 이 VirtualService 를 적용할 게이트웨이
  http:
  - route:
    - destination:            #4 이 트래픽의 목적 서비스
        host: webapp
        port:
          number: 80

image.png
이걸 만들면 이렇게 컨트롤 플레인에서 세팅이 보인다.
아래 인그레스 게이트웨이에 여러 세팅이 간 것을 볼 수 있다.
image.png
다시 라우팅 세팅 상태를 보면, 이제 뒷단에 트래픽을 라우팅할 리소스가 표시된다.

kubectl apply -f ch4/coolstore-vs.yaml

단순하게 localhost로 하면 안 됨.
호스트 헤더는 게이트웨이가 인식하는 호스트가 아니라 그렇다.

curl -s http://localhost:30000/api/catalog -H "Host: webapp.istioinaction.io"

전체 트래픽흐름 보기
보안 세팅하기

apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  name: coolstore-gateway
spec:
  selector:
    istio: ingressgateway
  servers:
  - port:
      number: 80  #1 HTTP 트래픽 허용
      name: http
      protocol: HTTP
    hosts:
    - "webapp.istioinaction.io"
  - port:
      number: 443 #2 HTTPS 트래픽 허용
      name: https 
      protocol: HTTPS
    tls:
      mode: SIMPLE #3 보안 연결
      credentialName: webapp-credential #4 TLS 인증서가 들어 있는 쿠버네티스 시크릿 이름
    hosts:
    - "webapp.istioinaction.io"

서버 원소하나에 tls 설정
이거 세팅하면 이스티오 에서도 확인된다.

막상 해도 ㄹㅇ ca 설정을 안해서 안 도리 거임.
cacert로 ca-chain 파일을 같이 넣자.
넣으면 인증은 되는데, locahost로 호출해서 실패.
그래서 아예 도메인을 바꿔서 보내야한다.

echo "127.0.0.1       webapp.istioinaction.io" | sudo tee -a /etc/hosts
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  name: coolstore-gateway
spec:
  selector:
    istio: ingressgateway
  servers:
  - port:
      number: 80
      name: http
      protocol: HTTP
    hosts:
    - "webapp.istioinaction.io"
    tls:
      httpsRedirect: true 
  - port:
      number: 443
      name: https
      protocol: HTTPS
    tls:
      mode: SIMPLE
      credentialName: webapp-credential
    hosts:
    - "webapp.istioinaction.io"

이제 야예 리다이렉트 시켜버린다.
image.png
게이트웨이 측에서 리다이렉트시킬 때, 원하는 포트로 가게 하는 방법은 없다.

apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: redirect-to-https
spec:
  hosts:
  - "example.com"
  gateways:
  - custom-gateway
  http:
  - match:
    - port: 80
    redirect:
      scheme: https
      port: 8443

요런 식으로 버서로 처리핤 ㅜ 있긴 한다.

apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  name: coolstore-gateway
spec:
  selector:
    istio: ingressgateway
  servers:
  - port:
      number: 443
      name: https-webapp
      protocol: HTTPS
    tls:
      mode: SIMPLE
      credentialName: webapp-credential
    hosts:
    - "webapp.istioinaction.io"
  - port:
      number: 443
      name: https-catalog
      protocol: HTTPS
    tls:
      mode: SIMPLE
      credentialName: catalog-credential
    hosts:
    - "catalog.istioinaction.io"

같은 포트여도 여러 가상호스트로 나눌 수 있다.

인증서에서 sni 를 통해 구분된다.
서버 이름 표시.
인증서 extension에 server name indecation 부분이 있다.
이걸로 실제 가상 호스트 도메인을 구분할 수 있다.
이스티오 설정에서도 이걸 반영해준다.

tcp 트래픽 처리도 가능.
근데 고급 기능은 사용할 수 없다.
재시도라던가 하는.
그래도 카프카나 몽고는 대응이 가능하다고 하다.

kubectl edit svc istio-ingressgateway -n istio-system
  - name: tcp-echo
    nodePort: 30006
    port: 31400
    protocol: TCP
    targetPort: 31400

tcp 전용 포트 추가하자.

apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  name: echo-tcp-gateway
spec:
  selector:
    istio: ingressgateway
  servers:
  - port:
      number: 31400
      name: tcp-echo
      protocol: TCP
    hosts:
    - "*"
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: tcp-echo-vs-from-gw
spec:
  hosts:
  - "*"
  gateways:
  - echo-tcp-gateway
  tcp:
  - match:
    - port: 31400
    route:
    - destination:
        host: tcp-echo-service
        port:
          number: 2701

tcp 처리를 위한 리소스 생성

telnet localhost 30006
ㅗ디!
ctrl + ] quit

카프카 처리는 오래 걸릴 것 같고, 몽고디비 실습?

마지막으로, sni 패스스루 방식
실제 tls 복호화는 백엔드에서 담당.
이때 호스트는 sni 값으로 판단.

인그레스 게이트웨이 여러 개 두기 가능
처음 설치할 때 같이 설정해주면 됨

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-user-gateway-injected
  namespace: istioinaction
spec:
  selector:
    matchLabels:
      ingress: my-user-gateway-injected
  template:
    metadata:
      annotations:
        sidecar.istio.io/inject: "true" #1 주입 활성화
        inject.istio.io/templates: gateway #2 gateweay 템플릿  
      labels:
        ingress: my-user-gateway-injected
    spec:
      containers:
      - name: istio-proxy #3 반드시 이 이름이어야 한다
        image: auto #4 미완성 이미지
...

게이트웨이 인젝션으로 인그레스를 만들 수도 있다.
이런 시긍로 게이트웨이ㅡㄹ 만드는 것도 가능하다.

로깅
기본 설정에서 파드 액세스 로깅은 비활성화.

kubectl get cm -n istio-system istio -o yaml
istioctl install --set meshConfig.accessLogFile=/dev/stdout

이걸로 표준 출력으로 나오게 만들자.

근데 이렇게 하기 보다는 telemetry api를 쓰는 게 낫다.
원하는 놈만 보이게

apiVersion: telemetry.istio.io/v1alpha1
kind: Telemetry
metadata:
  name: ingress-gateway
  namespace: istio-system
spec:
  selector:
    matchLabels:
      app: istio-ingressgateway #1 레이블과 일치하는 파드는 텔레메트리 설정을 가져온다
  accessLogging:
  - providers:
    - name: envoy #2 액세스 로그를 위한 프로바이더 설정
    disabled: false #3 disable 를 false 로 설정해 활성화한다

모든 프록시는 메시 내의 모든 서비스를 알고 있따.
이러면 점차 데이터 플레인 프록시 설정이 커진다.
그래서 sidecar 리소스를 두어 조금 줄일 수 있다.
service entry도.
참고로 이건 게이트웨이엔 적용 안 된다.

apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
metadata:
  name: control-plane
spec:
  profile: minimal
  components:
    pilot:
      k8s:
        env:
        - name: PILOT_FILTER_GATEWAY_CLUSTER_CONFIG
          value: "true"
  meshConfig:
    defaultConfig:
      proxyMetadata:
        ISTIO_META_DNS_CAPTURE: "true"
    enablePrometheusMerge: true

이렇게 설정하면 프록시에서 필요 이상 설정을 제거한다.

이거 관련 세팅은 토스 영상을 보느 ㄴ게 좋다.

관련 문서

이름 noteType created

참고


  1. https://www.envoyproxy.io/docs/envoy/v1.33.2/operations/admin#operations-admin-interface-config-dump-by-resource ↩︎

  2. https://istio.io/latest/docs/reference/commands/pilot-agent/#envvars ↩︎