DevOps위성 변화탐지 플랫폼 아키텍처 · 6/10

노드 하나가 죽어도 API 서버 주소는 그대로여야 한다 - 네트워크와 컨트롤플레인 이중화

kube-proxy를 걷어내고 Cilium(eBPF)으로 네트워크 정책을 한 계층에서 통제하고, kube-vip로 컨트롤플레인 진입점을 고정한 이유.

2026-07-247 min read
#Cilium#eBPF#kube-vip#Kubernetes#네트워크 정책#고가용성

문제: 서비스가 9개면 통신 규칙도 9배로 복잡해진다

모놀리식일 때는 "내부 통신"이라는 개념 자체가 없었다. 하나의 프로세스 안에서 함수를 호출하는 것뿐이었으니까. MSA로 쪼개고 나니 서비스 사이의 모든 호출이 네트워크를 타는 실제 통신이 됐고, 동시에 새로운 질문이 생겼다 - 어떤 서비스가 어떤 서비스와 통신할 수 있어야 하는가.

기본 Kubernetes 네트워킹(kube-proxy 기반)은 이 질문에 답하지 않는다. 기본값은 "모든 파드가 모든 파드와 통신 가능"이다. 인증을 게이트웨이로 끌어올린 구조(이전 글 참고)에서 "게이트웨이를 통과해야만 인증된 것"이라는 전제가 성립하려면, 백엔드 서비스를 게이트웨이 우회해서 직접 호출하는 경로 자체가 차단돼 있어야 한다. 이건 애플리케이션 코드가 아니라 네트워크 계층에서 강제해야 하는 문제다.

컨트롤플레인 쪽에는 또 다른 문제가 있었다. API 서버가 단일 노드에만 있으면 그 노드가 죽는 순간 클러스터 전체를 제어할 방법이 사라진다. 컨트롤플레인을 여러 노드로 이중화하더라도, 클라이언트(kubectl, kubelet, 다른 컨트롤플레인 컴포넌트)가 "어디로 접속해야 하는지"를 결정하는 고정된 진입점이 없으면 이중화 자체가 무의미해진다.

시도한 것

Cilium - eBPF로 네트워크 정책을 한 계층에서

Cilium은 eBPF(커널 안에서 안전하게 실행되는 프로그램)를 기반으로 하는 CNI(Container Network Interface)다. 기존 kube-proxy를 대체하면서, 네트워크 정책(L3/L4)뿐 아니라 L7(HTTP 경로·메서드 단위)까지 하나의 정책 계층에서 다룰 수 있다.

이걸 도입한 이유는 두 가지다.

  1. "게이트웨이만 백엔드를 호출할 수 있다"를 강제할 방법이 필요했다. NetworkPolicy로 각 백엔드 서비스의 인그레스를 게이트웨이 네임스페이스/파드 셀렉터로 제한하면, 애플리케이션이 아무 것도 하지 않아도 우회 호출 자체가 네트워크 계층에서 막힌다. 인증을 게이트웨이로 옮기는 구조는 이 전제가 없으면 성립하지 않는다.
  2. 가시성. Cilium의 Hubble은 클러스터 내부의 실제 트래픽 흐름을 관찰할 수 있게 해준다. 어떤 서비스가 어떤 서비스에 접근을 시도했는지(허용됐든 거부됐든) 확인할 수 있어서, 예상 밖의 통신 시도가 있으면 - 예를 들어 있어서는 안 될 우회 호출 시도 - 정책을 만들기 전에도 눈으로 먼저 확인할 수 있다.
Before (kube-proxy, 정책 없음)
  모든 파드 ←→ 모든 파드 통신 가능
  "게이트웨이만 백엔드 호출 가능"은 코드 수준 신뢰에 의존

After (Cilium NetworkPolicy)
  백엔드 서비스 인그레스 = 게이트웨이 파드/네임스페이스만 허용
  우회 호출은 네트워크 계층에서 자체 차단
  Hubble로 실제 트래픽 흐름 관찰 가능

kube-vip - 컨트롤플레인에 고정 주소 하나

컨트롤플레인은 3개 노드로 이중화했다. 문제는 "3개 노드 중 어디에 접속해야 하는가"였다. 특정 노드의 IP를 그대로 API 서버 주소로 쓰면, 그 노드가 죽었을 때 접속 주소 자체가 사라진다.

kube-vip는 3개 컨트롤플레인 노드 앞에 **고정된 가상 IP(VIP)**를 두고, 실제로 어떤 노드가 이 VIP를 응답하고 있는지를 노드 상태에 따라 동적으로 옮긴다. 클라이언트(kubectl, kubelet, 다른 컴포넌트)는 항상 같은 VIP로만 접속하면 되고, 그 뒤에서 어떤 노드가 살아있는지는 kube-vip가 관리한다.

[ kubectl / kubelet / 클라이언트 ]
        │  항상 같은 VIP로 접속
        ▼
   [ kube-vip 관리 VIP ]
        │
   ┌────┼────┐
   ▼    ▼    ▼
 노드1  노드2  노드3   ← 컨트롤플레인 3개, 하나가 죽어도 VIP는 살아있는 노드로 이동

결과

두 도구 모두 "장애가 안 나게 막는다"기보다 "장애가 나도 진입점과 통신 경계가 흔들리지 않게 한다"는 성격에 가깝다.

  • Cilium 도입 이후, 게이트웨이를 우회한 백엔드 직접 호출은 애플리케이션 로직과 무관하게 네트워크 계층에서 차단된다. 인증 아키텍처(1편)의 "통과 = 인증됨" 전제가 실제로 성립하는 건 이 계층 덕분이다.
  • kube-vip 덕분에 컨트롤플레인 노드 하나가 재시작되거나 장애가 나도, API 서버 접속 주소(VIP)는 그대로 유지된다. 클러스터를 조작하는 쪽에서는 노드 장애가 접속 문제로 이어지지 않는다.

두 구성 모두 평소에는 존재감이 없다. 진가는 노드 하나가 죽는 순간, 혹은 누군가 실수로 백엔드를 직접 호출하려는 순간에 드러난다.