
- 실습 환경
- 목적: 다른 네트워크에 있는 노드 간 쿠버네티스 클러스터 통신을 확인하기 위함
- router 노드: k8s 에 join 되지 않은 서버로 192.168.10.0/24 ↔ 192.168.20.0/24 대역 라우팅 역할 수행
- k8s-w0 노드: k8s-ctr, k8s-w1 노드와 다른 네트워크 대역에 배치
- k8s-w1 노드: k8s-ctr 과 같은 네트워크 대역에 배치
[ k8s-ctr -> k8s-w0 라우팅 ]


k8s-w0 대역 요청 시, router의 eth1 인터페이스로 이동하여 통신하게 됩니다.
router node 의 eth1, eht2 인터페이스가 게이트웨이 역할을 하여 노드 간 통신은 할 수 있는 상태입니다.
Overlay Network 가 필요한 이유
쿠버네티스 환경에서 위와 같이 클러스터 대역 중 일부 노드가 다른 네트워크 대역을 사용한다면, 상호 간 통신이 불가합니다. 위 실습 환경에서는 k8s-w0 노드와 k8s-ctr, k8s-w1 노드 간 통신이 불가한 거죠.
cilium 을 설치할 때 autoDirectNodeRoutes=true 옵션을 사용하는데 자동으로 라우팅을 해주지 않는 걸까요?
helm install cilium cilium/cilium --version $2 --namespace kube-system \
--set k8sServiceHost=192.168.10.100 --set k8sServicePort=6443 \
--set ipam.mode="cluster-pool" --set ipam.operator.clusterPoolIPv4PodCIDRList={"172.20.0.0/16"} --set ipv4NativeRoutingCIDR=172.20.0.0/16 \
--set routingMode=native --set autoDirectNodeRoutes=true \
... 생략 ...
autoDirectNodeRoutes 옵션은 같은 네트워크 대역 노드 간에 pod CIDR 대역을 static routing 방식으로 자동으로 추가해주는 옵션입니다. 다른 네트워크 대역의 경우, 중간에 네트워크 장비가 pod CIDR 대역을 라우팅 안 해주면 의미가 없기 때문에 라우팅 추가를 하지 않습니다.
[ k8s-ctr 노드의 라우팅 테이블 ]

172.20.0.0/16 pod CIDR 대역 중 172.20.1.0/24 pod 네트워크만 k8s-w1(192.168.10.101) 노드로 라우팅이 되어 있지만, 172.20.2.0/24 pod CIDR 대역 대의 라우팅(k8s-w0 노드)이 보이지 않습니다.
[ k8s-w1 노드의 라우팅 테이블 ]

172.20.0.0/16 pod CIDR 대역 중 172.20.0.0/24 pod 네트워크만 k8s-ctr(192.168.10.100) 노드로 라우팅이 되어 있지만, 172.20.2.0/24 pod CIDR 대역 대의 라우팅(k8s-w0 노드)이 보이지 않습니다.
[ k8s-w0 노드의 라우팅 테이블 ]

172.20.2.0/24 pod CIDR 자신의 네트워크 대역은 cilium 이 활성화되어 있지만, k8s-ctr 노드와 k8s-w1 노드로 라우팅되어 있지 않습니다. 실제 패킷 캡처를 통해 네트워크 통신 여부도 살펴보겠습니다.

다른 네트워크 대역으로 통신 시 router 를 지나가니, router 노드에서 tcpdump 로 패킷을 스니핑합니다. k8s-ctr 서버에 위치한 curl-pod 로 k8s-w0 에 위치한 webpod 로 통신 시, 정상적으로 통신이 되지 않는 현상을 볼 수 있습니다.
아래 캡쳐된 네트워크 패킷들을 보면, eth1 로 들어왔는데 인터넷 전용 인터페이스인 eth0 으로 빠져나갔습니다. (eth0 인터페이스는 외부에서 쿠버네티스에 접근하기 위한 용도로 k8s 클러스터에서 접근할 일이 없습니다!)
통신 불가의 문제를 해결하려면 static routing 을 노드가 생성될 때마다 추가할 수 있지만 수동 처리에는 한계가 있습니다.
BGP, Encapsulation (Overlay Network) 방법들을 통해 문제를 해결합니다.
Encapsulation (Overlay Network)
설령 pod 대역 대의 IP 주소를 알지 못 하더라도 라우터는 노드의 IP 주소를 알고 라우팅을 할 수 있기 때문에, 노드의 IP 주소로 한 번 감싸 패킷을 보내면 통신이 가능해집니다.

여타 다른 CNI 플러그인과 같이 VXLAN 모드, GENEVE 모드를 통해 원본 패킷을 감싸 보낼 수 있습니다. 다른 네트워크 플러그인에서는 Overlay Network 라고 부르는데 Cilium 에서는 encapsulation 이라고 부릅니다.
Encapsulation 설정
VXLAN 과 GENEVE 를 활성화하려면 CONFIG_VXLAN 과 CONFIG_GENEVE 커널 설정을 활성화 해야 합니다.
아래와 같이 커널 옵션을 살펴보면 'm' 모듈로 컴파일되어 있어 직접 커널에 로드해서 사용합니다. modprobe 지시자로 원하는 모드를 선택하여 Overlay Network 를 활성화합니다.

나머지 두 노드에도 똑같이 설정을 해줍니다.

커널 설정 완료 후 helm routingMode=tunnel 옵션과 tunnelProtocol 옵션을 활성화 하여 cilium 을 rollout 해주면 모든 세팅이 완료됩니다.
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
kubectl rollout restart -n kube-system ds/cilium

cilium 의 속성을 확인해보면 routing 모드가 tunnel 유형으로 바뀌고 tunnel 프로토콜이 vxlan 으로 변경된 것을 확인할 수 있습니다.
완료 후 변화된 점들을 하나씩 알아보겠습니다. 클러스터에 존재하는 서버들에 cilium_vxlan 인터페이스가 새롭게 생성되었습니다.

라우팅 테이블도 클러스터의 pod CIDR 대역들이 모두 올라온 것을 확인할 수 있습니다.


k8s-ctr 서버에서는 podCIDR 대역이 172.20.0.98 로 라우팅 되고, k8s-w1 서버에서는 podCIDR 대역이 172.20.1.11 로 라우팅 되고, k8s-w0 서버에서는 podCIDR 대역이 172.20.2.71 로 라우팅 되는데 이 세 IP 가 cilium 에서 라우팅을 위해 만든 IP 입니다.
# cilium 파드 이름 지정
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
Encapsulation 통신 과정
샘플 애플리케이션을 활용하여 통신 과정을 살펴보겠습니다.
자기 자신이 누구인지 알려주는 3 개의 webpod 와 컨트롤 노드에만 배치할 curl-pod 를 배포하고, router 노드에서 패킷들을 확인해봅니다.
# 샘플 애플리케이션 배포
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:
- sample-app
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
# k8s-ctr 노드에 curl-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
컨트롤 노드의 curl-pod 에서 다른 네트워크 대역인 k8s-w0 노드로 ping 을 보내고, router 노드에서는 tcpdump -i any udp port 8472 -nn 명령어를 통해 VXLAN 패킷을 잡아보겠습니다.


eth1 인터페이스로 k8s-ctr 노드에서 k8s-w0 노드로 통신하는 패킷 요청이 들어왔고, (overlay 라고 표시되어 있음)
내부 파드 IP 호출 흐름이 한 번 표시된 다음 eth2 인터페이스로 나가는 것을 볼 수 있습니다.
termshark 로도 확인해보겠습니다.
# 반복 접속
kubectl exec -it curl-pod -- sh -c 'while true; do curl -s --connect-timeout 1 webpod | grep Hostname; echo "---" ; sleep 1; done'
# 신규 터미널 [router] 로 저장하고,
tcpdump -i any udp port 8472 -w /tmp/vxlan.pcap
# termshark 로 열어서 확인
termshark -r /tmp/vxlan.pcap -d udp.port==8472,vxlan
termshark 가 overlay network 를 인식하지 못하므로 -d upd.port=8472,vxlan 옵션을 통해 decapsulation 합니다.

마찬가지로 IP Header 가 중복으로 보이며 VXLAN 헤더가 존재하는 것을 볼 수 있습니다.
'인프라 > 쿠버네티스' 카테고리의 다른 글
| [cilium] BGP 설정 방법 (1) | 2025.08.15 |
|---|---|
| [cilium] cilium 의 LoadBalancer 서비스 (2) | 2025.08.09 |
| [cilium] Routing & Masquerading (1) | 2025.07.31 |
| [cilium] IPAM (3) | 2025.07.31 |
| [cilium] Hubble Exporter (2) | 2025.07.23 |