카테고리 없음

Cilium Study - 3 ( Networking 노드에 pod들간의 통신 상세 )

바코더 2025. 8. 3. 08:42

IPAM ( IP AddreessMnagement )

FeatureKubernetes Host ScopeCluster Scope (default)Multi-Pool (Beta)CRD-backedAWS ENI…

Tunnel routing
Direct routing
CIDR Configuration Kubernetes Cilium Cilium External External (AWS)
Multiple CIDRs per cluster N/A N/A
Multiple CIDRs per node N/A N/A
Dynamic CIDR/IP allocation
  • Kubernetes 호스트 범위 IPAM 모드는ipam: Kubernetes 에서 활성화되며 클러스터의 각 개별 노드에 주소 할당을 위임
  • IP는 Kubernetes에 의해 각 노드에 연결된 PodCIDR 범위에서 할당
  • 이 모드에서는 Cilium 에이전트가 Kubernetes v1.Node 객체를 통해 PodCIDR 범위가 다음 방법 중 하나를 통해 활성화된 모든 주소 패밀리에 대해 제공될 때까지 시작 시 대기
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

샘플 애플리케이션 배포

# 샘플 애플리케이션 배포
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

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

 

tcpdump와 termshark 로 트래픽 확인

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

Cilium Cluster Scope & 마이그레이션

  • 클러스터 범위 IPAM 모드는 각 노드에 노드별 PodCIDR을 할당하고, 각 노드에서 호스트 범위 할당기를 사용해 IP를 배정
  • Kubernetes 호스트 범위 모드와 유사하나, Kubernetes가 v1.Node 리소드를 통해 PodCIDR을 할당하는 대신 Cilium 연산자가 v2.CiliumNode CRD로 관리
  • Kubernetes의 노드별 PodCIDR 구성에 의존하지 않음
  • 최소 마스크 길이는 /30이며 권장 최소 마스크 길이는 /29, 네트워크 및 브로드캐스트 주소로 2개 예약
  • 기본 Pod CIDR은 10.0.0.0/8이며 clusterPoolIPv4PodCIDRList로 설정 가능
# 반복 요청 해두기
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 --version 1.17.6 --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}'
cilium config view | grep ^ipam
ipam                                              cluster-pool

* helm version 1.18 출시로 helm upgrade 를 현재 version 1.17.6 으로 고정 

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
 
노드의 pod-cidr 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
 
curl Pod 배포 후 Pod IP 변경 확인
 
# 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

Routing

Encapsulation

  • Encapsulation 모드는 Cilium의 기본 네트워킹 인프라에서 최소한의 요구 사항으로 자동 실행
  • 모든 클러스터 노드는 UDP 기반 VXLAN(기본 포트 8472) 또는 Geneve(기본 포트 6081)를 이용해 터널 메시(mesh)를 형성하고 모든 트래픽을 캡슐화
  • 기본 네트워크는 IPv4 지원 및 캡슐화된 패킷 허용 방화벽(UDP 8472/VXLAN, UDP 6081/Geneve)이 필요
  • 장점
    • 단순성: PodCIDR을 인식할 필요 없이 노드 간 연결만 가능하면 토폴로지 제약 없음
    • 정체성 맥락 전송: 캡슐화 프로토콜로 보안 ID 같은 메타데이터 전달, 원격 노드에서의 추가 조회 최소화
  • 단점
    • MTU 오버헤드: VXLAN 기준 패킷당 약 50바이트 헤더 추가로 최대 처리량 저하, 점보 프레임 활성화로 완화 가능
  • 설정
    • tunnel-protocol: vxlan 또는 geneve 선택
    • tunnel-port: 캡슐화 프로토콜용 포트 지정 (기본 8472/VXLAN, 6081/Geneve)

Native_Routing

  • routing-mode: native 설정으로 캡슐화 없이 Linux 커널 라우팅 하위시스템을 통해 패킷 전달
  • Cilium은 로컬 엔드포인트를 벗어나는 모든 패킷을 커널에 위임하여 네이티브 패킷 전달 모드 활성화
  • 클러스터 네트워크는 PodCIDR을 직접 라우팅할 수 있어야 함
  • PodCIDR 라우팅 방안 1:
    • 각 노드가 모든 노드의 Pod IP를 인식해 커널 라우팅 테이블에 삽입
    • 동일 L2 네트워크에서는 auto-direct-node-routes: true로 자동 경로 삽입
  • PodCIDR 라우팅 방안 2:
    • 네트워크 내 라우터가 모든 PodCIDR 경로를 관리
    • 노드는 해당 라우터를 가리키는 기본 경로만 설정 (클라우드 제공자 통합 사용)
  • 주요 설정
    • ipv4-native-routing-cidr: x.x.x.x/y 로 네이티브 라우팅 CIDR 지정
    • auto-direct-node-routes: true 로 동일 L2 시 노드별 경로 자동 생성

노드 간 Pod 통신 상세 확인 ( Native Routing )

PodIP 확인

export WEBPODIP1=$(kubectl get -l app=webpod pods --field-selector spec.nodeName=k8s-ctr -o jsonpath='{.items[0].status.podIP}')
export WEBPODIP2=$(kubectl get -l app=webpod pods --field-selector spec.nodeName=k8s-w1  -o jsonpath='{.items[0].status.podIP}')
echo $WEBPODIP1 $WEBPODIP2

 

 

Masquerading

  • Pod에 할당된 RFC1918 개인 주소(예: 10.0.0.0/8)는 외부에서 라우팅 불가하므로 Cilium은 클러스터를 벗어나는 모든 트래픽의 소스 IP를 노드 IP로 자동 masquerade
  • Masquerade 비활성화:
enable-ipv4-masquerade: false
enable-ipv6-masquerade: false
  • 기본 동작: 노드의 IP 할당 CIDR 내 목적지는 masquerade 제외
    • 외부 네트워크에서 Pod IP 라우팅 가능 시 ipv4-native-routing-cidr: 10.0.0.0/8 (또는 IPv6용 ipv6-native-routing-cidr) 지정하면 해당 CIDR 내 목적지도 비-masquerade 처리
  • 구현 방식
    • eBPF-based (bpf.masquerade=true)
      • BPF Masquerading 프로그램을 실행하는 장치에서만 적용
      • BPF Host-Routing 모드 자동 활성화
      • 지원 프로토콜: TCP, UDP, ICMP
      • 출력 장치가 프로그램 실행 시 포드 → 외부 패킷을 해당 장치 IP로 masquerade
      • 디바이스 자동 선택(BPF NodePort 감지) 또는 devices Helm 옵션으로 수동 지정 가능
    • iptables-based
      • iptables NAT 규칙을 통해 masquerade
  • eBPF 마스커딩 시 클러스터 노드의 External IP로 향하는 트래픽은 예외 처리되어 masquerade되지 않음

 

CoreDNS

Pod의 DNS 설정 정보 확인

kubectl exec -it curl-pod -- cat /etc/resolv.conf

cat /var/lib/kubelet/config.yaml | grep cluster -A1

 

Pod에서 DNS 질의 확인

kubectl exec -it curl-pod -- curl kube-dns.kube-system.svc:9153/metrics | grep coredns_cache_ | grep -v ^#

도메인 질의

kubectl exec -it curl-pod -- nslookup webpod
kubectl exec -it curl-pod -- nslookup -debug webpod

kubectl exec -it curl-pod -- nslookup -debug google.com

coredns logging 활성화

 

NodeLocaDNS

  • NodeLocal DNSCache는 각 노드에서 DaemonSet 형태로 DNS 캐싱 에이전트를 실행해 클러스터 DNS 성능을 향상
  • 기존 ClusterFirst 모드의 Pods는 kube-dns 서비스 IP를 통해 iptables DNAT 및 연결 추적을 거쳐 CoreDNS로 쿼리 전달
  • NodeLocal DNSCache는 Pods가 동일 노드의 로컬 캐시 에이전트에 직접 쿼리하도록 하여 iptables DNAT과 연결 추적을 회피
  • 로컬 캐시 미스 시 기본 “cluster.local” 접미사에 대해 kube-dns 서비스에 재쿼리
  • UDP 쿼리를 TCP로 업그레이드해 tail 지연시간(최대 30초) 감소 및 연결 추적 테이블 과부하 방지
  • 노드 단위 DNS 요청에 대한 메트릭과 가시성 제공
  • 네거티브 캐싱을 활성화해 kube-dns 서비스로의 쿼리 수 추가 절감

IPtables vs IPVS 에 따라 구현 기법이 달라짐

1. ipvs

  • NodeLocal DNSCache 적용 시 Pod의 DNS 요청이 CoreDNS ClusterIP(예: 10.96.0.10)가 아니라 NodeLocal 캐시 IP(예: 169.254.25.10)로 전송됨
  • IPVS kube-proxy 모드에서는 iptables의 NOTRACK 룰을 무시하고 Load Balancing을 수행하므로 ClusterIP 기반 DNS 요청을 NodeLocal로 강제 전환 불가
  • NodeLocal DNSCache 적용 여부를 변경하려면 kubelet의 DNS 서버 설정을 수정하고 kubelet 및 모든 Pod을 재시작해야 함
  • IPVS 환경에서는 Pod가 ClusterIP를 우회해 NodeLocal DNSCache를 사용할 수 없어 적용이 제한됨

설치

kubedns 는 coredns 서비스의 ClusterIP를 변수 지정

kubedns=`kubectl get svc kube-dns -n kube-system -o jsonpath={.spec.clusterIP}`
domain='cluster.local'    ## default 값
localdns='169.254.20.10'  ## default 값
echo $kubedns $domain $localdns

NodeLocalDNS 설정 변경

sed -i "s/__PILLAR__LOCAL__DNS__/$localdns/g; s/__PILLAR__DNS__DOMAIN__/$domain/g; s/__PILLAR__DNS__SERVER__/$kubedns/g" nodelocaldns.yaml

설치

kubectl apply -f nodelocaldns.yaml

NodeLocalDNS log,debug 추가

curl Pod 삭제 후 재생성 했을 때 NodeLocalDNS 미사용 확인

Cilium Local RedirectPolicy 

  • IP 주소와 Port/Protocol tuple 또는 Kubernetes Service 로 향하는 포드 트래픽을 eBPF를 사용하여 노드 내 백엔드 포드로 로컬로 리디렉션할 수 있도록 하는 Cilium의 로컬 리디렉션 정책을 구성하는 방법
  • 백엔드 Pod의 네임스페이스는 정책의 네임스페이스와 일치

Cilium Upgrade

helm upgrade cilium cilium/cilium --namespace kube-system --reuse-values \
  --set localRedirectPolicy=true
kubedns=$(kubectl get svc kube-dns -n kube-system -o jsonpath={.spec.clusterIP})
sed -i "s/__PILLAR__DNS__SERVER__/$kubedns/g;" node-local-dns.yaml
vi -d nodelocaldns.yaml node-local-dns.yaml

변경된 NodeLocalDNS apply

kubectl apply -f node-local-dns.yaml

변경된 NodeLocalDNS cm 확인

CIliumLocalRedirectPolicy Apply 

Cilium-dbg 명령어로 lrp list 확인

NodeLocalDNS 로그를 통해 질의 응답 확인

kubectl exec -it curl-pod -- nslookup www.google.com