[네떡스터디🔥kans] Service Mesh: Istio - sidecar
CloudNet@ 가시다님이 진행하는 쿠버네티스 네트워크 스터디 KANS 3기 내용을 정리한 글입니다.
Sidecar Proxy의 역할
Istio에서 사이드카 프록시는 서비스 간 트래픽을 관리하는 핵심 역할을 담당합니다. 각 서비스에 배포된 사이드카는 네트워크 트래픽을 가로채고, 이를 통해 트래픽 라우팅, 보안, 모니터링 기능을 제공합니다. Istio는 Envoy 프록시를 사용해 모든 서비스 간 트래픽을 제어하며, 이를 통해 암호화, 인증, 로깅 등을 통합 설정으로 쉽게 적용할 수 있습니다. 이런 통합 관리 덕분에 개발자는 네트워크 세부 사항을 신경 쓰지 않고 애플리케이션 코드에만 집중할 수 있습니다.
Sidecar 아키텍처
사이드카 아키텍처는 서비스 간 통신을 간편하게 만들어 줍니다. Istio의 제어 평면인 istiod의 pilot이 각 서비스 인스턴스에 설치된 Envoy 프록시에 트래픽 제어 룰을 삽입하여 네트워크 설정을 중앙에서 관리할 수 있습니다.
Sidecar 방식의 장점과 단점
가장 큰 장점은 한 서비스의 프록시가 장애를 일으켜도 다른 서비스에는 영향을 미치지 않는다는 점입니다. 반면, 모든 서비스에 별도의 프록시 컨테이너를 붙여야 하기 때문에 리소스 사용량이 증가하고, 업그레이드 시 각 파드를 재시작해야 한다는 단점이 있습니다.
테스트 준비하기
클러스터 준비하기
클러스터를 생성할 때 다음과 같은 kind 설정을 사용할 수 있습니다.
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
- role: worker
- role: worker
networking:
disableDefaultCNI: true
kubeProxyMode: "none"
podSubnet: "10.1.0.0/16"
serviceSubnet: "10.2.0.0/16"
클러스터를 생성합니다.
kind create cluster --name blue --config kind.yaml
lb설정을 하기 위해 CNI는 cilium을 사용하겠습니다. (설정 생략)
2024.10.13 - [K8S/cilium] - Kind에서 Cilium으로 외부 접근 LoadBalancer 설정하기
Kind에서 Cilium으로 외부 접근 LoadBalancer 설정하기
Cilium을 사용하는 경우, Orbstack과 함께 하면 LoadBalancer(LB)가 자동으로 생성되는 편리함이 있습니다. 별도의 설정이 필요 없다는 점이 좋긴 하지만, 여러 개의 LB를 생성해서 테스트할 때는 불편할
nuguni.tistory.com
샘플 파드 구성하기
# blue 파드 생성
kubectl create deployment blue -n default --image kodekloud/webapp-color:v3
kubectl set env deployment/blue -n default APP_COLOR=blue
kubectl expose deployment blue -n default --port 8080
# green 파드 생성
kubectl create deployment green -n default --image kodekloud/webapp-color:v3
kubectl set env deployment/green -n default APP_COLOR=green
kubectl expose deployment green -n default --port 8080
Sidecar 모드로 설치하기
Istio를 설치할 때 기본적으로 사이드카 프록시 모드가 활성화됩니다. 네임스페이스에 라벨을 붙이거나 파드에 라벨을 붙여 사이드카 프록시를 생성할 수 있습니다.
istioctl로 설치하기
- minimal 프로필을 사용하면 Istio의 핵심 컨트롤 플레인만 설치됩니다. 이 경우 Ingress Gateway는 포함되지 않습니다.
- default 프로필을 사용하면 Ingress Gateway와 함께 Istio가 설치됩니다.
# minimal 설치하기
istioctl install --set profile=minimal -y
# default 설치하기
istioctl install --set profile=default -y
default 버전으로 설치했습니다.
Helm차트로 설치하기
Helm을 이용한 설치는 복잡하므로 이후 별도의 글로 다루도록 하겠습니다.
Gateway + VirtualService 구성
2024.10.07 - [K8S/🔥 network study🔥] - [네떡스터디🔥kans] Istio Gateway API
최신 Istio 버전에서는 Gateway API가 표준이 될 가능성이 높지만, Istio에서 제공하는 모든 기능을 Gateway API를 담을 수 없기 때문에 아직까지는 기존 리소스를 사용하는 것이 더 안정적입니다. 테스트에서는 Gateway와 VirtualService를 이용해 URI 경로별로 트래픽을 라우팅해보겠습니다.
URI 경로로 구분해서 트래픽 보내기
다음과 같은 구성으로 생성해보겠습니다.
Gateway 설정하기
Gateway는 외부에서 Istio 메쉬로 들어오는 트래픽의 진입점을 정의합니다. selector를 통해 어떤 ingress gateway를 통해 트래픽을 보낼지 설정할 수 있습니다. 기본으로 구성한 ingress gateway에는 istio=ingressgateway 라벨이 붙어있기 때문에 다음과 같이 설정하였습니다. 또한 모든 도메인에 대해 트래픽을 수락하도록 host를 *로 설정하였습니다.
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: color-gateway
spec:
selector:
istio: ingressgateway
servers:
- port:
number: 80
name: http
protocol: HTTP
hosts:
- "*"
VirtualService 설정하기
VirtualService는 Gateway로 들어온 트래픽을 어떻게 처리할지 정의합니다. URI 경로에 따라 각기 다른 서비스로 라우팅할 수 있습니다. 그렇기 때문에 어떤 gateway로부터 온 트래픽에 이 라우팅을 처리할 것인지 설정해야합니다. 만약 gateway에 아무런 값도 설정하지 않은 경우에는 기본 설정인 mesh로 들어가게 됩니다.
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: color-vs
spec:
hosts:
- "*"
gateways:
- color-gateway
http:
- match:
- uri:
exact: /blue
rewrite:
uri: "/"
route:
- destination:
host: blue # 서비스 이름
port:
number: 8080 # 포트 이름
- match:
- uri:
exact: /green
rewrite:
uri: "/"
route:
- destination:
host: green # 서비스 이름
port:
number: 8080 # 포트 이름
Hubble로 확인해보기
Hubble을 사용하면 Istio의 트래픽 흐름을 실시간으로 모니터링할 수 있습니다. Ingress Gateway에서 blue와 green으로 라우팅되는 트래픽을 확인할 수 있으며, 로그에서 출발지 IP와 트래픽 흐름의 세부 사항도 확인할 수 있습니다.
Hubble 로그를 통해 트래픽의 출발지가 istio-ingressgateway의 파드 IP임을 알 수 있습니다. 이는 외부에서 들어온 트래픽이 Ingress Gateway를 통해 각 서비스로 라우팅되기 때문입니다. 트래픽의 출발지 IP뿐 아니라, 요청이 어떻게 들어왔는지에 대한 구체적인 정보도 볼 수 있습니다.
아래는 hubble에서 확인한 부분입니다.
특이사항
Istio-proxy 없이도 기본적인 라우팅은 정상적으로 작동합니다. 그러나, 파드 간 세부적인 네트워크 설정을 제어하려면 사이드카 프록시가 반드시 필요합니다.
Envoy 룰 확인해보기
파드에 Istio-proxy(Envoy)를 추가한 후, Envoy의 설정 정보를 확인할 수 있습니다. 이 설정 정보는 트래픽 라우팅과 네트워크 통신의 세부적인 룰을 담고 있습니다.
Envoy 설정 덤프 방법
파드 내부에서 아래 명령어를 실행하면, Envoy의 현재 설정 정보를 덤프할 수 있습니다.
curl localhost:15000/config_dump
또는 istioctl 명령어를 사용하여 더 편리하게 설정을 확인할 수 있습니다.
istioctl proxy-config bootstrap <파드명>.<네임스페이스> -o json
Envoy 설정의 주요 유형
이렇게 덤프된 설정을 보면, 총 6가지 주요 설정 유형을 확인할 수 있습니다.
BootstrapConfigDump
이 설정에는 Envoy가 처음 시작될 때 사용된 옵션이 포함됩니다. 예를 들어, 어떤 노드에서 실행 중인지, 어떤 컨트롤 플레인과 연결되어 있는지 등의 정보가 담겨 있습니다. 전체 설정을 확인하지 않고, Bootstrap 설정만 따로 확인할 수도 있습니다.
istioctl proxy-config bootstrap <파드명>.<네임스페이스>
덤프된 설정에서 노드의 메타데이터를 조회하는 방법
jq '.configs[] | select(."@type" == "type.googleapis.com/envoy.admin.v3.BootstrapConfigDump").bootstrap.node.metadata' dump.json
ListenerConfigDump
Listener는 외부에서 들어오는 네트워크 연결을 수신하고 처리하는 역할을 합니다. Listener 설정에는 IP 주소, 포트, 필터 등의 정보가 포함됩니다.
# 기본 정보
istioctl proxy-config listener <파드명>.<네임스페이스>
# 상세 정보 확인하기
istioctl proxy-config listener <파드명>.<네임스페이스> -o json
Listener에는 static_listeners(정적 설정)와 dynamic_listeners(동적 설정) 두 가지 타입이 있습니다. 예를 들어, static listener에는 15021 포트(헬스체크용)와 15090 포트(메트릭용)가 포함될 수 있습니다.
RouteConfigDump
이 설정은 Envoy의 라우팅 정보를 제공합니다. 들어온 요청이 어떤 클러스터로 전달될지 결정하는 규칙들이 포함되어 있습니다. 예를 들어, 클라이언트 요청의 Host 헤더에서 포트 번호를 무시하거나, 응답 본문 크기를 제한하는 등의 설정이 가능합니다.
각 라우팅 정보에 설정된 옵션들을 정리해보겠습니다.
- ignorePortInHostMatching: 이 설정이 true로 되어 있으면, 호스트 기반 라우팅 시 포트 번호를 무시합니다. 즉, 클라이언트 요청의 Host 헤더에 포트 번호가 포함되어 있더라도, Envoy는 이를 무시하고 호스트 이름만으로 라우팅을 수행합니다.
- maxDirectResponseBodySizeBytes: Envoy가 직접 응답(direct response)을 보낼 때 응답 본문(Body)의 최대 크기를 바이트 단위로 설정합니다. 직접 응답은 Envoy가 상위 스트림으로 요청을 전달하지 않고 자체적으로 정적 응답을 클라이언트에게 반환할 때 사용됩니다.
- validateClusters: Envoy는 라우팅 설정에서 참조하는 클러스터가 유효한지 확인합니다. 즉, 클러스터가 존재하지 않거나 설정이 잘못된 경우 해당 라우트가 적용되지 않도록 설정할 수 있습니다.
- virtualHosts: 가상 호스트(Virtual Host) 설정을 정의하는 필드입니다. 가상 호스트는 여러 도메인 이름을 단일 서버에서 처리할 때 사용되며, 각 도메인별로 트래픽을 라우팅하는 규칙을 설정할 수 있습니다. 각 가상 호스트는 호스트 이름과 해당 라우팅 규칙을 포함합니다.
ClusterConfigDump
Cluster 설정은 Envoy가 연결된 클러스터와 관련된 정보를 제공합니다. 상위 스트림(Upstream)과의 연결 시 적용되는 옵션이나, 엔드포인트와의 연결 타임아웃을 확인할 수 있습니다.
xds-grpc와의 연결 타임아웃 확인
xds-grpc와의 연결 타임아웃을 확인하기 위해서는 다음 명령어를 사용할 수 있습니다.
istioctl proxy-config cluster green-664797fdbb-85mq2 -o json | jq '.[] | select(.name == "xds-grpc").connectTimeout'
이 명령어를 통해 xds-grpc 클러스터와의 연결에서 설정된 타임아웃 시간을 확인할 수 있습니다.
특정 프로토콜과 관련된 옵션 확인
추가적으로, 클러스터에 설정된 프로토콜과 관련된 옵션도 확인할 수 있습니다. 테스트 용도로 구성한 일반 서비스에 설정된 프로토콜을 확인해보겠습니다.
istioctl proxy-config cluster green-664797fdbb-85mq2 -o json | jq '.[] | select(.name =="outbound|8080||blue.default.svc.cluster.local").typedExtensionProtocolOptions'
blue.default.svc.cluster.local 서비스의 상위 스트림과 통신할 때 적용되는 프로토콜 옵션입니다.
useDownstreamProtocolConfig 옵션이 설정된 경우, 하위 스트림(Downstream)에서 사용하는 프로토콜과 동일한 프로토콜을 상위 스트림에서도 사용하게 됩니다. 즉, 하위 스트림이 HTTP/1.1을 사용하면 상위 스트림과의 통신도 HTTP/1.1로 이루어지고, 하위 스트림이 HTTP/2를 사용하면 상위 스트림도 HTTP/2로 통신합니다. 그리고 그 하위에 프로토콜 옵션이 세부적으로 설정되지 않았기 때문에, 기본값이 적용됩니다. 이는 특별한 설정 없이 기본적인 프로토콜 동작을 따르게 된다는 의미입니다.
예약된 클러스터 설정
Envoy에는 미리 설정된 3개의 예약된 클러스터가 있습니다.
- BlackHoleCluster: 트래픽을 차단하는 역할을 합니다. 목적지를 찾지 못하거나 허용되지 않은 트래픽은 이 클러스터로 보내져서 차단됩니다. 쉽게 말해, 메쉬에서 받아들일 수 없는 트래픽은 '블랙홀'로 보내서 없애게 됩니다.
- InboundPassthroughCluster: 외부에서 메쉬로 들어오는 트래픽을 필터링 없이 그대로 애플리케이션에 전달하는 클러스터입니다. 들어오는 트래픽에 대해서는 별도의 검사 없이 그냥 통과시키는 역할을 합니다.
- PassthroughCluster: 외부로 나가는 트래픽을 필터링하지 않고 애플리케이션에서 바로 전달하는 클러스터입니다. 메쉬 안의 서비스가 외부와 통신할 때, 따로 처리하지 않고 단순히 패킷을 전달합니다. 이 설정을 바꿔서 트래픽을 추적하려면, 해당 트래픽을 매시 안에 등록해야 하고, 이를 위해서는 ServiceEntry를 설정해야 합니다. 이렇게 하면 PassthroughCluster에서 나와 별도의 클러스터로 등록되게 됩니다.
EndpointConfigDump
Endpoint는 요청이 실제로 전달되는 서버나 서비스의 IP 주소와 포트를 나타냅니다. 이를 통해 해당 엔드포인트의 상태 정보를 확인할 수 있으며, Envoy가 엔드포인트와의 연결 중 수집한 통계 데이터를 확인할 수 있습니다.
상세한 정보를 보면, 서킷 브레이커와 관련된 설정이나 Envoy가 엔드포인트와의 연결을 처리하면서 수집한 통계 데이터를 볼 수 있습니다.
xds-grpc와의 연결 통계정보 확인해보기
istioctl proxy-config endpoint green-664797fdbb-85mq2 -o json | jq '.[] | select(.name == "xds-grpc").hostStatuses[0].stats'
각 통계 값은 다음과 같은 의미를 갖고 있습니다.
- cx_connect_fail: 연결 실패 횟수를 나타냅니다. Envoy가 클라이언트나 서버에 연결하려다 실패한 경우를 카운트합니다.
- cx_total: 총 연결 수를 나타냅니다. Envoy가 성공적으로 연결한 횟수입니다.
- rq_error: 요청 처리 중 발생한 오류 횟수입니다. 요청 처리 중 오류가 발생했을 때 카운트됩니다.
- rq_success: 성공적으로 처리된 요청 수입니다. Envoy가 정상적으로 요청을 처리한 경우를 나타냅니다.
- rq_timeout: 요청 처리 중 타임아웃이 발생한 횟수입니다. 요청에 대한 응답이 시간 내에 도착하지 않았을 때 카운트됩니다.
- rq_total: 총 요청 수입니다. Envoy가 처리한 전체 요청 수를 나타내며, 성공적 요청과 오류가 모두 포함될 수 있습니다.
- cx_active: 현재 활성화된 연결 수입니다. 현재 유지되고 있는 실시간 연결의 수를 나타냅니다.
- rq_active: 현재 활성화된 요청 수입니다. 실시간으로 처리 중인 요청의 수를 의미합니다.
SecretConfigDump
Envoy에서 사용하는 보안 정보(예: TLS 인증서, 키 등)에 대한 설정 정보를 내보냅니다. 이를 통해 Envoy가 보안 통신을 위해 사용하는 정보를 확인할 수 있습니다.
istioctl 명령어를 통해 인증서 정보를 확인하고 각각의 만료일도 확인해볼 수 있습니다.