Networking - 노드 파드 간 통신 2 & K8S 외부 노출¶
Cilium의 NodePort, LoadBalancer, Ingress 구성과 K8s 외부 노출 방식을 정리한다.
실습 환경 구성 및 아키텍처¶
확장된 실습 환경 구성¶
1.1 실습 환경 개요¶

4주차 실습 환경은 더욱 복잡한 네트워킹 시나리오를 다루기 위해 4노드 환경으로 확장되었다:
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ k8s-ctr │ │ k8s-w1 │ │ k8s-w0 │ │ router │
│ (Control Plane) │ │ (Worker Node 1) │ │ (Worker Node 2) │ │ (외부 서버) │
├─────────────────┤ ├─────────────────┤ ├─────────────────┤ ├─────────────────┤
│ eth0: NAT │ │ eth0: NAT │ │ eth0: NAT │ │ eth0: NAT │
│ eth1:192.168.10.│ │ eth1:192.168.10.│ │ eth1:192.168.20.│ │ eth1:192.168.10.│
│ 100 │ │ 101 │ │ 100 │ │ 200 │
│ │ │ │ │ │ │ eth2:192.168.20.│
│ PodCIDR: │ │ PodCIDR: │ │ PodCIDR: │ │ 200 │
│ 172.20.0.0/24 │ │ 172.20.1.0/24 │ │ 172.20.2.0/24 │ │ │
│ │ │ │ │ │ │ loop1: 10.10.1. │
│ │ │ │ │ │ │ 200/24 │
│ │ │ │ │ │ │ loop2: 10.10.2. │
│ │ │ │ │ │ │ 200/24 │
└─────────────────┘ └─────────────────┘ └─────────────────┘ └─────────────────┘
│ │ │ │
└───────────────────────┼───────────────────────┤ │
Host-Only Network │ │
(192.168.10.0/24) │ │
│ │
Host-Only Network │
(192.168.20.0/24) │
│ │
└───────────────────────┘
│
┌─────────────────┐
│ 사내망 시뮬레이션 │
│ 10.10.0.0/16 │
└─────────────────┘
- k8s-ctr: Control Plane 노드 (192.168.10.100)
- k8s-w1: Worker 노드 1 (192.168.10.101)
- k8s-w0: Worker 노드 2 (192.168.20.100) - 다른 네트워크 대역
- router: 외부 서버 (192.168.10.200, 192.168.20.200) - 두 네트워크 대역을 연결하는 라우터 역할, loop1/loop2 인터페이스를 통한 사내망 시뮬레이션
1.2 실습 환경 배포 및 확인¶
Vagrant를 통한 자동 배포:
# 실습 환경 배포
vagrant up
# 네트워크 인터페이스 정보 확인
# router 서버 네트워크 확인
sshpass -p 'vagrant' ssh vagrant@router ip -br -c -4 addr
# Expected output:
# lo UNKNOWN 127.0.0.1/8
# eth0 UP 10.0.2.15/24 metric 100
# eth1 UP 192.168.10.200/24
# eth2 UP 192.168.20.200/24
# loop1 UNKNOWN 10.10.1.200/24
# loop2 UNKNOWN 10.10.2.200/24
# k8s 노드들 네트워크 확인
ip -c -4 addr show dev eth1 # k8s-ctr
sshpass -p 'vagrant' ssh vagrant@k8s-w1 ip -c -4 addr show dev eth1 # k8s-w1
sshpass -p 'vagrant' ssh vagrant@k8s-w0 ip -c -4 addr show dev eth1 # k8s-w0
# 라우팅 정보 확인
ip -c route | grep static
sshpass -p 'vagrant' ssh vagrant@router ip -c route
네트워크 연결성 테스트:
# 기본 통신 확인
ping -c 1 10.10.1.200 # router loop1
ping -c 1 192.168.20.100 # k8s-w0 eth1
# 경로 추적 (Path MTU Discovery)
tracepath -n 192.168.20.100
# Expected output:
# 1?: [LOCALHOST] pmtu 1500
# 1: 192.168.10.200 1.222ms
# 1: 192.168.10.200 0.980ms
# 2: 192.168.20.100 1.620ms reached
# Resume: pmtu 1500 hops 2 back 2
1.3 Cilium v1.18 설치 상태¶
기본 설정 확인:
# Cilium 버전 및 상태 확인
cilium version
cilium status
# 현재 설정된 라우팅 모드 확인
cilium config view | grep routing-mode
cilium config view | grep auto-direct-node-routes
# Expected: routing-mode: native, auto-direct-node-routes: true
Native Routing Mode 심화 분석¶
Native Routing의 특징 및 동작 원리¶
1.1 autoDirectNodeRoutes 동작 이해¶
Native Routing 모드의 핵심 설정:
- --set routingMode=native
- --set autoDirectNodeRoutes=true
이 설정은 Cilium이 각 노드의 PodCIDR에 대한 직접 경로를 자동으로 생성하도록 한다.
# 현재 라우팅 테이블 확인
ip -c route
# 각 노드별 PodCIDR 확인
kubectl get nodes -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.spec.podCIDR}{"\n"}{end}'
# Expected output:
# k8s-ctr 172.20.0.0/24
# k8s-w1 172.20.1.0/24
# k8s-w0 172.20.2.0/24
# Worker 노드들의 라우팅 테이블 확인
sshpass -p 'vagrant' ssh vagrant@k8s-w1 ip -c route
sshpass -p 'vagrant' ssh vagrant@k8s-w0 ip -c route
1.2 샘플 애플리케이션 배포 및 라우팅 분석¶
애플리케이션 배포:
# 3개 노드에 분산 배포될 webpod 애플리케이션 생성
cat << EOF | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
name: webpod
spec:
replicas: 3
selector:
matchLabels:
app: webpod
template:
metadata:
labels:
app: webpod
spec:
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- webpod
topologyKey: "kubernetes.io/hostname"
containers:
- name: webpod
image: traefik/whoami
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: webpod
labels:
app: webpod
spec:
selector:
app: webpod
ports:
- protocol: TCP
port: 80
targetPort: 80
type: ClusterIP
EOF
# 테스트 클라이언트 Pod 배포
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
name: curl-pod
labels:
app: curl
spec:
nodeName: k8s-ctr
containers:
- name: curl
image: nicolaka/netshoot
command: ["tail"]
args: ["-f", "/dev/null"]
terminationGracePeriodSeconds: 0
EOF
1.3 Cilium 로드밸런싱 및 서비스 분석¶
배포 상태 확인:
# 배포 확인
kubectl get deploy,svc,ep webpod -owide
kubectl get endpointslices -l app=webpod
kubectl get ciliumendpoints
# Cilium 서비스 목록 확인
kubectl exec -n kube-system ds/cilium -- cilium-dbg service list
# eBPF 로드밸런서 맵 확인
kubectl exec -n kube-system ds/cilium -- cilium-dbg bpf lb list
kubectl exec -n kube-system ds/cilium -- cilium-dbg bpf lb list | grep 10.96.32.212
# NAT 테이블 확인
kubectl exec -n kube-system ds/cilium -- cilium-dbg bpf nat list
eBPF 맵 상세 분석:
# eBPF 맵 목록 (빈 엔트리 제외)
kubectl exec -n kube-system ds/cilium -- cilium-dbg map list | grep -v '0 0'
# 주요 eBPF 맵들:
# - cilium_lb4_services_v2: 서비스 정의
# - cilium_lb4_backends_v3: 백엔드 Pod 정보
# - cilium_lb4_reverse_nat: 역방향 NAT
# - cilium_ipcache_v2: IP 캐시
# 서비스 맵 상세 정보
kubectl exec -n kube-system ds/cilium -- cilium-dbg map get cilium_lb4_services_v2 | grep 10.96.32.212
# 백엔드 맵 정보
kubectl exec -n kube-system ds/cilium -- cilium-dbg map get cilium_lb4_backends_v3
# IP 캐시 맵 정보
kubectl exec -n kube-system ds/cilium -- cilium-dbg map get cilium_ipcache_v2
1.4 k8s-w0 통신 문제 및 분석¶
문제 상황: k8s-w0 노드는 다른 네트워크 대역(192.168.20.0/24)에 위치하여 직접 통신이 불가능한다.
# 기본 통신 테스트
kubectl exec -it curl-pod -- curl webpod | grep Hostname
# k8s-w0 노드의 Pod IP 확인
export WEBPOD=$(kubectl get pod -l app=webpod --field-selector spec.nodeName=k8s-w0 -o jsonpath='{.items[0].status.podIP}')
echo $WEBPOD
# 직접 통신 시도 (실패 예상)
kubectl exec -it curl-pod -- ping -c 2 -w 1 -W 1 $WEBPOD
패킷 추적 분석:
# router에서 ICMP 패킷 모니터링
# (router 서버에서 실행)
tcpdump -i any icmp -nn
# 예상 결과: k8s-ctr → router → 라우팅 실패
# 22:08:20.123415 eth1 In IP 172.20.0.89 > 172.20.2.36: ICMP echo request
# 22:08:20.123495 eth0 Out IP 172.20.0.89 > 172.20.2.36: ICMP echo request
# router의 라우팅 테이블 확인
ip route get 172.20.2.36
# Expected: 172.20.2.36 via 10.0.2.2 dev eth0 src 10.0.2.15 uid 0
해결 방안:
| 방안 | 설명 |
|---|---|
| 방안 1 | BGP를 통한 동적 라우팅 (5주차에서 다룸) |
| 방안 2 | Overlay Network (Encapsulation) 사용 |
| 방안 3 | Static Route 수동 설정 (임시 해결책) |
Overlay Network (Encapsulation) Mode¶
VXLAN Encapsulation 개념¶
1.1 VXLAN 터널링 원리¶

VXLAN(Virtual eXtensible Local Area Network)은 UDP 기반의 오버레이 터널링 프로토콜이다:
VXLAN 헤더 구조:
| 헤더 | 크기 |
|---|---|
| 외부 이더넷 헤더 | 14 bytes |
| 외부 IP 헤더 | 20 bytes |
| 외부 UDP 헤더 | 8 bytes |
| VXLAN 헤더 | 8 bytes |
| 내부 이더넷 헤더 | 14 bytes |
| 총 오버헤드 | 50 bytes |
VXLAN vs GENEVE 비교:
| 특징 | VXLAN | GENEVE |
|---|---|---|
| 헤더 크기 | 8 bytes (고정) | 8+ bytes (가변) |
| 메타데이터 | 제한적 | 확장 가능 |
| 성능 | 높음 | 보통 |
| 확장성 | 제한적 | 우수 |
| 사용 사례 | 일반적인 오버레이 | OpenStack, 복잡한 메타데이터 |
Calico와의 라우팅 모드 비교¶

Calico Direct 모드:
- 캡슐화 없음 - 높은 성능 - 네트워크 인프라 의존성 - BGP 필수Calico IPIP 모드:
- IP-in-IP 캡슐화 (20 bytes 오버헤드) - 네트워크 제약 극복 - VXLAN 대비 낮은 오버헤드Cilium vs Calico 라우팅 비교:
| 특징 | Cilium Native | Cilium VXLAN | Calico Direct | Calico IPIP |
|---|---|---|---|---|
| 오버헤드 | 없음 | 50 bytes | 없음 | 20 bytes |
| 네트워크 요구사항 | 높음 | 낮음 | 높음 | 낮음 |
| 성능 | 최고 | 보통 | 최고 | 높음 |
| eBPF 활용 | 완전 | 완전 | 제한적 | 제한적 |
| L7 정책 | 지원 | 지원 | 제한적 | 제한적 |
1.2 VXLAN 모드로 전환¶
커널 모듈 확인:
# VXLAN/GENEVE 커널 지원 확인
grep -E 'CONFIG_VXLAN=y|CONFIG_VXLAN=m|CONFIG_GENEVE=y|CONFIG_GENEVE=m|CONFIG_FIB_RULES=y' /boot/config-$(uname -r)
# Expected output:
# CONFIG_FIB_RULES=y # 커널에 내장됨
# CONFIG_VXLAN=m # 모듈로 컴파일됨 → 커널에 로드해서 사용
# CONFIG_GENEVE=m # 모듈로 컴파일됨 → 커널에 로드해서 사용
# 커널 모듈 로드
lsmod | grep -E 'vxlan|geneve'
modprobe vxlan
lsmod | grep -E 'vxlan|geneve'
# Worker 노드들에도 VXLAN 모듈 로드
for i in w1 w0 ; do
echo ">> node : k8s-$i <<"
sshpass -p 'vagrant' ssh vagrant@k8s-$i sudo modprobe vxlan
echo
done
Cilium VXLAN 모드 업그레이드:
# 기존 통신 상태 유지 (백그라운드)
kubectl exec -it curl-pod -- ping $WEBPOD1 &
# VXLAN 터널 모드로 업그레이드
helm upgrade cilium cilium/cilium \
--namespace kube-system \
--version 1.18.0 \
--reuse-values \
--set routingMode=tunnel \
--set tunnelProtocol=vxlan \
--set autoDirectNodeRoutes=false \
--set installNoConntrackIptablesRules=false
# Cilium 재시작
kubectl rollout restart -n kube-system ds/cilium
1.3 VXLAN 설정 확인¶
VXLAN 인터페이스 및 설정 확인:
# Cilium 기능 상태 확인
cilium features status
cilium features status | grep datapath_network
# 라우팅 모드 확인
kubectl exec -it -n kube-system ds/cilium -- cilium status | grep ^Routing
cilium config view | grep tunnel
# VXLAN 인터페이스 확인
ip -c addr show dev cilium_vxlan
# 모든 노드의 VXLAN 인터페이스 확인
for i in w1 w0 ; do
echo ">> node : k8s-$i <<"
sshpass -p 'vagrant' ssh vagrant@k8s-$i ip -c addr show dev cilium_vxlan
echo
done
1.4 VXLAN 라우팅 분석¶
라우팅 테이블 변화:
# Control Plane 노드 라우팅
ip -c route | grep cilium_host
# Expected routes:
# 172.20.0.238 dev cilium_host proto kernel scope link
# 172.20.0.0/24 via 172.20.0.238 dev cilium_host proto kernel src 172.20.0.238
# 172.20.1.0/24 via 172.20.0.238 dev cilium_host proto kernel src 172.20.0.238 mtu 1450
# 172.20.2.0/24 via 172.20.0.238 dev cilium_host proto kernel src 172.20.0.238 mtu 1450
# 경로 확인
ip route get 172.20.1.10 # k8s-w1 Pod
ip route get 172.20.2.10 # k8s-w0 Pod
# Worker 노드들 라우팅 확인
for i in w1 w0 ; do
echo ">> node : k8s-$i <<"
sshpass -p 'vagrant' ssh vagrant@k8s-$i ip -c route | grep cilium_host
echo
done
VXLAN 통신 분석¶
2.1 eBPF 터널 엔드포인트 확인¶
각 노드의 Cilium Pod 이름 확인:
# 노드별 Cilium Pod 이름 지정
export CILIUMPOD0=$(kubectl get -l k8s-app=cilium pods -n kube-system --field-selector spec.nodeName=k8s-ctr -o jsonpath='{.items[0].metadata.name}')
export CILIUMPOD1=$(kubectl get -l k8s-app=cilium pods -n kube-system --field-selector spec.nodeName=k8s-w1 -o jsonpath='{.items[0].metadata.name}')
export CILIUMPOD2=$(kubectl get -l k8s-app=cilium pods -n kube-system --field-selector spec.nodeName=k8s-w0 -o jsonpath='{.items[0].metadata.name}')
echo $CILIUMPOD0 $CILIUMPOD1 $CILIUMPOD2
# 각 노드의 router IP 확인
kubectl exec -it $CILIUMPOD0 -n kube-system -c cilium-agent -- cilium status --all-addresses | grep router
kubectl exec -it $CILIUMPOD1 -n kube-system -c cilium-agent -- cilium status --all-addresses | grep router
kubectl exec -it $CILIUMPOD2 -n kube-system -c cilium-agent -- cilium status --all-addresses | grep router
eBPF 맵 상태 확인:
# IP 캐시 맵 (노드별 터널 엔드포인트 정보)
kubectl exec -n kube-system $CILIUMPOD0 -- cilium-dbg bpf ipcache list
kubectl exec -n kube-system $CILIUMPOD1 -- cilium-dbg bpf ipcache list
kubectl exec -n kube-system $CILIUMPOD2 -- cilium-dbg bpf ipcache list
# Socket NAT 맵 (터널링 관련)
kubectl exec -n kube-system $CILIUMPOD0 -- cilium-dbg bpf socknat list
kubectl exec -n kube-system $CILIUMPOD1 -- cilium-dbg bpf socknat list
kubectl exec -n kube-system $CILIUMPOD2 -- cilium-dbg bpf socknat list
2.2 VXLAN 패킷 분석¶
패킷 캡처 및 분석:
# k8s-w0 노드의 Pod IP 확인
export WEBPOD=$(kubectl get pod -l app=webpod --field-selector spec.nodeName=k8s-w0 -o jsonpath='{.items[0].status.podIP}')
echo $WEBPOD
# 터미널 1: router에서 VXLAN 패킷 모니터링
tcpdump -i any udp port 8472 -nn
# 터미널 2: ICMP 테스트
kubectl exec -it curl-pod -- ping -c 2 -w 1 -W 1 $WEBPOD
# 패킷 분석 예시:
# 08:49:29.969241 eth1 In IP 192.168.10.100.54386 > 192.168.20.100.8472:
# OTV, flags I 0x08, overlay 0, instance 23926
# IP 172.20.0.44 > 172.20.2.43: ICMP echo request
VXLAN 트래픽 상세 분석:
# 터미널 1: 패킷을 파일로 저장
tcpdump -i any udp port 8472 -w /tmp/vxlan.pcap
# 터미널 2: HTTP 트래픽 생성
kubectl exec -it curl-pod -- sh -c 'while true; do curl -s --connect-timeout 1 webpod | grep Hostname; echo "---" ; sleep 1; done'
# 패킷 분석 도구 사용
tshark -r /tmp/vxlan.pcap -d udp.port==8472,vxlan
termshark -r /tmp/vxlan.pcap
termshark -r /tmp/vxlan.pcap -d udp.port==8472,vxlan
2.3 Hubble을 통한 오버레이 트래픽 모니터링¶
# Hubble 플로우 모니터링
hubble observe -f --protocol tcp --pod curl-pod
# VXLAN 모드에서의 플로우 로그 예시:
# Aug 3 00:02:26.403: default/curl-pod:40332 ID:23926 -> default/webpod-697b545f57-76lt6:80 ID:12438 to-overlay FORWARDED TCP Flags: SYN
# Aug 3 00:02:26.405: default/curl-pod:40332 ID:23926 <- default/webpod-697b545f57-76lt6:80 ID:12438 to-endpoint FORWARDED TCP Flags: SYN, ACK
# Aug 3 00:02:26.405: default/curl-pod:40332 ID:23926 -> default/webpod-697b545f57-76lt6:80 ID:12438 to-overlay FORWARDED TCP Flags: ACK
# 주요 상태 설명:
# - to-overlay: 패킷이 오버레이 네트워크로 전송됨
# - to-endpoint: 패킷이 대상 엔드포인트로 전달됨
MTU 고려사항¶
3.1 VXLAN MTU 문제¶
MTU 제한 확인:
# VXLAN 인터페이스 MTU 확인
ip -c addr show dev cilium_vxlan
# Expected: mtu 1450 (1500 - 50 bytes VXLAN overhead)
# MTU 테스트
kubectl exec -it curl-pod -- ping -M do -s 1500 $WEBPOD
# Expected error: ping: sendmsg: Message too long
# 적절한 크기로 테스트 (1450 - 28 = 1422 bytes payload)
kubectl exec -it curl-pod -- ping -M do -s 1422 $WEBPOD
- Don't Fragment (DF) 플래그:
-M do옵션으로 설정하여 조각화 방지 - Payload 크기:
-s옵션으로 ICMP 데이터 크기 지정 - VXLAN 오버헤드: 50 bytes 추가로 유효 MTU 감소 (1500 → 1450)
Kubernetes Service 심화¶
Service 타입별 특징 및 발전 단계¶
1.1 Service 발전 과정¶
- ClusterIP 타입

- NodePort 타입

- LoadBalancer 타입

| 단계 | 타입 | 설명 |
|---|---|---|
| 1단계 | Pod 생성 | 클러스터 내부에서만 접속 가능. Pod IP는 동적으로 변경됨. 직접 Pod IP로 접근 시 Pod 재시작 시 연결 끊김 |
| 2단계 | ClusterIP | 클러스터 내부에서만 접속 가능. 고정 Virtual IP와 Domain 주소 제공. 다수 Pod에 대한 로드밸런싱. 내부 DNS를 통한 서비스 디스커버리 |
| 3단계 | NodePort | 외부 클라이언트가 노드 IP와 특정 포트를 통해 접속. 모든 노드에서 동일한 포트로 서비스 접근 가능. 포트 범위 제한 (30000-32767). 높은 포트 번호로 인한 사용성 문제 |
| 4단계 | LoadBalancer | 클라우드 제공자의 로드밸런서 활용. 단일 External IP를 통한 서비스 접근. 프라이빗 클라우드에서는 MetalLB나 Cilium L2/BGP 필요. 가장 운영 친화적인 외부 노출 방식 |
Service 타입별 특성 비교:
| 특징 | ClusterIP | NodePort | LoadBalancer | ExternalName |
|---|---|---|---|---|
| 외부 접근 | X | O | O | N/A |
| 로드밸런싱 | O | O | O | X |
| 포트 제한 | X | O | X | N/A |
| 클라우드 의존성 | X | X | O | X |
| 운영 복잡성 | 낮음 | 보통 | 낮음 | 낮음 |
1.2 네트워크 주소 변환 (NAT) 개념¶
| 용어 | 설명 |
|---|---|
| S.IP | Source IP (출발지 IP) |
| D.IP | Destination IP |
| S.Port | Source Port (출발지 포트) |
| D.Port | Destination Port (도착지 포트) |
| SNAT | Source NAT (출발지 IP 변환) |
| DNAT | Destination NAT |
kube-proxy 모드 비교¶
2.1 kube-proxy 역할¶
kube-proxy는 각 노드에서 실행되는 네트워크 프록시로 Kubernetes Service 개념의 일부를 구현한다:
- 실행 위치: 각 노드에서 데몬셋으로 실행
- 지원 프로토콜: UDP, TCP, SCTP
- 주요 기능: 로드밸런싱, 서비스 엔드포인트 관리
- 제한사항: HTTP 레벨 처리는 불가능
2.2 프록시 모드별 특징¶

kube-proxy 모드별 성능 비교:
| 특징 | User Space | iptables | IPVS | nftables | eBPF (Cilium) |
|---|---|---|---|---|---|
| 성능 | 낮음 | 보통 | 높음 | 높음 | 최고 |
| 확장성 | 나쁨 | 제한적 | 우수 | 우수 | 우수 |
| 커널 의존성 | 낮음 | 보통 | 높음 | 높음 | 높음 |
| 메모리 사용량 | 높음 | 보통 | 낮음 | 낮음 | 낮음 |
| CPU 사용량 | 높음 | 보통 | 낮음 | 낮음 | 낮음 |
User Space 프록시 모드 (미사용)¶
- SPOF(Single Point of Failure) 위험 - 사용자 공간과 커널 공간 간 변환 오버헤드 - 현재는 사용하지 않음iptables 프록시 모드¶
- netfilter 서브시스템의 iptables API 활용 - kube-proxy는 규칙만 관리, 실제 데이터 트래픽은 netfilter가 처리 - 데몬셋으로 동작하여 SPOF 해결 - User Space 모드 대비 안정성과 성능 향상IPVS 프록시 모드¶
- Linux 커널의 L4 로드밸런서인 IPVS 활용 - 해시 테이블 기반으로 iptables보다 높은 성능 - 커널 공간에서 동작하여 낮은 지연시간 - 높은 네트워크 트래픽 처리량 지원nftables 프록시 모드¶
- iptables의 후속 기술, 향상된 성능과 확장성 - 커널 5.13 이상에서 지원 - 서비스 엔드포인트 변경을 더 빠르고 효율적으로 처리 - 아직 상대적으로 새로운 기술eBPF 모드 + XDP¶
- 기존 netfilter/iptables 우회 - 최고 성능의 패킷 처리 - XDP(eXpress Data Path)로 커널 바이패스 - Cilium에서 활용하는 고성능 방식Service LoadBalancer IP Address Management (LB IPAM)¶
LB IPAM 개념 및 필요성¶
1.1 LB IPAM 소개¶
LoadBalancer IP Address Management는 LoadBalancer 타입의 서비스에 External IP를 할당할 수 있게 해주는 기능이다:
- 클라우드 제공업체 의존성 해결: 프라이빗 클라우드 환경에서 LoadBalancer 서비스 지원
- Cilium 통합: Cilium BGP Control Plane 및 L2 Announcements와 통합
동작 방식:
- IP 풀 생성: CiliumLoadBalancerIPPool CRD로 IP 범위 정의
- 자동 할당: LoadBalancer 서비스 생성 시 IP 자동 할당
- 광고 메커니즘: BGP 또는 L2 Announcements를 통한 IP 광고
1.2 지원 기능¶
| 기능 | 설명 |
|---|---|
| Service Selectors | 특정 서비스에만 IP 할당 |
| Pool 비활성화 | 특정 풀 일시 중단 |
| Service 사용 확인 | IP 할당 상태 모니터링 |
| LoadBalancerClass | BGP 또는 L2 방식 지정 |
| IP 직접 요청 | 특정 IP 지정 할당 |
| Sharing Keys | 하나의 IP를 여러 포트로 공유 |
LB IPAM 실습¶
2.1 CiliumLoadBalancerIPPool 생성¶
# 기존 IP Pool 확인
kubectl get CiliumLoadBalancerIPPool -A
# IP Pool 생성 (충돌하지 않는 대역 사용)
cat << EOF | kubectl apply -f -
apiVersion: "cilium.io/v2"
kind: CiliumLoadBalancerIPPool
metadata:
name: "cilium-lb-ippool"
spec:
blocks:
- start: "192.168.10.211"
stop: "192.168.10.215"
EOF
# CiliumLoadBalancerIPPool 축약어 확인
kubectl api-resources | grep -i CiliumLoadBalancerIPPool
# 축약어: ippools, ippool, lbippool, lbippools
# IP Pool 상태 확인
kubectl get ippools
# Expected output:
# NAME DISABLED CONFLICTING IPS AVAILABLE AGE
# cilium-lb-ippool false False 5 5 20s
2.2 LoadBalancer 서비스 생성¶
# webpod 서비스를 LoadBalancer 타입으로 변경
kubectl patch svc webpod -p '{"spec":{"type":"LoadBalancer"}}'
# 서비스 상태 확인
kubectl get svc webpod
# Expected output:
# NAME TYPE CLUSTER-IP EXTERNAL-IP PORTS AGE
# webpod LoadBalancer 10.96.32.212 192.168.10.211 80:32039/TCP 150m
# External IP 확인
LBIP=$(kubectl get svc webpod -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
echo "LoadBalancer IP: $LBIP"
2.3 LoadBalancer IP 통신 테스트¶
클러스터 내부에서 테스트:
# 클러스터 내부에서 LB IP로 접근
curl -s $LBIP
kubectl exec -it curl-pod -- curl -s $LBIP
kubectl exec -it curl-pod -- curl -s $LBIP | grep Hostname
# 소스 IP 확인 (Pod 관점)
kubectl exec -it curl-pod -- curl -s $LBIP | grep RemoteAddr
# 로드밸런싱 확인
for i in {1..100}; do
kubectl exec -it curl-pod -- curl -s $LBIP | grep Hostname
done | sort | uniq -c | sort -nr
IP 할당 상태 확인:
# IP Pool 상태 상세 확인
kubectl get ippools
kubectl get ippools -o jsonpath='{.items[*].status.conditions[?(@.type!="cilium.io/PoolConflict")]}' | jq
# 서비스 상태 JSON 확인
kubectl get svc webpod -o json | jq
kubectl get svc webpod -o jsonpath='{.status}' | jq
2.4 외부 접근 문제¶
클러스터 외부에서 접근 시도:
# router에서 LB IP 접근 시도 (실패 예상)
# (router 서버에서 실행)
LBIP=192.168.10.211
curl --connect-timeout 1 $LBIP
# ARP 테이블 확인
arping -i eth1 $LBIP -c 1
# 지속적인 ARP 요청 (응답 없음)
arping -i eth1 $LBIP -c 100000
문제 원인: - LoadBalancer IP가 할당되었지만 외부 광고가 없음 - BGP 또는 L2 Announcements가 필요 - 네트워크 인프라가 해당 IP에 대한 경로를 모름
Cilium L2 Announcements¶
L2 Announcements 개념¶
1.1 MetalLB Layer2 모드 vs Cilium L2 Announcements¶

MetalLB Layer2 모드 동작:
- Speaker Pod가 LoadBalancer IP에 대한 ARP 응답
- 특정 노드에서만 IP 소유권 주장 (리더 선출)
- MAC 주소 학습을 통한 트래픽 전달
- 장애 시 다른 노드로 IP 이동
Cilium L2 Announcements 장점:
- MetalLB 대체: MetalLB를 대체할 수 있는 네이티브 기능
- eBPF 기반: 고성능 처리
- 통합성: Cilium 에코시스템과 완전 통합
- 안정성: 더 나은 성능과 안정성
1.2 L2 Announcements 활성화¶
Cilium L2 Announcements 설정:
# L2 Announcements 활성화
helm upgrade cilium cilium/cilium \
--namespace kube-system \
--reuse-values \
--set l2announcements.enabled=true
# 설정 확인
cilium config view | grep l2-announcements
# Expected: l2-announcements-enabled: true
# L2 Announcements 정책 생성
cat << EOF | kubectl apply -f -
apiVersion: "cilium.io/v2alpha1"
kind: CiliumL2AnnouncementPolicy
metadata:
name: default-l2-announcement-policy
spec:
serviceSelector:
matchLabels:
app: webpod
nodeSelector:
matchExpressions:
- key: node-role.kubernetes.io/control-plane
operator: DoesNotExist
interfaces:
- eth1
externalIPs: true
loadBalancerIPs: true
EOF
# 정책 확인
kubectl get CiliumL2AnnouncementPolicy
kubectl describe CiliumL2AnnouncementPolicy default-l2-announcement-policy
L2 Announcements 동작 확인¶
2.1 ARP 테이블 및 트래픽 확인¶
# LoadBalancer IP 재확인
LBIP=$(kubectl get svc webpod -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
echo "LoadBalancer IP: $LBIP"
# k8s 노드들에서 ARP 테이블 확인
ip -c neigh | grep $LBIP
sshpass -p 'vagrant' ssh vagrant@k8s-w1 ip -c neigh | grep $LBIP
sshpass -p 'vagrant' ssh vagrant@k8s-w0 ip -c neigh | grep $LBIP
# router에서 ARP 요청 및 응답 확인
# (router 서버에서 실행)
arping -i eth1 $LBIP -c 3
# ARP 테이블에서 응답 확인
arp -a | grep $LBIP
2.2 외부에서 LoadBalancer 서비스 접근¶
# router에서 HTTP 접근 (성공 예상)
# (router 서버에서 실행)
curl -s $LBIP
curl -s $LBIP | grep Hostname
# 지속적인 접근 테스트
while true; do
curl -s --connect-timeout 1 $LBIP | grep Hostname
sleep 1
done
2.3 L2 Announcements 로그 및 상태 확인¶
# Cilium L2 Announcements 관련 로그 확인
kubectl logs -n kube-system -l k8s-app=cilium -c cilium-agent | grep -i l2
# L2 Announcements 상태 확인
cilium status | grep -i l2
# LoadBalancer 서비스에 대한 L2 광고 확인
kubectl exec -n kube-system ds/cilium -c cilium-agent -- cilium service list | grep LoadBalancer
L2 Announcements 트러블슈팅¶
3.1 일반적인 문제점¶
문제 1: ARP 응답 없음
# L2 정책 확인
kubectl get CiliumL2AnnouncementPolicy -o yaml
# 노드 셀렉터 확인
kubectl get nodes --show-labels
# 인터페이스 설정 확인
ip -c addr show dev eth1
문제 2: 특정 노드에서만 응답
# 리더 선출 상태 확인
kubectl logs -n kube-system -l k8s-app=cilium -c cilium-agent | grep leader
# 모든 노드의 L2 상태 확인
for node in k8s-ctr k8s-w1 k8s-w0; do
echo "=== Node: $node ==="
kubectl get pods -n kube-system -l k8s-app=cilium --field-selector spec.nodeName=$node
done
3.2 성능 및 모니터링¶
# L2 Announcements 메트릭 확인
kubectl exec -n kube-system ds/cilium -c cilium-agent -- curl -s localhost:9962/metrics | grep l2
# 네트워크 인터페이스 통계
ip -s link show dev eth1
# ARP 캐시 만료 시간 확인
cat /proc/sys/net/ipv4/neigh/eth1/base_reachable_time_ms
모니터링 스택 구성¶
1.1 주요 구성 요소¶
| 컴포넌트 | 역할 |
|---|---|
| Prometheus | 메트릭 수집 및 저장 |
| Grafana | 시각화 및 대시보드 |
| AlertManager | 알림 관리 |
| Node Exporter | 노드 메트릭 수집 |
Cilium 관련 메트릭:
| 메트릭 | 포트 |
|---|---|
| Cilium Agent 메트릭 | 9962 |
| Cilium Operator 메트릭 | 9963 |
| Hubble 메트릭 | 9965 |
1.2 메트릭 수집 확인¶
# Cilium Agent 메트릭 확인
kubectl exec -n kube-system ds/cilium -c cilium-agent -- curl -s localhost:9962/metrics | head -20
# Cilium Operator 메트릭 확인
kubectl exec -n kube-system deploy/cilium-operator -- curl -s localhost:9963/metrics | head -20
# Hubble 메트릭 확인
kubectl exec -n kube-system deploy/hubble-relay -- curl -s localhost:9965/metrics | head -20
권장 모니터링 지표¶
2.1 Cilium 핵심 메트릭¶
성능 지표:
# eBPF 맵 사용률
cilium_datapath_conntrack_gc_entries
cilium_bpf_map_pressure
# 엔드포인트 재생성
cilium_endpoint_regenerations_total
# 패킷 드롭
cilium_drop_count_total
cilium_drop_bytes_total
서비스 지표:
# 로드밸런서 백엔드
cilium_services_events_total
cilium_k8s_client_api_calls_total
# L2 Announcements
cilium_l2_announcements_total
2.2 L2 Announcements 특화 메트릭¶
# L2 광고 성공/실패
kubectl exec -n kube-system ds/cilium -c cilium-agent -- curl -s localhost:9962/metrics | grep l2_announcement
YouTube eCHO Episode 시리즈¶
| 에피소드 | 내용 |
|---|---|
| eCHO Episode 1 | Cilium 소개 및 기본 개념 |
| eCHO Episode 7 | DNS with Laurent Bernaille |
| eCHO Episode 39 | Local Redirect Policy |
| eCHO Episode 56 | Service Mesh with Cilium |
| eCHO Episode 72 | BGP on Cilium |
공식 문서 및 블로그¶
| 문서 | 링크 |
|---|---|
| Cilium Service LoadBalancer & IPAM | docs.cilium.io |
| L2 Announcements Guide | docs.cilium.io |
| BGP Control Plane | docs.cilium.io |
| MetalLB Migration Guide | isovalent.com |
트러블슈팅 가이드¶
4.1 일반적인 문제점¶
Native Routing 문제:
# 라우팅 테이블 확인
ip route show table main
# BGP 피어 상태 확인 (BGP 사용 시)
cilium bgp peers
# 노드 간 연결성 확인
ping <other-node-ip>
L2 Announcements 문제:
# L2 정책 상태 확인
kubectl get CiliumL2AnnouncementPolicy -o yaml
# ARP 테이블 확인
ip neigh show
# 인터페이스 상태 확인
ip link show
4.2 성능 분석¶
네트워크 성능 측정:
# iperf3를 통한 대역폭 측정
kubectl run iperf3-server --image=networkstatic/iperf3 --port=5201
kubectl run iperf3-client --image=networkstatic/iperf3 --rm -it -- -c <server-ip>
# 지연시간 측정
kubectl exec -it curl-pod -- ping -c 100 <target-ip> | tail -1
핵심 성취 목표¶
네트워킹 모드 이해:
- Native Routing vs Overlay: 두 모드의 차이점 및 적용 시나리오
- VXLAN/GENEVE 터널링: UDP 기반 오버레이 캡슐화 메커니즘
- autoDirectNodeRoutes: 동일 네트워크 대역 노드 간 직접 경로 자동 생성
- MTU 고려사항: VXLAN 50 bytes 오버헤드로 인한 유효 MTU 감소 (1500 → 1450)
Service 외부 노출:
- LoadBalancer IPAM: CiliumLoadBalancerIPPool로 External IP 풀 관리
- L2 Announcements: ARP 기반으로 LoadBalancer IP를 외부에 광고
- kube-proxy 모드 비교: User Space → iptables → IPVS → nftables → eBPF 성능 진화
- 운영 고려사항: 규모별 적합한 외부 노출 방식 선택 기준