1. 실습 환경 구성 ( Vagrant + VirtualBox )
# VirtualBox 설치
brew install --cask virtualbox
VBoxManage --version
7.1.10r169112
# Vagrant 설치
brew install --cask vagrant
vagrant version
Installed Version: 2.4.7

- 기본 배포 가상 머신 : k8s-ctr, k8s-w1, k8s-w2
- eth0 : 10.0.2.15 모든 노드가 동일
- eth1 : 192.168.10.100, 101, 102
- 초기 프로비저닝으로 kubeadm init 과 join 실행됨
- CNI 미설치 상태로 배포 완료됨
mkdir cilium-lab && cd cilium-lab
curl -O https://raw.githubusercontent.com/gasida/vagrant-lab/refs/heads/main/cilium-study/1w/Vagrantfile
vagrant up


Vagrant ssh 실행 시 동작 : 가상머신의 eth0 IP는 10.0.2.15 로 모두 동일하며, 외부 인터넷 연결 역할을 함

- vagrant ssh 접속 시 호스트에 127.0.0.1(2222)를 목적지로 접속 → 이후 포트포워딩(S/DNAT)을 통해서 내부에 VM로 SSH 연결됨
- NAT Mode 에 10.0.2.2(GateWay), 10.0.2.3(DNS Server), 10.0.2.4(TFTP Server) 용도로 IP가 예약됨
# ssh 접속 전, 노드들의 eth0 IP 확인
for i in ctr w1 w2 ; do echo ">> node : k8s-$i <<"; vagrant ssh k8s-$i -c 'ip -c -4 addr show dev eth0'; echo; done #
>> node : k8s-ctr <<
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
altname enp0s8
inet 10.0.2.15/24 metric 100 brd 10.0.2.255 scope global dynamic eth0
valid_lft 85675sec preferred_lft 85675sec
>> node : k8s-w1 <<
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
altname enp0s8
inet 10.0.2.15/24 metric 100 brd 10.0.2.255 scope global dynamic eth0
valid_lft 85892sec preferred_lft 85892sec
>> node : k8s-w2 <<
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
altname enp0s8
inet 10.0.2.15/24 metric 100 brd 10.0.2.255 scope global dynamic eth0
valid_lft 85983sec preferred_lft 85983sec
k8s-ctr ' 접속
#
whoami
pwd
hostnamectl
htop
#
cat /etc/hosts
ping -c 1 k8s-w1
ping -c 1 k8s-w2
sshpass -p 'vagrant' ssh -o StrictHostKeyChecking=no vagrant@k8s-w1 hostname
sshpass -p 'vagrant' ssh -o StrictHostKeyChecking=no vagrant@k8s-w2 hostname
# vagrant ssh 로 접속 시 tcp 연결 정보 : NAT Mode 10.0.2.2(GateWay)
ss -tnp |grep sshd
ESTAB 0 0 [::ffff:10.0.2.15]:22 [::ffff:10.0.2.2]:52791 users:(("sshd",pid=5176,fd=4),("sshd",pid=5129,fd=4))
# nic 정보
ip -c addr
# default 라우팅 정보
ip -c route
# dns 서버 정보 : NAT Mode 10.0.2.3
resolvectl
#
kubectl cluster-info
# 노드 정보 : 상태, INTERNAL-IP 확인
kubectl get node -owide
# 파드 정보 : 상태, 파드 IP 확인 - kube-proxy 확인
kubectl get pod -A -owide
# 단축어 확인(kc = kubecolor) & coredns 파드 상태 확인
k describe pod -n kube-system -l k8s-app=kube-dns
kc describe pod -n kube-system -l k8s-app=kube-dns

[k8s-ctr] INTERNAL-IP 변경 설정
#
cat /var/lib/kubelet/kubeadm-flags.env
# INTERNAL-IP 변경 설정
NODEIP=$(ip -4 addr show eth1 | grep -oP '(?<=inet\s)\d+(\.\d+){3}')
sed -i "s/^\(KUBELET_KUBEADM_ARGS=\"\)/\1--node-ip=${NODEIP} /" /var/lib/kubelet/kubeadm-flags.env
systemctl daemon-reexec && systemctl restart kubelet
cat /var/lib/kubelet/kubeadm-flags.env
# KUBELET_KUBEADM_ARGS="--node-ip=192.168.10.100 --container-runtime-endpoint=unix:///run/containerd/containerd.sock --pod-infra-container-image=registry.k8s.io/pause:3.10"
#
kubectl get node -owide
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
k8s-ctr NotReady control-plane 24m v1.33.2 192.168.10.100 <none> Ubuntu 24.04.2 LTS 6.8.0-53-generic containerd://1.7.27
...
[k8s-w1/w2] INTERNAL-IP 변경 설정 할 것 → 설정 완료 후 아래 처럼 확인
kubectl get node -owide
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
k8s-ctr NotReady control-plane 26m v1.33.2 192.168.10.100 <none> Ubuntu 24.04.2 LTS 6.8.0-53-generic containerd://1.7.27
k8s-w1 NotReady <none> 24m v1.33.2 192.168.10.101 <none> Ubuntu 24.04.2 LTS 6.8.0-53-generic containerd://1.7.27
k8s-w2 NotReady <none> 23m v1.33.2 192.168.10.102 <none> Ubuntu 24.04.2 LTS 6.8.0-53-generic containerd://1.7.27
kubectl get pod -A -owide
NAMESPACE NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
kube-system coredns-674b8bbfcf-fl4tr 0/1 Pending 0 26m <none> <none> <none> <none>
kube-system coredns-674b8bbfcf-npvs9 0/1 Pending 0 26m <none> <none> <none> <none>
kube-system etcd-k8s-ctr 1/1 Running 0 26m 10.0.2.15 k8s-ctr <none> <none>
kube-system kube-apiserver-k8s-ctr 1/1 Running 0 26m 10.0.2.15 k8s-ctr <none> <none>
kube-system kube-controller-manager-k8s-ctr 1/1 Running 0 26m 10.0.2.15 k8s-ctr <none> <none>
kube-system kube-proxy-bwwjq 1/1 Running 0 23m 192.168.10.102 k8s-w2 <none> <none>
kube-system kube-proxy-hqqq7 1/1 Running 0 26m 192.168.10.100 k8s-ctr <none> <none>
kube-system kube-proxy-l9t87 1/1 Running 0 24m 192.168.10.101 k8s-w1 <none> <none>
kube-system kube-scheduler-k8s-ctr 1/1 Running 0 26m 10.0.2.15 k8s-ctr <none> <none>
2. Flannel CNI 인스톨
[k8s-ctr] Flannel 인스톨
#
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",
#
kubectl get pod -n kube-system -l k8s-app=kube-dns -owide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
coredns-674b8bbfcf-fl4tr 0/1 Pending 0 39m <none> <none> <none> <none>
coredns-674b8bbfcf-npvs9 0/1 Pending 0 39m <none> <none> <none> <none>
#
ip -c link
ip -c route
brctl show
#
iptables-save
iptables -t nat -S
iptables -t filter -S
iptables -t mangle -S
#
tree /etc/cni/net.d/
# Needs manual creation of namespace to avoid helm error
kubectl create ns kube-flannel
kubectl label --overwrite ns kube-flannel pod-security.kubernetes.io/enforce=privileged
helm repo add flannel https://flannel-io.github.io/flannel/
helm repo list
helm search repo flannel
helm show values flannel/flannel
# k8s 관련 트래픽 통신 동작하는 nic 지정
cat << EOF > flannel-values.yaml
podCidr: "10.244.0.0/16"
flannel:
args:
- "--ip-masq"
- "--kube-subnet-mgr"
- "--iface=eth1"
EOF
# helm 설치
helm install flannel --namespace kube-flannel flannel/flannel -f flannel-values.yaml
helm list -A
# 확인 : install-cni-plugin, install-cni
kc describe pod -n kube-flannel -l app=flannel
tree /opt/cni/bin/ # flannel
tree /etc/cni/net.d/
cat /etc/cni/net.d/10-flannel.conflist | jq
kc describe cm -n kube-flannel kube-flannel-cfg
...
net-conf.json:
----
{
"Network": "10.244.0.0/16",
"EnableNFTables": false,
"Backend": {
"Type": "vxlan"
}
}
[k8s-ctr] Flannel 설치 후 인터페이스 확인
# 설치 전과 비교해보자
ip -c link
ip -c route | grep 10.244.
(⎈|HomeLab:N/A) root@k8s-ctr:~# ip -c link
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP mode DEFAULT group default qlen 1000
link/ether 08:00:27:71:19:d8 brd ff:ff:ff:ff:ff:ff
altname enp0s8
3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP mode DEFAULT group default qlen 1000
link/ether 08:00:27:f8:c6:8b brd ff:ff:ff:ff:ff:ff
altname enp0s9
4: flannel.1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UNKNOWN mode DEFAULT group default
link/ether 1a:76:33:9e:b3:d6 brd ff:ff:ff:ff:ff:ff
5: cni0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UP mode DEFAULT group default qlen 1000
link/ether de:1c:2c:08:8e:57 brd ff:ff:ff:ff:ff:ff
6: vethf24e1e8c@if2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue master cni0 state UP mode DEFAULT group default qlen 1000
link/ether 3a:9a:e9:bc:a2:05 brd ff:ff:ff:ff:ff:ff link-netns cni-1bb1f9e4-093e-dac2-fa6b-ad6b0d10b089
7: veth758908f3@if2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue master cni0 state UP mode DEFAULT group default qlen 1000
link/ether 2a:33:a9:93:0c:2d brd ff:ff:ff:ff:ff:ff link-netns cni-48d23bd0-6870-62fd-65bf-a06dc7d4db2f
(⎈|HomeLab:N/A) root@k8s-ctr:~#
(⎈|HomeLab:N/A) 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.244.0.0/24 dev cni0 proto kernel scope link src 10.244.0.1
10.244.1.0/24 via 10.244.1.0 dev flannel.1 onlink
10.244.2.0/24 via 10.244.2.0 dev flannel.1 onlink
192.168.10.0/24 dev eth1 proto kernel scope link src 192.168.10.100
🔎 인터페이스 목록 및 역할 설명
4: flannel.1
- 유형: VXLAN 터널 인터페이스 (Flannel backend가 VXLAN인 경우)
- 역할:
- 다른 노드의 Pod와 통신할 때 사용되는 오버레이 터널 인터페이스입니다.
- VXLAN 패킷을 encapsulation/decapsulation하는 역할
- 각 노드는 자신의 Pod 네트워크를 VXLAN으로 패킷에 감싸고, 다른 노드의 Flannel.1로 전송합니다.
- MTU 1450: VXLAN 헤더를 고려한 값 (기본 MTU 1500 - VXLAN 헤더 50)
- 특징: 일반적으로 Flannel이 자동으로 생성하며 flannel.1, flannel.2 등 이름을 가집니다.
5: cni0
- 유형: bridge (브릿지) 인터페이스
- 역할:
- 같은 노드의 Pod 간 통신을 중계하는 가상 스위치 역할
- 각 Pod의 veth 인터페이스가 이 cni0 브릿지에 연결되어 있음
- Pod ↔ Pod 통신 시 패킷이 이 브릿지를 통해 흐름
- 생성 주체: CNI 플러그인 (/opt/cni/bin/bridge)에 의해 자동 생성됨
6 & 7: veth@if2 (예: vethf24e1e8c, veth758908f3)
- 유형: veth pair (Virtual Ethernet pair)
- 역할:
- Pod와 호스트 네트워크 스택을 연결하는 양쪽 끝이 연결된 인터페이스 쌍입니다.
- 한쪽은 Pod 네임스페이스에 존재하고, 다른쪽은 호스트 네임스페이스의 cni0에 연결
🧬 네트워크 구조 요약 (Flannel 사용 시)

Pod NIC (eth0) ─ vethXXXX ─ [cni0 bridge] - flannel.1 ─ eth0 ─ 다른 노드
# cni0 bridge의 맥주소를 pod가 어떻게 알까?
# Pod는 직접 cni0의 MAC 주소를 알지 않습니다.
# 대신, Pod는 자신의 default gateway의 MAC 주소를 ARP로 알아냅니다.
# 이 default gateway는 cni0 브릿지에 연결된 veth 쌍의 반대편 인터페이스입니다.
- arp flooding을 통해서 응답함
[ Pod eth0 ] --> ARP --> [ cni0 (bridge) ] --> replies with cni0 MAC
✅ 결론 요약
| flannel.1 | 노드 간 VXLAN 통신용 오버레이 터널 |
| cni0 | Pod 간 브리지 (같은 노드) |
| vethXXX@ifX | Pod ↔ Host 간 가상 인터페이스 쌍 |
이 구조를 이해하면 다음을 잘 알 수 있습니다:
- Pod 간 통신이 왜 되며,
- MTU 설정이 왜 중요한지,
- overlay와 native routing 방식의 차이가 어디서 생기는지 등
# 설치 전과 비교해보자
ip -c link
ip -c route | grep 10.244.
10.244.0.0/24 dev cni0 proto kernel scope link src 10.244.0.1
10.244.1.0/24 via 10.244.1.0 dev flannel.1 onlink
10.244.2.0/24 via 10.244.2.0 dev flannel.1 onlink
ping -c 1 10.244.1.0
ping -c 1 10.244.2.0
brctl show
iptables-save
iptables -t nat -S
iptables -t filter -S
# k8s-w1, k8s-w2 정보 확인
for i in w1 w2 ; do echo ">> node : k8s-$i <<"; sshpass -p 'vagrant' ssh -o StrictHostKeyChecking=no vagrant@k8s-$i ip -c link ; echo; done
for i in w1 w2 ; do echo ">> node : k8s-$i <<"; sshpass -p 'vagrant' ssh -o StrictHostKeyChecking=no vagrant@k8s-$i ip -c route ; echo; done
for i in w1 w2 ; do echo ">> node : k8s-$i <<"; sshpass -p 'vagrant' ssh -o StrictHostKeyChecking=no vagrant@k8s-$i brctl show ; echo; done
for i in w1 w2 ; do echo ">> node : k8s-$i <<"; sshpass -p 'vagrant' ssh -o StrictHostKeyChecking=no vagrant@k8s-$i sudo iptables -t nat -S ; echo; done
iptables 대규모 환경에서의 제약사항
- 규모가 커질수록 tables update 시간에 지연이 생긴다.

iptables -t nat -S
# 초기 설치시
iptables -t nat -S | wc -l
66
# svc 1개 증가시
iptables -t nat -S | wc -l
77
# Service 동작 처리에 iptables 규칙 활용 확인 >> Service 가 100개 , 1000개 , 10000개 증가 되면???
# 10만 rule 정도 쌓였을때 메모리 16GB 기준으로 패킷 드랍 가능성 있었음. 내 경험 기준
https://themapisto.tistory.com/267
[KANS] 쿠버네티스 네트워크 (6) Flannel CNI
목표:1. CNI 가 무엇인지 알아봅니다.2. Flannel CNI의 특징에 대해서 알아봅니다.그중에서도 오버레이 네트워크 / VXLAN / VLAN Container network interface 먼저 쿠버네티스 네트워킹 모델을 이해하려 합니다.
themapisto.tistory.com
Flannel CNI의 통신방식에 대해서 더 궁금한 부분은 해당 글을 읽어보시길 바랍니다.
Flannel CNI 삭제는 아래 Cilium 설치 전에 진행 함
3. Cilium CNI 설치
Requirements 확인 (커널 구성 옵션 활성화)
#
arch
aarch64
#
uname -r
6.8.0-53-generic
# [커널 구성 옵션] 기본 요구 사항
grep -E 'CONFIG_BPF|CONFIG_BPF_SYSCALL|CONFIG_NET_CLS_BPF|CONFIG_BPF_JIT|CONFIG_NET_CLS_ACT|CONFIG_NET_SCH_INGRESS|CONFIG_CRYPTO_SHA1|CONFIG_CRYPTO_USER_API_HASH|CONFIG_CGROUPS|CONFIG_CGROUP_BPF|CONFIG_PERF_EVENTS|CONFIG_SCHEDSTATS' /boot/config-$(uname -r)
CONFIG_BPF=y
CONFIG_BPF_SYSCALL=y
CONFIG_BPF_JIT=y
CONFIG_NET_CLS_BPF=m
CONFIG_NET_CLS_ACT=y
CONFIG_NET_SCH_INGRESS=m
CONFIG_CRYPTO_SHA1=y
CONFIG_CRYPTO_USER_API_HASH=m
CONFIG_CGROUPS=y
CONFIG_CGROUP_BPF=y
CONFIG_PERF_EVENTS=y
CONFIG_SCHEDSTATS=y
# [커널 구성 옵션] Requirements for Tunneling and Routing
grep -E 'CONFIG_VXLAN=y|CONFIG_VXLAN=m|CONFIG_GENEVE=y|CONFIG_GENEVE=m|CONFIG_FIB_RULES=y' /boot/config-$(uname -r)
CONFIG_FIB_RULES=y # 커널에 내장됨
CONFIG_VXLAN=m # 모듈로 컴파일됨 → 커널에 로드해서 사용
CONFIG_GENEVE=m # 모듈로 컴파일됨 → 커널에 로드해서 사용
## (참고) 커널 로드
lsmod | grep -E 'vxlan|geneve'
modprobe geneve
lsmod | grep -E 'vxlan|geneve'
# [커널 구성 옵션] Requirements for L7 and FQDN Policies
grep -E 'CONFIG_NETFILTER_XT_TARGET_TPROXY|CONFIG_NETFILTER_XT_TARGET_MARK|CONFIG_NETFILTER_XT_TARGET_CT|CONFIG_NETFILTER_XT_MATCH_MARK|CONFIG_NETFILTER_XT_MATCH_SOCKET' /boot/config-$(uname -r)
CONFIG_NETFILTER_XT_TARGET_CT=m
CONFIG_NETFILTER_XT_TARGET_MARK=m
CONFIG_NETFILTER_XT_TARGET_TPROXY=m
CONFIG_NETFILTER_XT_MATCH_MARK=m
CONFIG_NETFILTER_XT_MATCH_SOCKET=m
...
# [커널 구성 옵션] Requirements for Netkit Device Mode
grep -E 'CONFIG_NETKIT=y|CONFIG_NETKIT=m' /boot/config-$(uname -r)
고급 기능 동작을 위한 최소 커널 버전 ( Cilium Feature Minimum Kernel Version )
| WireGuard Transparent Encryption | >= 5.6 |
| Full support for Session Affinity | >= 5.7 |
| BPF-based proxy redirection | >= 5.7 |
| Socket-level LB bypass in pod netns | >= 5.7 |
| L3 devices | >= 5.8 |
| BPF-based host routing | >= 5.10 |
| Multicast Support in Cilium (Beta) (AMD64) | >= 5.10 |
| IPv6 BIG TCP support | >= 5.19 |
| Multicast Support in Cilium (Beta) (AArch64) | >= 6.0 |
| IPv4 BIG TCP support | >= 6.3 |
- Mounted eBPF filesystem : 일부 배포판 마운트되어 있음, 혹은 Cilium 설치 시 마운트 시도 - Docs
#
mount | grep /sys/fs/bpf
bpf on /sys/fs/bpf type bpf (rw,nosuid,nodev,noexec,relatime,mode=700)
- Privileges : Cilium 동작을 위해서 관리자 수준 권한 필요 - Docs
- Cilium interacts with the Linux kernel to install eBPF program which will then perform networking tasks and implement security rules. In order to install eBPF programs system-wide, CAP_SYS_ADMIN privileges are required. These privileges must be granted to cilium-agent.
- The quickest way to meet the requirement is to run cilium-agent as root and/or as privileged container.
- Cilium requires access to the host networking namespace. For this purpose, the Cilium pod is scheduled to run in the host networking namespace directly.
삭제 (Flannel) 전 route, ip link 확인

삭제 진행
#
helm uninstall -n kube-flannel flannel
helm list -A
#
kubectl get all -n kube-flannel
kubectl delete ns kube-flannel
#
kubectl get pod -A -owide
# 제거 전 확인
ip -c link
for i in w1 w2 ; do echo ">> node : k8s-$i <<"; sshpass -p 'vagrant' ssh -o StrictHostKeyChecking=no vagrant@k8s-$i ip -c link ; echo; done
brctl show
for i in w1 w2 ; do echo ">> node : k8s-$i <<"; sshpass -p 'vagrant' ssh -o StrictHostKeyChecking=no vagrant@k8s-$i brctl show ; echo; done
ip -c route
for i in w1 w2 ; do echo ">> node : k8s-$i <<"; sshpass -p 'vagrant' ssh -o StrictHostKeyChecking=no vagrant@k8s-$i ip -c route ; echo; done
# vnic 제거
ip link del flannel.1
ip link del cni0
for i in w1 w2 ; do echo ">> node : k8s-$i <<"; sshpass -p 'vagrant' ssh -o StrictHostKeyChecking=no vagrant@k8s-$i sudo ip link del flannel.1 ; echo; done
for i in w1 w2 ; do echo ">> node : k8s-$i <<"; sshpass -p 'vagrant' ssh -o StrictHostKeyChecking=no vagrant@k8s-$i sudo ip link del cni0 ; echo; done
# 제거 확인
ip -c link
for i in w1 w2 ; do echo ">> node : k8s-$i <<"; sshpass -p 'vagrant' ssh -o StrictHostKeyChecking=no vagrant@k8s-$i ip -c link ; echo; done
brctl show
for i in w1 w2 ; do echo ">> node : k8s-$i <<"; sshpass -p 'vagrant' ssh -o StrictHostKeyChecking=no vagrant@k8s-$i brctl show ; echo; done
ip -c route
for i in w1 w2 ; do echo ">> node : k8s-$i <<"; sshpass -p 'vagrant' ssh -o StrictHostKeyChecking=no vagrant@k8s-$i ip -c route ; echo; done
삭제 후 ip link , bridge , route 테이블 삭제 완료

기존 kube-proxy 삭제
#
kubectl -n kube-system delete ds kube-proxy
kubectl -n kube-system delete cm kube-proxy
# 배포된 파드의 IP는 남겨져 있음
kubectl get pod -A -owide
#
kubectl exec -it curl-pod -- curl webpod
#
iptables-save

cilium 설치
# Cilium 설치 with Helm
helm repo add cilium https://helm.cilium.io/
# 모든 NIC 지정 + bpf.masq=true + NoIptablesRules
helm install cilium cilium/cilium --version 1.17.5 --namespace kube-system \
--set k8sServiceHost=192.168.10.100 --set k8sServicePort=6443 \
--set kubeProxyReplacement=true \
--set routingMode=native \
--set autoDirectNodeRoutes=true \
--set ipam.mode="cluster-pool" \
--set ipam.operator.clusterPoolIPv4PodCIDRList={"172.20.0.0/16"} \
--set ipv4NativeRoutingCIDR=172.20.0.0/16 \
--set endpointRoutes.enabled=true \
--set installNoConntrackIptablesRules=true \
--set bpf.masquerade=true \
--set ipv6.enabled=false
# 확인
helm get values cilium -n kube-system
helm list -A
kubectl get crd
watch -d kubectl get pod -A
kubectl exec -it -n kube-system ds/cilium -c cilium-agent -- cilium-dbg status --verbose
KubeProxyReplacement: True [eth0 10.0.2.15 fd17:625c:f037:2:a00:27ff:fe71:19d8 fe80::a00:27ff:fe71:19d8, eth1 192.168.10.102 fe80::a00:27ff:fed3:64b (Direct Routing)]
Routing: Network: Native Host: BPF
Masquerading: BPF [eth0, eth1] 172.20.0.0/16 [IPv4: Enabled, IPv6: Disabled]
...
# 노드에 iptables 확인
iptables -t nat -S
for i in w1 w2 ; do echo ">> node : k8s-$i <<"; sshpass -p 'vagrant' ssh vagrant@k8s-$i sudo iptables -t nat -S ; echo; done
iptables-save
for i in w1 w2 ; do echo ">> node : k8s-$i <<"; sshpass -p 'vagrant' ssh vagrant@k8s-$i sudo iptables-save ; echo; done

pod cidr 및 IPAM 확인
#
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
k8s-w2 10.244.2.0/24
# 파드 IP 확인
kubectl get pod -owide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
curl-pod 1/1 Running 0 22m 10.244.0.2 k8s-ctr <none> <none>
webpod-697b545f57-hbkmr 1/1 Running 0 22m 10.244.2.4 k8s-w2 <none> <none>
webpod-697b545f57-vx27c 1/1 Running 0 22m 10.244.1.2 k8s-w1 <none> <none>
#
kubectl get ciliumnodes
kubectl get ciliumnodes -o json | grep podCIDRs -A2
"podCIDRs": [
"172.20.0.0/24"
--
"podCIDRs": [
"172.20.1.0/24"
--
"podCIDRs": [
#
kubectl rollout restart deployment webpod
kubectl get pod -owide
# k8s-ctr 노드에 curl-pod 파드 배포
kubectl delete pod curl-pod --grace-period=0
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 pod -owide
kubectl get ciliumendpoints
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 -- curl webpod | grep Hostname

cilium cli 설치 및 확인
# cilium 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
# cilium 상태 확인
which cilium
cilium status
cilium config view
kubectl get cm -n kube-system cilium-config -o json | jq
#
cilium config set debug true && watch kubectl get pod -A
cilium config view | grep -i debug
# cilium daemon = cilium-dbg
kubectl exec -n kube-system -c cilium-agent -it ds/cilium -- cilium-dbg config
kubectl exec -n kube-system -c cilium-agent -it ds/cilium -- cilium-dbg status --verbose
...
KubeProxyReplacement: True [eth0 10.0.2.15 fd17:625c:f037:2:a00:27ff:fe71:19d8 fe80::a00:27ff:fe71:19d8, eth1 192.168.10.102 fe80::a00:27ff:fef6:fcbc (Direct Routing)]
Routing: Network: Native Host: BPF
Attach Mode: TCX
Device Mode: veth
Masquerading: BPF [eth0, eth1] 172.20.0.0/16 [IPv4: Enabled, IPv6: Disabled]
...
KubeProxyReplacement Details:
Status: True
Socket LB: Enabled
Socket LB Tracing: Enabled
Socket LB Coverage: Full
Devices: eth0 10.0.2.15 fd17:625c:f037:2:a00:27ff:fe71:19d8 fe80::a00:27ff:fe71:19d8, eth1 192.168.10.102 fe80::a00:27ff:fef6:fcbc (Direct Routing)
Mode: SNAT
Backend Selection: Random
Session Affinity: Enabled
Graceful Termination: Enabled
NAT46/64 Support: Disabled
XDP Acceleration: Disabled
Services:
- ClusterIP: Enabled
- NodePort: Enabled (Range: 30000-32767)
- LoadBalancer: Enabled
- externalIPs: Enabled
- HostPort: Enabled
...
- cilium 설치 확인

KubeproxyReplacement: true
Attach Mode: TCX
Routing: Native
✅ TC의 문제점과 eBPF의 사용
TC는 오랫동안 Linux 네트워크 스택의 핵심 도구로 자리 잡아왔지만, 네트워크 정책을 세분화하고 다양한 트래픽을 관리하려면 여러 필터와 규칙을 조합해야 하므로 복잡성이 증가하고 관리가 어려워지는 단점이 있습니다. 특히, Cilium과 같은 eBPF 기반 네트워크 정책 엔진은 TC 레이어에 다양한 eBPF 프로그램을 추가로 로드하게 됩니다. 또한, Kubernetes와 같은 클라우드 네이티브 환경에서는 여러 네트워크 정책과 로드밸런싱 규칙이 동적으로 추가되고 삭제되면서 TC 레이어에 로드되는 eBPF 프로그램의 수도 크게 증가합니다. 이로 인해 TC의 복잡성이 더욱 가중되고, 각 규칙을 통과하는 과정에서 성능 저하가 발생할 수 있습니다.
📌 과거의 구조

✅ TCX: Traffic Control X (Next-Gen TC)
TCX는 기존 TC의 성능 문제와 관리 복잡성을 해결하기 위한 새로운 트래픽 제어 모듈입니다. TCX는 특히 eBPF와의 높은 연동성을 염두에 두고 설계되었으며, 다음과 같은 주요 기능과 장점을 가지고 있습니다.
📌 변경된 구조

✅ 정리 : TC와 TCX의 차이점
- 구조의 간소화: 기존 TC는 필터와 클래스의 복잡한 계층 구조를 가지고 있어 관리가 어려웠지만, TCX는 간소화된 구조로 eBPF 프로그램과 직접 연결되어 있습니다.
- 성능 최적화: TCX는 패킷을 빠르게 처리하기 위해 중간 계층을 줄였으며, TCX_NEXT와 TCX_DROP 같은 명령을 통해 즉각적인 패킷 제어가 가능합니다.
- 효율적인 리소스 사용: 불필요한 eBPF 프로그램을 제거하고 필요한 경우에만 로드하여 CPU 및 메모리 자원을 절약합니다.
- BPF 링크 지원: BPF 링크를 통해 eBPF 프로그램의 안전한 연결과 의존성 관리를 지원하여 다중 프로그램 환경에서의 안정성을 보장합니다.
'컨테이너 > 쿠버네티스 네트워크' 카테고리의 다른 글
| [Cilium] (4) 실리움 네트워킹 _ Hubble (2) | 2025.07.21 |
|---|---|
| [Cilium] (3) Cilium 통신 구조 ( Native Routing) (0) | 2025.07.15 |
| [Cilium] (1) Cilium 소개 및 개념 정리 (2) | 2025.07.14 |
| [KANS] 쿠버네티스 네트워크 (17) AWS EKS: VPC CNI (0) | 2024.11.01 |
| [KANS] 쿠버네티스 네트워크 (16) Cilium - pod통신, service 통신 (0) | 2024.10.26 |