본문 바로가기
Work/개발 노트

[Cilium study] 2주차 - Observability

by ★용호★ 2025. 7. 26.

들어가기 전 실습 환경 구성

  • 기본 배포 가상 머신 : k8s-ctr, k8s-w1, k8s-w2
  • 초기 프로비저닝으로 kubeadm init 과 join 실행됨
  • Cilium CNI 설치 상태로 배포 완료됨

Cilium을 설치 할 때 endpointHealthChecking.enabled 옵션을 통해 헬스체크 활성 여부를 선택할 수 있는데, 3~10대의 노드로 유지할 때는 헬스체크를 켜놓는 것이 유리하지만 11대 이상으로 노드 수가 많아질 경우에는 헬스 체크를 비활성화 하는 것을 권장합니다. 이는 아래 Cilium의 Scalability Report 문서에 명시되어 있으며, 노드 수가 10대를 넘어가는 경우 별도의 전문 모니터링 도구를 활용하는 것을 권장합니다. 

--set endpointHealthChecking.enabled=false and --set healthChecking=false disable endpoint health checking entirely. However it is recommended that those features be enabled initially on a smaller cluster (3-10 nodes) where it can be used to detect potential packet loss due to firewall rules or hypervisor settings.

참고 : https://docs.cilium.io/en/stable/operations/performance/scalability/report/

 

실습 환경 배포

mkdir cilium-lab && cd cilium-lab

curl -O https://raw.githubusercontent.com/gasida/vagrant-lab/refs/heads/main/cilium-study/2w/Vagrantfile

vagrant up

 

# 클러스터 관련 명령어는 k8s-ctr에서 실행
vagrant ssh k8s-ctr
vagrant ssh k8s-w1
vagrant ssh k8s-w2

#
ifconfig | grep -iEA1 'eth[0-9]:'

# 클러스터 정보 확인
kubectl cluster-info

# cilium 상태 확인
which cilium
cilium status
cilium config view
kubectl get cm -n kube-system cilium-config -o json | jq

 

 

Hubble

Hubble은 Kubernetes 환경에서 네트워크와 보안 가시성을 제공하는 플랫폼입니다. Cilium과 eBPF(Extended Berkeley Packet Filter) 위에 구축되어, 서비스 간 통신과 네트워크 인프라의 동작을 투명하게 관찰할 수 있게 합니다. 특별히 서비스 의존성, 통신 지도, 네트워크/애플리케이션 모니터링, 보안 이벤트까지 다양한 정보를 실시간으로 확인할 수 있습니다. 아래는 Hubble의 주요 특징들 입니다. 

  • 서비스 간 통신 맵 시각화
    어떤 서비스들이 서로 통신하는지, 그 빈도와 의존성을 시각적으로 파악할 수 있습니다.
  • 네트워크 모니터링 및 알림
    네트워크 통신이 실패하는 경우(예: DNS 오류, TCP/HTTP 문제 등) 원인을 분석하고, 최근 발생한 오류, TCP SYNC 요청 미응답률 등 상세한 네트워크 상태를 실시간으로 모니터링할 수 있습니다.
  • 애플리케이션 레벨 모니터링
    서비스별 또는 전체 클러스터 내에서 HTTP 4xx/5xx 에러 비율, 95·99 퍼센트 응답 지연(latency), 서비스별 패턴 분석이 가능합니다.
  • 보안 관점 가시성
    네트워크 정책에 의해 차단된 연결, 외부로부터 접근한 서비스, 특정 DNS 이름을 해석한 서비스 목록 등 보안 이벤트를 확인할 수 있습니다.

Hubble은 API를 제공하며 기본적으로 Cilium 에이전트가 실행되는 개별 노드의 범위 내에서 작동합니다. 이는 로컬 Cilium 에이전트가 관찰한 트래픽에 대한 네트워크 인사이트를 제한합니다. 즉, 노드가 3개라면 각 노드 마다 Hubble API를 요청해서 노드별 지표를 수집해야하는 제약이 존재합니다. 이를 해소하기 위한 방법은 Hubble Relay를 사용하는 것입니다. 

Hubble Relay를 배포하면 클러스터 메시 시나리오에서 전체 클러스터 또는 여러 클러스터에 대한 네트워크 가시성이 제공됩니다. 이 모드에서는 Hubble CLI를 Hubble Relay 서비스로 안내하거나 Hubble UI를 통해 Hubble 데이터에 액세스할 수 있습니다. Hubble UI는 웹 인터페이스로, L3/L4 및 심지어 L7 계층에서 서비스 종속성 그래프를 자동으로 검색할 수 있게 하여 사용자 친화적인 시각화 및 서비스 맵으로서의 데이터 흐름 필터링을 가능하게 합니다.

Hubble의 동작 방식

  • eBPF 활용
    Hubble은 eBPF의 동적·프로그래머블 특성을 활용해, 커널 수준에서 데이터 플레인 이벤트를 가볍게 수집합니다. 모든 데이터 수집·가공 과정이 커널 내에서 이루어지므로 오버헤드가 낮고, 필요에 따라 세밀하게 관찰 대상을 조정할 수 있습니다.
  • 완전한 분산 방식
    Hubble은 클러스터 내 여러 노드에 분산된 구조로 동작해, 장애 시에도 가용성과 확장성이 뛰어납니다.

Hubble 설치

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 hubble.export.static.enabled=true \
--set hubble.export.static.filePath=/var/run/cilium/hubble/events.log \
--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\,traffic_direction}"

 

기존 설정은 유지한채 hubble을 위한 추가 설정을 셋팅합니다. hubble을 활성화하면서 relay와 ui도 활성화를 하고, 로깅과 메트릭에 대한 부분도 추가로 설정합니다. 그러면 아래와 같이 Hubble Relay가 활성화 된 것을 확인할 수 있습니다. 

 

Hubble을 활성화 한 후 변화된 리스닝 포트 정보를 확인해보면 아래와 같습니다. 

ss -tnlp ❘ grep -iE 'cilium❘hubble'

4244, 9962, 9965 포트가 새로 추가 된 것을 확인할 수 있습니다. Hubble relay는 각 노드의 4244 포트(hubble-peer)를 통해 지표를 수집합니다. 

 

Hubble UI는 nginx를 통해 제공되며, 앞서 Hubble을 활성화할 때 지정한 NodePort를 통해 접근할 수 있습니다. 

터미널에서는 hubble observe -f 명령으로 지표들을 실시간으로 확인할 수 있습니다. 

hubble observe -f

Hubble 실습

실습에는 Hubble 공식 사이트에서 제공하는 StarWars 데모 애플리케이션을 활용합니다. 

  • 스타워즈에서 영감을 받은 예제에서는 데스스타, 타이파이터, 엑스윙의 세 가지 마이크로서비스 애플리케이션이 있습니다.
  • 데스스타는 포트 80에서 HTTP 웹서비스를 실행하며, 이 서비스는 두 개의 포드 복제본에 걸쳐 데스스타에 대한 요청을 로드 밸런싱하는 Kubernetes 서비스로 노출됩니다.
  • 데스스타 서비스는 제국의 우주선에 착륙 서비스를 제공하여 착륙 포트를 요청할 수 있도록 합니다.
  • 타이파이터 포드는 일반적인 제국 선박의 착륙 요청 클라이언트 서비스를 나타내며, 엑스윙은 동맹 선박의 유사한 서비스를 나타냅니다.
  • 데스스타 착륙 서비스에 대한 접근 제어를 위한 다양한 보안 정책을 테스트할 수 있도록 존재합니다.
kubectl apply -f https://raw.githubusercontent.com/cilium/cilium/1.17.6/examples/minikube/http-sw-app.yaml

# 파드 라벨 labels 확인
kubectl get pod --show-labels

 

패킷 캡처해보기

이제 트래픽이 잘 캡처되는지 확인하기 위해 아래와 같이 반복적으로 xwing Pod에서 deathstart로 요청을 전달합니다. 

 

그러면 아래와 같이 Hubble UI를 통해 캡처된 정보를 기반으로 트래픽 흐름을 확인할 수 있습니다. 

 

tiefighter Pod에서도 마찬가지로 트래픽을 전달하면 즉시 Hubble UI를 통해 확인할 수 있겠죠

 

만약 특정 서비스의 트래픽만 터미널에서 확인해보고 싶다면 각 노드의 cilium-agent Pod에서 endpoint list 명령으로 대상 서비스의  IDENTIFY를 확인하여 필터링 할 수 있습니다.

 

네트워크 정책 만들어보기

Hubble을 활성화할 때 기본적으로 네트워크 정책은 하나도 만들어져 있지 않습니다. 실습을 통해 아래와 같이 CIlium의 deathstar에 대한 네트워크 정책을 만들어서 tiefighter는 허용하지만 xwing은 차단하도록 설정해봅니다.

  • Cilium을 사용할 때 보안 정책을 정의할 때 엔드포인트 IP 주소는 중요하지 않습니다. 대신 포드에 할당된 레이블을 사용하여 보안 정책을 정의할 수 있습니다. 정책은 클러스터 내에서 실행 중이거나 실행 중인 위치에 관계없이 레이블을 기반으로 올바른 포드에 적용됩니다.
  • 데스스타 착륙 요청을 라벨이 있는 선박(org=empire)으로만 제한하는 기본 정책부터 시작하겠습니다. 이렇게 하면 org=empire 라벨이 없는 선박은 데스스타 서비스와 연결조차 할 수 없습니다. 이 정책은 IP 프로토콜(네트워크 계층 3)과 TCP 프로토콜(네트워크 계층 4)에만 적용되는 간단한 정책이므로 흔히 L3/L4 네트워크 보안 정책이라고 합니다.
  • 참고: 실리움은 상태별 연결 추적을 수행합니다. 이는 정책이 프론트엔드가 백엔드에 도달할 수 있도록 허용하면, 동일한 TCP/UDP 연결 내에서 백엔드 응답의 일부인 모든 필수 응답 패킷이 자동으로 프론트엔드에 도달하도록 허용한다는 것을 의미합니다. → 리턴 패킷 자동 허용!

위에서 설명한 네트워크 정책을 만들어보면 아래와 같습니다.

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

 

  • CiliumNetworkPolicys는 "endpointSelector"를 사용하여 팟 레이블에서 정책이 적용되는 소스와 목적지를 식별합니다.
  • 위 정책은 TCP 포트 80에서 레이블(org=empire)이 있는 모든 Pod에서 레이블(org=empire, class=deathstar)이 있는 deathstar Pod로 전송되는 트래픽을 화이트리스트로 작성합니다.

연결 테스트를 해보면 org=empire 레이블을 가지고 있지 않은 xwing Pod에서의 요청은 아래와 같이 Drop 되고, org=empire 레이블을 가지고 있는 tiefighter Pod에서는 요청이 정상적으로 수행됩니다. 

 

Hubble UI에서도 xwing은 Drop되고 tiefighter는 정상 접근되는 것을 확인할 수 있습니다. 

 

Cilium의 네트워크 정책은 apply 즉시 반영되기 때문에 꼼꼼하게 점검 후 반영해야합니다. 그렇지 않으면 운영 중 네트워크 차단으로 인한 장애가 발생할 수도 있습니다. Cilium의 네트워크 정책의 장점은 L3/L4 레벨에서 동작하며, eBPF를 통해 패킷 필터링이 된다는 것입니다. 만약 L7의 필터링이 필요한 경우에는 userspace까지 거쳐야 하고 이는 아래 그림과 같이 Optional feature로써 필요한 경우 활용할 수 있습니다. 

L7 네트워크 정책 적용해보기

  • 위의 간단한 시나리오에서는 tiefighter / xwing에게 데스스타 API에 대한 전체 액세스 권한을 부여하거나 아예 액세스 권한을 부여하지 않는 것으로 충분했습니다. 그러나 마이크로서비스 간에 가장 강력한 보안(즉, 최소 권한 격리를 강제하는 것)을 제공하기 위해서는 데스스타 API를 호출하는 각 서비스가 합법적인 운영에 필요한 HTTP 요청 세트만 수행하도록 제한해야 합니다.
  • 예를 들어, 데스스타 서비스가 임의의 제국 선박이 호출해서는 안 되는 일부 유지보수 API를 노출한다고 가정해 보겠습니다.

deathstar 서비스로 tiefighter의 접근을 허용하고 있지만 일부 API는 관리용도로 활용되어 접근을 막아야하는 상황입니다. 현재는 API에 대한 네트워크 정책이 없기 때문에 기본적인 접근이 허용되어 있는 tiefighter는 접근이 가능합니다. 하지만 이로 인해 deathstar에 오류를 발생시키고 있습니다. 

 

이 요청을 차단하기 위해서는 IP:Port 기반의 네트워크 정책으로는 불가능하고 특정 API에 대한 접근만 차단하기 위해 L7의 네트워크 정책이 필요합니다. 아래와 같이 기존 네트워크 정책에 추가하여 정책을 갱신합니다.

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"

 

이제 http 프로토콜을 지정해서 hubble observe 명령으로 L7 요청만 필터링 할 수 있습니다. 먼저 정상 접근부터 로그를 확인해보겠습니다. 

kubectl exec tiefighter -- curl -s -XPOST deathstar.default.svc.cluster.local/v1/request-landing

정상 접근을 확인할 수 있고, L7에서 필터링을 했기 때문에 어떤 path로 API를 요청했는지 확인할 수 있습니다. Hubble UI에서도 아까와 달리 L7 info에 정보가 표기된 것을 확인할 수 있습니다. 

 

 

이제 접근하면 안되는 API인 /exhaust-port로 접근을 시도해보겠습니다. 

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

설정한 정책대로 접근이 차단된 것을 확인할 수 있습니다. 

 

댓글