Skip to content

Latest commit

 

History

History
131 lines (87 loc) · 11.2 KB

File metadata and controls

131 lines (87 loc) · 11.2 KB

v0.9.8 — LoxiLB HA Egress: 인바운드 LB 상태 기계를 아웃바운드 게이트웨이로 뒤집기

메타데이터

항목 내용
프로젝트 LoxiLB
관련 릴리스 v0.9.8 (2025-01-27)
설계 배경 loxilb-io/loxilb#877 — Kubernetes Egress Support
주요 구현 #909 — Initial support for egress (3a16979b, 2024-12-23 머지), #934 — fixes for incluster mode (ae51e557, 2025-01-16 머지)
후속 보완 #910, #911, #935
발견 출처 v0.9.8 GitHub Release의 #909~#912, #923, #934~#935 항목
검증 근거 PR #909/#934/#935의 실제 diff(common/common.go, pkg/loxinet/rules.go, pkg/loxinet/cluster.go, api/loxinlp/nlp.go)와 공식 egress 가이드
소스 라이선스 Apache License 2.0

개요

LoxiLB v0.9.8은 Kubernetes Pod의 외부 통신을 정해진 출발지 IP로 내보내고, 담당 LoxiLB 인스턴스가 실패하면 다른 인스턴스가 그 역할을 이어받는 HA egress의 초기 구현을 추가했다. 핵심은 별도의 완전히 새로운 egress 엔진을 만드는 대신, 기존 LB 규칙·VIP 광고·방화벽 SNAT·클러스터 HA 상태 기계를 egress 모드로 연결한 것이다. 이때 egress 규칙은 일반적인 인바운드 LB처럼 eBPF LB datapath에 설치되지 않고, 클러스터 기본 경로와 SNAT 소유권을 어느 노드가 가질지 조정하는 제어 객체로 쓰인다.

사전 지식

Kubernetes egress에서 중요한 것은 목적지보다 안정적인 출발지다

Pod가 외부 API나 데이터베이스에 접속하면 패킷의 Pod IP는 보통 노드 또는 게이트웨이의 IP로 SNAT된다. Pod 재스케줄링이나 노드 변경에 따라 외부에서 보이는 출발지 IP가 달라지면, 외부 방화벽의 allowlist나 상대 시스템의 IP 기반 식별 정책을 안정적으로 구성하기 어렵다. 그래서 egress gateway는 선택된 Pod의 트래픽을 한 경로로 모으고, 외부에는 미리 정한 egress VIP 하나로 보이게 한다.

인바운드 ServiceType: LoadBalancer는 외부의 VIP로 들어온 연결을 여러 Pod endpoint로 분산한다. egress는 방향이 반대다. 여러 Pod에서 외부로 나가는 연결을 한 게이트웨이로 모은 뒤 출발지 주소를 고정한다. 그러나 두 기능 모두 다음 상태를 필요로 한다.

  • 논리 규칙과 대상 endpoint
  • 클러스터에서 VIP를 소유할 활성 인스턴스
  • 활성 인스턴스 변경 시 주소·경로·datapath 상태 동기화
  • SNAT과 연결 추적 상태

LoxiLB가 기존 LB/HA 구조를 egress에도 재사용할 수 있었던 이유다.

HA egress는 대기 노드의 트래픽까지 활성 노드로 보내야 한다

VIP만 활성 노드로 옮겨서는 충분하지 않다. Pod의 기본 경로가 대기 LoxiLB 인스턴스를 향하고 있다면, 그 인스턴스도 받은 패킷을 현재 활성 인스턴스로 전달해야 한다. 초기 구현은 --clusterinterface로 지정한 인터페이스 위에 전용 VXLAN 네트워크를 만들고, egress endpoint를 클러스터 peer로 등록한다. HA 상태에 따라 기본 경로를 이 내부 클러스터 게이트웨이 또는 원래 외부 게이트웨이로 전환할 수 있는 전달 경로를 먼저 만든 셈이다.

변경 분석

변경 전: LB의 HA는 인바운드 VIP에만 적용됐다

기존 LB 규칙은 VIP를 로컬 주소/BGP/클라우드 경로에 광고하고, eBPF LB datapath에 VIP→endpoint 변환 규칙을 설치하는 인바운드 중심 구조였다. Pod의 아웃바운드 트래픽은 이 규칙의 대상이 아니었기 때문에, 외부에서 보이는 출발지 IP를 LoxiLB HA 상태와 함께 이동시키는 제어 경로가 없었다.

[변경 전]

외부 클라이언트 ──▶ LoxiLB VIP ──▶ Pod endpoints
                       │
                       └─ 기존 HA가 VIP 광고와 LB datapath를 동기화

Pod ──▶ 노드/일반 기본 게이트웨이 ──SNAT──▶ 외부 서비스
         │
         ├─ LoxiLB의 VIP 소유권과 무관
         └─ 노드·경로에 따라 외부 출발지 IP가 달라질 수 있음

하나의 egress 플래그를 API에서 HA 경로까지 전달한다

PR #909는 LbServiceArg, API model, Swagger, REST handler, 내부 ruleEntegress 값을 추가했다. 단순한 API 옵션처럼 보이지만, 이 값은 endpoint host와 VIP map까지 보존된다. 그래야 HA 상태가 나중에 바뀌어 RulesSyncToClusterState()가 전체 규칙을 다시 동기화할 때도 해당 VIP가 일반 인바운드 VIP인지 egress 제어용 VIP인지 구분할 수 있다.

또한 이미 존재하는 LB 규칙의 egress 모드를 제자리에서 바꾸는 것은 거부한다. 같은 키를 가진 규칙이라도 일반 LB와 egress는 datapath 설치 여부와 경로 조작이 다르므로, endpoint만 수정하듯 모드를 바꾸면 이전 상태가 일부 남을 수 있다. 삭제 후 다시 만드는 명시적 전환을 요구해 상태 기계의 불변식을 지킨 것이다.

wildcard 서비스는 클러스터 게이트웨이 규칙으로 바뀌고 일반 LB datapath를 건너뛴다

egress LB는 0.0.0.0 또는 ::를 서비스 주소로 받아 "특정 목적지 VIP"가 아니라 아웃바운드 경로 전체를 나타낸다. AddLbRule()은 이 wildcard와 egress=true 조합을 내부 클러스터 게이트웨이 주소로 바꾼다. 이어 LB2DP()는 egress 규칙이면 즉시 반환한다.

즉 이 규칙은 모든 외부 패킷에 대해 일반적인 VIP→endpoint eBPF 변환을 설치하는 규칙이 아니다. 대신 endpoint를 egress cluster node로 등록하고, VIP/HA 동기화 경로가 기본 route와 SNAT 상태를 조정하도록 만드는 제어면 앵커다. 인바운드 LB 객체 모델은 재사용하되 datapath 의미는 분리한 설계다.

HA 상태가 기본 경로와 SNAT의 소유자를 함께 바꾼다

egress endpoint가 추가되면 ClusterNodeAdd(..., Egress: true)가 전용 VXLAN peer를 구성한다. HA 상태가 바뀌면 AdvRuleVIP(..., egress)CIAddClusterRoute()를 호출한다.

  • 활성(MASTER) 인스턴스는 원래 외부 기본 경로를 사용하고 egress VIP/SNAT 규칙을 활성화한다.
  • 대기 인스턴스는 기본 경로를 내부 클러스터 게이트웨이 쪽으로 바꿔, 자신에게 들어온 아웃바운드 트래픽을 활성 인스턴스로 넘긴다.
  • OnDefault로 표시된 SNAT 방화벽 규칙은 기본 HA 인스턴스의 상태와 함께 datapath에 추가·제거된다.

PR #934는 in-cluster 모드에서 원래 default route의 gateway뿐 아니라 source address도 기억해 두었다가, 활성 경로 복원 시 클러스터 subnet용 SNAT을 함께 구성하도록 보완했다. 경로와 주소 변환을 별개로 전환하면 failover 뒤 반환 경로가 어긋날 수 있으므로 둘을 같은 HA 이벤트에 묶은 것이다.

설계 결정 및 트레이드오프

별도 egress 오케스트레이터 대신 기존 LB/HA 상태 기계를 재사용했다

새 구현이 LbServiceArg, ruleEnt, vipMap, ClusterNode, firewall option을 관통하는 이유는 기존의 검증된 생명주기를 그대로 쓰기 위해서다. VIP 참조 수, endpoint 추가·삭제, HA 전환 시 전체 규칙 재동기화 같은 기능을 새로 복제하지 않아도 된다. 반면 하나의 egress 의미가 API·제어면·route·firewall에 걸쳐 전파되므로, 플래그 누락이 조용한 상태 불일치로 이어질 수 있고 초기 릴리스에 여러 후속 patchset이 필요했다.

대기 노드를 버리지 않고 VXLAN으로 활성 노드에 연결했다

대기 노드가 트래픽을 거부하도록 만들면 Pod 측 next hop도 failover 때 함께 바꿔야 한다. 전용 cluster VXLAN과 default route 전환을 사용하면 Pod 설정은 그대로 둔 채 LoxiLB 내부에서 활성 노드로 우회시킬 수 있다. 그 대가로 LoxiLB가 호스트의 기본 경로와 SNAT 규칙을 관리하게 되고, 전용 subnet/interface 구성과 원래 경로 복원이 정확해야 한다.

초기 구현은 active/backup 소유권을 택했다

여러 인스턴스가 동시에 같은 egress VIP로 SNAT하는 active/active 방식은 처리량 면에서 유리하지만 연결 추적, 반환 경로, 외부 VIP 광고를 노드 간에 일관되게 유지해야 한다. v0.9.8은 MASTER가 외부 경로와 egress 상태를 소유하고 BACKUP이 내부 tunnel로 전달하는 구조를 택했다. 안정적인 단일 출발지와 단순한 소유권을 얻는 대신, 활성 노드가 데이터 경로의 병목이 되고 failover 수렴 시간 동안 영향이 생길 수 있다.

[변경 후]

선택된 Pod
    │ default route
    ▼
LoxiLB BACKUP ── 전용 VXLAN / cluster gateway ──▶ LoxiLB MASTER
                                                    │
                                                    ├─ egress VIP 소유
                                                    ├─ OnDefault SNAT 활성
                                                    └─ 원래 외부 default route
                                                             │
                                                             ▼
                                                        외부 서비스

HA 전환:
  새 MASTER  → cluster 경유 default route 제거, 외부 경로·SNAT 활성
  새 BACKUP  → 외부 직접 경로 대신 cluster gateway로 전달

더 살펴볼 점

  • active/backup 한계를 넘어 여러 egress 인스턴스가 연결 상태를 나눠 갖는 active/active 설계가 추가될 수 있을까?
  • 전용 VXLAN과 default route를 직접 관리하는 방식은 CNI별 policy routing 또는 여러 routing table이 있는 노드에서 어떻게 경계를 정해야 할까?
  • egress 모드를 제자리에서 바꾸지 못하게 한 불변식을 향후 선언형 CRD reconcile이 삭제·재생성 과정까지 안전하게 감춰줄 수 있을까?

참고 자료

참고 외 별도 확인 링크

본문 참고 자료로 충분했다.