10장 Troubleshooting the data plane

김진원·2025년 5월 15일

Istio

목록 보기
10/16

CloudNet@에서 진행하는 Istio Study 6주차 10장 내용입니다.

📕 This chapter cover

  • Troubleshooting a misconfigured workload
  • Detecting and preventing misconfigurations using istioctl and Kiali
  • Using istioctl to investigate the service proxy configuration
  • Making sense of Envoy logs
  • Using telemetry to gain insights into apps


10.1 The most common mistake: A misconfigured data plane

Istio는 VirtualService, DestinationRule 같은 CRD로 누출하며, Envoy 설정으로 변환되어 Data Plane에 적용됩니다.

새 리소스를 적용한 후 데이터 플레인의 동작이 예상과 다를 때 가장 일반적인 원인은 우리가 설정을 잘못한 것이다.

  • 트러블슈팅을 위해 20% version-v1, 나머지 80% version-v2로 라우팅하는 VirtualService 리소스 예제입니다.

DestinationRule 리소스가 없으면 인그레스 게이트웨이는 부분집합 version-v1과 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 # catalog-gateway 배포
kubectl apply -f ch10/catalog-virtualservice-subsets-v1-v2.yaml -n istioinaction

# Gateway 
cat ch10/catalog-gateway.yaml
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  name: catalog-gateway
  namespace: istioinaction
spec:
  selector:
    istio: ingressgateway
  servers:
  - hosts:
    - "catalog.istioinaction.io"
    port:
      number: 80
      name: http
      protocol: HTTP

# VirtualService
cat ch10/catalog-virtualservice-subsets-v1-v2.yaml
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: catalog-v1-v2
  namespace: istioinaction
spec:
  hosts:
  - "catalog.istioinaction.io"
  gateways:
  - "catalog-gateway"
  http:
  - route:
    - destination:
        host: catalog.istioinaction.svc.cluster.local
        subset: version-v1
        port:
          number: 80
      weight: 20
    - destination:
        host: catalog.istioinaction.svc.cluster.local
        subset: version-v2
        port:
          number: 80
      weight: 80

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

  • 통신 확인: 부분집합 설정 누락, 503 ‘Service Unavailable’ 출력
kubectl logs -n istio-system -l app=istio-ingressgateway -f


10.2 Identifying data-plane issues

10.2.1 How to verify that the data plane is up to date

  • 데이터 플레인 설정은 설계상 궁극적으로 일관성을 가진다.
  • 즉, 환경(서비스, 엔드포인트, 상태)이나 설정의 변화는 컨트롤 플레인과 적절히 동기화하기 전까지는 데이터 플레인에 즉시 반영되지 않는다.

워크로드와 이벤트 개수가 늘어나는 대규모 클러스터에서는 데이터 플레인을 동기화하는 데 필요한 시간도 비례해 늘어난다.

  • istioctl proxy-status 로 데이터 플레인이 최신 설정과 동기화했는지 확인

  • SYNCED : istiod가 보낸 마지막 설정을 엔보이가 확인했다.

  • NOT SENT : istiod가 아무것도 엔보이로 보내지 않았다. 보통은 istiod가 보낼 것이 없기 때문이다.

  • STALE : istiod가 엔보이에 업데이트를 보냈지만 확인받지 못했다. 이는 다음 중 하나를 나타낸다.

    • istiod가 과부하됐거나, 엔보이와 istiod 사이의 커넥션 부족 또는 끊김이거나, Istio의 버그다.
  • 설정을 받지 못한 stale 상태의 워크로드가 없다.

  • 컨트롤 플레인에 문제가 있을 가능성은 낮으므로 데이터 플레인 구성 요소를 조사해야 한다.

  • 데이터 플레인 구성 요소에서 가장 일반적인 문제는 잘못된 워크로드 설정입니다. 키알리로 빠르게 검증 가능


10.2.2 Discovering misconfigurations with Kiali

  • 내장 편집기에서 경고 메시지 확인

  • 다음은 KIA1107 경고의 해결책 부분이다.

    • 존재하지 않은 부분집합을 가리키는 루트를 수정.
    • 부분집합 이름의 오타를 수정하거나 DestinationRule 에서 빠트린 부분집합을 정의

키알리 검증은 도움이 되므로, 워크로드가 예상대로 동작하지 않을 때 취하는 첫 조치 중 하나이다.


10.2.3 Discovering misconfigurations with istioctl

잘못 설정된 워크로드를 자동으로 트러블슈팅하는 데 가장 유용한 istioctl 명령어 두 가지는 istioctl analyze 와 istioctl describe 이다.

# istioctl 로 이스티오 설정 분석하기

  • istioctl analyze 명령어는 이스티오 설정을 분석하는 강력한 진단 도구
  • 이미 문제가 발생한 클러스터에 실행하거나, 리소스를 잘못 구성하는 것을 방지하고자 클러스터에 적용하기 전에 설정이 유효한지 검사할 수 있다.
  • 감지된 문제
# 이전 명령어 종료 코드 확인
echo $? # (참고) 0 성공
79

출력은 부분집합을 찾지 못했음을 보여준다. 오류 메시지 외에 istio 오류 코드 IST0101 도 제공


# 워크로드별로 설정 오류 찾기

  • describe는 워크로드별 설정을 기술하는데 사용한다.
  • describe는 워크로드 하나에 직간접적으로 영향을 미치는 이스티오 설정을 분석해 요약 내용을 출력한다.
  • 실행
  • 문제 해결 후 확인

10.3 Discovering misconfigurations manually from the Envoy config

10.3.1 Envoy administration interface

  • 엔보이 관리 인터페이스는 프록시의 특정 부분(로그 수준 증가 등)을 수정하는 기능과 엔보이 설정을 노출한다. 포트 15000으로 접근 할 수 있다.
#
kubectl port-forward deploy/catalog -n istioinaction 15000:15000
open http://localhost:15000

# 현재 적재한 엔보이 설정 출력 : 데이터양이 많다!
curl -s localhost:15000/config_dump | wc -l
  13952

출력은 너무 커서 기본적으로 사람이 읽을 수 없다.


10.3 Querying proxy configurations using istioctl

# 요청을 라우팅하기 위한 엔보이 API의 상호작용

  • 아래 그림은 요청 라우팅을 설정하는 엔보이 API입니다.

이 API는 프록시에 다음과 같은 영향을 미친다.

  • 엔보이 리스너 listeners 는 네트워크 설정(다운스트림 트래픽을 프록시로 허용하는 IP 주소 및 포트 등)을 정의한다.
    • 허용된 커넥션에 HTTP 필터 filter 체인이 만들어진다. 체인에서 가장 중요한 필터는 라우터 필터로, 고급 라우팅 작업을 수행한다.
    • 엔보이 루트 routes 는 가상 호스트를 클러스터에 일치시키는 규칙 집합이다. 루트는 순서대로 처리된다.
      • 일치하는 첫 번째 항목이 트래픽을 워크로드 클러스터로 라우팅하는 데 사용된다.
      • 루트는 정적으로 설정할 수 도 있지만, 이스티오에서는 RDS를 사용해 동적으로 설정한다.
    • 엔보이 클러스터 clusters 에서, 각 클러스터에는 유사한 워크로드에 대한 엔드포인트 그룹이 있다.
      • 부분집합 Subsets 은 클러스터 내에서 워크로드를 더 분할하는 데 사용하며 덕분에 정밀한 트래픽 관리가 가능해진다.
    • 엔보이 엔드포인트는 요청을 처리하는 워크로드의 IP 주소를 나타낸다.

# 엔보이 리스터 설정 쿼리하기

  • 인그레스 게이트웨이 NodePort 30000 포트로 도착 트래픽을 클러스터에서 허용한 지 확인
  • 트래픽 허용은 엔보이 리스너 역할, Istio에서 Gateway 리소스 설정
  • Gateway의 리스너 설정 쿼리, 80번 포트 트래픽 허용 확인

  • 루트 http.8080이 80 포트가 아니라 8080포트에서 리스닝하도록 설정

  • 포트 8080이 올라오는 포트인지 확인

kubectl get svc -n istio-system  istio-ingressgateway -o yaml | grep "ports:" -A10
  ports:
  - name: status-port
    nodePort: 30840
    port: 15021
    protocol: TCP
    targetPort: 15021
  - name: http2
    nodePort: 30000
    port: 80
    protocol: TCP
    targetPort: 8080
  • 트래픽이 nodePort 30000 포트에 인입 시, istio-ingressgateway 서비스는 인그레스 게이트웨이(파드)에 tcp 8080 포트로 전달(도달)하게 됨.
    • 만약 k8s 클러스터 내부에서 clusterIP혹은 서비스명으로 tcp 80 요청 시 → 인그레스 게이트웨이(파드)에 tcp 8080 포트로 전달(도달)하게 됨.
  • 그 트래픽을 인그레스 게이트웨이로 허용하는 리스너가 존재 확인.
  • 리스너의 라우팅은 루트 http.8080이 수행한다는 사실.

# 엔보이 루트 설정 쿼리하기

  • 엔보이 루트 설정은 트래픽을 라우팅할 클러스터를 결정하는 규칙 집합을 정의한다.
  • Istio는 엔보이 루트를 VirtualService 리소스로 설정한다. 한편, 클러스터는 디스커비리로 자동 설정되거나 DestinationRule 리소스로 정의된다.
  • http.8080 루트의 트래픽을 어느 클러스터로 라우팅할지 알아내기 위해 설정을 쿼리
# http.8080 루트의 트래픽을 어느 클러스터로 라우팅할지 알아내기 위해 설정을 쿼리
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
## 호스트 catalog.istioinaction.io 의 트래픽 중 URL이 경로 접두사 /*과 일치하는 것이 istioinaction 네임스페이스의 catalog 서비스에 있는 catalog VirtualService 로 라우팅됨을 보여준다.

# 세부 정보 확인
docker exec -it myk8s-control-plane istioctl proxy-config routes deploy/istio-ingressgateway -n istio-system --name http.8080 -o json
...
                "routes": [
                    {
                        "match": {
                            "prefix": "/" # 일치해야 하는 라우팅 규칙
                        },
                        "route": {
                            "weightedClusters": {
                                "clusters": [ # 규칙이 일치할 때 트래픽을 라우팅하는 클러스터
                                    {
                                        "name": "outbound|80|version-v1|catalog.istioinaction.svc.cluster.local",
                                        "weight": 20
                                    },
                                    {
                                        "name": "outbound|80|version-v2|catalog.istioinaction.svc.cluster.local",
                                        "weight": 80
                                    }
                                ],
                                "totalWeight": 100
                            },
...
  • 루트가 일치할 때 트래픽을 수신하는 클러스터가 둘을 확인
    • outbound|80|version-v1|catalog.istioinaction.svc.cluster.local
    • outbound|80|version-v2|catalog.istioinaction.svc.cluster.local

# 엔보이 클러스터 설정 쿼리하기

  • 엔보이 클러스터 설정은 요청을 라우팅할 수 있는 백엔드 서비스를 정의한다.
  • istioctl proxy-config clusters 의 플래그 direction, fqdn, port, subent 을 사용하면 특정 클러스터만 출력할 수 있다.
  • 플래그에서 사용할 정보는 그림 10.9와 같이 앞서 가져온 클러스터 이름에 포함돼 있다.

docker exec -it myk8s-control-plane istioctl proxy-config clusters deploy/istio-ingressgateway -n istio-system --fqdn catalog.istioinaction.svc.cluster.local --port 80
SERVICE FQDN                                PORT     SUBSET     DIRECTION     TYPE     DESTINATION RULE
catalog.istioinaction.svc.cluster.local     80       -          outbound      EDS 

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
SERVICE FQDN     PORT     SUBSET     DIRECTION     TYPE     DESTINATION RULE

subset version-v1 이나 version-v2 용 클러스터는 없었다! ⇒ 이 부분 집합에 대한 클러스터가 없으면 요청은 실패한다.


# istioctl analyze 명령어를 사용해서, 설정할 yaml 파일이 식별한 서비스 메시 오류를 고칠 수 있는지 확인
docker exec -it myk8s-control-plane istioctl analyze /istiobook/ch10/catalog-destinationrule-v1-v2.yaml -n istioinaction
✔ No validation issues found when analyzing /istiobook/ch10/catalog-destinationrule-v1-v2.yaml.
  • DestinationRule을 적용하면 클러스터 설정의 문제가 고쳐진다

  • 문제 해결

# 문제 해결
cat ch10/catalog-destinationrule-v1-v2.yaml
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
SERVICE FQDN                                PORT     SUBSET         DIRECTION     TYPE     DESTINATION RULE
catalog.istioinaction.svc.cluster.local     80       -              outbound      EDS      catalog.istioinaction
catalog.istioinaction.svc.cluster.local     80       version-v1     outbound      EDS      catalog.istioinaction
catalog.istioinaction.svc.cluster.local     80       version-v2     outbound      EDS      catalog.istioinaction

CATALOG_POD1=$(kubectl get pod -n istioinaction -l app=catalog -o jsonpath='{.items[0].metadata.name}')
docker exec -it myk8s-control-plane istioctl x des pod -n istioinaction $CATALOG_POD1
docker exec -it myk8s-control-plane istioctl analyze -n istioinaction


# 클러스터는 어떻게 설정되는가?

엔보이 프록시에는 클러스터 엔드포인트를 발견하기 위한 여러 가지 방법이 있다.

  • 사용 중인 방법은 istioctl에서 version-v1 클러스터를 JSON 형식으로 출력해보면 알 수 있다.
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
...
        "name": "outbound|80|version-v1|catalog.istioinaction.svc.cluster.local",
        "type": "EDS",
        "edsClusterConfig": {
            "edsConfig": {
                "ads": {},
                "initialFetchTimeout": "0s",
                "resourceApiVersion": "V3"
            },
            "serviceName": "outbound|80|version-v1|catalog.istioinaction.svc.cluster.local"
        },
...

edsClusterConfig 가 엔드포인트를 쿼리하는 데 ADS Aggregated Discovery Service 를 사용하도록 설정됐음을 보여준다.


# 엔보이 클러스터 엔드포인트 쿼리하기

인그레스 게이트웨이에서 클러스터의 엔드포인트를 istioctl proxy-config endpoints 명령어로 수동으로 쿼리하는데 이 정보를 사용할 수 있다.


10.3.3 Troubleshooting application issues

엔보이 액세스 로그와 메트릭을 사용해 이 문제들 중 일부를 트러블슈팅해본다.


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

  • catalog v1 HTTP Request Response Time(ms)에 p99 확인

  • catalog v2 HTTP Request Response Time(ms)에 p99 확인

  • Grafana Dashboard
  • catalog 워크로드가 간헐적으로 응답을 느리게 반환하도록 설정
# catalog v2 파드 중 첫 번째 파드 이름 변수 지정
CATALOG_POD=$(kubectl get pods -l version=v2 -n istioinaction -o jsonpath={.items..metadata.name} | cut -d ' ' -f1)
echo $CATALOG_POD
catalog-v2-56c97f6db-d74kv

# 해당 파드에 latency (지연) 발생하도록 설정
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 ;
blowups=[object Object]
  • v2 P90, P99 레이턴스 확인

  • Istio 에 요청 처리 제한 시간 0.5초가 되도록 VirtualService 설정

kubectl get vs -n istioinaction
NAME            GATEWAYS              HOSTS                          AGE
catalog-v1-v2   ["catalog-gateway"]   ["catalog.istioinaction.io"]   6h44m

# 타임아웃(0.5s) 적용
kubectl patch vs catalog-v1-v2 -n istioinaction --type json \
-p '[{"op": "add", "path": "/spec/http/0/timeout", "value": "0.5s"}]'

# 적용확인 
kubectl get vs catalog-v1-v2 -n istioinaction -o jsonpath='{.spec.http[?(@.timeout=="0.5s")]}' | jq
...
  "timeout": "0.5s"
}

# 신규 터미널
for in in {1..9999}; do curl http://catalog.istioinaction.io:30000/items -w "\nStatus Code %{http_code}\n"; sleep 1; done
upstream request timeout
Status Code 504
upstream request timeout
Status Code 504
..

kubectl logs -n istio-system -l app=istio-ingressgateway -f
[2025-05-09T08:45:41.636Z] "GET /items HTTP/1.1" 504 UT response_timeout - "-" 0 24 501 - "172.18.0.1" "curl/8.7.1" "cb846eff-07ac-902e-9890-7af478c84166" "catalog.istioinaction.io:30000" "10.10.0.13:3000" outbound|80|version-v2|catalog.istioinaction.svc.cluster.local 10.10.0.7:58078 10.10.0.7:8080 172.18.0.1:61108 - -
[2025-05-09T08:45:43.175Z] "GET /items HTTP/1.1" 200 - via_upstream - "-" 0 502 375 374 "172.18.0.1" "curl/8.7.1" "3f2de0c1-5af2-9a33-a6ac-bca08c1ee271" "catalog.istioinaction.io:30000" "10.10.0.13:3000" outbound|80|version-v2|catalog.istioinaction.svc.cluster.local 10.10.0.7:58084 10.10.0.7:8080 172.18.0.1:61118 - -
...

kubectl logs -n istio-system -l app=istio-ingressgateway -f | grep 504
[2025-05-16T06:47:37.938Z] "GET /items HTTP/1.1" 504 UT response_timeout - "-" 0 24 509 - "172.18.0.1" "curl/8.5.0" "996863ed-d0c4-93e5-94c1-7b3951f1f29f" "catalog.istioinaction.io:30000" "10.10.0.3:3000" outbound|80|version-v2|catalog.istioinaction.svc.cluster.local 10.10.0.13:39964 10.10.0.13:8080 172.18.0.1:39652 - -
[2025-05-16T06:47:43.816Z] "GET /items HTTP/1.1" 504 UT response_timeout - "-" 0 24 502 - "172.18.0.1" "curl/8.5.0" "bbd3aac8-d8a8-9b59-8187-66adb1f88a42" "catalog.istioinaction.io:30000" "10.10.0.3:3000" outbound|80|version-v2|catalog.istioinaction.svc.cluster.local 10.10.0.13:38130 10.10.0.13:8080 172.18.0.1:47108 - -

#
kubectl logs -n istioinaction -l version=v2 -c istio-proxy -f
[2025-05-09T08:42:38.152Z] "GET /items HTTP/1.1" 0 DC downstream_remote_disconnect - "-" 0 0 500 - "172.18.0.1" "curl/8.7.1" "69fef43c-2fea-9e51-b33d-a0375b382d86" "catalog.istioinaction.io:30000" "10.10.0.13:3000" inbound|3000|| 127.0.0.6:36535 10.10.0.13:3000 172.18.0.1:0 outbound_.80_.version-v2_.catalog.istioinaction.svc.cluster.local default
...
  • catalog v2

  • Grafana: 500 증가


# 엔보이 액세스 로그 이해하기 + 엔보이 액세스 로그 형식 바꾸기

  • 기본적으로 Istio는 프록시가 로그를 TEXT 형식으로 기록
  • JSON 형식을 사용하게 설정 : 이 형식의 이점은 값이 키와 연결돼 의미를 알 수 있다.
kubectl logs -n istio-system -l app=istio-ingressgateway -f | grep 504
[2025-05-16T07:17:11.343Z] "GET /items HTTP/1.1" 504 UT response_timeout - "-" 0 24 502 - "172.18.0.1" "curl/8.5.0" "a4c9993f-c6a8-930c-87a1-8ef404d065c1" "catalog.istioinaction.io:30000" "10.10.0.3:3000" outbound|80|version-v2|catalog.istioinaction.svc.cluster.local 10.10.0.13:44180 10.10.0.13:8080 172.18.0.1:51328 - -
[2025-05-16T07:17:14.165Z] "GET /items HTTP/1.1" 504 UT response_timeout - "-" 0 24 500 - "172.18.0.1" "curl/8.5.0" "afe6edf7-0ce2-9179-abed-c921b57ce837" "catalog.istioinaction.io:30000" "10.10.0.3:3000" outbound|80|version-v2|catalog.istioinaction.svc.cluster.local 10.10.0.13:35200 10.10.0.13:8080 172.18.0.1:51354 - -
[2025-05-16T07:17:17.739Z] "GET /items HTTP/1.1" 504 UT response_timeout - "-" 0 24 507 - "172.18.0.1" "curl/8.5.0" "96a24149-8ddc-95ba-889f-e17b91d07a67" "catalog.istioinaction.io:30000" "10.10.0.3:3000" outbound|80|version-v2|catalog.istioinaction.svc.cluster.local 10.10.0.13:54988 10.10.0.13:8080 172.18.0.1:51388 - -
[2025-05-16T07:17:32.277Z] "GET /items HTTP/1.1" 504 UT response_timeout - "-" 0 24 503 - "172.18.0.1" "curl/8.5.0" "0940b9a1-eed7-9db5-ade7-b310b17b1d36" "catalog.istioinaction.io:30000" "10.10.0.3:3000" outbound|80|version-v2|catalog.istioinaction.svc.cluster.local 10.10.0.13:60022 10.10.0.13:8080 172.18.0.1:45930 - -

# MeshConfig 설정 수정
KUBE_EDITOR="nano" kubectl edit -n istio-system cm istio
...
  mesh: |-
    accessLogFile: /dev/stdout # 기존 설정되어 있음
    accessLogEncoding: JSON # 추가
...

# 형식 설정 후 로그 확인
kubectl logs -n istio-system -l app=istio-ingressgateway -f | jq
...
{
  "upstream_host": "10.10.0.13:3000", # 요청을 받는 업스트림 호스트
  "bytes_received": 0,
  "upstream_service_time": null,
  "response_code_details": "response_timeout",
  "upstream_cluster": "outbound|80|version-v2|catalog.istioinaction.svc.cluster.local",
  "duration": 501, # 500ms 인 제한 시간 초과
  "response_code": 504,
  "path": "/items",
  "protocol": "HTTP/1.1",
  "upstream_transport_failure_reason": null,
  "connection_termination_details": null,
  "method": "GET",
  "requested_server_name": null,
  "start_time": "2025-05-09T08:56:38.988Z",
  "downstream_remote_address": "172.18.0.1:59052",
  "upstream_local_address": "10.10.0.7:57154",
  "downstream_local_address": "10.10.0.7:8080",
  "bytes_sent": 24,
  "authority": "catalog.istioinaction.io:30000",
  "x_forwarded_for": "172.18.0.1",
  "request_id": "062ad02a-ff36-9dcc-8a7d-68eabb01bbb5",
  "route_name": null,
  "response_flags": "UT", # 엔보이 응답 플래그, UT(Upstream request Timeout)로 중단됨, '업스트림 요청 제한 시간 초과'
  "user_agent": "curl/8.7.1"
}
...

CATALOG_POD=$(kubectl get pods -l version=v2 -n istioinaction -o jsonpath={.items..metadata.name} | cut -d ' ' -f1)

kubectl get pod -n istioinaction $CATALOG_POD -owide

NAME                         READY   STATUS    RESTARTS       AGE   IP          NODE                  NOMINATED NODE   READINESS GATES
catalog-v2-56c97f6db-h9kjw   2/2     Running   4 (155m ago)   22h   10.10.0.3   myk8s-control-plane   <none>           <none>

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

  • 현재 로깅 확인
docker exec -it myk8s-control-plane istioctl proxy-config log deploy/istio-ingressgateway -n istio-system
istio-ingressgateway-6bb8fb6549-hcdnc.istio-system:
active loggers:
  admin: warning
  alternate_protocols_cache: warning
  aws: warning
  assert: warning
  backtrace: warning
  cache_filter: warning
  client: warning
  config: warning
  connection: warning # 커넥션 범위에서는 네트워크 계층과 관련된 정보를 기록.
  ...
  http: warning # HTTP 범위에서는 HTTP 헤더, 경로 등 애플리케이션과 관련된 졍보를 기록.
  ...
  router: warning # 라우팅 범위에서는 요청이 어느 클러스터로 라우팅되는지 같은 세부 사항을 기록.
...
  • 관심 영역의 로깅 수준만 정확하게 높일 수 있다.

    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


  • connection , http , router , pool 로거의 수준을 debug로 변경
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
k logs -n istio-system -l app=istio-ingressgateway -f > istio-igw-log.txt # 편집기로 열어서 보기
...
  • 편집기 확인
# 504 검색
2025-05-09T09:17:17.762027Z	debug	envoy http external/envoy/source/common/http/filter_manager.cc:967	[C18119][S12425904214070917868] Sending local reply with details response_timeout	thread=38
2025-05-09T09:17:17.762072Z	debug	envoy http external/envoy/source/common/http/conn_manager_impl.cc:1687	[C18119][S12425904214070917868] encoding headers via codec (end_stream=false):
':status', '504'
'content-length', '24'
'content-type', 'text/plain'
'date', 'Fri, 09 May 2025 09:17:17 GMT'
'server', 'istio-envoy'
	thread=38

# 커넥션 ID(C18119)로 다시 검색

## [C18119] new stream  # 시작
2025-05-09T09:17:17.262341Z	debug	envoy http external/envoy/source/common/http/conn_manager_impl.cc:329	[C18119] new stream	thread=38
2025-05-09T09:17:17.262425Z	debug	envoy http external/envoy/source/common/http/conn_manager_impl.cc:1049	[C18119][S12425904214070917868] request headers complete (end_stream=true):
':authority', 'catalog.istioinaction.io:30000'
':path', '/items'
':method', 'GET'
'user-agent', 'curl/8.7.1'
'accept', '*/*'
	thread=38

## /items 요청이 cluster로 매칭됨
2025-05-09T09:17:17.262445Z	debug	envoy http external/envoy/source/common/http/conn_manager_impl.cc:1032	[C18119][S12425904214070917868] request end stream	thread=38
2025-05-09T09:17:17.262468Z	debug	envoy connection external/envoy/source/common/network/connection_impl.h:92	[C18119] current connecting state: false	thread=38
025-05-09T09:17:17.262603Z	debug	envoy router external/envoy/source/common/router/router.cc:470	[C18119][S12425904214070917868] cluster 'outbound|80|version-v2|catalog.istioinaction.svc.cluster.local' match for URL '/items'	thread=38
2025-05-09T09:17:17.262683Z	debug	envoy router external/envoy/source/common/router/router.cc:678	[C18119][S12425904214070917868] router decoding headers:
':authority', 'catalog.istioinaction.io:30000'
':path', '/items'
':method', 'GET'
':scheme', 'http'
'user-agent', 'curl/8.7.1'
'accept', '*/*'
'x-forwarded-for', '172.18.0.1'
'x-forwarded-proto', 'http'
'x-envoy-internal', 'true'
'x-request-id', 'a6bc39e7-9215-950f-96ea-4cb5f6b12deb'
'x-envoy-decorator-operation', 'catalog-v1-v2:80/*'
'x-envoy-peer-metadata', 'ChQKDkFQUF9DT05UQUlORVJTEgIaAAoaCgpDTFVTVEVSX0lEEgwaCkt1YmVybmV0ZXMKGwoMSU5TVEFOQ0VfSVBTEgsaCTEwLjEwLjAuNwoZCg1JU1RJT19WRVJTSU9OEggaBjEuMTcuOAqcAwoGTEFCRUxTEpEDKo4DCh0KA2FwcBIWGhRpc3Rpby1pbmdyZXNzZ2F0ZXdheQoTCgVjaGFydBIKGghnYXRld2F5cwoUCghoZXJpdGFnZRIIGgZUaWxsZXIKNgopaW5zdGFsbC5vcGVyYXRvci5pc3Rpby5pby9vd25pbmctcmVzb3VyY2USCRoHdW5rbm93bgoZCgVpc3RpbxIQGg5pbmdyZXNzZ2F0ZXdheQoZCgxpc3Rpby5pby9yZXYSCRoHZGVmYXVsdAowChtvcGVyYXRvci5pc3Rpby5pby9jb21wb25lbnQSERoPSW5ncmVzc0dhdGV3YXlzChIKB3JlbGVhc2USBxoFaXN0aW8KOQofc2VydmljZS5pc3Rpby5pby9jYW5vbmljYWwtbmFtZRIWGhRpc3Rpby1pbmdyZXNzZ2F0ZXdheQovCiNzZXJ2aWNlLmlzdGlvLmlvL2Nhbm9uaWNhbC1yZXZpc2lvbhIIGgZsYXRlc3QKIgoXc2lkZWNhci5pc3Rpby5pby9pbmplY3QSBxoFZmFsc2UKGgoHTUVTSF9JRBIPGg1jbHVzdGVyLmxvY2FsCi8KBE5BTUUSJxolaXN0aW8taW5ncmVzc2dhdGV3YXktNmJiOGZiNjU0OS1oY2RuYwobCglOQU1FU1BBQ0USDhoMaXN0aW8tc3lzdGVtCl0KBU9XTkVSElQaUmt1YmVybmV0ZXM6Ly9hcGlzL2FwcHMvdjEvbmFtZXNwYWNlcy9pc3Rpby1zeXN0ZW0vZGVwbG95bWVudHMvaXN0aW8taW5ncmVzc2dhdGV3YXkKFwoRUExBVEZPUk1fTUVUQURBVEESAioACicKDVdPUktMT0FEX05BTUUSFhoUaXN0aW8taW5ncmVzc2dhdGV3YXk='
'x-envoy-peer-metadata-id', 'router~10.10.0.7~istio-ingressgateway-6bb8fb6549-hcdnc.istio-system~istio-system.svc.cluster.local'
'x-envoy-expected-rq-timeout-ms', '500'
'x-envoy-attempt-count', '1'
	thread=38

## upstream timeout 으로 client 에서 끊음 (disconnect)
2025-05-09T09:17:17.262701Z	debug	envoy pool external/envoy/source/common/conn_pool/conn_pool_base.cc:265	[C17947] using existing fully connected connection	thread=38
2025-05-09T09:17:17.262710Z	debug	envoy pool external/envoy/source/common/conn_pool/conn_pool_base.cc:182	[C17947] creating stream	thread=38
2025-05-09T09:17:17.262736Z	debug	envoy router external/envoy/source/common/router/upstream_request.cc:581	[C18119][S12425904214070917868] pool ready	thread=38
2025-05-09T09:17:17.761697Z	debug	envoy router external/envoy/source/common/router/router.cc:947	[C18119][S12425904214070917868] upstream timeout	thread=38 # 업스트림 서버가 설정된 타임아웃 내에 응답하지 않아 요청이 실패
2025-05-09T09:17:17.761762Z	debug	envoy router external/envoy/source/common/router/upstream_request.cc:500	[C18119][S12425904214070917868] resetting pool request	thread=38
2025-05-09T09:17:17.761776Z	debug	envoy connection external/envoy/source/common/network/connection_impl.cc:139	[C17947] closing data_to_write=0 type=1	thread=38
2025-05-09T09:17:17.761779Z	debug	envoy connection external/envoy/source/common/network/connection_impl.cc:250	[C17947] closing socket: 1	thread=38
2025-05-09T09:17:17.761920Z	debug	envoy connection external/envoy/source/extensions/transport_sockets/tls/ssl_socket.cc:320	[C17947] SSL shutdown: rc=0	thread=38
2025-05-09T09:17:17.761982Z	debug	envoy pool external/envoy/source/common/conn_pool/conn_pool_base.cc:484	[C17947] client disconnected, failure reason: 	thread=38
2025-05-09T09:17:17.761997Z	debug	envoy pool external/envoy/source/common/conn_pool/conn_pool_base.cc:454	invoking idle callbacks - is_draining_for_deletion_=false	thread=38

## 504 응답
2025-05-09T09:17:17.762027Z	debug	envoy http external/envoy/source/common/http/filter_manager.cc:967	[C18119][S12425904214070917868] Sending local reply with details response_timeout	thread=38
2025-05-09T09:17:17.762072Z	debug	envoy http external/envoy/source/common/http/conn_manager_impl.cc:1687	[C18119][S12425904214070917868] encoding headers via codec (end_stream=false):
':status', '504'
'content-length', '24'
'content-type', 'text/plain'
'date', 'Fri, 09 May 2025 09:17:17 GMT'
'server', 'istio-envoy'
	thread=38
2025-05-09T09:17:17.762253Z	debug	envoy pool external/envoy/source/common/conn_pool/conn_pool_base.cc:215	[C17947] destroying stream: 0 remaining	thread=38
2025-05-09T09:17:17.763718Z	debug	envoy connection external/envoy/source/common/network/connection_impl.cc:656	[C18119] remote close	thread=38
2025-05-09T09:17:17.763731Z	debug	envoy connection external/envoy/source/common/network/connection_impl.cc:250	[C18119] closing socket: 0	thread=38
  • 두 가지 발견
    1. 응답이 느린 업스트림의 IP 주소가 액세스 로그에서 가져온 IP 주소와 일치한다는 점이다. 이는 오동작하는 인스턴스가 딱 하나
    2. 로그 [C17947] client disconnected 에 표시된 대로 클라이언트(프록시)는 업스트림 커넥션을 종료했다.
      이는 업스트림 인스턴스가 제한 시간 설정을 초과해 클라이언트(프록시)가 요청을 종료한다는 우리의 예상과 일치한다.

10.3.4 Inspect network traffic with tcpdump

특정 파드에서 tcpdump 후 wireshark 로 분석해보기

kubectl sniff -n istioinaction $CATALOG_POD -i lo
sudo kubectl sniff -n istioinaction $CATALOG_POD -i lo
ERRO[0000] failed to start remote sniffing, stopping wireshark  error="executing sniffer failed, exit code: '1'"

  1. 특정 파드에서 tcpdump 후 Wireshark로 불러오기
# slow 파드 정보 확인
CATALOG_POD=$(kubectl get pods -l version=v2 -n istioinaction -o jsonpath={.items..metadata.name} | cut -d ' ' -f1)
kubectl get pod -n istioinaction $CATALOG_POD -owide

# istio-proxy 에서 기본 정보 확인
kubectl exec -it -n istioinaction $CATALOG_POD -c istio-proxy -- sudo whoami
kubectl exec -it -n istioinaction $CATALOG_POD -c istio-proxy -- tcpdump -h
kubectl exec -it -n istioinaction $CATALOG_POD -c istio-proxy -- ip -c addr
kubectl exec -it -n istioinaction $CATALOG_POD -c istio-proxy -- ip add show dev eth0
kubectl exec -it -n istioinaction $CATALOG_POD -c istio-proxy -- ip add show dev lo

# istio-proxy 에 eth0 에서 패킷 덤프
kubectl exec -it -n istioinaction $CATALOG_POD -c istio-proxy -- sudo tcpdump -i eth0 tcp port 3000 -nnq
kubectl exec -it -n istioinaction $CATALOG_POD -c istio-proxy -- sudo tcpdump -i eth0 tcp port 3000 -nn
kubectl exec -it -n istioinaction $CATALOG_POD -c istio-proxy -- sudo tcpdump -i eth0 tcp port 3000

  1. Wireshark 에서 TLS 암호 통신 확인 : istio-ingressgateway → [ (캡처 지점) istio-proxy ⇒ catalog application ]

Client Hello (SNI 확인) : EDS 의 클러스터 이름으로 접속
outbound.80.version-v2_.catalog.istioinaction.svc.cluster.local

  • 암호화된 내용 확인 : Encrypted Application Data 에 값 확인

  1. Wireshark 에서 평문 통신 확인 : istio-ingressgateway → [ istio-proxy (캡처 지점) ⇒ catalog application ]
  • istio-proxy 가 HTTPS를 복호화해서 평문으로 애플리케이션으로 요청 : x-envoy, x-b3 등 헤더 추가 확인

  • Statistics → Flow Graph 확인 : 정상적으로 GET 요청과 200 응답 확인


  1. catalog v2 가 늦게 응답을 해서 istio-proxy 가 timeout 으로 먼저 종료 확인
  • 필터 ((tcp.stream == 1 and http) or tcp.flags == 0x0011 or tcp.flags == 0x0004) : TCP RST, FIN/ACK 플래그 필터링 추가

No. 38번에서 요청 후 0.5초 이상 응답이 없으니 (42번)44번에 istio-ingressgateway istio-proxy 가 TCP RST 로 연결 종료
⇒ 즉, 현재 구성 상 istio-ingressgw → catalog 이므로, istio-ingressgw 가 TCP Timeout 후 종료 처리함
이후 45번은 catalog v2 istio-proxy 가 FIN/ACK를 applcation 에게 전달 이후 연결 종료


10.4 Understanding your application using Envoy telemetry

10.4.1 Finding the rate of failing requests in Grafana

  • [인그레스 게이트웨이 : 응답 플래그 UT, 상태 코드 504] ⇒ (요청 타임아웃) ⇒ [catalog v2 : 응답 플래그 DC, 상태 코드 0]

클라이언트와 서버가 설정한 응답 플래그와 응답 코드의 차이점


10.4.2 Querying the affected Pods using Prometheus

그라파나 대시보드의 정보가 부족하면 프로메테우스에 직접 쿼리할 수 있다.

기준을 충족하는 메트릭을 쿼리

  • destination 이 보고한 요청
  • destination 서비스가 catalog 인 요청
  • 응답 플래그가 DC(다운스트림 커넥션 종료)인 요청 ⇒ 서버 입장에서는 응답을 하려는데, 클라이언트가 먼저 끊어 버린 것!
sort_desc( # 가장 높은 값부터 내림차순 정렬
  sum( # irate 값들을 집계
    irate( #  요청 수 초당 증가율
      istio_requests_total {
        reporter="destination",   # 서버(destination) 측에서 보고한 메트릭만 필터링
        destination_service=~"catalog.istioinaction.svc.cluster.local",   # catalog 가 서버(destination)측인 메트릭만 필터링
        response_flags="DC"       # DC (다운스트림 커넥션 종료)로 끝난 메트릭만 필터링
      }[5m]
    )
  )by(response_code, pod, version) # 응답 코드(response_code), 대상 pod, 버전(version) 별로 분리 => sum.. 합산
)

-> 오직 워크로드 하나만 실패를 보고 하고 있음을 보여준다.


  • 퀴리를 조금 수정해서 확인 : 여러 개 파드 중 catalog v2 만 응답 코드 0 기록 확인
sort_desc(sum(irate(istio_requests_total{reporter="destination", destination_service=~"catalog.istioinaction.svc.cluster.local"}[5m]))by(response_code, pod, version))

  • Istio는 표준 메트릭에 필요한 정보가 없으며, 7장의 7.4절에서 소개한 방법처럼 커스텀 메트릭을 추가할 수 있다.
  • 또한 프로메테우스 클라이언트 라이브러리를 사용해 애플리케이션에 모니터링을 원하는 대로 설정할 수도 있다.


  • istioctl 명령어를 사용해 서비스 메시와 서비스 프록시에 대한 통찰력을 얻는다.
    • proxy-status 는 데이터 플레인 동기화 상태의 개요를 보여준다.
    • analyze는 서비스 메시 설정을 분석한다.
    • describe는 요약을 가져오고 서비스 프록시 설정을 검증한다.
    • proxy-config는 서비스 프록시 설정을 쿼리하고 수정한다.
  • istioctl analyze 명령을 사용해 클러스터에 적용하기 전에 설정을 검증할 수 있다.
  • 키알리와 그 검증 기능을 사용해 일반적인 설정 실수를 잡아낼 수 있다.
  • 장애 상황을 살펴보려면 프로메테우스와 수집한 메트릭을 사용하자.
  • ksniff(tcpdump)를 사용해 영향을 받는 파드의 네트워크 트래픽을 캡처할 수 있다.
  • istioctl proxy-config log 명령어를 사용해 엔보이 프록시의 로깅 수준을 높일 수 있다.


부록 D 이스티오 구성 요소 트러블 슈팅하기

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

https://www.anyflow.net/sw-engineer/istio-internals-by-port

D.1 Information exposed by the Istio 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

# 확인
kubectl get gw,vs -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
  • 이스티오 사이드카 기능
    • 헬스체크
      • 프록시로서의 엔보이는 트래픽을 처리할 수 있는 즉시 준비 상태다.
      • 그러나 서비스 메시의 관점에서 보면 이 정도로는 충분하지 않다.
      • 프록시가 트래픽을 처리하기 전에 설정을 받았는지, ID를 할당받았는지 등의 더 많은 확인이 필요하다.
    • 메트릭 수집 및 노출
      • 서비스 내에서 메트릭을 생성하는 세 가지 구성 요소는 애플리케이션, 에이전트, 엔보이 프록시다.
      • 에이전트는 다른 구성 요소의 메트릭을 집계해 노출한다.
  • 서비스 노출 포트

  • 에이전트 디버깅 및 내부 상태 조사에 유용한 포트

    • 15000 : (엔보이 프로세스) 엔보이 프록시 관리 인터페이스
    • 15090 : (엔보이 프로세스) 엔보이 프록시 메트릭을 노출 (xDS 통계, 커넥션 통계, HTTP 통계, 이상값 outlier 통계, 헬스 체크 통계, 서킷 브레이커 통계 등)
    • 15004 : (파일럿 에이전트 프로세스) 에이전트를 통해 이스티오 파일럿 디버그 엔드포인트를 노출. 파일럿과의 연결 문제를 디버깅에 유용.
    • 15020 : (파일럿 에이전트 프로세스) 파일럿 에이전트 디버기용 엔드포인트들을 노출.

# D.1.1 이스티오 에이전트를 조사하고 트러블슈팅하기 위한 엔드포인트들

  • 15020 포트의 엔드포인트들
    • /healthz/ready : 엔보이 및 DNS 프록시에서 일련의 검사를 수행한다.
      • 이느 워크로드가 클라이언트 요청을 처리할 준비가 됐는지 확인하기 위한 것이다.
    • /stats/prometheus : 엔보이 프록시와 애플리케이션의 메트릭을 자체 메트릭과 병합하고 긁어갈 수 있도록 노출한다.
    • /quitquitquit : 파일럿 에이전트의 프로세스를 종료시킨다.
    • /app-health/ : 이스티오 프록시 사이드카의 환경 변수 ISTIO_KUBE_APP_PROBERS로 정의한 애플리케이션 프로브를 실행한다.
#
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

#
kubectl get pod -n istioinaction -l app=liveness-http
kubectl describe pod -n istioinaction -l app=liveness-http
...
Containers:
  liveness-http:
    Container ID:   containerd://edaf01bff5d553e03290b3d44f60bb26958319e615a27a9b38309aad9b2df477
    Image:          docker.io/istio/health:example
    Image ID:       docker.io/istio/health@sha256:d8a2ff91d87f800b4661bec5aaadf73d33de296d618081fa36a0d1cbfb45d3d5
    Port:           8001/TCP
    Host Port:      0/TCP
    State:          Running
      Started:      Sat, 10 May 2025 16:58:35 +0900
    Ready:          True
    Restart Count:  0
    Liveness:       http-get http://:15020/app-health/liveness-http/livez delay=5s timeout=1s period=5s #success=1 #failure=3
    ...
  istio-proxy:
    Container ID:  containerd://d4b0955372bdb7b3e1490eb3f290c6c6f5a9f2691eabea4cebafaafa8be85fc9
    Image:         docker.io/istio/proxyv2:1.17.8
    Image ID:      docker.io/istio/proxyv2@sha256:d33fd90e25c59f4f7378d1b9dd0eebbb756e03520ab09cf303a43b51b5cb01b8
    Port:          15090/TCP
    ...
    Readiness:  http-get http://:15021/healthz/ready delay=1s timeout=3s period=2s #success=1 #failure=30
    Environment:
      ...                          
      ISTIO_META_POD_PORTS:          [
                                         {"containerPort":8001,"protocol":"TCP"}
                                     ]
      ISTIO_META_APP_CONTAINERS:     liveness-http
      ISTIO_META_CLUSTER_ID:         Kubernetes
      ISTIO_META_NODE_NAME:           (v1:spec.nodeName)
      ISTIO_META_INTERCEPTION_MODE:  REDIRECT
      ISTIO_META_WORKLOAD_NAME:      liveness-http
      ISTIO_META_OWNER:              kubernetes://apis/apps/v1/namespaces/istioinaction/deployments/liveness-http
      ISTIO_META_MESH_ID:            cluster.local
      TRUST_DOMAIN:                  cluster.local
      ISTIO_KUBE_APP_PROBERS:        {"/app-health/liveness-http/livez":{"httpGet":{"path":"/foo","port":8001,"scheme":"HTTP"},"timeoutSeconds":1}}


kubectl get pod -n istioinaction -l app=liveness-http -o json | jq '.items[0].spec.containers[0].livenessProbe.httpGet'
{
  "path": "/app-health/liveness-http/livez",
  "port": 15020,
  "scheme": "HTTP"
}
  • 헬스체크 확인
  • /debug/ndsz : istiod가 NDS Name Discovery Service API로 DNS 프록시에 설정한 호스트네임들을 나열한다.
  • /debug/pprof/* : 성능 문제, 메모리 누수 등을 디버깅하는 데 도움이 되는 Go 언어 프로파일링 엔드포인트

  • 접근 확인
#
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


# D.1.2 이스티오 에이전트를 통해 이스티오 파일럿 디버그 엔드포인트들 쿼리하기

  • 에이전트는 기본적으로 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

  • 노출된 정보는 이스티오 파일럿 디버그 엔드포인트들이 노출하는 정보의 부분집합이다.
  • 또한 istioctl에 새로 추가된 istioctl x internal-debug 명령어가 동일한 엔드포인트를 노출한다.

D.2 Information exposed by the Istio Pilot

파일럿은 서비스 메시를 검사하고 디버깅하기 위한 정보들도 노출한다.

kubectl -n istio-system exec -it deploy/istiod -- netstat -tnl
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State      
tcp        0      0 127.0.0.1:9876          0.0.0.0:*               LISTEN     
tcp6       0      0 :::15017                :::*                    LISTEN     
tcp6       0      0 :::15014                :::*                    LISTEN     
tcp6       0      0 :::15012                :::*                    LISTEN     
tcp6       0      0 :::15010                :::*                    LISTEN     
tcp6       0      0 :::8080                 :::*                    LISTEN 

# pilot-discovery 프로세스 확인
kubectl -n istio-system exec -it deploy/istiod -- ss -tnlp
State          Recv-Q         Send-Q                 Local Address:Port                  Peer Address:Port         Process                                          
LISTEN         0              4096                       127.0.0.1:9876                       0.0.0.0:*             users:(("pilot-discovery",pid=1,fd=8))          
LISTEN         0              4096                               *:15017                            *:*             users:(("pilot-discovery",pid=1,fd=12))         
LISTEN         0              4096                               *:15014                            *:*             users:(("pilot-discovery",pid=1,fd=9))          
LISTEN         0              4096                               *:15012                            *:*             users:(("pilot-discovery",pid=1,fd=10))         
LISTEN         0              4096                               *:15010                            *:*             users:(("pilot-discovery",pid=1,fd=11))         
LISTEN         0              4096                               *:8080                             *:*             users:(("pilot-discovery",pid=1,fd=3)) 

#
kubectl describe pod -n istio-system -l app=istiod
...
Containers:
  discovery:
    Container ID:  containerd://f13d7ad8a32cc0cecf47392ef426ea4687ce12d1abf64b5a6d2a60c2f8934e04
    Image:         docker.io/istio/pilot:1.17.8
    Image ID:      docker.io/istio/pilot@sha256:cb9e7b1b1c7b8dcea37d5173b87c40f38a5ae7b44799adfdcf8574c57a52ad2c
    Ports:         8080/TCP, 15010/TCP, 15017/TCP
    Host Ports:    0/TCP, 0/TCP, 0/TCP
    Args:
      discovery
      --monitoringAddr=:15014
      --log_output_level=default:info
      --domain
      cluster.local
      --keepaliveMaxServerConnectionAge
      30m
    ...
    Readiness:  http-get http://:8080/ready delay=1s timeout=5s period=3s #success=1 #failure=3
    Environment:
      REVISION:                                     default
      JWT_POLICY:                                   third-party-jwt
      PILOT_CERT_PROVIDER:                          istiod
      POD_NAME:                                     istiod-8d74787f-ltkhs (v1:metadata.name)
      POD_NAMESPACE:                                istio-system (v1:metadata.namespace)
      SERVICE_ACCOUNT:                               (v1:spec.serviceAccountName)
      KUBECONFIG:                                   /var/run/secrets/remote/config
      PILOT_TRACE_SAMPLING:                         100
      PILOT_ENABLE_PROTOCOL_SNIFFING_FOR_OUTBOUND:  true
      PILOT_ENABLE_PROTOCOL_SNIFFING_FOR_INBOUND:   true
      ISTIOD_ADDR:                                  istiod.istio-system.svc:15012
      PILOT_ENABLE_ANALYSIS:                        false
      CLUSTER_ID:                                   Kubernetes
...

  • 서비스용 포트
    • 15010 : xDS API 및 인증서 발급을 평문으로 노출한다. 트래픽을 스니핑할 수 있으므로 이 포트는 사용하지 않는 것이 좋다.
    • 15012 : 15010 포트와 노출하는 정보는 같지만 보안을 적용한다. 이 포트는 TLS를 사용해 ID를 발급하여, 후속 요청은 상호 인증된다.
    • 15014 : 11장에서 다룬 것과 같은 컨트롤 플레인 메트릭을 노출한다.
    • 15017 : 쿠버네티스 API 서버가 호출하는 웹훅 서버를 노출한다.
      • 쿠버네티스 API 서버는 새로 만들어진 파드에 사이드카를 주입하고, Gateway나 VirtualServie 같은 이스티오 리소스를 검증하기 위해 호출한다.
  • 디버깅 및 검사 포트
    • 8080 : 이스티오 파일럿 디버그 엔드포인트를 노출한다.
    • 9876 : istiod 프로세스에 대한 검사 정보를 노출한다.

# D.2.1 이스티오 파일럿 디버그 엔드포인트

  • 이스티오 파일럿 디버그 엔드포인트는 파일럿이 알고 있는 전체 서비스 메시의 설정과 상태를 노출한다.

  • 엔드포인트는 다음과 같은 질문들에 답한다.

    • 프록시는 동기화됐는가?
    • 프록시에 대한 마지막 푸시는 언제 수행됐는가?
    • xDS API의 상태는 어떤가?
  • 디버그 엔드포인트 접근

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"
  },
...

디버그 엔드포인가 노출될 경우 오용될 수 있는 민감 정보가 포함돼 있다.
운영 환경에서는 이스티오를 설치할 때 환경 변수 ENABLE_DEBUG_ON_HTTP 를 false 로 설정해 디버그 엔드포인트를 비활성화를 권장한다.
이렇게 하면 해당 엔드포인트에 의존하는 도구가 제 역할을 할 수 없지만, 향후 릴리스에서는 이러한 엔드포인트가 xDS를 통해 안전하게 노출됩니다.

  • 파일럿이 알고 있는 서비스 메시 상태를 나타내는 엔드포인트
    • /debug/adsz : 클러스터, 루트, 리스너 설정
    • /debug/adsz?push=true : 이 파일럿이 관리하는 모든 프록시에 대한 푸시를 트리거한다.
    • /debug/edsz=*proxyID*=*<pod>.<namespace>* : 프록시가 알고 있는 엔드포인트들
    • /debug/authorizationz : 네임스페이스에 적용되는 인가 정책 목록
  • 파일럿이 알고 있는 데이터 플레인 설정을 나타내는 엔드포인트
    • /debug/config_distribution : 이 파일럿 인스턴스에 연결된 모든 엔보이의 버전 상태
    • /debug/config_dump?proxyID=<pod>.<namespace> : 이스티오 파일럿의 현재 알려진 상태에 따라 엔보이 설정을 생성한다.
    • /debug/syncz : 이 파일럿이 관리하는 프록시들을 표시한다.

# D.2.2 ControlZ 인터페이스

  • 이스티오 파일럿에는 파일럿 프로세스의 현재 상태와 몇 가지 사소한 설정 가능성을 확인 할 수 있는 관리자 인터페이스가 함께 제공된다.
  • 이 인터페이스는 아래 표 D.1 에서 다룬 것 처럼 파일럿 인스턴스와 관련된 정보를 빠르게 조회할 수 있다.
페이지설명
로깅 범위이 프로세스에 대한 로깅은 범위별로 구성돼 있어 범위별로 로깅 단계를 별도로 설정할 수 있다.
메모리 사용량이 정보는 Go 런타임에서 수집되며 이 프로세스의 메모리 소비량을 나타낸다.
환경 변수이 프로세스에 정의된 환경 변수 집합이다.
프로세스 정보이 프로세스에 대한 정보다.
명령줄 인수이 프로세스를 시작할 때 사용한 명령줄 인수 집합이다.
버전 정보바이너리(예: 이스티오 파일럿 1.7.3)와 Go 런타임(go 1.14.7)에 대한 정보다.
메트릭파일럿에서 노출하는 메트릭을 가져오는 방법 중 하나다.
시그널실행 중인 프로세스에 SUGUSR1 시그널을 보낼수 있다.
  • 접속 확인
kubectl -n istio-system port-forward deploy/istiod 9876

이스티오 파일럿을 디버깅 해야 할 때 로깅 범위 변경 사용 가능.

0개의 댓글