GKE 네트워크 관측 가능성 문제 해결

이 문서에서는 GKE Dataplane V2 모니터링 가능성, Hubble, Cloud Monitoring을 사용하여 Google Kubernetes Engine (GKE) 클러스터의 네트워킹 문제를 진단하는 방법과 진단 절차를 설명합니다.

아키텍처 개요 및 개념적 권장사항은 네트워크 관측 가능성 권장사항을 참고하세요.

문제 해결 결정 트리 및 핵심 개념

절차를 검토하기 전에 다음 결정 매트릭스를 사용하여 GKE 네트워킹 스택의 어떤 계층에서 문제가 발생할 가능성이 있는지 파악하고 해당 섹션으로 이동하세요.

증상 또는 진단 평가 질문 의심되는 등급 권장 절차
포드가 외부 도메인 또는 내부 Kubernetes 서비스 (DNS 시간 초과, NXDOMAIN, SERVFAIL)를 확인할 수 없습니다. Tier 1: 포드 및 서비스 (DNS) DNS 변환 실패 진단하기
서비스가 통신할 수 없습니다. 포드 간 연결 시간 초과 또는 패킷 삭제 Tier 1: 포드 및 서비스 (정책 또는 패킷 손실) 패킷 손실 및 NetworkPolicy 차단 진단
워크로드 복제본의 트래픽 부하가 고르지 않거나 포드에서 높은 비율의 TCP 재설정 (RST)이 로깅됩니다. 1단계: 포드 및 서비스 (부하 분산 또는 전송) 트래픽 불균형 및 TCP 재설정 진단
노드 간 일반 지연 시간, 간헐적 시간 초과 또는 CNI 다시 시작 Tier 2: 노드 및 CNI (커널) 노드 수준 지연 시간 및 CNI 병목 현상 트리아지
포드가 GKE 외부의 리소스 (Cloud SQL, 외부 API 또는 기타 VPC)에 연결할 수 없습니다. 3단계: VPC 및 라우팅 GKE와 VPC 또는 외부 연결 문제 구분
방화벽 규칙, 경로 또는 NetworkPolicy가 트래픽을 차단하는지 확인하기 위해 자동화된 경로 시뮬레이션이 필요합니다. 3단계: VPC 및 라우팅 (시뮬레이션) 연결 테스트를 사용하여 연결 진단하기
인터넷으로 트래픽을 전송하고 NAT를 거치는 워크로드를 식별해야 합니다. 4단계: 외부 게이트웨이 및 비용 NAT 트래픽 식별 (인터넷으로의 이그레스)
영역 간 데이터 전송 비용이 높거나 SQL 쿼리를 작성하지 않고도 상위 토커를 시각화해야 합니다. 4단계: 외부 게이트웨이 및 비용 Flow Analyzer를 사용하여 클러스터 트래픽 비용 및 성능 분석하기

핵심 네트워킹 개념

Kubernetes 또는 Google Cloud 네트워킹을 처음 접하는 경우 다음 핵심 개념을 염두에 두세요.

  • eBPF (Extended Berkeley Packet Filter): Linux 커널 내에서 직접 보안 모니터링 및 라우팅 프로그램을 실행할 수 있는 운영체제 기술입니다. GKE Dataplane V2는 eBPF를 사용하여 패킷을 라우팅하고 성능 오버헤드가 최소화된 NetworkPolicy를 적용합니다.
  • IP 매스커레이딩 (SNAT): 패킷의 소스 IP 주소를 재작성하는 프로세스입니다. 비공개 IP 주소가 있는 GKE 포드가 인터넷 또는 외부 VPC 리소스와 통신할 때 GKE는 외부 시스템이 응답을 라우팅하는 방법을 알 수 있도록 포드 IP 주소를 노드 IP 주소로 마스커레이드(재작성)합니다.
  • 연결 추적 (Conntrack): 모든 활성 네트워크 연결을 추적하는 커널 기능입니다. GKE Dataplane V2 클러스터에서 이 추적은 두 테이블로 분할됩니다. 표준 Linux 커널 conntrack (ip-masq-agent에서 사용)과 eBPF 맵에 저장된 Cilium 및 GKE Dataplane V2 관리 conntrack 테이블입니다. 노드가 너무 많은 동시 연결을 처리하면 이러한 추적 테이블 중 하나가 가득 차서 (conntrack 소진) 노드가 새 패킷을 자동으로 삭제할 수 있습니다.
  • Hubble: GKE Dataplane V2의 관측 가능성 엔진입니다. eBPF 위에 실행되며 트래픽 흐름, 패킷 손실, NetworkPolicy 평가에 대한 실시간 가시성을 제공합니다.

Tier 1: 포드 및 서비스 (애플리케이션) 모니터링 가능성

포드 및 서비스 계층은 포드, 서비스, 클러스터 DNS 간의 네트워크 통신을 다룹니다. 이 계층의 문제는 일반적으로 애플리케이션 연결 시간 초과, 이름 확인 실패 또는 불균형한 부하 분산으로 나타납니다.

DNS 변환 실패 진단

DNS 문제를 해결하기 전에 진단 범위와 기본 요건을 검토하세요.

  • 중점 분야: 포드와 CoreDNS 또는 NodeLocal DNSCache 간 통신, DNS 지연 시간, 업스트림 DNS 변환 시간 초과, FQDN NetworkPolicy 유효성 검사
  • 기본 요건: GKE Dataplane V2 측정항목 사용 설정, kubectl 액세스
  • CNI 호환성: GKE Dataplane V2 (고급 데이터 경로) 및 표준 GKE CNI
  • 증상: 포드에서 dial tcp: lookup <domain>: i/o timeout, NXDOMAIN 또는 아웃바운드 API 호출의 간헐적 지연 시간이 로깅됩니다.
  • 목표: DNS 장애가 클러스터 내부(kube-dns 또는 NodeLocal DNSCache 포화)에서 발생하는지, NetworkPolicy가 UDP 또는 TCP 포트 53을 차단하는지, 아니면 업스트림 네트워크 저하로 인해 발생하는지 확인합니다.

1단계: 기본 연결 가능 여부 확인

DNS 레이어를 문제 해결하기 전에 영향을 받는 포드 내부에서 IP 주소를 사용하여 대상에 직접 연결할 수 있는지 확인합니다.

# 1. Test raw IP reachability (bypasses DNS entirely)
kubectl exec -it my-pod -n default -- curl -v --connect-timeout 5 http://10.240.0.10:8080

# 2. Test domain resolution
kubectl exec -it my-pod -n default -- curl -v --connect-timeout 5 http://my-service.default.svc.cluster.local:8080
  • IP 연결은 성공했지만 도메인이 실패한 경우: 문제는 DNS 변환 레이어에 있습니다. 2단계로 진행합니다.
  • 둘 다 실패하는 경우: 네트워크 수준 라우팅 또는 정책 적용 문제입니다. 패킷 손실 및 NetworkPolicy 차단 진단으로 이동합니다.
FQDN NetworkPolicy DNS 사전 채우기 확인

클러스터에서 FQDN 기반 NetworkPolicies (FQDNNetworkPolicy)를 사용하는 경우 도메인 이름이 명시적으로 허용되는지 확인합니다. 포드가 GKE Dataplane V2 DNS 프록시 캐시에 미리 채워지지 않았거나 정책에 의해 허용되지 않는 외부 도메인을 쿼리하는 경우 GKE Dataplane V2는 변환된 IP 주소로의 이그레스 트래픽을 차단합니다.

# Verify whether UDP or TCP port 53 egress is permitted in the Pod's namespace
kubectl get networkpolicy -n default -o yaml | grep -A 5 -B 2 "port: 53"

2단계: Cloud Monitoring에서 DNS 측정항목 확인

GKE는 kubernetes.io/networking/dns/ 접두사 아래 Cloud Monitoring에 기본 DNS 측정항목을 노출합니다.

Cloud Monitoring에서 DNS 측정항목을 확인하려면 다음을 수행하세요.

  1. Google Cloud 콘솔에서 Cloud Monitoring > 대시보드로 이동합니다.
  2. 사전 정의된 GKE DNS 관측 가능성 - 클러스터 보기 대시보드를 선택하거나 측정항목 탐색기로 이동하여 kubernetes.io/networking/dns/로 필터링합니다.
  3. 다음 기본 신호를 평가합니다 (NodeLocal DNSCache의 경우 측정항목 경로에서 kubedns를 node_local_dns로 대체).
측정항목 이름 경고 기준 근본 원인
kubernetes.io/networking/dns/kubedns/max_concurrent_rejected_request_count > 0 동시 쿼리 한도에 도달했습니다. kube-dns 또는 NodeLocal DNSCache가 쿼리를 삭제하고 있습니다.
kubernetes.io/networking/dns/kubedns/dns_request_latencies p99 > 100ms kube-dns 또는 NodeLocal DNSCache 전반에서 엔드 투 엔드 DNS 변환 지연 시간이 높습니다.
kubernetes.io/networking/dns/kubedns/forwarding_request_latencies p99 > 100ms 업스트림 DNS 서버 지연 시간 또는 포화 상태
DNS 성능 및 시간 초과 트리아지 시퀀스

다음 트리아지 순서에 따라 DNS 지연 시간, 캐시 누락, 업스트림 시간 초과를 진단하세요.

  1. 캐시 적중률 확인: cache_status 라벨로 그룹화된 kubernetes.io/networking/dns/kubedns/dns_cache_request_count (또는 node_local_dns/dns_cache_request_count) 쿼리 cache_status="hit"이 낮고 cache_status="miss"이 높으면 애플리케이션이 FQDN이 아닌 쿼리 (예: my-service.default.svc.cluster.local 대신 my-service)를 실행하여 /etc/resolv.conf의 모든 항목에서 검색 경로 순회가 발생할 수 있습니다.
  2. 업스트림 지연 시간 평가: 높은 forwarding_request_latencies는 업스트림 DNS 서버에 문제가 있음을 나타냅니다(예: Cloud Interconnect 또는 Cloud VPN을 통해 연결된 회사 온프레미스 DNS 또는 Cloud DNS 제한).
  3. 커스텀 DNS 재정의 감사: 잘못 구성된 스텁 또는 업스트림 전달을 위해 커스텀 kube-dns ConfigMap을 검사합니다.

    kubectl get configmap kube-dns -n kube-system -o yaml
    

3단계: Hubble CLI로 실시간 DNS 트래픽 스트리밍

Hubble CLI 도우미 별칭을 사용하여 노드 커널에서 스트리밍된 실시간 DNS 요청 및 응답을 검사합니다.

# 1. Ensure the helper alias is set in your terminal session
alias gke-hubble="kubectl exec -it -n gke-managed-dpv2-observability deployment/hubble-relay -c hubble-cli -- hubble"

# 2. Observe live DNS (Port 53) traffic for a specific Pod
gke-hubble observe --pod default/my-pod --port 53

4단계: 수정사항 검증

동시 쿼리 거부가 발생한 경우 NodeLocal DNSCache를 적용하여 클러스터 전체 kube-dns 한도에 도달하지 않고 노드에서 직접 고빈도 DNS 조회를 흡수합니다.

# Verify NodeLocal DNSCache DaemonSet is running
kubectl get daemonset node-local-dns -n kube-system

패킷 손실 및 NetworkPolicy 차단 진단

패킷 손실 및 정책 거부를 조사하기 전에 진단 범위와 기본 요건을 검토하세요.

  • 중점 분야: 포드 객체 간 또는 포드와 서비스 객체 간 트래픽 감소, NetworkPolicy 적용, 커널 eBPF 삭제 이유
  • 기본 요건: GKE Dataplane V2 흐름 관측 가능성이 사용 설정되어 있고 NetworkPolicy 로깅이 구성되어 있어야 합니다.
  • CNI 호환성: GKE Dataplane V2만 해당
  • 증상: 애플리케이션 연결 시도가 Connection timed out 또는 Connection reset by peer로 실패합니다.
  • 목표: 보안 정책을 시행착오로 변경하지 않고 패킷을 삭제하는 정확한 NetworkPolicy 또는 eBPF 이유를 파악합니다.

1단계: Hubble 드롭 측정항목 모니터링

GKE Dataplane V2가 패킷을 삭제하면 삭제 이유와 소스 및 대상 메타데이터로 태그가 지정된 hubble_drop_total 측정항목이 방출됩니다. Hubble 드롭 측정항목을 모니터링하려면 다음을 실행하세요.

  1. 아직 구성하지 않은 경우 Google Cloud Managed Service for Prometheus PodMonitoring 리소스를 배포하여 Hubble 측정항목을 스크래핑합니다.

    apiVersion: monitoring.googleapis.com/v1
    kind: PodMonitoring
    metadata:
      name: hubble-metrics
      namespace: gke-managed-dpv2-observability
    spec:
      selector:
        matchLabels:
          k8s-app: cilium
      endpoints:
      - port: hubble-metrics
        interval: 30s
    
  2. Cloud Monitoring > 측정항목 탐색기에서 다음 쿼리를 실행하여 이유별 삭제를 확인합니다.

    sum by (reason) (rate(hubble_drop_total[5m])) > 0
    
  3. 일반적인 reason 코드를 해석합니다.

    • Policy denied: Kubernetes NetworkPolicy가 명시적 또는 암시적으로 연결을 차단하고 있습니다.
    • CT: Map insertion failed: 연결 추적 (conntrack) 테이블이 소진되었습니다.
    • Unsupported L3 protocol: IPv4 또는 IPv6가 아닌 패킷 또는 손상된 헤더입니다.

2단계: Cloud Logging에서 NetworkPolicy 로그 확인

NetworkPolicy 로깅은 모든 정책 결정에 대해 구조화된 JSON 로그를 내보냅니다. Cloud Logging에서 NetworkPolicy 로그를 쿼리하려면 다음을 수행하세요.

  1. Google Cloud 콘솔에서 Cloud Logging > 로그 탐색기로 이동합니다.
  2. 다음 쿼리를 실행합니다.

    resource.type="k8s_node"
    log_name:"projects/PROJECT_ID/logs/events"
    jsonPayload.connection.verdict="DENY"
    jsonPayload.src.pod_name="my-source-pod"
    
  3. JSON 페이로드를 검사합니다.

    • jsonPayload.drop_reason: 패킷이 삭제된 이유를 표시합니다.
    • jsonPayload.policies: 평가된 NetworkPolicy를 나열합니다. DENY 판정과 함께 빈 목록이 반환되면 네임스페이스가 기본 거부 모드로 작동하고 트래픽을 허용하는 정책이 없습니다.

NetworkPolicy 로그가 표시되지 않으면 클러스터의 NetworkLogging 커스텀 리소스에서 로깅이 사용 설정되어 있는지 확인합니다. 예를 들어 spec.cluster.deny.log 필드가 true로 설정되어 있는지 확인합니다.

kubectl get networklogging default -o yaml

3단계: Hubble CLI로 라이브 드롭 추적하기

Hubble CLI를 사용하여 실시간 패킷을 검사하여 라이브 드롭을 직접 스트리밍합니다.

gke-hubble observe --verdict DROPPED --namespace default --follow

출력 예시:

TIMESTAMP             SOURCE               DESTINATION          TYPE     VERDICT
10:14:22.102          default/frontend     default/backend:80   to-stack DROPPED (Policy denied by NetworkPolicy: backend-deny-all)

출력은 트래픽을 차단하는 정확한 NetworkPolicy(backend-deny-all)를 나타냅니다.

4단계: conntrack 소진 확인

드롭 이유가 CT: Map insertion failed인 경우:

  1. GKE Dataplane V2 에이전트 로그에서 conntrack 테이블 포화 상태를 검사합니다.

    kubectl logs -n kube-system daemonset/anetd -c cilium-agent --tail=100 | grep "Conntrack table full"
    
  2. 영향을 받는 노드에서 conntrack 테이블의 최대 크기를 확인합니다.

    kubectl exec -it -n kube-system daemonset/anetd -c cilium-agent -- cilium status --all-controllers | grep -i conntrack
    

    conntrack 테이블이 가득 찬 경우 더 많은 노드에 워크로드를 수평 확장하거나 클라이언트 포드에서 연결률을 줄이세요.


트래픽 불균형 및 TCP 재설정 진단

트래픽 불균형 및 연결 재설정 문제를 해결하기 전에 진단 범위와 기본 요건을 검토하세요.

  • 중점 분야: 부하 분산 불균형, TCP 핸드셰이크 실패, 갑작스러운 연결 종료
  • 기본 요건: GKE Dataplane V2 측정항목이 사용 설정되어 있어야 합니다.
  • CNI 호환성: GKE Dataplane V2
  • 증상: 특정 포드 복제본이 과도한 트래픽을 수신하는 반면 다른 포드 복제본은 유휴 상태로 유지됩니다. 클라이언트 애플리케이션이 connection reset by peer 또는 broken pipe을 기록합니다.
  • 목표: 트래픽 불균형이 전송 계층 (OSI 계층 4, TCP)의 연결 지속성으로 인해 발생하는지 아니면 애플리케이션 계층 (OSI 계층 7, HTTP/2 또는 gRPC)으로 인해 발생하는지 확인하고 TCP RST 패킷의 소스를 식별합니다.

1단계: 포드 수준 트래픽 흐름 비교

트래픽이 복제본에 균등하게 분산되는지 확인하려면 다음 단계를 따르세요.

  1. Cloud Monitoring에서 배포의 모든 포드에 걸쳐 수신 트래픽 흐름 수를 쿼리합니다.

    sum by (pod) (rate(pod_flow_ingress_flows_count{destination_workload="my-service"}[5m]))
    
  2. 포드 간 트래픽 분산을 평가합니다. 단일 포드가 대부분의 트래픽을 수신하는 경우 연결 재사용 또는 고정 세션을 조사합니다.

    • gRPC 또는 HTTP/2: 장기 TCP 연결로 인해 모든 요청이 하나의 TCP 스트림을 통해 하나의 백엔드 포드로 이동합니다. 전송 계층(OSI 계층 4, TCP) Kubernetes 서비스 라우팅은 설정된 HTTP/2 연결 내에서 요청을 분산할 수 없습니다.
    • ClientIP 세션 어피니티: 서비스가 sessionAffinity: ClientIP로 구성되어 있는지 확인합니다.
    • 헤드리스 서비스: 클라이언트는 DNS를 한 번 변환하고 단일 IP 주소를 영구적으로 캐시할 수 있습니다.

2단계: TCP 재설정 측정항목 분석

TCP 재설정 (RST)은 연결을 즉시 종료합니다. 엔드포인트가 알 수 없는 포트의 패킷을 수신하거나 애플리케이션이 버퍼에 읽지 않은 데이터가 있는 연결을 닫을 때 운영체제 커널에 의해 방출됩니다.

Cloud Monitoring에서 다음 MQL 쿼리를 실행합니다.

fetch prometheus_target
| metric 'prometheus.googleapis.com/hubble_tcp_flags_total/counter'
| filter (metric.flag == 'RST')
| align rate(1m)
| every 1m
| group_by [metric.source, metric.destination, metric.traffic_direction], sum(val())

쿼리 결과를 검토하여 재설정의 소스를 확인합니다.

  • 나가는 RST (traffic_direction=egress): 로컬 포드가 재설정을 생성합니다. 포드 애플리케이션이 비정상 종료되거나 연결 제한에 도달하거나 연결을 적극적으로 거부하는지 확인합니다.
  • 수신 RST (traffic_direction=ingress): 원격 피어 (외부 데이터베이스, API 또는 원격 포드)가 재설정을 전송했습니다. 대상 서버 상태 및 방화벽 상태를 확인합니다.

3단계: TCP 재설정을 라이브 스트리밍

Hubble CLI를 사용하여 실시간 재설정 핸드셰이크를 캡처합니다.

gke-hubble observe --type trace --verdict FORWARDED --tcp-flags RST --namespace default

4단계: 해결 및 실행 가능한 수정사항

트래픽 불균형 또는 TCP 재설정의 원인에 따라 다음 해결 단계를 적용하세요.

  • 애플리케이션 레이어 (OSI 레이어 7) 또는 gRPC 연결 지속성의 경우:
    • 애플리케이션 계층 (OSI 계층 7) 요청 수준 부하 분산을 사용 설정하려면 Cloud Service Mesh를 배포하세요.
    • 주기적인 연결 재설정을 강제하도록 클라이언트 측 연결 제한 또는 연결 유지 제한 시간 (예: gRPC MAX_CONNECTION_AGE 및 MAX_CONNECTION_AGE_GRACE)을 구성합니다.
  • 서비스 IP 어피니티: 애플리케이션 상태에 엄격하게 필요한 경우가 아니면 service.spec.sessionAffinity를 삭제합니다.
  • 헤드리스 서비스 DNS 캐싱: 애플리케이션 런타임 (예: JVM networkaddress.cache.ttl)이 DNS 결과를 무기한 캐시하지 않도록 합니다.
  • 애플리케이션 백로그 큐 오버플로: 애플리케이션 수신 대기 큐가 가득 차면 Linux 커널은 수신되는 SYN 패킷을 삭제하거나 TCP RST를 전송합니다. 포드 복제본을 수평 확장하거나 애플리케이션 수신 백로그(somaxconn)를 늘립니다.

Tier 2: 노드 및 CNI (커널) 모니터링 가능성

노드 및 CNI 계층에는 호스트 Linux 커널, eBPF 프로그램, 노드 네트워크 인터페이스가 포함됩니다. 이 계층의 병목 현상은 영향을 받는 노드에서 실행되는 모든 워크로드에 영향을 미칩니다.

시스템 무결성 검사: anetd의 무단 패치 감지

GKE Dataplane V2는 kube-system 네임스페이스에서 관리형 DaemonSet (anetd)으로 실행됩니다. Cloud Logging에서 Kubernetes 감사 로그를 쿼리하여 승인되지 않은 사용자 또는 자동화된 스크립트가 anetd를 패치하거나 다시 시작했는지 감지할 수 있습니다.

protoPayload.methodName="io.k8s.core.v1.daemonsets.patch" OR
protoPayload.methodName="io.k8s.core.v1.daemonsets.update"
protoPayload.resourceName="namespaces/kube-system/daemonsets/anetd"

승인되지 않은 패치가 감지되면 DaemonSet을 기본 구성으로 되돌리거나 노드 풀 재생성을 트리거하여 관리 상태를 복원하세요.


노드 수준 지연 시간 및 CNI 병목 현상 분류

노드 수준 지연 시간과 커널 병목 현상을 진단하기 전에 진단 범위와 기본 요건을 검토하세요.

  • 중점 분야: 호스트 커널 지연 시간, VM 인터페이스의 패킷 손실, GKE Dataplane V2 eBPF 에이전트 포화, conntrack 소진
  • 기본 요건: Compute Engine VM 측정항목 사용 설정, kubectl 액세스
  • CNI 호환성: GKE Dataplane V2 및 표준 GKE CNI
  • 증상: 크로스 노드 트래픽에 지연 시간 급증 또는 무작위 드롭이 발생하지만 인트라 노드 트래픽은 정상입니다.
  • 목표: 호스트 VM 네트워크 제한, Linux 커널 삭제, CNI 수준 병목 현상을 구분합니다.

1단계: GKE 외부 문제와 GKE 내부 문제 구분

Compute Engine VM 기준 테스트 실행: GKE 클러스터 노드와 동일한 VPC 서브넷에 독립형 Compute Engine VM을 배포합니다. VM에서 대상 대상으로의 연결을 테스트합니다.

  • 독립형 VM에서 동일한 패킷 손실 또는 지연 시간이 발생하는 경우: 문제는 GKE 외부 (VPC 방화벽, Cloud NAT, Cloud Interconnect 또는 외부 서버)에 있습니다. GKE와 VPC 또는 외부 연결 문제 격리로 진행합니다.
  • 독립형 VM이 정상적으로 통신하지만 GKE 포드가 실패하는 경우: 문제는 GKE (노드 수준 eBPF, conntrack 또는 CNI) 내에 있습니다. 2단계로 진행합니다.

2단계: 애플리케이션 문제와 노드 및 CNI 계층 문제 구분

지연 시간이 애플리케이션에서 발생하는지 아니면 노드 및 CNI 계층에서 발생하는지 확인하려면 다음을 실행하세요.

  1. 애플리케이션 리소스 포화도 확인: 노드에서 CPU 제한 또는 메모리 압력이 발생하지 않아 사용자 공간에서 패킷 처리가 지연되지 않는지 확인합니다.

    kubectl top nodes
    kubectl top pods -n default
    
  2. Linux 커널 conntrack 수 검사: 호스트에서 활성 conntrack 수를 확인합니다.

    # On a node where you have debugging access
    cat /proc/sys/net/netfilter/nf_conntrack_count
    cat /proc/sys/net/netfilter/nf_conntrack_max
    

    nf_conntrack_count가 nf_conntrack_max에 가까워지면 호스트 커널이 새 TCP SYN 패킷을 삭제합니다.

3단계: Compute Engine 원격 분석을 사용하여 VM 수준 패킷 손실 확인

Google Cloud Compute Engine은 VM 수준 네트워크 인터페이스 측정항목을 Cloud Monitoring으로 내보냅니다.

Cloud Monitoring > 측정항목 탐색기에서 다음을 쿼리합니다.

sum by (drop_reason) (rate(compute_googleapis_com:instance_network_dropped_packets_count[5m]))
  • FQ_CODEL_DROP: 공정 대기열 또는 CoDel 대기열 포화로 인해 패킷이 삭제되었습니다 (VM 출구 대역폭 한도 초과).
  • FIREWALL_RULE_DROP: VPC 방화벽 규칙에 의해 삭제된 패킷입니다.
  • RATE_LIMIT_DROP: VM이 네트워크 인터페이스의 초당 최대 패킷 수 (PPS) 할당량을 초과하여 패킷이 삭제되었습니다.

4단계: eBPF를 사용하여 커널 수준 삭제 조사

VM 수준 측정항목에 손실이 0으로 표시되지만 GKE 포드에서 여전히 패킷이 손실되는 경우 eBPF 맵 손실에 대해 GKE Dataplane V2 에이전트 (anetd)를 검사합니다.

kubectl logs -n kube-system daemonset/anetd -c cilium-agent --tail=200 | grep -i "drop"

ct-map-insertion-failed 또는 fib-lookup-failed를 찾습니다.


3단계: VPC 및 라우팅 (클라우드 네트워크) 관측 가능성

VPC 및 클라우드 라우팅 계층은 GKE 노드를 다른 Google Cloud 서비스, 온프레미스 네트워크, 인터넷에 연결합니다. 여기서 발생하는 오류는 일반적으로 VPC 방화벽 규칙, 맞춤 경로 또는 게이트웨이 구성에서 비롯됩니다.

GKE와 VPC 또는 외부 연결 문제 구분

클러스터 내 장애에서 외부 네트워크 문제를 격리하기 전에 진단 범위와 기본 요건을 검토하세요.

  • 중점 분야: Kubernetes 내부 라우팅과 VPC 클라우드 라우팅 간의 경계 격리
  • 기본 요건: gcloud CLI, 연결 테스트를 만들 권한
  • CNI 호환성: 모든 클러스터
  • 증상: 포드가 외부 리소스 (예: Cloud SQL, 온프레미스 API 또는 서드 파티 엔드포인트)에 연결되지 않습니다.
  • 목표: GKE 노드 내에서 또는 Google Cloud VPC 또는 외부 네트워크 내에서 드롭이 발생하는지 신속하게 확인합니다.

1단계: Compute Engine VM 기준 테스트

기준 VM을 배포하고 GKE 외부에서 문제가 지속되는지 평가하려면 다음을 수행하세요.

  1. GKE 노드 풀과 동일한 VPC 서브넷 및 영역에 임시 Compute Engine VM 인스턴스를 배포합니다.

    gcloud compute instances create gke-baseline-tester \
        --zone=us-central1-a \
        --subnet=gke-subnet \
        --machine-type=e2-micro
    
  2. SSH를 사용하여 인스턴스에 연결하고 대상과의 연결을 테스트합니다.

    curl -v --connect-timeout 5 https://api.example.com
    
  3. 결과 평가:

    • Compute Engine VM에 연결할 수 없는 경우: VPC 또는 외부 네트워크 (방화벽 규칙, 라우팅 테이블, Cloud NAT IP 소진 또는 외부 IP 화이트리스트)에 문제가 있습니다.
    • Compute Engine VM이 성공적으로 연결되는 경우: 문제는 GKE 내부에 있습니다 (NetworkPolicy가 이그레스를 차단하거나, 마스커레이드되지 않은 포드 CIDR 또는 컨테이너 수준 DNS).

2단계: 주문형 연결 테스트 실행

노드 VM에서 대상으로 Google Cloud 연결 테스트를 실행합니다.

gcloud network-management connectivity-tests create test-node-to-dest \
    --source-instance=projects/PROJECT_ID/zones/us-central1-a/instances/gke-baseline-tester \
    --destination-ip-address=203.0.113.10 \
    --destination-port=443 \
    --protocol=TCP

Google Cloud 콘솔에서 결과를 확인하여 VPC 방화벽 규칙 또는 경로가 트래픽을 삭제하는지 확인합니다.


연결 테스트를 사용하여 연결 진단

연결 테스트는 실제 트래픽을 전송하지 않고 GKE 및 VPC 리소스 간의 패킷 경로를 시뮬레이션합니다. 이 시뮬레이션에서는 서비스 ClusterIP-to-Pod DNAT 변환, GKE Dataplane V2 NetworkPolicy 인그레스 및 이그레스 규칙, 노드 IP 마스커레이딩 (SNAT)을 평가합니다. 자동 경로 시뮬레이션을 실행하기 전에 진단 범위와 필수 요건을 검토하세요.

  • 중점 분야: GKE 포드, 서비스, NetworkPolicies, VPC 경로의 자동화된 정적 경로 시뮬레이션
  • 기본 요건: Network Intelligence Center 사용 설정, Network Management API 사용 설정
  • CNI 호환성: GKE Dataplane V2 (향상된 분석)
  • 증상: 수동 검사 시 모든 구성이 유효한 것으로 표시되지만 연결이 설명 없이 끊깁니다.
  • 목표: Pod 소스에서 대상으로의 전체 패킷 경로를 정적으로 시뮬레이션하고 추적하여 삭제를 유발하는 정확한 정책 줄을 식별합니다.

시나리오 A: GKE NetworkPolicy가 측정항목 수집을 차단하는지 확인

보안 네임스페이스의 포드에서 측정항목을 스크래핑할 때 Google Cloud Managed Service for Prometheus 수집기가 기본 거부 NetworkPolicy에 의해 차단될 수 있습니다.

gcloud network-management connectivity-tests create test-gmp-to-pod \
    --source-ip-address=10.0.0.15 \
    --destination-gke-pod=projects/PROJECT_ID/locations/LOCATION/clusters/CLUSTER_NAME/k8s/namespaces/prod/pods/backend-pod \
    --destination-port=8080 \
    --protocol=TCP

Google Cloud 콘솔에서 테스트 트레이스를 검사합니다. GKE Network Policy evaluation 단계에서 DROP로 테스트가 종료되면 수집기 포드의 트래픽을 허용하는 인그레스 규칙을 추가해야 합니다.

시나리오 B: GKE 서비스에 대한 연결 가능 여부 확인

클라이언트 VM에서 내부 Kubernetes 서비스로의 연결 가능성을 시뮬레이션합니다.

gcloud network-management connectivity-tests create test-vm-to-service \
    --source-instance=projects/PROJECT_ID/zones/us-central1-a/instances/client-vm \
    --destination-ip-address=10.96.0.100 \
    --destination-port=80 \
    --protocol=TCP

시뮬레이션된 트레이스에는 다음이 표시됩니다.

  1. VPC 경로 일치
  2. VPC 방화벽 이그레스 및 인그레스 허용
  3. GKE 노드에 도착
  4. 백엔드 포드 IP 주소에 대한 서비스 DNAT
  5. 백엔드 포드에서 인그레스 NetworkPolicy 평가

시나리오 C: 포드-인터넷 이그레스 문제 진단

포드가 인터넷의 외부 API에 연결할 수 없는 경우:

  1. 포드에서 외부 공개 IP 주소 (예: 8.8.8.8)로 테스트를 만듭니다.

    gcloud network-management connectivity-tests create test-pod-to-internet \
        --source-gke-pod=projects/PROJECT_ID/locations/LOCATION/clusters/CLUSTER_NAME/k8s/namespaces/prod/pods/app-pod \
        --destination-ip-address=8.8.8.8 \
        --destination-port=53 \
        --protocol=UDP
    
  2. 드롭 지점을 검사합니다.

    • NetworkPolicy에서 삭제됨: 포드에 0.0.0.0/0로의 트래픽을 허용하는 이그레스 NetworkPolicy가 없습니다.
    • VPC 방화벽에서 삭제됨: VPC 방화벽 규칙이 노드 서브넷에서 나가는 트래픽을 거부합니다.
    • Cloud NAT 또는 경로에서 삭제됨: 서브넷에 인터넷 게이트웨이로 연결되는 기본 경로가 없거나 서브넷에 Cloud NAT가 구성되어 있지 않습니다.

4단계: 외부 게이트웨이 및 비용 (인터넷 및 NAT) 관측 가능성

외부 게이트웨이 계층은 Cloud NAT 또는 외부 게이트웨이를 통해 공개 인터넷 대상으로의 아웃바운드 트래픽을 관리합니다. 이 등급의 관측 가능성을 통해 이그레스가 많은 워크로드를 식별하고 데이터 전송 비용을 제어할 수 있습니다.

NAT 트래픽 식별 (인터넷으로의 이그레스)

아웃바운드 인터넷 및 NAT 트래픽을 분석하기 전에 진단 범위와 기본 요건을 검토하세요.

  • 중점 분야: 아웃바운드 인터넷 트래픽, Cloud NAT 포트 사용률, 외부 데이터 전송 비용
  • 기본 요건: GKE Dataplane V2 흐름 관측 가능성이 사용 설정되어 있어야 합니다.
  • CNI 호환성: GKE Dataplane V2
  • 증상: Cloud NAT 포트 소진 오류 또는 예기치 않게 높은 아웃바운드 인터넷 이그레스 비용
  • 목표: 외부 인터넷 엔드포인트로 트래픽을 전송하는 특정 GKE 포드 및 서비스 객체를 식별합니다.

1단계: GKE Dataplane V2의 'to-stack' 및 'world' 개념 이해

GKE Dataplane V2의 경우:

  • world: GKE 클러스터 외부 및 VPC 외부 (공용 인터넷)의 모든 대상을 나타냅니다.
  • to-stack: eBPF 컨테이너 veth 인터페이스에서 호스트 Linux 네트워킹 스택으로 전환되는 패킷을 나타내며, Cloud NAT에 도달하기 전에 IP 마스커레이드(SNAT)를 거칩니다.

2단계: Hubble CLI로 NAT 트래픽 스트리밍 및 필터링

클러스터에서 시작되는 아웃바운드 인터넷 흐름을 실시간으로 스트리밍합니다.

# Stream egress flows heading to external internet ("world")
gke-hubble observe \
    --traffic-direction egress \
    --verdict FORWARDED \
    --to-identity world \
    --follow

출력 예시:

TIMESTAMP             SOURCE               DESTINATION          TYPE     VERDICT
10:25:01.120          default/worker-pod   142.250.190.46:443   to-stack FORWARDED

상위 아웃바운드 토커를 식별하려면 Hubble JSON 출력을 jq에 파이프하여 포드별 외부 이그레스 흐름을 집계하면 됩니다.

timeout 60s gke-hubble observe \
    --traffic-direction egress \
    --verdict FORWARDED \
    --to-identity world \
    -o json | jq -r '.flow.source.namespace + "/" + .flow.source.pod_name' | sort | uniq -c | sort -nr | head -n 10

3단계: 측정항목을 사용하여 외부 트래픽 모니터링하기

Cloud Monitoring에서 외부 흐름의 양을 추적합니다.

fetch prometheus_target
| metric 'prometheus.googleapis.com/pod_flow_egress_flows_count/counter'
| filter (metric.destination_identity == 'world')
| align rate(1m)
| every 1m
| group_by [metric.source_workload, metric.source_namespace], sum(val())

Flow Analyzer를 사용하여 클러스터 트래픽 비용 및 성능 분석

트래픽 흐름과 교차 영역 비용을 시각화하기 전에 진단 범위와 기본 요건을 검토하세요.

  • 중점 분야: 교차 영역 데이터 전송 비용, 상위 토커, SQL 쿼리 없이 노드 간 트래픽 가시성
  • 기본 요건: INCLUDE_ALL_METADATA로 VPC 흐름 로그 사용 설정, 노드 내 가시성 사용 설정, 로그 버킷에서 모니터링 가능성 분석 사용 설정
  • CNI 호환성: 모든 클러스터
  • 증상: 월별Google Cloud 청구서에 영역 간 데이터 전송 요금이 높게 청구됩니다.
  • 목표: 원시 로그를 쿼리하지 않고 교차 영역 트래픽을 생성하는 GKE 워크로드를 시각적으로 식별하고 배치를 최적화합니다.

기본 요건

GKE에 Flow Analyzer를 사용하려면 다음 단계를 따르세요.

  1. VPC 흐름 로그: metadata="INCLUDE_ALL_METADATA"를 사용하여 클러스터 서브넷에서 사용 설정해야 합니다.
  2. 노드 내 가시성: 포드 간 트래픽이 VPC 흐름 로깅 파이프라인에 노출되도록 클러스터에서 사용 설정해야 합니다.
  3. 로그 애널리틱스: Cloud Logging의 _Default 버킷을 모니터링 가능성 분석을 사용하도록 업그레이드해야 합니다.

1단계: Flow Analyzer에서 GKE 상위 소비자 식별

Flow Analyzer에서 대량 워크로드를 보려면 다음 단계를 따르세요.

  1. Google Cloud 콘솔에서 Flow Analyzer 페이지로 이동합니다.
  2. 소스 버킷을 클릭하고 흐름 로그가 포함된 로그 버킷을 선택합니다. 다른 곳으로 라우팅하지 않은 경우 이 버킷은 _Default 버킷입니다.
  3. 트래픽 집계에서 소스 - 대상을 선택합니다.
  4. 분석 기간을 설정합니다.
  5. 흐름 기준에서 GKE 포드 또는 워크로드 필드를 선택합니다.
  6. 새 쿼리 실행을 클릭합니다. 최고 데이터 흐름 차트에는 가장 많은 데이터를 이동하는 워크로드가 표시됩니다.

2단계: 영역 간 트래픽 비용 분석

교차 영역 트래픽에는 데이터 전송 요금이 부과됩니다. 영역 간에 전송되는 워크로드를 찾으려면 다음 단계를 따르세요.

  1. 흐름 정리 기준에서 소스 영역 및 대상 영역 필드를 선택합니다.
  2. 새 쿼리 실행을 클릭하고 모든 데이터 흐름 테이블을 읽습니다. 소스 영역과 대상 영역이 다른 행이 교차 영역 트래픽입니다. Flow Analyzer 필터는 값과 일치하므로 '같지 않음'을 기준으로 필터링할 수 없습니다. 대신 결과에서 영역 쌍을 비교하세요.
  3. 트래픽이 많은 영역 쌍을 펼쳐 기본 소스 및 대상 GKE 워크로드를 확인합니다.

해결:

  • Kubernetes topologySpreadConstraints 또는 podAffinity를 구현하여 통신하는 서비스를 동일한 가용성 존에 공동 배치합니다.
  • 트래픽이 시작 영역 내에 유지되도록 서비스에서 토폴로지 인식 라우팅 (service.kubernetes.io/topology-mode: Auto)을 사용 설정합니다.

3단계: 모니터링 가능성 분석으로 드릴다운 (고급 SQL 쿼리의 경우)

Flow Analyzer에서 로그 애널리틱스에서 보기를 클릭하여 흐름 데이터에 대해 SQL 쿼리를 실행합니다.

다음 SQL 쿼리는 상위 교차 영역 Pod talker를 계산합니다.

SELECT
  JSON_VALUE(json_payload.src_gke_details.pod.workload.workload_name) AS src_workload,
  JSON_VALUE(json_payload.dest_gke_details.pod.workload.workload_name) AS dest_workload,
  JSON_VALUE(json_payload.src_instance.zone) AS src_zone,
  JSON_VALUE(json_payload.dest_instance.zone) AS dest_zone,
  SUM(CAST(JSON_VALUE(json_payload.bytes_sent) AS INT64)) / 1024 / 1024 / 1024 AS total_gb_sent
FROM
  `PROJECT_ID.global._Default._AllLogs`
WHERE
  log_name LIKE '%vpc_flows%'
  AND timestamp >= TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 7 DAY)
  AND JSON_VALUE(json_payload.src_instance.zone) != JSON_VALUE(json_payload.dest_instance.zone)
GROUP BY
  1, 2, 3, 4
ORDER BY
  total_gb_sent DESC
LIMIT 20;

Hubble CLI 참조 및 쿼리 요약본

Hubble CLI는 GKE Dataplane V2 커널 링 버퍼에서 직접 실시간 네트워크 흐름 데이터를 스트리밍하고 필터링합니다.

설정: 도우미 별칭 만들기

Hubble은 클러스터 컨트롤 플레인 내에서 실행되므로 로컬 바이너리를 배포하지 않고 Hubble 명령어를 실행하도록 셸 별칭을 구성합니다.

alias gke-hubble="kubectl exec -it -n gke-managed-dpv2-observability deployment/hubble-relay -c hubble-cli -- hubble"

일반적인 필터링 레시피

목표 문제 해결 Hubble CLI 명령어
클러스터 전체에서 손실된 모든 패킷을 실시간으로 관찰 gke-hubble observe --verdict DROPPED --follow
네임스페이스에 관계없이 특정 포드의 모든 트래픽 스트리밍 gke-hubble observe --pod default/my-pod --follow
두 특정 네임스페이스 간 트래픽 필터링 gke-hubble observe --from-namespace frontend --to-namespace backend
특정 포트 (예: 포트 80)의 트래픽 격리 gke-hubble observe --port 80
실시간 DNS 쿼리 및 응답 검사 gke-hubble observe --port 53
실시간 TCP 재설정 (RST 패킷) 보기 gke-hubble observe --type trace --verdict FORWARDED --tcp-flags RST
공개 인터넷으로 향하는 모든 아웃바운드 트래픽 스트리밍 gke-hubble observe --traffic-direction egress --to-identity world
HTTP 애플리케이션 계층 (OSI 계층 7) 트래픽 검사 gke-hubble observe --protocol http

부정을 사용한 고급 필터링 (--not)

알려진 대량 트래픽 또는 정상 트래픽을 제외하여 이상치에 집중할 수 있습니다.

# Observe drops, but exclude internal kube-system health probes and DNS
gke-hubble observe \
    --verdict DROPPED \
    --not --namespace kube-system \
    --not --port 53

출력 형식 및 jq 통합

프로그래매틱 방식으로 흐름 레코드를 처리하려면 JSON 형식으로 출력하세요.

# Extract only source, destination, and drop reason from the last 100 flows
gke-hubble observe --verdict DROPPED -o json --last 100 | \
    jq -r '[.time, .flow.source.pod_name, .flow.destination.pod_name, .flow.drop_reason_desc] | @tsv'

제한사항

실시간 문제 해결을 위해 Hubble CLI를 사용할 때는 다음 기술적 제한사항에 유의하세요.

  • 임시 노드 로컬 링 버퍼: Hubble 흐름은 각 개별 노드의 메모리 내 링 버퍼에 저장됩니다. 트래픽이 많은 이벤트 중에는 오래된 흐름 로그가 몇 초 내에 덮어쓰여집니다. 과거 데이터 분석의 경우 Cloud Logging의 NetworkPolicy 로깅 및 VPC 흐름 로그를 사용하세요.
  • 내장된 논리적 OR 없음: Hubble CLI 플래그는 논리적 AND를 사용하여 여러 인수를 평가합니다. 포트 80 또는 포트 443과 같은 여러 조건을 검색하려면 별도의 명령어를 실행하거나 jq를 사용하여 JSON 출력을 필터링하세요.

다음 단계