이제 어느덧 스터디 3주차에 접어들었다.
이번주는 집안일이 있어서, 스터디 온라인 시간에 직접 참여하지는 못했고 녹화영상으로 참여를 했다.
2주차까지는 Cilium 그리고 Hubble에 대해서 설치하고 간략하게 알아보는 시간이였다면
이제 3주차부터는 Cilium 사용이 네트워크에 어떻게 영향을 미치는지에 대해 본격적으로 알아보는 시간이다.
특이 이번주는 Native Routing(Direct Routing)에 대해서 알아본다.
- 회사에서도 Cilium을 사용하고 있는데 회사에서는 VXLAN 모드로 사용한다.
- Direct Routing을 사용하면 그만큼 NAT도 안하고, 패킷 오버헤드도 생기지 않아서 좋긴 하지만
- 다른 대역의 노드와 통신할때는 결국 라우터에서 Pod CIDR 대역으로 라우팅을 해줘야 하고
- 그리고 이를 BGP로 지원해줘야하기 떄문에 복잡해서 현재는 VXLAN 모드로 운영하고 있다.
실습 환경 구성
이번주 실습은 전주와 다르게 Router가 등장하다.
Router는 단순히 같은 노드이지만 다른 대역의 인터페이스를 가지는 노드이다.
같은 대역 또는 다른 IP대역에 대해서 Native Routing이 어떻게 동작하는지 알아보기 위함이다.

설치는 마찬가지로 Vagrantfile로 진행하면 된다. 그리고 가장 중요한 Cilium Helm values이다.
보면 여러가지가 있지만 중요한것만 보면
- ipam 모드가 kubernetes 이다.
- 이는 Controller Manager가 각 노드에 할당하는 PodCIDR를 사용하는 것이다.
- ipv4NativeRoutingCIDR가 있다.
- 이는 해당 PodCIDR에서는 NAT를 하지 않고 Pod Real IP로 통신하겠다는 뜻이다.
- 이번주차에서 다뤄볼 내용이며, 이에 따라서 어떻게 RoutingTable이 잡히는지 보면 된다.
- 마지막으로 bpf.masquerade이다.
- 이는 기본갓값이 true인데, 당연하게 Pod가 외부랑 통신할 때 노드 IP로 NAT되는지 여부이다.
- 이번주차에서는 route에 사내망 대역이 있다. 그리고 masquerade 옵션을 통해서 NAT 하지않고 통신하도록 한다.
- 원래는 사내망 대역은 클러스터 입장에서는 외부이기 때문에 노드 IP로 NAT되어 통신이 되는것이 일반적인 상식이다.
helm install cilium cilium/cilium --version $2 --namespace kube-system \
--set k8sServiceHost=192.168.10.100 --set k8sServicePort=6443 \
--set ipam.mode="kubernetes" --set k8s.requireIPv4PodCIDR=true --set ipv4NativeRoutingCIDR=10.244.0.0/16 \
--set routingMode=native --set autoDirectNodeRoutes=true --set endpointRoutes.enabled=true \
--set kubeProxyReplacement=true --set bpf.masquerade=true --set installNoConntrackIptablesRules=true \
--set endpointHealthChecking.enabled=false --set healthChecking=false \
--set hubble.enabled=true --set hubble.relay.enabled=true --set hubble.ui.enabled=true \
--set hubble.ui.service.type=NodePort --set hubble.ui.service.nodePort=30003 \
--set prometheus.enabled=true --set operator.prometheus.enabled=true --set hubble.metrics.enableOpenMetrics=true \
--set hubble.metrics.enabled="{dns,drop,tcp,flow,port-distribution,icmp,httpV2:exemplars=true;labelsContext=source_ip\,source_namespace\,source_workload\,destination_ip\,destination_namespace\,destination_workload\,traffic_direction}" \
--set operator.replicas=1 --set debug.enabled=true >/dev/null 2>&1
그래서 실습 환경을 만들고 나서
ciliumnode crd 또는 node의 정보를 보면 kubeadm config에서 지정한 kubernetes 자체 CIDR를 사용한다.

그리고 cilium-config을 보면 이번 주차에서 주요하게 보고자 하는 설정값이 잘 들어가있다.
{
"apiVersion": "v1",
"data": {
'''
"enable-bpf-masquerade": "true",
"enable-ipv4-masquerade": "true",
"ipam": "kubernetes",
"ipv4-native-routing-cidr": "10.244.0.0/16",
"routing-mode": "native",
'''
},
}
IPAM
IPAM은 흔히 네트워크 엔드포인트, 즉 Pod에 대한 IP 할당과 관리를 하는것을 의미한다.
통상적인 시스템에서는 kube-proxy이 IPAM의 역할을 한다.
하지만 cilium은 kube-proxy의 역할을 대체할 수 있기 때문에 cilium이 IPAM의 역할을 할 수 있다.

이중에서 kubernetes 그리고 cilium 에서 자체적으로 관리하는 cluster-pool 모드에 대해서 알아본다.
Kubernetes IPAM
가장 일반적인 방법으로 클러스터 노드에서 각 객체별로 IP CIDR를 할당해서 사용하는 방식이다.
(⎈|HomeLab:kube-system) root@k8s-ctr:~# kubectl get nodes -o jsonpath='{range .items[*]}{.metadata.name}{", POD CIDR: "}{.spec.podCIDR}{"\n"}{end}'
k8s-ctr, POD CIDR: 10.244.0.0/24
k8s-w1, POD CIDR: 10.244.1.0/24
---
kc describe pod -n kube-system kube-controller-manager-k8s-ctr
'''
Command:
kube-controller-manager
--allocate-node-cidrs=true << 노드 spec.podCIDR로 할당하겠다는 의미이다.
--cluster-cidr=10.244.0.0/16
'''
---
(⎈|HomeLab:kube-system) root@k8s-ctr:~# k get pods -o wide |grep 10.244
coredns-674b8bbfcf-twfmd 1/1 Running 0 10h 10.244.0.142 k8s-ctr <none> <none>
coredns-674b8bbfcf-vgb9r 1/1 Running 0 10h 10.244.0.143 k8s-ctr <none> <none>
hubble-relay-5dcd46f5c-mgxfc 1/1 Running 0 10h 10.244.0.78 k8s-ctr <none> <none>
hubble-ui-76d4965bb6-pcnxr 2/2 Running 0 10h 10.244.0.253 k8s-ctr <none> <none>
결과적으로 cilium은 daemonset으로 배포되어 있다.
그리고 내부적으로는 node 정보를 watch 형태로 스트림 데이터를 받고 있다.
그래서 node.sepc.podCIDR를 실시간으로 확인할 수 있고, cilium 내부 IPAM Pool에 넣고 이를 사용한다.
- 결과적으로 node에서 podCIDR를 제공할지, 아니면 cilum에서 podCIDR를 관리할지의 차이밖에 없다.
그리고 TEST APP을 배포하면 예상했던것과 같이 podCIDR 대역인 10.244.0.0/16으로 IP가 할당되어 있다.
(⎈|HomeLab:kube-system) root@k8s-ctr:~# k get pods,svc -owide|grep web
pod/webpod-697b545f57-68f72 1/1 Running 0 61s 10.244.1.13 k8s-w1 <none> <none>
pod/webpod-697b545f57-hm62q 1/1 Running 0 61s 10.244.0.248 k8s-ctr <none> <none>
service/webpod ClusterIP 10.96.232.58 <none> 80/TCP 61s app=webpod
이 상태에서 curl-pod을 띄워서 통신 테스트를 해보면 당연하게 통신이 된다.

Cilium IPAM Mig
현재 kubernetes IPAM 모드를 사용하고 있고, cilium이 관리하는 cluster pool IPAM로 변경하고자 한다.

일반적으로 기존 Cluster에서 IPAM 모드를 변경하는것은 권장하지 않는다.
IPAM 모드를 변경하려면 기본적으로 이전 IPAM 에서 할당했던 서비스 Pod을 모두 재시작해야한다.
이 과정에서 서비스 단절이 발생할 수 있다.
기존 cilium helm values에 ipam 모드와 IPCIDR만 변경해서 업그레이드 해보자.
- cilium 1.18이 릴리즈 되었다.
- 그래서 --version 옵션이 없으면 cilium 1.18로 배포를 시도하고 추가적인 values가 필요하므로 버전을 고정한다.
helm upgrade cilium cilium/cilium --namespace kube-system --reuse-values \
--set ipam.mode="cluster-pool" --set ipam.operator.clusterPoolIPv4PodCIDRList={"172.20.0.0/16"} --set ipv4NativeRoutingCIDR=172.20.0.0/16\
--version 1.17.6
그러면 ipam 모드는 변경됬다.
하지만 cilium에서는 node의 spec.podCIDR를 보고 이미 저장했기 때문에 기존 podCIDR는 변경되지 않는다.
(⎈|HomeLab:kube-system) root@k8s-ctr:~# cilium config view | grep ^ipam
ipam cluster-pool
ipam-cilium-node-update-rate 15s
---
(⎈|HomeLab:kube-system) root@k8s-ctr:~# kubectl get ciliumnode -o json | grep podCIDRs -A2
"podCIDRs": [
"10.244.0.0/24"
],
--
"podCIDRs": [
"10.244.1.0/24"
],
cilium, cilium-operator를 rollout을 해야지만 반영이 된다.
(⎈|HomeLab:kube-system) root@k8s-ctr:~# kubectl -n kube-system rollout restart deploy/cilium-operator
deployment.apps/cilium-operator restarted
(⎈|HomeLab:kube-system) root@k8s-ctr:~#
(⎈|HomeLab:kube-system) root@k8s-ctr:~# kubectl delete ciliumnode k8s-ctr
ciliumnode.cilium.io "k8s-ctr" deleted
(⎈|HomeLab:kube-system) root@k8s-ctr:~# kubectl delete ciliumnode k8s-w1
ciliumnode.cilium.io "k8s-w1" deleted
(⎈|HomeLab:kube-system) root@k8s-ctr:~# kubectl -n kube-system rollout restart ds/cilium
daemonset.apps/cilium restarted
---
(⎈|HomeLab:kube-system) root@k8s-ctr:~# kubectl get ciliumnode -o json | grep podCIDRs -A2
"podCIDRs": [
"172.20.1.0/24"
],
--
"podCIDRs": [
"172.20.0.0/24"
],
그리고 모든 pod을 재시작해줘야 최종적으로cilium IPAM의 podCIDR로 모든 pod IP가 변경된다.

노드는 spec.podCIDR가 10.244.0.0/16으로 되어 있으나, 이것을 사용하지 않고 cilium podCIDR를 사용했다.

cilium에서 DicrectRouting을 사용했다.
그리고 ipv4NativeRoutingCIDR를 172.20.0.0./16으로 설정하였기 때문에 이에 대한 라우팅테이블이 잡혀있다.
- k8s-w1에서 사용하는 podCIDR인 172.20.0.0/24에 대해서는 k8s-w1 노드로 라우팅테이블이 잡혀있다.

최종적으로 k8s-ctr -> k8s-w1으로 테스트를 해보면 NodeIP로 NAT가 되는게 아니라,
각 노드에 있는 pod IP를 사용하여 별도 NAT 없이 통신하는것을 볼 수 있다.
cilium에서 DicrectRounting으로 되어 있고, NativeRoutingCIDR를 172.20.0.0/16으로 잡았기 때문이다.
즉, 무슨 뜻이냐면 172.20.0.0/16의 podCIDR끼리는 별도 NAT를 시키지 않고 통신을 하겠다는것을 의미한다.

단순히 NAT를 하지 않는것인지 왜 좋은가? 하는 의문점을 가질 수 있다.
좋은점은 Overlay 방식과 비교해서 불필요한 캡슐화 과정이 없기 때문에 그만큼 네트워크 지연이 감소한다는것이다.
- 캡슐화를 하게 되면, 서버측/클라이언트측에서 디캡슐화를 하는 과정에서 CPU 오버헤드를 사용하고 그만큼 MTU도 커진다.
그리고 PodIP가 그대로 노출되기 떄문에 Monitroing이나 Debug하기도 훨씬 편하다.
물론 장점만 있는것은 아니다. 위 그림과 같이 dicrectRouting을 하게되면 podCIDR별로 StaticRoute를 설정해줘야한다.
그렇기 때문에 대규모 노드 환경에서는 라우팅테이블이 많아진다.
그리고 라우팅테이블에 제한이 있는 클라우드 환경에서는 사용이 어렵다.
- Overlay 방식에서는 라우팅은 cilium이 관리한다.
현재 재직중인 회사에서는 Overlay 방식, 즉 VXLAN 모드를 사용한다.
그래서 서로 다른 노드에 있는 서비스들끼리는 테스트를 할때는 트래픽이 많을떄는 tcpdump 필터링을 추가하거나 번거로웠다.
그래서 DicrectRounting을 사용하면 좋겠다라고 생각했었다. 네트워크 지연도 줄어들고 장점만 생각했었는데
이번주차를 해보니깐 가장 중요한 라우팅테이블을 어떻게 설정해야하지..? 하는 생각이 들었다.
라우팅테이블은 보통 네트워크팀에서 관리하기 떄문에 다른팀과 협업이 필요하고
기존의 방식과 많이 다른 부분이기 때문에 성능이 정말 좋아지는지, 이로 인해 Loop가 도는곳은 없는지 검증도 많이 필요할것 같다.
이번에는 실습 환경과 IPAM을 변경하는것에 대해서 알아보았다.
다음에는 DirectRouting에 대해서 자세히 알아보고, CoreDNS + nodeLocalDNS에 대해서 알아보려고 한다.
'기술 토론장 > [K8s] Kubernetes' 카테고리의 다른 글
| [Cilium][4주차] Node & Pod 네트워크 통신, Native vs VXLAN (6) | 2025.08.09 |
|---|---|
| [Cilium][3주차] Node & Pod 네트워크 통신 상세 - Routing, DNS (0) | 2025.08.03 |
| [Cilium][2주차] 심화학습 과제! (3) | 2025.07.23 |
| [Cilium][2주차] Prometheus/Grafana을 통한 Cilium 가시성 확보 (0) | 2025.07.22 |
| [Cilium][2주차] Hubble을 통한 Cilium Traffic 가시성 확보 (3) | 2025.07.21 |