본 내용은 gasida님의 Cilium 스터디를 진행 후 정리한 내용입니다.
꾸준히 업데이트 하면서 작성됩니다
실습 환경

이번 환경에서는 네트워크 구성을 보기 위해 router 서버가 별도로 구성됩니다.
router : 사내망 10.10.0.0/16 대역 통신과 연결, k8s 에 join 되지 않은 서버, loop1/loop2 dump 인터페이스 배치
Cilium CNI 설치
helm 설치 시 사용 되는 옵션부터 정리해 보겠습니다.
version은 1.17.6 입니다.
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
#--set ipam.mode="cluster-pool" --set ipam.operator.clusterPoolIPv4PodCIDRList={"172.20.0.0/16"} --set ipv4NativeRoutingCIDR=172.20.0.0/16 \
네트워크 옵션
- --set k8sServiceHost=192.168.10.100 --set k8sServicePort=6443
- Kubernetes API 서버의 주소와 포트를 명시
- --set ipam.mode="kubernetes"
- Kubernetes PodCIDR 정보를 그대로 사용(IPAM은 쿠버네티스가 관리).
- --set k8s.requireIPv4PodCIDR=true
- Kubernetes 노드에 반드시 PodCIDR(IPv4)이 사전 할당
- --set ipv4NativeRoutingCIDR=10.244.0.0/16
- 클러스터 PodCIDR 정의
- --set routingMode=native
- Native Routing : overay 없이 L3 라우팅
- --set autoDirectNodeRoutes=true
- Node 간 라우팅을 자동으로 설정 (BGP 없이도)
- --set endpointRoutes.enabled=true
- 각 파드에 대한 직접적인 라우팅테이블(/32)이 노드 라우팅 테이블에 추가
kube-proxy 대체
- --set kubeProxyReplacement=true
- kube-proxy를 완전히 대체
- Cilium이 Service LB를 처리합니다
- --set bpf.masquerade=true
- --set installNoConntrackIptablesRules=true
- iptables conntrack 관련 rule 설치 안 함 (BPF conntrack 사용)
- 커널의 iptables conntrack 대신 cilium eBPF 기반 conntrack 사용
Linux 커널은 conntrack이라는 기능으로 연결 상태(NEW, ESTABLISHED, RELATED 등)를 추적합니다
커널의 Connection Tracking (conntrack)
: Linux 커널의 netfilter 프레임워크 안에 포함된 기능
Cilium은 iptables를 우회하고, eBPF로 자체 연결 추적 기능을 구현합니다.
이미 eBPF로 연결 추적중이므로 중복 제거
헬스 체크
- --set endpointHealthChecking.enabled=false
- --set healthChecking=false
- Cilium 자체 health checking 기능 비활성화
- However it is recommended that those features be enabled initially on a smaller cluster (3-10 nodes) where it can be used to detect potential packet loss due to firewall rules or hypervisor settings.
- 소규모에서는 키는 것을 추천
- cilium-agent 데몬셋 로그확인
https://docs.cilium.io/en/stable/operations/performance/scalability/report/
Hubble
- --set hubble.enabled=true
- Hubble 기능 활성화
- --set hubble.relay.enabled=true
- Hubble Relay 활성화
- --set hubble.ui.enabled=true
- Hubble UI 활성화
- --set hubble.ui.service.type=NodePort --set hubble.ui.service.nodePort=30003
- Hubble UI를 NodePort(30003)로 노출
- --set hubble.metrics.enabled="{dns,drop,tcp,flow,port-distribution,icmp,httpV2:...}"
- Hubble이 수집하는 메트릭 종류 지정 (dns, tcp, drop, flow 등)
- --set hubble.metrics.enableOpenMetrics=true
- OpenMetrics 포맷 지원
모니터링
- --set prometheus.enabled=true
- Cilium Prometheus exporter 활성화.
- --set operator.prometheus.enabled=true
- Operator 측도 Prometheus 메트릭 활성화.
주석부분
Cilium의 Cluster pool IPAM 모드를 사용해서 파드 IP를 직접 할당하는 방식입니다.
--set ipam.mode="cluster-pool" \
--set ipam.operator.clusterPoolIPv4PodCIDRList={"172.20.0.0/16"} \
--set ipv4NativeRoutingCIDR=172.20.0.0/16
1. --set ipam.mode="cluster-pool"
• IP 할당을 Kubernetes가 아니라 Cilium Operator가 직접 관리
• Kubernetes가 PodCIDR을 할당하지 않아도 Cilium이 자체적으로 처리
2. --set ipam.operator.clusterPoolIPv4PodCIDRList={"172.20.0.0/16"}
• Cilium이 사용할 전체 IP 풀을 지정
• Cilium은 대역을 나눠서 각 노드에 /24씩 할당 (예: 172.20.0.0/24, 172.20.1.0/24 등)
3. --set ipv4NativeRoutingCIDR=172.20.0.0/16
• 라우팅 테이블 설정에 사용될 전체 PodCIDR
• native routing을 쓸 때 필수로 필요
Cilium & Hubble CLI 설치
CILIUM_CLI_VERSION=$(curl -s https://raw.githubusercontent.com/cilium/cilium-cli/main/stable.txt)
CLI_ARCH=amd64
if [ "$(uname -m)" = "aarch64" ]; then CLI_ARCH=arm64; fi
curl -L --fail --remote-name-all https://github.com/cilium/cilium-cli/releases/download/${CILIUM_CLI_VERSION}/cilium-linux-${CLI_ARCH}.tar.gz >/dev/null 2>&1
tar xzvfC cilium-linux-${CLI_ARCH}.tar.gz /usr/local/bin
rm cilium-linux-${CLI_ARCH}.tar.gz
HUBBLE_VERSION=$(curl -s https://raw.githubusercontent.com/cilium/hubble/master/stable.txt)
HUBBLE_ARCH=amd64
if [ "$(uname -m)" = "aarch64" ]; then HUBBLE_ARCH=arm64; fi
curl -L --fail --remote-name-all https://github.com/cilium/hubble/releases/download/$HUBBLE_VERSION/hubble-linux-${HUBBLE_ARCH}.tar.gz >/dev/null 2>&1
tar xzvfC hubble-linux-${HUBBLE_ARCH}.tar.gz /usr/local/bin
rm hubble-linux-${HUBBLE_ARCH}.tar.gz
그외 설치
echo "[TASK 11] Install Prometheus & Grafana"
kubectl apply -f https://raw.githubusercontent.com/cilium/cilium/1.17.6/examples/kubernetes/addons/prometheus/monitoring-example.yaml >/dev/null 2>&1
kubectl patch svc -n cilium-monitoring prometheus -p '{"spec": {"type": "NodePort", "ports": [{"port": 9090, "targetPort": 9090, "nodePort": 30001}]}}' >/dev/null 2>&1
kubectl patch svc -n cilium-monitoring grafana -p '{"spec": {"type": "NodePort", "ports": [{"port": 3000, "targetPort": 3000, "nodePort": 30002}]}}' >/dev/null 2>&1
echo "[TASK 12] Dynamically provisioning persistent local storage with Kubernetes"
kubectl apply -f https://raw.githubusercontent.com/rancher/local-path-provisioner/v0.0.31/deploy/local-path-storage.yaml >/dev/null 2>&1
kubectl patch storageclass local-path -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"true"}}}' >/dev/null 2>&1
k9s 설치
https://github.com/derailed/k9s
GitHub - derailed/k9s: 🐶 Kubernetes CLI To Manage Your Clusters In Style!
🐶 Kubernetes CLI To Manage Your Clusters In Style! - derailed/k9s
github.com
# arm64 CPU
wget https://github.com/derailed/k9s/releases/latest/download/k9s_linux_arm64.deb -O /tmp/k9s_linux_arm64.deb
apt install /tmp/k9s_linux_arm64.deb
# amd64 CPU
wget https://github.com/derailed/k9s/releases/latest/download/k9s_linux_amd64.deb -O /tmp/k9s_linux_amd64.deb
apt install /tmp/k9s_linux_amd64.deb
#
which k9s
IPAM
IP Address Management
네트워크 엔드포인트 (컨테이너 등)에 대한 IP 할당과 관리

| Kubernetes Host Scope | 쿠버네티스가 직접 노드 단위로 PodCIDR을 할당. Cilium은 그대로 사용 |
| Cluster Scope (default) | Cilium이 클러스터 전체 IP 풀을 관리해서 각 노드에 분배 (기본값) |
| Multi-Pool (Beta) | 여러 IP 풀을 만들고 워크로드나 네임스페이스에 따라 선택적으로 할당 (실험적) |
| CRD-backed | IP pool을 CRD로 선언해서 API 기반으로 동적 관리 가능 |
| AWS ENI | AWS EC2의 ENI (Elastic Network Interface)를 직접 활용하는 IPAM 방식 (cloud-native) |
- Tunnel routing : VXLAN 같은 오버레이 터널 기반 라우팅 지원
- Direct routing : 터널 없이 L3 네이티브 라우팅 지원 여부
- CIDR Configure : CIDR 설정 위치
- Multiple CIDRs per cluster : 클러스터 전체에서 여러 CIDR 블록을 지원하는지
-> 초기 172.20.0.0/16 을 다쓰면 172.30.0.0/16 과 같은 여러 서브넷을 유연하게 확장
- Multiple CIDRs per node : 하나의 노드에 여러 개의 CIDR 블록을 붙일 수 있는지
-> 하나의 노드에서 여러 서브넷 PodCIDR 블록을 동시에 붙여서 사용
-> Multi-Pool 모드 또는 ENI 기반 IPAM에서 주로 사용
-> 특정 워크로드의 별도 대역 할당 및 보안강화, 유연성 강화
- Dynamic CIDR/IP allocation : 클러스터 운영 중 IP 풀을 동적으로 확장/관리할 수 있는지
-> 클러스터 재시작 또는 Cilium 재설치 없이 IP 풀을 동적으로 조정 가능합니다 (무중단, 정책 기반 확장)
Kubernetes Host Scope

쿠너네티스 호스트 범위 IPAM 모드는 클러스터의 각 개별 노드에 주소 할당을 위임합니다.
IP는 쿠버네티스에 의해 각 노드에 연결된 PodCIDR 범위에서 할당됩니다.
kube-controller-manager가 각 Node에 podCIDR을 할당되어서
제공되는 IP 범위를 알아야 Cilium은 기동됩니다.
# 클러스터 정보 확인
kubectl cluster-info dump | grep -m 2 -E "cluster-cidr|service-cluster-ip-range"
"--service-cluster-ip-range=10.96.0.0/16",
"--cluster-cidr=10.244.0.0/16",
# ipam 모드 확인
cilium config view | grep ^ipam
ipam kubernetes
# 노드별 파드에 할당되는 IPAM(PodCIDR) 정보 확인
# --allocate-node-cidrs=true 로 설정된 kube-controller-manager에서 CIDR을 자동 할당함
kubectl get nodes -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.spec.podCIDR}{"\n"}{end}'
k8s-ctr 10.244.0.0/24
k8s-w1 10.244.1.0/24
--allocate-node-cidrs 옵션 확인
cat /etc/kubernetes/manifests/kube-controller-manager.yaml | grep allocate-node-cidrs

ps -ef | grep kube-controller-manager | grep allocate-node-cidrs

k8s-ctr 노드는 자신에게 할당된 클러스터 대역인 10.244.0.0/16에서 할당합니다.
kc describe pod -n kube-system kube-controller-manager-k8s-ctr
...
Command:
kube-controller-manager
--allocate-node-cidrs=true
--cluster-cidr=10.244.0.0/16
--service-cluster-ip-range=10.96.0.0/16
...
kubectl get ciliumnode -o json | grep podCIDRs -A2
# 파드 정보 : 상태, 파드 IP 확인
kubectl get ciliumendpoints.cilium.io -A
샘플 어플리케이션 배포 및 확인
# 샘플 애플리케이션 배포
cat << EOF | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
name: webpod
spec:
replicas: 2
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
# 배포 확인
kubectl get deploy,svc,ep webpod -owide
kubectl get endpointslices -l app=webpod
kubectl get ciliumendpoints # IP 확인
kubectl exec -it -n kube-system ds/cilium -c cilium-agent -- cilium-dbg endpoint list
# 통신 확인
kubectl exec -it curl-pod -- curl webpod | grep Hostname
kubectl exec -it curl-pod -- sh -c 'while true; do curl -s webpod | grep Hostname; sleep 1; done'
hubble 확인
# hubble ui 웹 접속 주소 확인 : default 네임스페이스 확인
NODEIP=$(ip -4 addr show eth1 | grep -oP '(?<=inet\s)\d+(\.\d+){3}')
echo -e "http://$NODEIP:30003"
# hubble relay 포트 포워딩 실행
cilium hubble port-forward&
hubble status
# flow log 모니터링
hubble observe -f --protocol tcp --to-pod curl-pod
hubble observe -f --protocol tcp --from-pod curl-pod
hubble observe -f --protocol tcp --pod curl-pod
l 26 08:15:33.840: default/curl-pod (ID:37934) <> 10.96.88.194:80 (world) pre-xlate-fwd TRACED (TCP)
Jul 26 08:15:33.840: default/curl-pod (ID:37934) <> default/webpod-697b545f57-2h59t:80 (ID:23913) post-xlate-fwd TRANSLATED (TCP)
Jul 26 08:15:33.840: default/curl-pod:53092 (ID:37934) -> default/webpod-697b545f57-2h59t:80 (ID:23913) to-network FORWARDED (TCP Flags: SYN)
Jul 26 08:15:33.841: default/curl-pod:53092 (ID:37934) <- default/webpod-697b545f57-2h59t:80 (ID:23913) to-endpoint FORWARDED (TCP Flags: SYN, ACK)
pre-xlate-fwd , TRACED : NAT (IP 변환) 전 , 추적 중인 flow
post-xlate-fwd , TRANSLATED : NAT 후의 흐름 , NAT 변환이 일어났음
# 호출 시도
kubectl exec -it curl-pod -- curl webpod | grep Hostname
kubectl exec -it curl-pod -- curl webpod | grep Hostname
혹은
kubectl exec -it curl-pod -- sh -c 'while true; do curl -s webpod | grep Hostname; sleep 1; done'
# tcpdump 확인 : 파드 IP 확인
tcpdump -i eth1 tcp port 80 -nn
17:23:25.920613 IP 10.244.0.144.39112 > 10.244.1.180.80: Flags [P.], seq 1:71, ack 1, win 502, options [nop,nop,TS val 3745105977 ecr 1971332111], length 70: HTTP: GET / HTTP/1.1
#
tcpdump -i eth1 tcp port 80 -w /tmp/http.pcap
#
termshark -r /tmp/http.pcap

Cluster Scope & 마이그레이션 실습

클러스터 범위 IPAM 모드는 각 노드에 노드별 PodCIDR을 할당하고 각 노드에 호스트 범위 할당기를 사용하여 IP를 할당합니다.
Kubernetes가 Kubernetes v1.Node 리소스를 통해 노드별 PodCIDR을 할당하는 대신,
Cilium operator가 v2.CiliumNode 리소스(CRD)를 통해 노드별 PodCIDR을 관리합니다.
기본값은 10.0.0.0/8 입니다. (clusterPoolIPv4PodCIDRList)
최소 마스크 길이는 /30이며 권장 최소 마스크 길이는 /29 이상입니다.
2개 주소는 예약주소입니다. (네트워크, 브로드캐스트 주소)
| CIDR블록 | 총 주소 | 사용 가능 개수 | 설명 |
| /30 | 4개 | 2개 | 2개는 예약 (네트워크/브로드캐스트) |
| /29 | 8개 | 6개 | 권장 최소값 |
| /24 | 256개 | 254개 | 일반적인 노드당 CIDR |
# 반복 요청 해두기
kubectl exec -it curl-pod -- sh -c 'while true; do curl -s webpod | grep Hostname; sleep 1; done'
# Cluster Scopre 로 설정 변경
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
kubectl -n kube-system rollout restart deploy/cilium-operator # 오퍼레이터 재시작 필요
kubectl -n kube-system rollout restart ds/cilium
# 변경 확인
kubectl get nodes -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.spec.podCIDR}{"\n"}{end}'
처음 주석해두었던 명령어로 helm upgrade를 진행합니다.
IPAM 변경에는 오퍼레이터 재시작과 데몬셋 재시작이 필요합니다.

cilium config view | grep ^ipam
ipam cluster-pool
kubectl get ciliumnode -o json | grep podCIDRs -A2
kubectl get ciliumendpoints.cilium.io -A

#
kubectl delete ciliumnode k8s-w1
kubectl -n kube-system rollout restart ds/cilium
kubectl get ciliumnode -o json | grep podCIDRs -A2
kubectl get ciliumendpoints.cilium.io -A
#
kubectl delete ciliumnode k8s-ctr
kubectl -n kube-system rollout restart ds/cilium
kubectl get ciliumnode -o json | grep podCIDRs -A2
kubectl get ciliumendpoints.cilium.io -A
# 파드 IP 변경 되는가?

-> endpointRoutes.enabled=true가 적용되어 각 Pod IP에 대해 별도 라우팅이 생성됩니다.
(이 라우팅이 없으면 cilium_host를 통해 전달됩니다)
172.20.0.0/24 via 192.168.10.101 dev eth1
다른노드로는 autoDirectNodeRoutes=true에 의해 설정된 정적 라우팅 됩니다.
-> eth1 을 통해 해당 노드로 전달됩니다.
# 노드의 poccidr static routing 자동 변경 적용 확인
ip -c route
sshpass -p 'vagrant' ssh vagrant@k8s-w1 ip -c route
# 직접 rollout restart 하자!
kubectl get pod -A -owide | grep 10.244.
kubectl -n kube-system rollout restart deploy/hubble-relay deploy/hubble-ui
kubectl -n cilium-monitoring rollout restart deploy/prometheus deploy/grafana
kubectl rollout restart deploy/webpod
kubectl delete pod curl-pod
# hubble cli 가 cilium hubble relay에 연결되도록 포트포워딩
cilium hubble port-forward&
4245 로컬 포트가 포워딩 됩니다.
-> Hubble Relay gRPC API (CLI 연결용)

Routing
Encapsulation (VXLAN, GENEVE)
https://docs.cilium.io/en/stable/network/concepts/routing/
Cilium 기본 네트워킹 인프라에서 요구 사항이 가장 적은 모드 (default)
이 모드에서는 모든 클러스터 노드가 UDP 기반 캡슐화 프로토콜 VXLAN 또는 Geneve를 사용하여 터널의 메시를 형성합니다
Cilium 노드 간의 모든 트래픽이 캡슐화됩니다.
Cilium 노드가 이미 서로 연결될 수 있다면 모든 라우팅 요구 사항이 이미 충족
기본 네트워크는 IPv4를 지원해야 합니다.
기본 네트워크와 방화벽은 캡슐화된 패킷을 허용해야 합니다:
- VXLAN (default) : UDP 8472
- Geneve : UDP 6081
- 장점
- 단순성 Simplicity
- 클러스터 노드를 연결하는 네트워크는 PodCIDR을 인식할 필요가 없습니다. (별도 라우팅 설정X)
- 클러스터 노드는 여러 라우팅 또는 링크 계층 도메인을 생성할 수 있습니다.
- 단순성 Simplicity
라우팅 도메인 : 서로 다른 L3 서브넷
링크 계층 도메인 : L2 브로드캐스트 영역
-
-
-
- 클러스터 노드가 IP/UDP를 사용하여 서로 연결할 수 있는 한 기본 네트워크의 토폴로지는 중요하지 않습니다.
- UDP 통과하면 작동하므로 복잡한 L3 구성없이 동작합니다.
- 클러스터 노드가 IP/UDP를 사용하여 서로 연결할 수 있는 한 기본 네트워크의 토폴로지는 중요하지 않습니다.
-
- 정체성 맥락 Identity context
- 캡슐화 프로토콜은 네트워크 패킷과 함께 메타데이터를 전송할 수 있게 해줍니다.
- Cilium은 소스 보안 ID와 같은 메타데이터를 전송하는 이 기능을 활용합니다.
- The identity transfer is an optimization designed to avoid one identity lookup on the remote node.
-
- 단점
- MTU Overhead
- 캡슐화 헤더를 추가하면 페이로드에 사용할 수 있는 유효 MTU가 네이티브 라우팅(VXLAN의 경우 네트워크 패킷당 50바이트)보다 낮아집니다. / 실제 유효 MTU 약 1450
- 이로 인해 특정 네트워크 연결에 대한 최대 처리량이 낮아집니다.
- 이는 점보 프레임(9000바이트당 오버헤드 50바이트)을 활성화함으로써 크게 완화될 수 있습니다.
- 물리 NIC, vSwitch, 가상 네트워크 모두에서 MTU 9000을 설정
- MTU Overhead
- 설정
- tunnel-protocol: Set the encapsulation protocol to vxlan or geneve, defaults to vxlan.
- tunnel-port: Set the port for the encapsulation protocol. Defaults to 8472 for vxlan and 6081 for geneve
Native-Routing

- 네이티브 라우팅 데이터 경로는 라우팅 모드에서 Native로 활성화되며 네이티브 패킷 전달 모드를 활성화합니다.
- 네이티브 패킷 전달 모드는 캡슐화를 수행하는 대신 Cilium이 실행되는 네트워크(노드)의 라우팅 기능을 활용합니다.
- 네이티브 라우팅 모드에서는 Cilium이 다른 로컬 엔드포인트로 주소 지정되지 않은 모든 패킷을 Linux 커널의 라우팅 하위 시스템에 위임합니다.
- 이는 패킷이 로컬 프로세스가 패킷을 방출한 것처럼 라우팅된다는 것을 의미합니다
- -> 패킷은 Cilium이 아닌, 노드 자체의 커널이 처리하는 일반 트래픽처럼 전송됩니다
- 따라서 클러스터 노드를 연결하는 네트워크는 PodCIDR을 라우팅할 수 있어야 합니다.
- PodCIDR 라우팅 방안 1
- 각 개별 노드는 다른 모든 노드의 모든 Pod IP를 인식하고 이를 표현하기 위해 Linux 커널 라우팅 테이블에 삽입됩니다.
- 모든 노드가 단일 L2 네트워크를 공유하는 경우 auto-direct-node-routes: true하여 이 문제를 해결할 수 있습니다.

# 각 노드의 PodCIDR은 kubernetes에 등록
k8s-w1: PodCIDR = 172.20.1.0/24, Node IP = 192.168.10.101
k8s-w2: PodCIDR = 172.20.2.0/24, Node IP = 192.168.10.102
# Cilium 은 이 정보를 Kubernetes API를 통해 알고 옵션이 true이면 정적경로를 추가
# autoDirectNodeRoutes=true
172.20.2.0/24 via 192.168.10.102 dev eth1
- 그렇지 않으면 BGP 데몬과 같은 추가 시스템 구성 요소를 실행하여 경로를 배포해야 합니다.
- PodCIDR 라우팅 방안 2
- 노드 자체는 모든 포드 IP를 라우팅하는 방법을 모르지만 다른 모든 포드에 도달하는 방법을 아는 라우터가 네트워크에 존재합니다.
- 이 시나리오에서는 Linux 노드가 이러한 라우터를 가리키는 기본 경로를 포함하도록 구성됩니다.
- 노드가 L3로 분리되고 route로 자동광고가 필요한 경우
- 이 모델은 클라우드 환경에서 일반적입니다
- AWS, GCP, Azure 등의 가상 네트워크 라우터가 Pod IP를 이해하고 처리해주는 구조
- 설정
- routing-mode: native: Enable native routing mode.
- ipv4-native-routing-cidr: x.x.x.x/y: Set the CIDR in which native routing can be performed.
- auto-direct-node-routes: true : 동일 L2 네트워크 공유 시, 걱 노드의 PodCIDR에 대한 Linux 커널 라우팅 테이블에 삽입.
Masquerading
구현방식 : eBPF 기반 vs iptables 기반
https://docs.cilium.io/en/stable/network/concepts/masquerading/

- 포드에 사용되는 IPv4 주소는 일반적으로 프라이빗 IP (RFC1918) 에서 할당되므로 공개적으로 라우팅할 수 없습니다.
- Cilium은 노드의 IP 주소가 이미 네트워크에서 라우팅 가능하기 때문에 클러스터를 떠나는 모든 트래픽의 소스 IP 주소를 자동으로 masquerade(SNAT) 합니다.
- 만약 masquerade 기능을 OFF 하려면, enable-ipv4-masquerade: false , enable-ipv6-masquerade: false
- 기본 동작은 로컬 노드의 IP 할당 CIDR 내에서 모든 목적지를 제외하는 것입니다.
- 같은 노드 내부 통신이나 같은 CIDR 범위 통신은 SNAT 하지 않습니다
- 더 넓은 네트워크에서 Pod IP를 라우팅할 수 있는 경우, 해당 네트워크는 ipv4-native-routing-cidr: 10.0.0/8 (또는 IPv6 주소의 경우 ipv6-native-routing-cidr: fd00:/100) 옵션을 사용하여 지정할 수 있습니다.
- 네트워크 인프라가 Pod IP 대역을 라우팅 가능하면 SNAT 필요하지 않습니다
# ipv4-native-routing-cidr: 10.0.0.0/8
목적지가 해당 범위 내 있는 IP 인 경우 masquerade (SNAT) 하지않고 출발지 IP (Pod IP)를 그대로 유지합니다
구현방식
eBPF-based : bpf.masquerade=true
- By default, BPF masquerading also enables the BPF Host-Routing mode
- eBPF Host Routing은 Istio와 호환되지 않습니다
- Istio는 자체 프록시(istio-proxy, Envoy)가 iptables와 veth 장치 기반으로 트래픽을 제어
- eBPF Host Routing은 이를 우회하기 때문에, Istio가 기대하는 트래픽 흐름이 깨질 수 있음
| 구분 | 전통적인 방식 | eBPF Host Routing |
| 패킷 처리 | veth → iptables → routing table | eBPF 프로그램이 직접 경로 결정 |
| 네임스페이스 전환 | 표준 Linux 함수 호출 | eBPF로 직접 빠르게 |
| 성능 | 비교적 느림 | 빠름 (경량화된 경로) |
| iptables 사용 | 필수 | 우회함 |
| 호환성 | 대부분 호환 | 일부 Istio와 충돌 가능 |
by GPT
- Masquerading은 eBPF Masquerading 프로그램을 실행하는 장치에서만 수행할 수 있습니다.
- 즉 특정 인터페이스에 eBPF 프로그램이 붙어있어야 수행 가능
- 이는 출력 장치가 프로그램을 실행하는 경우 포드에서 외부 주소로 전송된 패킷이 Masquerading(출력 장치 IPv4 주소로)된다는 것을 의미합니다.
(⎈|HomeLab:N/A) root@k8s-ctr:~# kubectl exec -it -n kube-system ds/cilium -c cilium-agent -- cilium status | grep Masquerading
Masquerading: BPF (ip-masq-agent) [eth0, eth1] 172.20.0.0/16 [IPv4: Enabled, IPv6: Disabled]
-> eth0, eth1 인터페이스를 통해 나가는 Pod -> 외부트래픽에 대한 SNAT를 수행합니다.
- The eBPF-based masquerading can masquerade packets of the following L4 protocols: TCP, UDP, ICMP
- 4계층 프로토콜 중 TCP, UDP, ICMP에 대해서만 SNAT를 지원합니다
- 기본적으로 ipv4-native-routing-cidr 범위를 벗어난 IP 주소로 향하는 포드의 모든 패킷은 Masquerading (SNAT)
- ipv4-native-routing-cidr = 172.20.0.0/16
- 다른 (클러스터) 노드(Node IP)로 향하는 패킷은 제외됩니다
- Cilium은 클러스터 내 노드 IP로 향하는 모든 트래픽은 NAT 제외 대상으로 기본 처리
- eBPF 마스커딩이 활성화되면 포드에서 클러스터 노드의 External IP로의 트래픽도 마스커딩되지 않습니다

## ipv4-native-routing-cidrs 범위는 masquerading 하지 않습니다
# cilium config view | grep ipv4-native-routing-cidr
ipv4-native-routing-cidr 172.20.0.0/16
# 노드 IP로 통신 시 확인
tcpdump -i eth1 icmp -nn
kubectl exec -it curl-pod -- ping 192.168.10.101

- iptables-based
- 이것은 모든 커널 버전에서 작동할 레거시 구현입니다
- Cilium이 관리하지 않는 네트워크 인터페이스(예: eth0, ens3)로 나가는 트래픽은 모두 SNAT 처리
- the option egress-masquerade-interfaces: eth0 can be used.
- 옵션을 통해 SNAT을 수행할 네트워크 인터페이스를 지정할 수 있습니다
- the option enable-masquerade-to-route-source: "true"
- 일반적으로는 노드의 primary IP (예: eth0) 로 SNAT 합니다
- 트래픽의 목적지에 따라 선택된 출발지 IP를 사용해 SNAT 합니다
masquerading 실습
# 현재 설정 확인
kubectl exec -it -n kube-system ds/cilium -c cilium-agent -- cilium status | grep Masquerading
Masquerading: BPF [eth0, eth1] 172.20.0.0/16 [IPv4: Enabled, IPv6: Disabled]
#
cilium config view | grep ipv4-native-routing-cidr
ipv4-native-routing-cidr 172.20.0.0/16
# iptables 확인
iptables-save | grep -v KUBE | iptables-restore
iptables-save
sshpass -p 'vagrant' ssh vagrant@k8s-w1 "sudo iptables-save | grep -v KUBE | sudo iptables-restore"
sshpass -p 'vagrant' ssh vagrant@k8s-w1 sudo iptables-save
# 통신 확인
kubectl exec -it curl-pod -- curl -s webpod | grep Hostname
kubectl exec -it curl-pod -- curl -s webpod | grep Hostname
router eth1 192.168.10.200 통신 확인
# 터미널 2개 사용
[k8s-ctr] tcpdump -i eth1 icmp -nn 혹은 hubble observe -f --pod curl-pod
[router] tcpdump -i eth1 icmp -nn
# router eth1 192.168.10.200 로 ping >> IP 확인해보자!
kubectl exec -it curl-pod -- ping 192.168.10.101
kubectl exec -it curl-pod -- ping 192.168.10.200
...
---
# 터미널 2개 사용
[k8s-ctr] tcpdump -i eth1 tcp port 80 -nnq 혹은 hubble observe -f --pod curl-pod
[router] tcpdump -i eth1 tcp port 80 -nnq
# router eth1 192.168.10.200 로 curl >> IP 확인해보자!
kubectl exec -it curl-pod -- curl -s webpod
kubectl exec -it curl-pod -- curl -s webpod
kubectl exec -it curl-pod -- curl -s 192.168.10.200
...
router loop1/2 통신 확인
# router
ip -br -c -4 addr
loop1 UNKNOWN 10.10.1.200/24
loop2 UNKNOWN 10.10.2.200/24
...
# k8s-ctr
ip -c route | grep static
10.10.0.0/16 via 192.168.10.200 dev eth1 proto static
# 터미널 2개 사용
[k8s-ctr] tcpdump -i eth1 tcp port 80 -nnq 혹은 hubble observe -f --pod curl-pod
[router] tcpdump -i eth1 tcp port 80 -nnq
# router eth1 192.168.10.200 로 curl >> IP 확인해보자!
kubectl exec -it curl-pod -- curl -s 10.10.1.200
kubectl exec -it curl-pod -- curl -s 10.10.2.200
두 실습 모두 파드 IP가 그대로 확인됩니다 (SNAT 되지않음)

ip-masq-agent
ip-masq-agent는 어떤 목적지 IP에 대해 Masquerading(SNAT)을 수행할지 말지를 제어하는 정책 관리자
설정은 Helm 또는 ConfigMap 으로 관리됩니다
A packet sent from a pod to a destination which belongs to any CIDR from the nonMasqueradeCIDRs is not going to be masqueraded.
-> 사내망과 NAT 없는 통신 필요 시 해당 설정에 대역들 추가 할 것!
-> ClusterMesh 시 Native-Routing 설정 시에도 활용.
ip-masq-agent 설정 파일(예: ConfigMap)에 nonMasqueradeCIDRs 값을 명시하지 않으면
아래의 CIDR 목록이 자동으로 SNAT 제외 대상으로 등록됩니다.
# 사설 IP 대역들
10.0.0.0/8
172.16.0.0/12
192.168.0.0/16
100.64.0.0/10
192.0.0.0/24
192.0.2.0/24
192.88.99.0/24
198.18.0.0/15
198.51.100.0/24
203.0.113.0/24
240.0.0.0/4
ipMasqAgent 설정
# 아래 설정값은 cilium 데몬셋 자동 재시작됨
helm upgrade cilium cilium/cilium --namespace kube-system --reuse-values \
--set ipMasqAgent.enabled=true --set ipMasqAgent.config.nonMasqueradeCIDRs='{10.10.1.0/24,10.10.2.0/24}'
cilium hubble port-forward&
# ip-masq-agent configmap 생성 확인
kubectl get cm -n kube-system ip-masq-agent -o yaml | yq
kc describe cm -n kube-system ip-masq-agent
k9s

# cilium config view | grep -i ip-masq
enable-ip-masq-agent true
# kubectl -n kube-system exec ds/cilium -c cilium-agent -- cilium-dbg bpf ipmasq list
IP PREFIX/ADDRESS
10.10.1.0/24
10.10.2.0/24
169.254.0.0/16
'devops > cilium' 카테고리의 다른 글
| 4주차 - Networking#2 (3) | 2025.08.09 |
|---|---|
| 3주차 - Networking#1 - CoreDNS, NodeLocal DNSCache (5) | 2025.08.02 |
| 2주차 - Monitoring & Metrics (3) | 2025.07.26 |
| 2주차 - Hubble (3) | 2025.07.26 |
| 1주차 - cilium 설치 (0) | 2025.07.19 |