Hubble 내부 구조
Hubble 내부 구조 (Hubble internals)
Hubble이 Cilium과 eBPF 위에서 서비스 통신과 네트워킹 인프라에 대한 깊은 가시성을 제공하는 내부 구조를 설명해요.
출처: Hubble internals
본문
참고
이 문서 섹션은 Hubble에 기여하는 데 관심이 있는 개발자를 대상으로 해요. 이를 위해 Hubble 내부 구조를 설명해요.
참고
이 문서는 Hubble 서버(때로는 "Hubble embedded"라고 함)와 Hubble Relay 컴포넌트를 다루지만 Hubble UI와 CLI는 다루지 않아요.
Hubble은 Cilium과 eBPF 위에 구축되어 완전히 투명한 방식으로 서비스의 통신과 동작, 그리고 네트워킹 인프라에 대한 깊은 가시성을 가능하게 해요. Hubble의 설계 목표 중 하나는 이 모든 것을 대규모로 달성하는 거예요.
Hubble의 서버 컴포넌트는 낮은 오버헤드로 높은 성능을 달성하기 위해 Cilium 에이전트에 내장돼요. Hubble 서버가 제공하는 gRPC 서비스는 Unix 도메인 소켓으로 로컬에서 소비되거나, 더 일반적으로 Hubble Relay를 통해 소비될 수 있어요. Hubble Relay는 모든 Hubble 인스턴스를 인지하는 독립 컴포넌트로, 각각의 gRPC API에 연결해 전체 클러스터 가시성을 제공해요. 이 기능은 보통 멀티노드(multi-node)라고 불러요. Hubble Relay의 주요 목표는 Hubble UI와 CLI가 안전하게 노출하고 소비할 수 있는 풍부한 API를 제공하는 거예요.
Hubble 아키텍처
Hubble은 Cilium 프로세스에서 gRPC 서비스를 노출해 클라이언트가 flow 및 기타 유형의 데이터를 받을 수 있게 해요.
Hubble 서버
Hubble 서버 컴포넌트는 두 개의 gRPC 서비스를 구현해요. Observer 서비스는 로컬 Unix 도메인 소켓 외에도 선택적으로 TCP 소켓으로 노출될 수 있고, Peer 서비스는 둘 다에서 제공되며 TCP로 활성화될 때 Kubernetes Service로도 노출돼요.
Observer 서비스
Observer 서비스는 핵심 서비스예요. GetFlows, GetNodes, GetNamespaces, ServerStatus의 네 가지 RPC 엔드포인트를 제공해요.
GetNodes는 각 Hubble 인스턴스와 관련된 메트릭 및 기타 정보 목록을 반환해요.ServerStatus는GetNodes의 정보 요약을 반환해요.GetNamespaces는 지난 한 시간 안에 네트워크 flow가 있었던 네임스페이스 목록을 반환해요.GetFlows는 flow 관련 이벤트의 스트림을 반환해요.
GetFlows를 사용하면 호출자는 페이로드 스트림을 받아요. 요청 파라미터는 호출자가 허용 목록(allow list)과 거부 목록(deny list) 형태의 필터를 지정해 데이터를 세밀하게 필터링할 수 있게 해요. 여러 flow 필터가 제공되면 flow가 포함/제외되려면 그중 하나만 일치하면 돼요. 허용과 거부 필터가 모두 지정되면 결과는 거부 목록과 동시에 일치하지 않는 허용 목록에 매칭된 모든 flow를 포함해요.
GetFlows 요청에 응답하기 위해 Hubble은 Cilium의 이벤트 모니터에서 온 모니터링 이벤트를 사용자 공간 링 버퍼 구조에 저장해요. 모니터링 이벤트는 Cilium 모니터에 새 리스너를 등록해 얻어요. 링 버퍼는 메모리에 구성 가능한 양의 이벤트를 저장할 수 있어요. 이벤트는 지속적으로 소비되며, 링 버퍼가 가득 차면 오래된 이벤트를 덮어써요.
또한 Observer 서비스는 Cilium 에이전트 이벤트 데이터를 노출하는 GetAgentEvents와 Cilium datapath 디버그 이벤트를 노출하는 GetDebugEvents RPC 엔드포인트도 제공해요. 둘 다 GetFlows와 비슷하지만 필터링 기능을 구현하지 않아요.

효율을 위해 내부 버퍼 길이는 1로 채워진 비트 마스크 + 1이에요. 이 비트 마스크의 최상위 비트는 'n'의 최상위 비트 위치와 같아요. 즉, 내부 버퍼 크기는 항상 2의 거듭제곱이며 작성자(writer)용으로 1개 슬롯이 예약돼 있어요. 결과적으로 사용자 관점에서 링 버퍼 용량은 2의 거듭제곱 - 1이에요. 링 버퍼는 핫 코드 경로이므로 잠금 메커니즘을 사용하지 않고 대신 원자 연산을 사용하도록 설계됐어요. 이 접근 방식은 성능상 이점이 있지만 복잡한 컴포넌트라는 단점도 있어요.
복잡한 특성 때문에 링 버퍼는 보통 이 데이터 구조의 복잡성을 읽기용으로 추상화하는 링 리더를 통해 접근해요. 링 리더는 'previous'와 'next' 메서드로 한 번에 하나의 이벤트를 읽을 수 있게 하고, 링 버퍼에 쓰여질 때 이벤트를 연속적으로 읽는 follow 모드도 구현해요.
Peer 서비스
Peer 서비스는 클러스터의 Hubble peer에 대한 정보를 스트림으로 보내요. Notify 메서드가 호출되면 클러스터의 모든 peer에 대한 정보를 보고하고, 이후 업데이트되거나 추가되거나 제거된 peer에 대한 정보를 보내요. 따라서 호출자가 모든 Hubble 인스턴스를 추적하고 각각의 gRPC 서비스를 조회할 수 있게 해요.
이 서비스는 Kubernetes Service로 노출되며, 주로 Hubble Relay가 모든 Hubble 인스턴스의 클러스터 전체 보기를 갖기 위해 사용해요.
Peer 서비스는 Cilium의 노드 관리자에 구독해 peer 변경 알림을 얻어요. 이를 위해 내부적으로 Cilium의 datapath 노드 핸들러 인터페이스를 구현하는 핸들러를 정의해요.
Hubble Relay
Hubble Relay는 멀티노드 지원을 제공하는 Hubble 컴포넌트예요. Hubble 인스턴스에 대한 정보를 얻고 그들의 gRPC API를 소비해 전체 클러스터(또는 ClusterMesh 시나리오에서는 여러 클러스터)의 이벤트를 다루는 더 풍부한 API를 제공하기 위해 Peer 서비스를 활용해요.
Hubble Relay는 처음에 Cilium v1.8 릴리스와 함께 기술 프리뷰로 도입됐고, Cilium v1.9 릴리스에서 안정화(stable)로 선언됐어요.
Hubble Relay는 멀티노드용 Observer 서비스를 구현해요. 이를 위해 peer 매니저로 클러스터의 모든 Hubble peer와 영구 연결을 유지해요. 이 컴포넌트는 호출자에게 peer 목록을 제공해요. 호출자는 peer에 도달할 수 없을 때 이를 보고할 수 있고, 그러면 peer 매니저가 재연결을 시도해요.
Hubble Relay가 클러스터의 모든 노드에 연결하므로 Hubble 서버 인스턴스들은 API(기본적으로 포트 4244)를 사용 가능하게 만들어야 해요. 기본적으로 Hubble 서버 엔드포인트는 TCP 포트로 노출될 때 접근을 Hubble Relay로만 제한하기 위해 상호 TLS(mTLS)로 보호돼요.