Cloudnet Cilium 3주차 스터디를 진행하며 정리한 글입니다.
쿠버네티스 환경에서 Cilium을 CNI로 사용할 경우, 네트워크 패킷이 노드 간 어떻게 전달되는지에 따라 다양한 데이터 경로 설정이 존재합니다.
이번 포스팅에서는 이 글에서는 Cilium에서 제공하는 대표적인 두 가지 네트워킹 방식인 Encapsulation 모드와 Native-Routing 모드에 대해 알아보겠습니다.
Encapsulation 방식 (VXLAN, Geneve 기반 터널링)
Encapsulation 모드는 Cilium의 기본 네트워크 설정으로, 클러스터 노드 간에 VXLAN(UDP 8472) 또는 Geneve(UDP 6081) 기반의 터널을 형성하여 패킷을 캡슐화해 전달합니다.
모든 Pod 간 통신은 터널 메시 위에서 캡슐화되어 전송되며 별도의 네트워크 라우팅 설정이 거의 필요 없습니다.
장점
- 간단한 설정 : PodCIDR이나 복잡한 네트워크 라우팅을 고려하지 않아도 됨
- 유연한 네트워크 구성 : L2 네트워크에 제한받지 않고, IP 연결만 가능하면 동작
- 정체성 전파 : VXLAN/Geneve 프로토콜의 메타데이터를 활용해 보안 ID 정보를 함께 전송
단점
- MTU 감소 및 성능 저하 : 캡슐화로 인해 패킷당 오버헤드가 발생하고, 이는 Throughput 저하로 이어짐
(예: VXLAN은 약 50바이트 MTU 손실) - 방화벽 포트 열어야 함 : UDP 8472(VXLAN) 또는 6081(Geneve)을 허용해야 함
Native-Routing 방식 (PodCIDR 기반 라우팅)

Cilium의 Native-Routing 모드는 캡슐화를 사용하지 않고, 리눅스의 기본 라우팅 기능을 그대로 활용하는 방입니다.Cilium은 패킷을 캡슐화하지 않고, 그냥 일반 IP 패킷처럼 리눅스 커널이 직접 라우팅하도록 맡깁니다. 마치 로컬에서 다른 서버로 ping을 보내는 것과 같은 방식으로 처리됩니다.
이 방식이 동작하려면 노드 간에 Pod IP(PodCIDR)를 어떻게 라우팅할지 알아야 합니다.
방식 1: 각 노드가 직접 다 알기
- 각 노드는 다른 노드의 PodCIDR을 직접 라우팅 테이블에 등록합니다.
- 단일 L2 네트워크(예: 같은 스위치에 다 물려 있음)라면 Cilium이 자동으로 처리할 수 있습니다.
- auto-direct-node-routes: true 옵션을 켜면 각 노드가 서로의 PodCIDR을 자동으로 인식해서 설정해줍니다.
- 이 방식은 온프레미스나 가상머신 기반 IDC 환경에서 자주 사용됩니다.
방식 2: 라우터가 대신 알아서 처리
- 각 노드는 Pod IP가 어디 있는지 모르지만, 대신 라우터나 클라우드 네트워크가 알아서 처리해줍니다.
- 이 경우, 각 노드는 그냥 기본 게이트웨이(라우터)만 알면 됩니다.
- 이 방식은 클라우드 환경에서 주로 사용되며, GCP, AWS, Azure에 맞게 자동 설정됩니다.
이러한 Native-Routing 방식은 Encapsulation 방식과 상반되는 장단점을 가집니다.
장점
- MTU 손실 없음 : 캡슐화를 하지 않기 때문에 오버헤드가 없고 네이티브 성능을 기대
- 간결한 트래픽 흐름 : 물리 네트워크 상에서 직접 라우팅되므로 디버깅과 분석이 용이합니다.
단점
- 복잡한 네트워크 구성 필요 : 모든 노드가 다른 노드의 PodCIDR을 인식하거나, 외부 라우터가 이를 지원해야 함
- 클라우드 환경에서는 네트워크 제약 존재 : VPC 라우팅 제한이 있는 경우에는 별도 설정(BGP, AWS ENI 등) 필요
노드 간 파드 통신 상세 확인 (Native Routing)
export WEBPODIP1=$(kubectl get -l app=webpod pods --field-selector spec.nodeName=k8s-ctr -o jsonpath='{.items[0].status.podIP}')
export WEBPODIP2=$(kubectl get -l app=webpod pods --field-selector spec.nodeName=k8s-w1 -o jsonpath='{.items[0].status.podIP}')
echo $WEBPODIP1 $WEBPODIP2
# curl-pod 에서 WEBPODIP2 로 ping
root@k8s-ctr:~# kubectl exec -it curl-pod -- ping $WEBPODIP2
PING 172.20.0.116 (172.20.0.116) 56(84) bytes of data.
64 bytes from 172.20.0.116: icmp_seq=1 ttl=62 time=0.991 ms
64 bytes from 172.20.0.116: icmp_seq=2 ttl=62 time=0.398 ms
^C
--- 172.20.0.116 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1004ms
rtt min/avg/max/mdev = 0.398/0.694/0.991/0.296 ms
# 커널 라우팅 확인
root@k8s-ctr:~# ip -c route
default via 10.0.2.2 dev eth0 proto dhcp src 10.0.2.15 metric 100
10.0.2.0/24 dev eth0 proto kernel scope link src 10.0.2.15 metric 100
10.0.2.2 dev eth0 proto dhcp scope link src 10.0.2.15 metric 100
10.0.2.3 dev eth0 proto dhcp scope link src 10.0.2.15 metric 100
10.10.0.0/16 via 192.168.10.200 dev eth1 proto static
172.20.0.0/24 via 192.168.10.101 dev eth1 proto kernel
172.20.1.99 dev lxc8b7378a068a9 proto kernel scope link
172.20.1.137 dev lxc934f4a2e5e88 proto kernel scope link
172.20.1.220 dev lxc947dc3379e6a proto kernel scope link
192.168.10.0/24 dev eth1 proto kernel scope link src 192.168.10.100
root@k8s-ctr:~# sshpass -p 'vagrant' ssh vagrant@k8s-w1 ip -c route
default via 10.0.2.2 dev eth0 proto dhcp src 10.0.2.15 metric 100
10.0.2.0/24 dev eth0 proto kernel scope link src 10.0.2.15 metric 100
10.0.2.2 dev eth0 proto dhcp scope link src 10.0.2.15 metric 100
10.0.2.3 dev eth0 proto dhcp scope link src 10.0.2.15 metric 100
10.10.0.0/16 via 192.168.10.200 dev eth1 proto static
172.20.0.23 dev lxc609f25f72da3 proto kernel scope link
172.20.0.116 dev lxc7b45d1ad94f5 proto kernel scope link
172.20.0.167 dev lxcdd13da375bd1 proto kernel scope link
172.20.0.175 dev lxcf4a287d6c2f3 proto kernel scope link
172.20.0.197 dev lxc6e9b0c254907 proto kernel scope link
172.20.0.217 dev lxcccced5c19afe proto kernel scope link
172.20.1.0/24 via 192.168.10.100 dev eth1 proto kernel
192.168.10.0/24 dev eth1 proto kernel scope link src 192.168.10.101
# 확인
root@k8s-ctr:~# hubble observe -f --pod curl-pod
Aug 2 16:58:36.953: default/curl-pod (ID:9908) -> default/webpod-7f475cbd84-z8qhj (ID:39964) to-endpoint FORWARDED (ICMPv4 EchoRequest)
Aug 2 16:58:36.953: default/curl-pod (ID:9908) <- default/webpod-7f475cbd84-z8qhj (ID:39964) to-network FORWARDED (ICMPv4 EchoReply)
Aug 2 16:58:36.977: default/curl-pod (ID:9908) -> default/webpod-7f475cbd84-z8qhj (ID:39964) to-network FORWARDED (ICMPv4 EchoRequest)
Aug 2 16:58:36.978: default/curl-pod (ID:9908) <- default/webpod-7f475cbd84-z8qhj (ID:39964) to-endpoint FORWARDED (ICMPv4 EchoReply)
root@k8s-ctr:~# tcpdump -i eth1 icmp
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on eth1, link-type EN10MB (Ethernet), snapshot length 262144 bytes
01:59:53.655815 IP 172.20.1.137 > 172.20.0.116: ICMP echo request, id 37, seq 1, length 64
01:59:53.656699 IP 172.20.0.116 > 172.20.1.137: ICMP echo reply, id 37, seq 1, length 64
01:59:54.656774 IP 172.20.1.137 > 172.20.0.116: ICMP echo request, id 37, seq 2, length 64
01:59:54.657207 IP 172.20.0.116 > 172.20.1.137: ICMP echo reply, id 37, seq 2, length 64


Native-Routing 모드에서 실제로 노드 간 Pod-to-Pod 통신이 커널 라우팅을 통해 이루어지는지 검증하기 위해, ping, ip route, hubble, tcpdump를 활용해 통신 흐름을 확인했습니다. Native-Routing 모드가 적용되어 있고 (routing-mode: native) PodCIDR 간 경로가 커널 라우팅 테이블에 설정되어 있었습니다.
특히, tcpdump를 통해 터널 없이 실제로 ICMP 패킷이 물리 NIC에서 직접 전달되는 것을 확인함으로써, 캡슐화 없이 네이티브 라우팅이 동작하고 있음을 확인할 수 있었습니다.
'스터디 > Cilium' 카테고리의 다른 글
| [Cilium] CoreDNS, NodeLocal DNSCache, Cilium Local Redirect Policy (6) | 2025.08.03 |
|---|---|
| [Cilium] eBPF 기반 NAT Masquerading 동작 및 ip-masq-agent를 통한 SNAT 제외 확인하기 (3) | 2025.08.03 |
| [Cilium] IPAM (3) | 2025.08.03 |
| [Cilium] Prometheus, Grafana을 활용한 Cilium 모니터링 (6) | 2025.07.27 |
| [Cilium] Cilium Observability - Hubble 설치 및 CiliumNetworkPolicy 적용 (3) | 2025.07.27 |