본문 바로가기

컨테이너/쿠버네티스 네트워크

[Cilium] (2) Cilium 설치

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

cni는 설치가 안되어 있는 상태 , 오른쪽 창은 virtual box로 3개 vm이 생성된 상태

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의 복잡성이 더욱 가중되고, 각 규칙을 통과하는 과정에서 성능 저하가 발생할 수 있습니다.

📌 과거의  구조

https://nuguni.tistory.com/101

 

 TCX: Traffic Control X (Next-Gen TC)

TCX는 기존 TC의 성능 문제와 관리 복잡성을 해결하기 위한 새로운 트래픽 제어 모듈입니다. TCX는 특히 eBPF와의 높은 연동성을 염두에 두고 설계되었으며, 다음과 같은 주요 기능과 장점을 가지고 있습니다.

 

📌 변경된 구조

https://nuguni.tistory.com/101

✅ 정리 :  TC와 TCX의 차이점

  • 구조의 간소화: 기존 TC는 필터와 클래스의 복잡한 계층 구조를 가지고 있어 관리가 어려웠지만, TCX는 간소화된 구조로 eBPF 프로그램과 직접 연결되어 있습니다.
  • 성능 최적화: TCX는 패킷을 빠르게 처리하기 위해 중간 계층을 줄였으며, TCX_NEXT와 TCX_DROP 같은 명령을 통해 즉각적인 패킷 제어가 가능합니다.
  • 효율적인 리소스 사용: 불필요한 eBPF 프로그램을 제거하고 필요한 경우에만 로드하여 CPU 및 메모리 자원을 절약합니다.
  • BPF 링크 지원: BPF 링크를 통해 eBPF 프로그램의 안전한 연결과 의존성 관리를 지원하여 다중 프로그램 환경에서의 안정성을 보장합니다.