본문 바로가기
devops/cilium

3주차 - Networking#1 - IPAM, Routing, Masquerading

by gnobaaaar 2025. 8. 1.
본 내용은 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

 

termshark

 

 

 

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 변경 되는가?

 

ip -c route

 

-> 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 연결용)

172.20.x.x 대역으로 파드IP 변경되었습니다.

 

 

 

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)
      • 클러스터 노드는 여러 라우팅 또는 링크 계층 도메인을 생성할 수 있습니다.
 라우팅 도메인 : 서로 다른 L3 서브넷
링크 계층 도메인 : L2 브로드캐스트 영역
        • 클러스터 노드가 IP/UDP를 사용하여 서로 연결할 수 있는 한 기본 네트워크의 토폴로지는 중요하지 않습니다.
          • UDP 통과하면 작동하므로 복잡한 L3 구성없이 동작합니다.
    • 정체성 맥락 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을 설정
  • 설정
    • 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하여 이 문제를 해결할 수 있습니다.

ip -c route 에 포함된 Pod IP

 # 각 노드의 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

 

출발지 IP가 그대로 보입니다

 

 

  • 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

ConfiMap 에서 설정된 nonMasqueradeCIDRs

 

# 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