[Istio] Troubleshooting

xgro·2025년 5월 16일
0

Istio

목록 보기
11/17
post-thumbnail

📌 Notice

Istio Hands-on Study (=Istio)
직접 실습을 통해 Isito를 배포 및 설정하는 내용을 정리한 블로그입니다.

CloudNet@에서 스터디를 진행하고 있습니다.

Gasida님께 다시한번 🙇 감사드립니다.

EKS 관련 이전 스터디 내용은 아래 링크를 통해 확인할 수 있습니다.



📌 Overview

이번 포스팅에서는 Istio의 데이터 플레인과 컨트롤 플레인에서 발생하는 문제를 효과적으로 식별하고 해결하는 방법을 다룹니다.

특히 istioctl, Kiali, Grafana, Prometheus 등 다양한 도구들을 활용해 잘못된 설정을 탐지하고, Envoy 프록시 및 Istio 에이전트, 파일럿(Pilot) 내부 구조와 상태를 면밀히 조사하는 과정을 실습 중심으로 정리했습니다.

  • 10장에서는 데이터 플레인에서 발생할 수 있는 설정 오류, 네트워크 병목, 지연 현상 등을 진단하는 기법을 소개하며,
  • 부록 D장에서는 Istio 내부 컴포넌트(Pilot, Sidecar 등)의 디버그 엔드포인트 및 로깅, 메트릭, 상태 확인 기능을 직접 활용해 내부 동작을 심층적으로 이해할 수 있도록 돕습니다.

이러한 내용을 통해 Istio 기반의 서비스 메시 운영자는 블랙박스로 느껴질 수 있는 트래픽 흐름과 설정 동기화 과정을 시각화하고, 필요한 정보를 기반으로 빠르게 원인을 파악할 수 있는 기반 역량을 갖출 수 있습니다.



📌 데이터 플레인 트러블슈팅하기

애플리케이션이 네트워크를 통해 통신할 때는 다양한 문제가 발생할 수 있습니다.

Istio가 존재하는 주요 이유 중 하나는 이러한 네트워크 문제를 자동으로 복원하거나 대응할 수 있도록 지원하는 데 있습니다. Istio는 타임아웃, 재시도, 서킷 브레이커 등 복원 기능을 제공하며, 네트워크 상의 문제를 빠르게 조명하고 대처할 수 있는 기반을 마련합니다.

하지만 Istio의 핵심 구성 요소인 서비스 프록시(Envoy) 자체가 예상과 다르게 동작할 경우에는 문제 해결이 쉽지 않을 수 있습니다.

이 장에서는 이러한 상황에서 활용할 수 있는 다양한 도구와 방법을 다루며, 다음과 같은 질문에 대한 실마리를 제공합니다:

  • 잘못된 워크로드 설정은 어떻게 파악할 수 있을까?
  • istioctlKiali를 통해 설정 오류를 미리 감지하거나 방지할 수 있을까?
  • Envoy 프록시의 동작은 어떤 설정에 의해 결정되는가?
  • 프록시 로그를 해석하여 무엇을 알 수 있을까?
  • Istio 텔레메트리를 통해 애플리케이션의 상태를 어떻게 관찰할 수 있을까?

라우팅 요청에 참여하는 주요 구성 요소

요청이 네트워크를 통해 전달될 때 다음과 같은 구성 요소들이 함께 작동합니다:

  • istiod: 제어 플레인 컴포넌트로, 데이터 플레인이 원하는 상태(desired state)를 유지하도록 보장합니다.
  • 인그레스 게이트웨이: 외부 트래픽을 클러스터로 유입시키는 진입 지점입니다.
  • 서비스 프록시(Envoy): 접근 제어를 수행하고, 클러스터 내부에서 트래픽을 애플리케이션으로 전달합니다.
  • 애플리케이션: 실제 비즈니스 로직을 수행하며, 필요한 경우 다른 서비스로 요청을 전달합니다.

이 체인 중 어느 하나라도 문제가 발생하면, 전체 서비스의 동작에 영향을 줄 수 있습니다.
특히 클러스터나 시스템 전체에 영향을 주는 문제가 발생했을 경우, 모든 구성 요소를 일일이 디버깅할 여유는 없습니다.

따라서 이번 장에서는 프록시의 설정과 상태를 빠르게 조사하고 진단하는 도구들에 집중합니다. 이를 통해 예상치 못한 동작의 원인을 찾아내고, 시스템을 정상 상태로 되돌리는 과정에 집중할 예정입니다.



👉 Step 01. 가장 흔한 실수: 잘못 설정한 데이터 플레인

Istio를 사용하는 사용자들이 가장 자주 겪는 실수 중 하나는 데이터 플레인의 잘못된 설정입니다. 특히 VirtualService나 DestinationRule 같은 리소스를 구성할 때 설정 누락이 발생하기 쉽고, 이로 인해 트래픽 전달이 실패할 수 있습니다.

✅ Istio의 설정 흐름 이해하기

Istio는 사람이 읽을 수 있는 형태의 리소스(CRD)들을 사용합니다.

예를 들어:

  • VirtualService, DestinationRule 같은 CRD(Custom Resource Definition)를 정의
  • 이 리소스들은 Envoy의 설정으로 변환되어 데이터 플레인에 적용됨

하지만, 리소스를 적용한 후 트래픽이 정상적으로 동작하지 않는 경우, 대부분은 설정이 잘못되었기 때문입니다.

✅ 실습 예제 시나리오

다음 예제는 부분집합(subset) 설정이 누락된 상황에서 트래픽이 실패하는 사례를 통해 트러블슈팅 방법을 소개합니다.

  1. catalog 애플리케이션의 v1과 v2 버전 배포
  2. Gateway를 통해 catalog.istioinaction.io 호스트로 트래픽을 받음
  3. VirtualService를 통해 20%는 version-v1, 80%는 version-v2로 라우팅
# 샘플 애플리케이션 배포
kubectl apply -f services/catalog/kubernetes/catalog.yaml -n istioinaction # catalog v1
kubectl apply -f ch10/catalog-deployment-v2.yaml -n istioinaction # catalog v2
kubectl apply -f ch10/catalog-gateway.yaml -n istioinaction # Gateway
kubectl apply -f ch10/catalog-virtualservice-subsets-v1-v2.yaml -n istioinaction # VirtualService

# 리소스 확인
kubectl get deploy,svc -n istioinaction
kubectl get gw,vs -n istioinaction 

💡 문제 발생 지점

VirtualServicesubset: version-v1과 version-v2로 트래픽을 라우팅하지만, DestinationRule 리소스가 존재하지 않으면 해당 subset은 클러스터에 존재하지 않게 됩니다.

그 결과:

  • Envoy는 subset에 대응되는 Upstream Cluster를 찾지 못하고
  • 모든 요청이 실패하며 503 Service Unavailable을 반환

✅ 오류 로그 확인

Envoy에서는 해당 오류를 NC (No Cluster) 플래그로 기록합니다:

kubectl logs -n istio-system -l app=istio-ingressgateway -f

# 예시로그
[2025-05-09T01:54:51.145Z] "GET /items HTTP/1.1" 503 NC cluster_not_found - "-" 0 0 0 - "172.18.0.1" "curl/8.7.1" "90a7d941-cbc4-91ae-9da1-bc95695d5c50" "catalog.istioinaction.io:30000" "-" - - 10.10.0.7:8080 172.18.0.1:64130 - -

# 반복 호출 시도
for i in {1..100}; do curl http://catalog.istioinaction.io:30000/items -w "\nStatus Code %{http_code}\n"; sleep .5;  done
Status Code 503


👉 Step 02. 데이터 플레인 문제 식별하기

Istio 운영 중 발생하는 문제의 대부분은 데이터 플레인에서 발생합니다. 그로 인해 많은 운영자들이 곧바로 Envoy 로그를 들여다보거나 서비스 프록시 설정을 점검하는 등의 디버깅을 시작하곤 합니다. 그러나 이 장에서는 먼저 컨트롤 플레인 문제를 배제하는 것이 얼마나 중요한지를 강조합니다.

문제 해결의 올바른 출발점

Istio에서 컨트롤 플레인의 주요 역할은 다음과 같습니다:

  • 데이터 플레인(서비스 프록시 등)에 최신 구성(desired state)을 전파하고 동기화하는 것

따라서 데이터 플레인에서 발생하는 문제를 정확히 진단하기 위해서는, 컨트롤 플레인과 데이터 플레인이 제대로 동기화되었는지를 먼저 확인해야 합니다.

흔한 실수

문제가 발생했을 때 곧바로 Envoy 로그나 애플리케이션 설정만 들여다보는 접근은, 문제의 근본 원인이 컨트롤 플레인의 동기화 실패일 경우 잘못된 방향으로 디버깅을 유도할 수 있습니다.

✅ 데이터 플레인이 최신 상태인지 확인하는 방법

Istio에서 데이터 플레인 설정은 설계상 결국 일관성(eventual consistency)을 가지도록 되어 있습니다.

다시 말해, 서비스나 설정이 변경되더라도, 그것이 즉시 데이터 플레인에 반영되는 것은 아니며, 컨트롤 플레인과의 동기화 과정을 거쳐야 합니다.

예를 들어, 컨트롤 플레인은 서비스의 각 파드 IP 주소와 같은 엔드포인트 정보를 데이터 플레인으로 전달합니다.

이 중 하나가 비정상 상태가 되면 다음과 같은 흐름이 발생합니다:

  1. kubelet이 주기적으로 파드 상태를 확인
  2. Kubernetes API 서버가 상태 확인 실패를 감지
  3. API 서버가 이를 이해당사자에게 알림
  4. istiod가 설정을 갱신하고 비정상 엔드포인트를 제거
  5. 트래픽은 더 이상 비정상 인스턴스로 전달되지 않음

👉🏻 대규모 클러스터에서는 이 과정이 느려질 수 있으며, 이에 대한 성능 개선은 Chapter 11에서 다룰 예정입니다.


🔍 istioctl proxy-status로 동기화 상태 확인하기

컨트롤 플레인과 데이터 플레인이 제대로 동기화되었는지를 확인하려면 다음 명령어를 사용할 수 있습니다:

docker exec -it myk8s-control-plane istioctl proxy-status

출력 예시:

NAME                                               CLUSTER        CDS     LDS     EDS     RDS       ECDS        ISTIOD                  VERSION
catalog-6cf4b97d-l44zk.istioinaction               Kubernetes     SYNCED  SYNCED  SYNCED  SYNCED    NOT SENT    istiod-8d74787f-ltkhs   1.17.8
catalog-v2-56c97f6db-d74kv.istioinaction           Kubernetes     SYNCED  SYNCED  SYNCED  SYNCED    NOT SENT    istiod-8d74787f-ltkhs   1.17.8
catalog-v2-56c97f6db-m6pvj.istioinaction           Kubernetes     SYNCED  SYNCED  SYNCED  SYNCED    NOT SENT    istiod-8d74787f-ltkhs   1.17.8
istio-egressgateway-85df6b84b7-2f4th.istio-system  Kubernetes     SYNCED  SYNCED  SYNCED  NOT SENT  NOT SENT    istiod-8d74787f-ltkhs   1.17.8
istio-ingressgateway-6bb8fb6549-hcdnc.istio-system Kubernetes     SYNCED  SYNCED  SYNCED  SYNCED    NOT SENT    istiod-8d74787f-ltkhs   1.17.8

각 컬럼의 의미:

  • SYNCED: Envoy가 istiod로부터 보낸 최신 설정을 수신했음을 의미
  • NOT SENT: istiod가 해당 컴포넌트에 설정을 보낼 필요가 없어 아무것도 보내지 않았음을 의미
  • STALE: istiod가 설정을 보냈지만 Envoy가 이를 확인하지 못한 상태
    (원인: istiod 과부하, 연결 문제, 혹은 Istio 버그)

위 출력 결과에 따르면, 모든 컴포넌트가 SYNCED 상태이며 설정 누락이나 동기화 지연이 없음을 알 수 있습니다.

따라서 컨트롤 플레인의 문제 가능성은 낮고, 다음 단계로 데이터 플레인 구성 요소, 특히 워크로드 설정을 집중적으로 조사해야 합니다.

이 과정에서 Kiali는 유용한 시각화 도구로, 잘못된 설정을 빠르게 검증할 수 있습니다.


✅ 키알리로 잘못된 설정 발견하기

Istio 설정이 예상대로 작동하지 않는다면, 가장 먼저 확인할 수 있는 도구 중 하나가 Kiali입니다.

Kiali는 시각적인 대시보드와 함께 리소스 유효성 검사(validation) 기능을 제공하여, 잘못된 설정을 빠르게 식별할 수 있도록 도와줍니다.


🔍 경고 메시지 확인 흐름

  1. Kiali 대시보드에서 Overview 탭을 확인합니다.
  2. istioinaction 네임스페이스에 경고 아이콘이 표시되어 있음을 확인합니다.
  3. 해당 네임스페이스를 클릭하면 Istio Config 탭으로 이동합니다.
  4. 다시 클릭하면, 내장 편집기를 통해 경고 메시지를 직접 확인할 수 있습니다.


⚠️ 예시 경고: KIA1107 - Subset not found

경고 아이콘 위에 마우스를 올리면, "KIA1107 - Subset not found" 와 같은 메시지가 나타납니다.

이 오류는 VirtualService에서 참조한 subset이 DestinationRule에 정의되어 있지 않을 때 발생합니다.

원인:

  • 오타 또는 존재하지 않는 subset 참조
  • DestinationRule 내 subset 정의 누락

🔗 공식 문서 참고: Kiali Validation Docs - KIA1107


✅ istioctl로 잘못된 설정 발견하기

Istio 설정에서 문제가 발생했을 때, istioctl가장 강력한 CLI 기반 진단 도구입니다.

특히 다음 두 명령어는 잘못된 워크로드 설정을 자동으로 분석하는 데 매우 유용합니다:

  • istioctl analyze
  • istioctl describe (또는 x des 단축어)

🔍 istioctl analyze: 설정 전체를 진단하기

istioctl analyze 명령어는 현재 클러스터 상태나 적용 전 설정 파일을 검사하여 잠재적인 문제를 사전에 발견합니다.

# 도움말 및 분석기 목록 보기
docker exec -it myk8s-control-plane istioctl analyze -h
docker exec -it myk8s-control-plane istioctl analyze --list-analyzers

# 네임스페이스 단위로 실행
docker exec -it myk8s-control-plane istioctl analyze -n istioinaction

# 출력 예시:
Error [IST0101] (VirtualService istioinaction/catalog-v1-v2) Referenced host+subset in destinationrule not found: "catalog.istioinaction.svc.cluster.local+version-v1"
Error [IST0101] (VirtualService istioinaction/catalog-v1-v2) Referenced host+subset in destinationrule not found: "catalog.istioinaction.svc.cluster.local+version-v2"
Error: Analyzers found issues when analyzing namespace: istioinaction.

IST0101 오류는 DestinationRule에 정의되지 않은 subset을 VirtualService가 참조할 때 발생합니다.


🔎 istioctl describe: 워크로드 단위 설정 분석

특정 워크로드(Pod) 기준으로 어떤 Istio 설정이 적용되었는지 요약하여 보여줍니다.

  • 이 파드는 서비스 메시의 일부인가?
  • 어떤 VirtualService, DestinationRule이 적용되는가?
  • mTLS 모드는 어떻게 설정되었는가?
# 대상 파드 이름 조회
CATALOG_POD1=$(kubectl get pod -n istioinaction -l app=catalog -o jsonpath='{.items[0].metadata.name}')

# describe 실행
docker exec -it myk8s-control-plane istioctl x des pod -n istioinaction $CATALOG_POD1

# 출력 예시 (문제 발생 시):
VirtualService: catalog-v1-v2
  WARNING: No destinations match pod subsets (checked 1 HTTP routes)
  Warning: Route to subset version-v1 but NO DESTINATION RULE defining subsets!
  Warning: Route to subset version-v2 but NO DESTINATION RULE defining subsets!


🛠️ 문제 해결 후 재확인

# DestinationRule 정의 추가
kubectl apply -f ch10/catalog-destinationrule-v1-v2.yaml

# 다시 describe 실행
docker exec -it myk8s-control-plane istioctl x des pod -n istioinaction $CATALOG_POD1

# 출력 예시 (해결 후):
DestinationRule: catalog for "catalog.istioinaction.svc.cluster.local"
  Matching subsets: version-v1
  (Non-matching subsets version-v2)

Istio 설정의 문제를 식별하고 해결책을 제시하는 데 충분하며, 대부분의 일반적인 오류를 빠르게 파악할 수 있습니다.



👉 Step 03. 엔보이 설정에서 수동으로 잘못된 설정 발견하기

앞에서 소개한 istioctl analyze, describe, Kiali 대시보드 등을 사용했음에도 불구하고 여전히 문제가 해결되지 않는다면, 이제는 엔보이 설정 전체를 수동으로 조사해야 할 시점입니다.

이러한 저수준 진단은 다소 번거롭지만, Istio 내부의 구성이나 프록시 설정이 예상대로 반영되지 않았을 때 매우 유용합니다.

✅ 엔보이 관리(admin) 인터페이스

Envoy는 각 서비스 프록시마다 관리 인터페이스(admin interface)를 노출하며, 이를 통해 설정을 직접 확인하거나 디버깅용 설정을 수정할 수 있습니다.

기본 포트: 15000
접근 방법: kubectl port-forward로 포트 포워딩 후 웹 브라우저 또는 curl로 확인 가능

# catalog 파드에서 Envoy admin 포트 열기
kubectl port-forward deploy/catalog -n istioinaction 15000:15000

# 브라우저로 확인
open http://localhost:15000

# 엔보이 전체 설정 덤프 (매우 방대한 출력)
curl -s localhost:15000/config_dump | wc -l
# 출력 예시:
13952

⚠️ 출력이 지나치게 방대함

  • config_dump 명령어로 출력되는 JSON은 수천 줄에 달하며, 사람의 눈으로 일일이 분석하기엔 어려움이 큽니다.
  • 따라서 이 설정은 전체 구조를 이해하기 위한 참고용이며, 특정 설정(예: 클러스터, 리스너, 라우트 등)을 골라서 보는 것이 일반적입니다.

✅ istioctl로 프록시 설정 쿼리하기

istioctl proxy-config 명령어는 Envoy 프록시가 보유한 설정을 xDS API 기반으로 쿼리할 수 있도록 해줍니다.

방대한 설정 덤프(config_dump) 대신, 클러스터, 엔드포인트, 리스너, 라우트, 시크릿 설정 등을 개별적으로 확인할 수 있습니다.


🔍 주요 하위 명령어

명령어설명
cluster클러스터 설정 확인
endpoint엔드포인트 설정 확인
listener리스너 설정 확인
route라우트 설정 확인
secretTLS 등 비밀 설정 확인

🔁 요청을 라우팅하기 위한 Envoy API의 상호작용

  • 리스너 (Listener): 다운스트림 트래픽을 수신하는 IP/포트를 정의
  • 필터 체인: 리스너에 연결된 필터 목록. 핵심은 라우터 필터
  • 루트 (Route): 가상 호스트 → 클러스터 간 매핑 규칙
  • 클러스터 (Cluster): 유사 워크로드 엔드포인트 그룹
  • 엔드포인트 (Endpoint): 요청을 실제 처리할 워크로드의 IP

📥 리스너 설정 확인

docker exec -it myk8s-control-plane istioctl proxy-config listener deploy/istio-ingressgateway -n istio-system

# 출력 예시:
ADDRESS     PORT   MATCH   DESTINATION
0.0.0.0     8080   ALL     Route: http.8080
0.0.0.0     15021  ALL     Inline Route: /healthz/ready
0.0.0.0     15090  ALL     Inline Route: /stats/prometheus

  • 리스너는 8080 포트에 설정되어 있음
  • NodePort 30000 → Service의 targetPort 8080 → IngressGateway의 8080 리스너로 도달
kubectl get svc -n istio-system istio-ingressgateway -o yaml | grep "ports:" -A10


📤 라우트 설정 확인

docker exec -it myk8s-control-plane istioctl proxy-config routes deploy/istio-ingressgateway -n istio-system --name http.8080

# 출력 예시:
NAME        DOMAINS                      MATCH     VIRTUAL SERVICE
http.8080   catalog.istioinaction.io     /         catalog-v1-v2.istioinaction

# 상세 JSON 출력:
docker exec -it myk8s-control-plane istioctl proxy-config routes deploy/istio-ingressgateway -n istio-system --name http.8080 -o json

→ outbound|80|version-v1|catalog..., version-v2로 라우팅 설정이 되어 있음을 확인


🧩 클러스터 설정 확인

docker exec -it myk8s-control-plane istioctl proxy-config clusters deploy/istio-ingressgateway -n istio-system \
--fqdn catalog.istioinaction.svc.cluster.local --port 80

→ subset이 정의되지 않은 상태에서는 version-v1, v2 클러스터가 존재하지 않음

# 해결을 위해 DestinationRule 정의 필요:
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: catalog
  namespace: istioinaction
spec:
  host: catalog.istioinaction.svc.cluster.local
  subsets:
  - name: version-v1
    labels:
      version: v1
  - name: version-v2
    labels:
      version: v2

# 적용 전 검증
docker exec -it myk8s-control-plane istioctl analyze /istiobook/ch10/catalog-destinationrule-v1-v2.yaml -n istioinaction
✔ No validation issues found

# 적용 후 재확인:
kubectl apply -f ch10/catalog-destinationrule-v1-v2.yaml

docker exec -it myk8s-control-plane istioctl proxy-config clusters deploy/istio-ingressgateway -n istio-system \
--fqdn catalog.istioinaction.svc.cluster.local --port 80

출력:
SUBSET        DESTINATION RULE
version-v1    catalog.istioinaction
version-v2    catalog.istioinaction


🔎 클러스터의 구성 방식

docker exec -it myk8s-control-plane istioctl proxy-config clusters deploy/istio-ingressgateway -n istio-system \
--fqdn catalog.istioinaction.svc.cluster.local --port 80 --subset version-v1 -o json

# 출력 예시
- "type": "EDS": Endpoint Discovery Service
- "ads": {}: Aggregated Discovery Service (ADS) 사용

📡 엔드포인트 설정 확인

docker exec -it myk8s-control-plane istioctl proxy-config endpoints deploy/istio-ingressgateway -n istio-system \
--cluster "outbound|80|version-v1|catalog.istioinaction.svc.cluster.local"

# 출력 예시:
ENDPOINT        STATUS   CLUSTER
10.10.0.12:3000 HEALTHY  outbound|80|version-v1|catalog...

→ IP가 실제 워크로드인지 확인:
kubectl get pod -n istioinaction --field-selector status.podIP=10.10.0.12 -owide --show-labels

proxy-config 명령어는 Envoy 설정의 특정 항목만 필터링해서 보기 좋게 보여줍니다.

listener → route → cluster → endpoint 순으로 요청이 라우팅되며, 이 체인을 수동으로 검증할 수 있습니다.

이 과정을 통해 설정 누락이나 mismatch 문제를 빠르게 확인하고 복구할 수 있습니다.


✅ 애플리케이션 문제 트러블슈팅하기

마이크로서비스 아키텍처에서는 서비스 프록시가 남기는 로그와 메트릭이 매우 유용한 트러블슈팅 도구가 됩니다.

예를 들어, 성능 병목, 비정상적인 엔드포인트, 반복되는 요청 실패 등의 문제를 Envoy 로그와 Istio 메트릭을 통해 분석할 수 있습니다.

이번 실습에서는 catalog 서비스 중 일부 인스턴스가 간헐적으로 응답 지연을 일으키도록 설정한 뒤, 이를 다양한 도구로 확인하고 원인을 추적해 봅니다.


⏱️ 간헐적으로 제한 시간을 초과하는 느린 워크로드 준비하기

  • catalog 서비스 v2 중 한 파드에 latency 장애를 주입합니다.
  • Istio VirtualService에 timeout(0.5초)을 설정하여 프록시가 타임아웃을 유발하도록 구성합니다.
# 정상 상태에서 통신 확인
for i in {1..9999}; do curl http://catalog.istioinaction.io:30000/items -w "\nStatus Code %{http_code}\n"; sleep 1; done

# Kiali와 Grafana로 성공률 및 p99 레이턴시 확인
# catalog v2 파드 중 하나에 지연 장애 주입
CATALOG_POD=$(kubectl get pods -l version=v2 -n istioinaction -o jsonpath={.items..metadata.name} | cut -d ' ' -f1)

kubectl -n istioinaction exec -c catalog $CATALOG_POD -- curl -s -X POST -H "Content-Type: application/json" \
-d '{"active": true, "type": "latency", "volatile": true}' localhost:3000/blowup

# Istio timeout 설정
kubectl patch vs catalog-v1-v2 -n istioinaction --type json \
-p '[{"op": "add", "path": "/spec/http/0/timeout", "value": "0.5s"}]'

# 결과 확인: HTTP 504 오류, Envoy 로그의 response_timeout, UT 응답 플래그


📄 엔보이 액세스 로그 이해하기

Envoy 기본 로그는 TEXT 형식이라 읽기 어려움 → JSON 형식으로 변경 추천

# ConfigMap 수정
KUBE_EDITOR="nano" kubectl edit -n istio-system cm istio

# 아래 항목 추가
accessLogEncoding: JSON

- 이후 로그를 jq로 확인하면 다음과 같이 해석 가능:
{
  "upstream_host": "10.10.0.13:3000",
  "duration": 501,
  "response_code": 504,
  "response_flags": "UT",
  ...
}504 응답이며 response_timeout 발생, 해당 IP를 가진 파드 조회하여 문제 파드 식별 가능
kubectl get pod -n istioinaction -o wide | grep 10.10.0.13


🔧 엔보이 게이트웨이의 로깅 수준 높이기

디버깅을 위해 istioctl proxy-config log 명령어로 로깅 범위와 수준을 조정할 수 있습니다.

각 범위에 로깅 수준을 서로 다르게 지정할 수 있는 덕분에 엔보이가 만들어내는 로그에 질식하지 않고 관심 영역의 로깅 수준만 정확하게 높일 수 있습니다.

  • connection : Logs related to layer 4 (transport); TCP connection details
  • http : Logs related to layer 7 (application); HTTP details
  • router: Logs related to the routing of HTTP requests
  • pool : Logs related to how a connection pool acquires or drops a connection’s upstream host
docker exec -it myk8s-control-plane istioctl proxy-config log deploy/istio-ingressgateway -n istio-system \
--level http:debug,router:debug,connection:debug,pool:debug

# 로그 파일 저장 및 분석
kubectl logs -n istio-system -l app=istio-ingressgateway -f > istio-igw-log.txt

이러한 Envoy의 상세 로그는 서비스 프록시가 어떻게 동작하는지를 깊이 있게 보여주며,
복잡한 마이크로서비스 환경에서의 트러블슈팅 능력을 크게 향상시켜 줍니다.



👉 Step 04. 엔보이 텔레메트리로 자신의 애플리케이션 이해하기

✅ 그라파나에서 실패한 요청 비율 찾기 Finding the rate of failing requests in Grafana

실패한 요청 비율을 그라파나를 통해서 찾아보겠습니다.

Grafana - Istio Service 대시보드 ⇒ Service(catalog.istioinaction..) , Reporter(source) 선택

🟠 클라이언트 성공률 확인

  • 클라이언트 성공률은 약 70% 수준으로, 요청 중 약 30%는 실패하고 있음을 보여줍니다.
  • 이러한 실패는 상태 코드 504 (Gateway Timeout)으로 나타나며, 클라이언트 측 실패율로 집계됩니다.

🟢 서버 성공률 확인

  • 서버 성공률은 100%로 나타납니다.
  • 이는 서버 측에서는 5xx 에러가 없으며, 문제가 없음을 의미합니다.
  • 이유는 Envoy 프록시가 다운스트림 연결이 끊긴 경우 응답 코드 0으로 처리하며, 이 응답은 서버 실패로 간주되지 않기 때문입니다.

🔁 클라이언트 ↔ 서버 응답 플래그 차이

  • Ingress Gateway: 응답 플래그 UT, 상태 코드 504 → 요청 제한 시간 초과
  • catalog v2: 응답 플래그 DC, 상태 코드 0 → 다운스트림 연결 종료 감지

이 차이로 인해 Grafana는 클라이언트에서는 실패율을 높게, 서버에서는 100% 성공으로 표시하게 됩니다.


✅ Prometheus를 사용해 영향받는 파드 쿼리하기

Grafana 대시보드는 전체 서비스 수준의 정보를 제공하지만, 문제가 발생한 특정 파드를 정확히 식별하기엔 한계가 있습니다.

이럴 때는 Prometheus를 직접 쿼리하여 파드 단위의 세부 메트릭을 확인하는 것이 효과적입니다.


🔎 목표: 응답 실패율이 높은 파드를 찾기

다음 조건을 만족하는 PromQL 쿼리를 통해 실패율이 높은 파드를 식별할 수 있습니다:

  • destination(서버) 측에서 보고한 요청만 필터링
  • catalog 서비스로 향하는 요청만 필터링
  • 응답 플래그가 DC(Downstream Connection termination)인 요청만 필터링
    → 서버는 응답하려 했지만, 클라이언트(프록시)가 먼저 연결을 끊은 경우

📋 PromQL 쿼리 예시

sort_desc(
  sum(
    irate(
      istio_requests_total{
        reporter="destination",
        destination_service=~"catalog.istioinaction.svc.cluster.local",
        response_flags="DC"
      }[5m]
    )
  ) by (response_code, pod, version)
)

이 쿼리는 다음을 의미합니다:

  • istio_requests_total: 요청 수를 수집하는 Istio 표준 메트릭
  • irate([...][5m]): 5분 동안 초당 증가율
  • sum(... by pod, version): 파드 및 버전별로 집계
  • sort_desc(...): 실패율이 높은 순으로 정렬


📊 결과 해석

위 결과는 단 하나의 catalog v2 파드만 DC 응답 플래그를 반복적으로 보고하고 있음을 보여줍니다.

이 특정 파드가 문제를 일으키는 인스턴스임을 정확히 확인할 수 있습니다.

📌 참고 사항

  • Istio의 기본 메트릭만으로는 파드 내부 상태까지 파악하기 어려울 수 있습니다.
  • 7장 7.4절에서 소개한 방식처럼 커스텀 메트릭을 추가하거나,
  • Prometheus 클라이언트 라이브러리를 애플리케이션에 직접 붙여 세밀한 지표를 수집할 수 있습니다.



🔥 Appendix. 이스티오 구성 요소 트러블 슈팅하기

Internal Architecture by Port : Istiod(컨트롤플레인) + Istio Proxy(데이터플레인) 도식화 - Blog

✅ 이스티오 에이전트가 노출하는 정보

이스티오 사이드카에 포함된 에이전트(pilot-agent)는 트래픽 프록시 역할 외에도 다양한 디버깅/모니터링 기능을 제공합니다.

이 절에서는 에이전트와 관련된 포트와 엔드포인트를 실습을 통해 탐색하고, 이들을 활용한 트러블슈팅 방법을 다룹니다.


🛠️ 실습 환경 초기화 및 구성

# 기존 리소스 삭제
kubectl delete -n istioinaction deploy,svc,gw,vs,dr,envoyfilter --all

# 샘플 애플리케이션 배포
kubectl apply -f services/catalog/kubernetes/catalog.yaml -n istioinaction
kubectl apply -f services/webapp/kubernetes/webapp.yaml -n istioinaction
kubectl apply -f services/webapp/istio/webapp-catalog-gw-vs.yaml -n istioinaction

# 정상 작동 확인
curl -s http://webapp.istioinaction.io:30000/api/catalog | jq

# 반복 호출
while true; do curl -s http://webapp.istioinaction.io:30000/api/catalog ; date "+%Y-%m-%d %H:%M:%S" ; sleep 1; echo; done

🔍 에이전트/프록시가 사용하는 포트 정보

이스티오 사이드카는 많은 기능을 제공합니다.

  • 헬스체크 Health checking
    • 프록시로서의 엔보이는 트래픽을 처리할 수 있는 즉시 준비 상태다.
    • 그러나 서비스 메시의 관점에서 보면 이 정도로는 충분하지 않다.
    • 프록시가 트래픽을 처리하기 전에 설정을 받았는지, ID를 할당받았는지 등의 더 많은 확인이 필요하다.
  • 메트릭 수집 및 노출 Metrics collection and exposure
    • 서비스 내에서 메트릭을 생성하는 세 가지 구성 요소는 애플리케이션, 에이전트, 엔보이 프록시다.
    • 에이전트는 다른 구성 요소의 메트릭을 집계해 노출한다.
# 포트 확인
kubectl -n istioinaction exec -it deploy/webapp -c istio-proxy -- netstat -tnl

# 포트별 프로세스 확인
kubectl -n istioinaction exec -it deploy/webapp -c istio-proxy -- ss -tnlp

# 주요 포트 및 역할:
포트	프로세스	설명
15000	envoy	Envoy 관리 인터페이스 (config dump 등)
15001	envoy	애플리케이션 → 외부로 나가는 트래픽
15006	envoy	외부 → 애플리케이션으로 들어오는 트래픽
15020	pilot-agent	메트릭, 헬스체크, 디버깅 등
15021	envoy	Kubernetes readinessProbe 포트
15004	pilot-agent	Istiod 디버깅 요청 라우팅
15090	envoy	Prometheus 메트릭 노출
15053	pilot-agent	로컬 DNS 프록시

🧩 주요 엔드포인트

🔹 15020 포트 (pilot-agent)

  • /healthz/ready: envoy 및 DNS 프록시 준비 상태 확인
  • /stats/prometheus: envoy + agent 메트릭 병합 출력
  • /quitquitquit: agent 프로세스 종료
  • /app-health/<app>/livez: 애플리케이션의 Liveness Probe 결과
  • /debug/ndsz: DNS 프록시 대상 호스트 이름 목록
  • /debug/pprof/: 성능/메모리 디버깅용 Go pprof
# 예시: /app-health/ 연동 실습
kubectl apply -f - <<EOF
apiVersion: apps/v1
kind: Deployment
metadata:
  name: liveness-http
  namespace: istioinaction
spec:
  selector:
    matchLabels:
      app: liveness-http
      version: v1
  template:
    metadata:
      labels:
        app: liveness-http
        version: v1
    spec:
      containers:
      - name: liveness-http
        image: docker.io/istio/health:example
        ports:
        - containerPort: 8001
        livenessProbe:
          httpGet:
            path: /foo
            port: 8001
          initialDelaySeconds: 5
          periodSeconds: 5
EOF

# 에이전트에서 쿠버네티스 liveness 프로브를 프록시로 라우팅
kubectl exec -n istioinaction deploy/liveness-http -c istio-proxy -- \
curl -s localhost:15020/app-health/liveness-http/livez -v


#
kubectl exec -n istioinaction deploy/webapp -c istio-proxy -- curl -s localhost:15020/healthz/ready -v

# webapp 워크로드의 병합된 통계 확인 : istio_agent로 시작하는 메트릭(에이전트에서 온 것) + envoy로 시작하는 메트릭(프록시에서 온 것)
kubectl exec -n istioinaction deploy/webapp -c istio-proxy -- curl -s localhost:15020/stats/prometheus
## 응답에서는 istio_agent로 시작하는 메트릭(에이전트에서 온 것)과 envoy로 시작하는 메트릭(프록시에서 온 것)을 볼 수 있는데,
## 이는 이 둘이 병합됐음을 보여준다.

#
kubectl exec -n istioinaction deploy/webapp -c istio-proxy -- curl -s localhost:15020/quitquitquit

#
kubectl exec -n istioinaction deploy/webapp -c istio-proxy -- curl -s localhost:15020/debug/ndsz

#
kubectl port-forward deploy/webapp -n istioinaction 15020:15020
open http://localhost:15020/debug/pprof # 혹은 웹 브라우저에서 열기


🧪 디버깅에 유용한 접근 예시

에이전트는 기본적으로 15004 포트에서 몇 가지 istiod 디버그 엔드포인트들을 노출하고 있습니다.

이 엔드포인트들에 한 요청은 xDS 이벤트 형태로 안전하게 istiod로 전달되는데, 이는 에이전트에서 컨트롤 플레인으로의 연결 상태를 확인 할 수 있는 좋은 방법입니다.

이를 보려면, 프록시 중 하나의 셸 커넥션을 가져와서 파일럿 에이전트의 15004 포트에 /debug/sync 엔드포인트로 요청합니다.

#
kubectl exec -n istioinaction deploy/webapp -c istio-proxy -- curl -s localhost:15004/debug/syncz -v
kubectl exec -n istioinaction deploy/webapp -c istio-proxy -- curl -s localhost:15004/debug/syncz | jq
...
      "@type": "type.googleapis.com/envoy.service.status.v3.ClientConfig",
      "node": {
        "id": "catalog-6cf4b97d-fbftr.istioinaction", # 워크로드 ID
        "metadata": {
          "CLUSTER_ID": "Kubernetes"
        }
      },
      "genericXdsConfigs": [
        {
          "typeUrl": "type.googleapis.com/envoy.config.listener.v3.Listener",
          "configStatus": "SYNCED" # xDS API는 최신 상태로 동기화됬다
        },
        {
          "typeUrl": "type.googleapis.com/envoy.config.route.v3.RouteConfiguration",
          "configStatus": "SYNCED" # xDS API는 최신 상태로 동기화됬다
        },
        {
          "typeUrl": "type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment",
          "configStatus": "SYNCED" # xDS API는 최신 상태로 동기화됬다
        },
        {
          "typeUrl": "type.googleapis.com/envoy.config.cluster.v3.Cluster",
          "configStatus": "SYNCED" # xDS API는 최신 상태로 동기화됬다
        },
...

# 하위 명령 출력 내용과 동일
docker exec -it myk8s-control-plane istioctl x internal-debug -h
docker exec -it myk8s-control-plane istioctl x internal-debug syncz

✅ 이스티오 파일럿이 노출하는 정보

이스티오의 컨트롤 플레인 구성요소인 파일럿(pilot) 은 전체 서비스 메시의 구성 상태를 관리하며,
이를 점검하고 디버깅하기 위한 다양한 정보를 외부에 노출합니다. 이 정보는 운영자뿐 아니라 외부 도구나 서비스에도 유용하게 활용될 수 있습니다.


🔍 파일럿이 노출하는 포트와 프로세스

# 포트 및 프로세스 확인
kubectl -n istio-system exec -it deploy/istiod -- netstat -tnl
kubectl -n istio-system exec -it deploy/istiod -- ss -tnlp

# Pod 내부 구성 확인
kubectl describe pod -n istio-system -l app=istiod

주요 포트 역할은 다음과 같습니다:

포트 기능 설명
15010 - xDS API 및 인증서를 평문(HTTP)으로 노출. 보안상 사용 지양
15012 - xDS API 및 인증서를 TLS로 보호. 상호 인증이 포함됨
15014 - 컨트롤 플레인 메트릭 노출
15017 - 쿠버네티스 API 서버와 연동되는 웹훅 서버. 사이드카 주입 및 Istio 리소스 검증
8080 - Istio 디버그 엔드포인트 (비보안, 민감 정보 주의)
9876 - 파일럿 내부 상태 확인용 ControlZ 관리자 인터페이스


이스티오 파일럿 디버그 엔드포인트

이스티오의 파일럿(Pilot)은 클러스터 내 전체 서비스 메시 설정을 관리하는 컨트롤 플레인 구성 요소입니다.

이 파일럿은 디버깅 목적으로 여러 HTTP 기반의 디버그 엔드포인트를 노출하며, 이를 통해 운영자는 현재 설정된 서비스 메시 상태를 확인하고 프록시와의 동기화 여부, xDS API 상태 등을 조사할 수 있습니다.

이러한 엔드포인트는 다음과 같은 질문들에 대한 답을 제공합니다:

  • 프록시는 동기화되었는가? (Are the proxies synchronized?)
  • 프록시에 대한 마지막 설정 푸시는 언제 발생했는가? (When was the last push to a proxy performed?)
  • xDS API의 구성 상태는 어떤가? (What’s the state of the xDS APIs?)
#
kubectl -n istio-system port-forward deploy/istiod 8080
open http://localhost:8080/debug

# 파일럿이 알고 있는 서비스 메시 상태
## 클러스터, 루트, 리스너 설정
curl -s http://localhost:8080/debug/adsz | jq

## 이 파일럿이 관리하는 모든 프록시에 대한 푸시를 트리거한다.
curl -s http://localhost:8080/debug/adsz?push=true
Pushed to 4 servers

## /debug/edsz=proxyID=<pod>.<namespace> : 프록시가 알고 있는 엔드포인트들
curl -s http://localhost:8080/debug/edsz=proxyID=webapp.istioninaction

## /debug/authorizationz : 네임스페이스에 적용되는 인가 정책 목록
curl -s http://localhost:8080/debug/authorizationz | jq


# 파일럿이 알고 있는 데이터 플레인 설정을 나타내는 엔드포인트
## 이 파일럿 인스턴스에 연결된 모든 엔보이의 버전 상태 : 현재 비활성화되어 있음
curl -s http://localhost:8080/debug/config_distribution
Pilot Version tracking is disabled. It may be enabled by setting the PILOT_ENABLE_CONFIG_DISTRIBUTION_TRACKING environment variable to true

## 이스티오 파일럿의 현재 알려진 상태에 따라 엔보이 설정을 생성한다.
curl -s http://localhost:8080/debug/config_dump?=proxyID=webapp.istioninaction

## 이 파일럿이 관리하는 프록시들을 표시한다.
curl -s http://localhost:8080/debug/syncz | jq
...
  {
    "cluster_id": "Kubernetes",
    "proxy": "webapp-7685bcb84-lwsvj.istioinaction",
    "istio_version": "1.17.8",
    "cluster_sent": "ff5e6b2c-e857-4e12-b17e-46ad968567f4",
    "cluster_acked": "ff5e6b2c-e857-4e12-b17e-46ad968567f4",
    "listener_sent": "7280c908-010d-4788-807f-7138e74fe72e",
    "listener_acked": "7280c908-010d-4788-807f-7138e74fe72e",
    "route_sent": "2a1916c3-9c05-4ce5-8cfa-d777105b9205",
    "route_acked": "2a1916c3-9c05-4ce5-8cfa-d777105b9205",
    "endpoint_sent": "dffacd32-2674-4e39-8e76-17016ff32514",
    "endpoint_acked": "dffacd32-2674-4e39-8e76-17016ff32514"
  },
...

  • 파일럿이 알고 있는 서비스 메시 상태를 나타내는 엔드포인트
    • /debug/adsz : 클러스터, 루트, 리스너 설정
    • /debug/adsz?push=true : 이 파일럿이 관리하는 모든 프록시에 대한 푸시를 트리거한다.
    • /debug/edsz=*proxyID*=*<pod>.<namespace>* : 프록시가 알고 있는 엔드포인트들
    • /debug/authorizationz : 네임스페이스에 적용되는 인가 정책 목록

  • 파일럿이 알고 있는 데이터 플레인 설정을 나타내는 엔드포인트
    • /debug/config_distribution : 이 파일럿 인스턴스에 연결된 모든 엔보이의 버전 상태
    • /debug/config_dump?proxyID=<pod>.<namespace> : 이스티오 파일럿의 현재 알려진 상태에 따라 엔보이 설정을 생성한다.
    • /debug/syncz : 이 파일럿이 관리하는 프록시들을 표시한다.
      • 또한 프록시로 보낸 최신 논스 nonce 와 응답받은 최신 논스도 보여준다. 이 둘이 동일하면 프록시의 설정이 최신인 것이다.

it shows the latest nonce sent to the proxy and the latest nonce acknowledged. When those are the same, the proxy has the latest configuration.

✅ ControlZ 인터페이스

이스티오 파일럿에는 파일럿 프로세스의 현재 상태와 몇 가지 사소한 설정 가능성을 확인 할 수 있는 관리자 인터페이스가 함께 제공합니다.

이 인터페이스는 아래 표 D.1 에서 다룬 것 처럼 파일럿 인스턴스와 관련된 정보를 빠르게 조회할 수 있습니다.

페이지설명
로깅 범위 (Logging Scopes)이 프로세스에 대한 로깅은 범위별로 구성돼 있으며, 각 범위별로 로깅 단계를 별도로 설정할 수 있습니다.
메모리 사용량 (Memory Usage)Go 런타임에서 수집한 정보로, 해당 프로세스의 메모리 소비량을 나타냅니다.
환경 변수 (Environment Variables)프로세스에 정의된 모든 환경 변수들의 집합을 확인할 수 있습니다.
프로세스 정보 (Process Information)현재 실행 중인 파일럿 프로세스에 대한 기본 정보를 제공합니다.
명령줄 인수 (Command-Line Arguments)이스티오 파일럿이 시작될 때 사용된 명령줄 인수 목록입니다.
버전 정보 (Version Info)실행 중인 이스티오 바이너리의 버전과 함께 사용 중인 Go 런타임 버전 정보를 보여줍니다.
메트릭 (Metrics)파일럿에서 수집되고 노출되는 메트릭 데이터를 확인할 수 있는 항목입니다.
시그널 (Signals)실행 중인 프로세스에 SIGUSR1 등의 시그널을 직접 보낼 수 있는 제어 기능입니다.
#
kubectl -n istio-system port-forward deploy/istiod 9876
open http://localhost:9876



📌 Conclusion

Istio 환경에서는 네트워크 문제나 트래픽 설정 오류가 단순히 서비스 간 통신 장애로 그치지 않고, 비즈니스 영향으로 직결될 수 있는 민감한 요소가 됩니다.

이번 블로그에서 소개한 다양한 실습과 도구들은 그러한 장애를 조기에 탐지하고, 정확한 원인을 신속히 파악해 대응할 수 있도록 도와주는 무기입니다.

특히, 다음과 같은 핵심 관점을 갖는 것이 중요합니다:

  • 문제 발생 시 컨트롤 플레인을 빠르게 배제하고 데이터 플레인 쪽 설정과 상태를 집중적으로 확인하라.
  • Envoy의 proxy-config 명령, Grafana의 P99 지표, Prometheus 쿼리 등을 적절히 조합해 특정 파드/버전 단위로 원인을 좁혀 나가라.
  • Pilot과 Agent의 디버그 엔드포인트는 예외 상황에서 서비스 메시 내부의 실제 동작 상태를 깊이 파악하는 도구가 될 수 있다.

이러한 실습 경험은 단지 장애 대응 뿐 아니라, 서비스 메시 성능 개선 및 아키텍처 안정성 확보에도 중요한 기초 체력이 됩니다.

profile
안녕하세요! DevOps 엔지니어 이재찬입니다. 블로그에 대한 피드백은 언제나 환영합니다! 기술, 개발, 운영에 관한 다양한 주제로 함께 나누며, 더 나은 협업과 효율적인 개발 환경을 만드는 과정에 대해 인사이트를 나누고 싶습니다. 함께 여행하는 기분으로, 즐겁게 읽어주시면 감사하겠습니다! 🚀

0개의 댓글