[Cilium Study] 2주차 - 1. Cilium Hubble을 통한 네트워크 관측

지난 1주 차 포스팅에서는 Cilium과 eBPF의 기본 개념을 맛보고, 복잡한 iptables의 세계에서 벗어날 수 있다는 희망을 보았습니다. 하지만 CNI를 설치하고 클러스터가 잘 동작한다고 해서 모든 것을

tech-recipe.tistory.com

 이전 Hubble 포스팅에서는 네트워크 흐름을 실시간으로 관찰하는 방법에 대해 알아보았습니다. 하지만 시스템의 상태를 지속적으로 추적하고 잠재적인 문제를 감지하기 위해서는 수치화된 데이터를 수집하고 분석하는 과정이 필수적입니다. 이것이 바로 모니터링(Monitoring) 의 영역입니다.

 이번 포스팅에서는 Cilium 환경에서 모니터링 시스템의 표준으로 자리 잡은 Prometheus(프로메테우스)Grafana(그라파나) 를 설치하고, 이를 활용하여 클러스터의 주요 메트릭을 수집하고 시각화하는 방법을 다루겠습니다.


1. 모니터링과 관측 가능성(Observability)

이미지 출처: https://cilium.io/use-cases/metrics-export/

 

시스템을 이해하는 접근 방식에는 모니터링과 관측 가능성, 두 가지 주요 개념이 있습니다.

  • 모니터링(Monitoring): CPU, 메모리 사용량과 같이 사전에 정의된 메트릭을 추적하여 시스템의 상태를 감시하고, 문제가 발생했을 때 경고를 발생시키는 활동입니다. 주로 "시스템이 다운되었는가?"와 같이 알려진 문제(Known-Unknowns) 를 감지하는 데 중점을 둡니다.
  • 관측 가능성(Observability): 로그, 메트릭, 트레이스 등 시스템이 외부로 출력하는 데이터를 통해 그 내부 상태를 추론하고, 예상치 못한 알려지지 않은 문제(Unknown-Unknowns) 의 원인을 파악하는 능력입니다. "왜 특정 요청의 지연 시간이 급증했는가?"와 같은 질문에 답할 수 있게 해줍니다.

 관측 가능성은 일반적으로 메트릭, 로그, 추적(Tracing) 이라는 세 가지 데이터를 통해 구현됩니다.

관측 가능성의 3대 요소

비교 항목 메트릭 (Metrics) 로그 (Logs) 추적 (Tracing)
정의 수치로 표현된 시계열 데이터 시스템 이벤트의 기록 단일 요청의 전체 처리 과정 추적
목적 시스템 성능 모니터링 및 경고 이벤트 분석 및 디버깅 서비스 간 호출 경로 및 병목 분석
대표 도구 Prometheus, Grafana ELK Stack, Loki Jaeger, Zipkin

2. Prometheus & Grafana 설치

 실습 환경에서는 사전 구성된 YAML 파일을 통해 Prometheus와 Grafana 스택을 간편하게 배포합니다.

Prometheus & Grafana 스택 배포

 monitoring-example.yaml 파일은 Prometheus, Grafana 및 관련 설정을 한 번에 배포합니다. 이 설정에는 Cilium 및 Hubble 대시보드가 Grafana에 자동으로 포함되는 내용이 정의되어 있습니다.

kubectl apply -f [https://raw.githubusercontent.com/cilium/cilium/1.17.6/examples/kubernetes/addons/prometheus/monitoring-example.yaml](https://raw.githubusercontent.com/cilium/cilium/1.17.6/examples/kubernetes/addons/prometheus/monitoring-example.yaml)

Cilium 및 Hubble 메트릭 활성화

 Cilium 에이전트, Operator, Hubble이 메트릭을 외부에 노출하도록 Helm 설정을 통해 활성화해야 합니다. 이 설정은 이전 실습에서 이미 완료되었습니다.

  • prometheus.enabled=true: Cilium 에이전트의 메트릭을 활성화합니다.
  • operator.prometheus.enabled=true: Cilium Operator의 메트릭을 활성화합니다.
  • hubble.metrics.enabled: Hubble의 메트릭 목록을 활성화합니다.

외부 접속을 위한 NodePort 설정

 배포된 Prometheus와 Grafana 서비스는 기본적으로 ClusterIP 타입이므로, 외부 웹 UI에서 접근하기 위해 NodePort 타입으로 변경합니다.

# Prometheus 서비스 타입을 NodePort로 변경
kubectl patch svc -n cilium-monitoring prometheus -p '{"spec": {"type": "NodePort", "ports": [{"port": 9090, "nodePort": 30001}]}}'

# Grafana 서비스 타입을 NodePort로 변경
kubectl patch svc -n cilium-monitoring grafana -p '{"spec": {"type": "NodePort", "ports": [{"port": 3000, "nodePort": 30002}]}}'

 설정 후 노드 IP와 지정된 포트(예: Prometheus - 30001, Grafana - 30002)를 통해 접속할 수 있습니다.


3. Prometheus & Grafana 사용법

Prometheus UI

 Prometheus UI는 데이터 수집 상태를 확인하고 PromQL을 테스트하는 데 유용합니다.

  • Status → Targets: Prometheus가 현재 메트릭을 수집하고 있는 대상(endpoint)들의 상태를 확인할 수 있습니다.
  • Status → Configuration: 현재 적용된 Prometheus의 설정 파일을 조회할 수 있습니다.
  • Graph: PromQL(Prometheus Query Language)을 사용해 메트릭을 직접 쿼리하고 그래프로 시각화할 수 있습니다.

Grafana UI

 Grafana는 수집된 데이터를 시각적으로 표현하는 데 사용됩니다.

  • Data Sources: Grafana가 데이터를 가져올 소스를 설정합니다. 배포된 스택에는 Prometheus가 이미 등록되어 있습니다.
  • Dashboards: Prometheus로 수집한 데이터를 시각화하는 공간입니다. monitoring-example.yaml을 통해 Cilium, Hubble 관련 대시보드가 미리 생성되어 있습니다.

4. PromQL 쿼리 예제 분석

 Grafana의 "Cilium Metrics" 대시보드에 있는 map ops 패널의 쿼리를 통해 PromQL의 동작을 이해할 수 있습니다.

예제 쿼리

topk(5, avg(rate(cilium_bpf_map_ops_total{k8s_app="cilium", pod=~"$pod"}[5m])) by (pod, map_name, operation))

단계별 분석

  1. cilium_bpf_map_ops_total{...}: cilium_bpf_map_ops_total이라는 Counter 타입 메트릭을 선택합니다.
  2. rate(...[5m]): 위 메트릭의 최근 5분간 초당 평균 증가율을 계산합니다.
  3. avg(...) by (pod, map_name, operation): 계산된 증가율을 pod, map_name, operation 레이블 기준으로 그룹화하여 평균을 계산합니다.
  4. topk(5, ...): 그룹화된 결과 중 값이 가장 큰 상위 5개를 선택하여 보여줍니다.

5. 커스텀 Grafana 대시보드 만들기

 Grafana에서는 PromQL을 사용하여 다양한 시각화 패널로 구성된 맞춤형 대시보드를 만들 수 있습니다.

패널 타입별 활용법

패널 타입 설명 예시 PromQL 쿼리
Gauge 단일 메트릭이 임계값 대비 어느 정도인지를 보여줍니다. 1 - (avg(rate(node_cpu_seconds_total{mode="idle"}[1m])) by (instance)) (노드별 CPU 사용률)
Bar chart 범주형 데이터를 막대그래프로 보여줍니다. count(kube_deployment_status_replicas_available) by (namespace) (네임스페이스별 디플로이먼트 개수)
Stat 중요한 단일 수치를 크게 표시합니다. kube_deployment_spec_replicas{deployment="nginx"} (Nginx 파드 개수)
Time series 시간에 따른 데이터 변화를 그래프로 보여줍니다. sum(rate(node_cpu_seconds_total[5m])) by (instance) (노드별 5분간 CPU 사용 변화율)
Table 데이터를 테이블 형태로 보여줍니다. node_os_info (노드 OS 정보)

6. Grafana Alerting

 Grafana를 사용하여 특정 조건이 충족되었을 때 알림을 보내도록 구성할 수 있습니다.

알림 설정 구성 요소

  • Contact points: 슬랙(Slack), 이메일 등 알림을 수신할 채널을 설정합니다.
  • Notification policy: 어떤 알림을 어떤 Contact point로 보낼지 정책을 정의합니다.
  • Alert rule: 특정 PromQL 쿼리 결과가 임계값을 넘는 등 알림을 발생시킬 조건을 생성합니다.

알림 설정 순서

  1. Contact points 설정: 알림을 받을 채널(이메일, 슬랙 등)을 구성합니다.
  2. Notification policy 정의: 알림 라우팅 규칙을 설정합니다.
  3. Alert rule 생성: 알림 발생 조건 및 임계값을 설정합니다.
  4. 테스트 및 모니터링: 설정된 알림이 정상적으로 동작하는지 확인합니다.

결론

 Prometheus와 Grafana를 통한 모니터링 시스템은 Cilium 환경에서 네트워크 성능과 보안을 효과적으로 관찰할 수 있게 해줍니다. PromQL을 활용한 메트릭 쿼리와 Grafana의 다양한 시각화 옵션을 통해 시스템의 상태를 실시간으로 파악하고, 알림 기능을 통해 문제 상황에 신속하게 대응할 수 있습니다.

 지난 포스팅에서는 Cilium과 eBPF의 기본 개념에 대해 다루었습니다. CNI가 정상적으로 배포되어 클러스터가 동작하더라도, 파드 간의 네트워크 흐름이나 적용된 정책을 직관적으로 파악하기는 어렵습니다. 이러한 내부 동작을 시각적으로 확인하고 분석하기 위해서는 별도의 관측 도구가 필요합니다.

 Cilium 환경에서 이 역할을 수행하는 것이 바로 Hubble(허블) 입니다. Hubble은 Cilium에 특화된 관측 가능성(Observability) 플랫폼으로, 이번 포스팅에서는 Hubble을 설치하고 활용하여 쿠버네티스 네트워크를 관찰하는 방법에 대해 알아보겠습니다.


1. Hubble 소개

이미지 출처: https://github.com/cilium/hubble

 Hubble은 Cilium과 eBPF를 기반으로 구축된 분산 네트워킹 및 보안 관측 플랫폼입니다. eBPF를 직접 활용하여 낮은 오버헤드로 서비스 통신, 네트워크 인프라에 대한 깊은 가시성을 제공하는 것이 핵심적인 특징입니다.

Hubble의 주요 기능

 Hubble을 통해 얻을 수 있는 주요 기능은 다음과 같습니다.

  • 서비스 의존성 및 통신 맵: 서비스 간의 통신 흐름과 의존성 그래프를 시각화하고, HTTP 호출과 같은 L7 트래픽을 확인할 수 있습니다.
  • 네트워크 모니터링 및 알림: DNS 조회 실패, TCP 연결 중단 등 네트워크 통신의 실패 여부와 원인을 파악합니다.
  • 애플리케이션 모니터링: 특정 서비스의 HTTP 4xx/5xx 응답 코드 비율이나 95/99번째 백분위수 지연 시간 등을 측정합니다.
  • 보안 관측: 네트워크 정책에 의해 차단된 연결을 확인하고, 클러스터 외부에서의 접근이나 특정 DNS 조회 이력을 추적합니다.

Hubble 구성 요소

 Hubble은 다음과 같은 주요 구성 요소로 이루어져 있습니다.

  • Hubble API: 각 노드의 Cilium 에이전트 내에서 관찰된 트래픽에 대한 인사이트를 제공합니다.
  • Hubble CLI: 로컬 유닉스 도메인 소켓을 통해 Hubble API를 쿼리하는 데 사용되는 CLI 도구입니다.
  • Hubble Relay: 클러스터 전체의 Hubble API 데이터를 집계하여 중앙화된 가시성을 제공하는 서비스입니다.
  • Hubble UI: Hubble Relay를 통해 수집된 데이터를 사용자 친화적인 서비스 맵과 필터링 기능을 갖춘 웹 인터페이스로 시각화합니다.

2. Hubble 설치 및 설정

 Cilium 설치 후, helm upgrade 또는 cilium CLI 명령을 사용하여 Hubble을 활성화할 수 있습니다.

Hubble 활성화

방법 1: helm upgrade 사용

 Hubble UI 활성화, NodePort 타입으로 서비스 노출, Prometheus 메트릭 활성화를 동시에 진행할 수 있습니다.

helm upgrade cilium cilium/cilium --namespace kube-system --reuse-values \
  --set hubble.enabled=true \
  --set hubble.relay.enabled=true \
  --set hubble.ui.enabled=true \
  --set hubble.ui.service.type=NodePort \
  --set hubble.ui.service.nodePort=31234 \
  --set prometheus.enabled=true \
  --set operator.prometheus.enabled=true \
  --set hubble.metrics.enableOpenMetrics=true \
  --set hubble.metrics.enabled="{dns,drop,tcp,flow,port-distribution,icmp,httpV2:exemplars=true;labelsContext=source_ip\,source_namespace\,source_workload\,destination_ip\,destination_namespace\,destination_workload}"

방법 2: cilium CLI 사용

 간단하게 Hubble과 UI를 활성화하는 경우 사용합니다.

cilium hubble enable --ui

Hubble UI 접속

 UI 서비스가 NodePort로 설정되면 아래 명령으로 접속 주소를 확인할 수 있습니다.

NODEIP=$(ip -4 addr show eth1 | grep -oP '(?<=inet\s)\d+(\.\d+){3}')
echo -e "http://$NODEIP:31234"

웹 브라우저로 해당 주소에 접속한 후, kube-system 네임스페이스를 선택하여 서비스 맵을 확인합니다.

Hubble CLI 사용 및 API 접근

로컬 PC에 Hubble CLI 설치

 로컬 환경에 맞는 Hubble CLI 바이너리를 다운로드하여 설치합니다.

포트 포워딩을 통한 API 접속

 로컬 머신에서 클러스터의 Hubble Relay 서비스로 포트 포워딩을 설정하여 Hubble API에 접근할 수 있습니다.

cilium hubble port-forward &

포트 포워딩 후 hubble status 명령으로 API 접근을 확인합니다.

hubble status
# Healthcheck (via localhost:4245): Ok
# Current/Max Flows: 12,285/12,285 (100.00%)
# Flows/s: 41.28

3. Hubble 활용 실습 (Star Wars 데모)

데모 애플리케이션 배포

 Star Wars 예제 애플리케이션(deathstar, tiefighter, xwing)을 배포하여 트래픽을 생성합니다.

kubectl apply -f [https://raw.githubusercontent.com/cilium/cilium/1.17.6/examples/minikube/http-sw-app.yaml](https://raw.githubusercontent.com/cilium/cilium/1.17.6/examples/minikube/http-sw-app.yaml)

L3/L4 정책 적용 및 관찰

정책 미적용 상태 확인

 초기에는 네트워크 정책이 없으므로 xwingtiefighter 모두 deathstar 서비스에 접근할 수 있습니다. hubble observe 명령으로 트래픽을 모니터링할 수 있습니다.

# xwing에서 deathstar로 호출
kubectl exec xwing -- curl -s -XPOST deathstar.default.svc.cluster.local/v1/request-landing

# tiefighter에서 deathstar로 호출
kubectl exec tiefighter -- curl -s -XPOST deathstar.default.svc.cluster.local/v1/request-landing

Hubble UI에서도 xwingtiefighterdeathstar로 연결되는 것을 확인할 수 있습니다.

L3/L4 정책 적용

 org=empire 레이블을 가진 파드만 deathstar에 접근하도록 L3/L4 CiliumNetworkPolicy를 적용합니다. 이 정책은 tiefighter의 접근은 허용하지만, xwing의 접근은 차단합니다.

# sw_l3_l4_policy.yaml
apiVersion: "cilium.io/v2"
kind: CiliumNetworkPolicy
metadata:
  name: "rule1"
spec:
  description: "L3-L4 policy to restrict deathstar access to empire ships only"
  endpointSelector:
    matchLabels:
      org: empire
      class: deathstar
  ingress:
  - fromEndpoints:
    - matchLabels:
        org: empire
    toPorts:
    - ports:
      - port: "80"
        protocol: "TCP"
```bash
# 정책 적용
kubectl apply -f https://raw.githubusercontent.com/cilium/cilium/1.17.6/examples/minikube/sw_l3_l4_policy.yaml

정책 적용 후 관찰

 다시 xwing에서 deathstar로의 접근을 시도하면 타임아웃이 발생합니다.

kubectl exec xwing -- curl -s -XPOST deathstar.default.svc.cluster.local/v1/request-landing --connect-timeout 2

 Hubble CLI로 차단된(DROPPED) 패킷을 확인할 수 있습니다.

hubble observe -f --type drop

L7 정책 적용 및 관찰

L7 정책의 필요성

 L3/L4 정책만으로는 같은 org=empire 레이블을 가진 tiefighter가 허용되지 않은 API(예: PUT /v1/exhaust-port)를 호출하는 것을 막을 수 없습니다.

L7 (HTTP) 정책 적용

 기존 정책(rule1)을 수정하여 tiefighterPOST /v1/request-landing API만 호출하도록 제한하는 L7 정책을 추가합니다.

# sw_l3_l4_l7_policy.yaml
apiVersion: "cilium.io/v2"
kind: CiliumNetworkPolicy
metadata:
  name: "rule1"
spec:
  description: "L7 policy to restrict access to specific HTTP call"
  endpointSelector:
    matchLabels:
      org: empire
      class: deathstar
  ingress:
  - fromEndpoints:
    - matchLabels:
        org: empire
    toPorts:
    - ports:
      - port: "80"
        protocol: TCP
      rules:
        http:
        - method: "POST"
          path: "/v1/request-landing"
```bash
kubectl apply -f [https://raw.githubusercontent.com/cilium/cilium/1.17.6/examples/minikube/sw_l3_l4_l7_policy.yaml](https://raw.githubusercontent.com/cilium/cilium/1.17.6/examples/minikube/sw_l3_l4_l7_policy.yaml)

정책 적용 후 관찰

 tiefighter에서 허용되지 않은 exhaust-port로의 PUT 요청을 보내면 "Access denied" 응답을 받습니다.

kubectl exec tiefighter -- curl -s -XPUT deathstar.default.svc.cluster.local/v1/exhaust-port

 Hubble에서 해당 요청이 정책에 의해 차단(DROPPED)되었음을 L7 수준에서 확인할 수 있습니다.

hubble observe -f --pod deathstar --verdict DROPPED
# ... http-request DROPPED (HTTP/1.1 PUT [http://deathstar.default.svc.cluster.local/v1/exhaust-port](http://deathstar.default.svc.cluster.local/v1/exhaust-port))

4. Hubble Exporter (흐름 로그)

 Hubble Exporter는 Hubble의 흐름(flow) 로그를 파일에 저장하는 기능입니다. 파일 로테이션, 크기 제한, 필터링을 지원합니다.

설정 및 확인

 Helm 업그레이드 시 관련 플래그를 설정하여 활성화할 수 있습니다.

# helm upgrade ...
  --set hubble.export.static.enabled=true \
  --set hubble.export.static.filePath=/var/run/cilium/hubble/events.log

 Cilium 파드 내에서 로그 파일이 정상적으로 생성되는지 확인할 수 있습니다.

kubectl -n kube-system exec ds/cilium -- tail -f /var/run/cilium/hubble/events.log | jq

성능 튜닝 및 동적 설정

 allowList, denyList, fieldMask 같은 옵션을 사용하여 저장되는 로그의 양을 조절하여 성능에 미치는 영향을 최소화할 수 있습니다. 또한, ConfigMap을 통해 Cilium 파드를 재시작하지 않고도 흐름 로그 설정을 동적으로 변경할 수 있습니다.

결론

 Hubble은 Cilium과 eBPF를 기반으로 하여 Kubernetes 클러스터의 네트워크를 효과적으로 관찰하고 정책을 적용할 수 있는 강력한 도구입니다. L3/L4부터 L7까지의 네트워크 정책을 세밀하게 제어할 수 있으며, 실시간 트래픽 모니터링과 보안 관측을 통해 클러스터의 네트워크 상태를 명확하게 파악할 수 있습니다.

+ Recent posts