반응형

< 오타 > k8s-w1 eth1 인터페이스 192.168.10.101 입니다.

 

  • 실습 환경
    • 목적: 다른 네트워크에 있는 노드 간 쿠버네티스 클러스터 통신을 확인하기 위함
    • router 노드: k8s 에 join 되지 않은 서버로 192.168.10.0/24 ↔ 192.168.20.0/24 대역 라우팅 역할 수행
    • k8s-w0 노드: k8s-ctr, k8s-w1 노드와 다른 네트워크 대역에 배치
    • k8s-w1 노드: k8s-ctr 과 같은 네트워크 대역에 배치
더보기

[ k8s-ctr -> k8s-w0 라우팅 ]

 

k8s-w0 대역 요청 시, router의 eth1 인터페이스로 이동하여 통신하게 됩니다.

router node 의 eth1, eht2 인터페이스가 게이트웨이 역할을 하여 노드 간 통신은 할 수 있는 상태입니다.

 

Overlay Network 가 필요한 이유 

쿠버네티스 환경에서 위와 같이 클러스터 대역 중 일부 노드가 다른 네트워크 대역을 사용한다면, 상호 간 통신이 불가합니다. 위 실습 환경에서는 k8s-w0 노드와 k8s-ctr, k8s-w1 노드 간 통신이 불가한 거죠.

 

cilium 을 설치할 때 autoDirectNodeRoutes=true 옵션을 사용하는데 자동으로 라우팅을 해주지 않는 걸까요?

 

helm install cilium cilium/cilium --version $2 --namespace kube-system \
--set k8sServiceHost=192.168.10.100 --set k8sServicePort=6443 \
--set ipam.mode="cluster-pool" --set ipam.operator.clusterPoolIPv4PodCIDRList={"172.20.0.0/16"} --set ipv4NativeRoutingCIDR=172.20.0.0/16 \
--set routingMode=native --set autoDirectNodeRoutes=true \

... 생략 ...

 

autoDirectNodeRoutes 옵션은 같은 네트워크 대역 노드 간에 pod CIDR 대역을 static routing 방식으로 자동으로 추가해주는 옵션입니다. 다른 네트워크 대역의 경우, 중간에 네트워크 장비가 pod CIDR 대역을 라우팅 안 해주면 의미가 없기 때문에 라우팅 추가를 하지 않습니다.

 

[ k8s-ctr 노드의 라우팅 테이블 ]

 

172.20.0.0/16 pod CIDR 대역 중 172.20.1.0/24 pod 네트워크만 k8s-w1(192.168.10.101) 노드로 라우팅이 되어 있지만, 172.20.2.0/24 pod CIDR 대역 대의 라우팅(k8s-w0 노드)이 보이지 않습니다.

 

[ k8s-w1 노드의 라우팅 테이블 ]

 

172.20.0.0/16 pod CIDR 대역 중 172.20.0.0/24 pod 네트워크만 k8s-ctr(192.168.10.100) 노드로 라우팅이 되어 있지만, 172.20.2.0/24 pod CIDR 대역 대의 라우팅(k8s-w0 노드)이 보이지 않습니다.

 

[ k8s-w0 노드의 라우팅 테이블 ]

 

172.20.2.0/24 pod CIDR 자신의 네트워크 대역은 cilium 이 활성화되어 있지만, k8s-ctr 노드와 k8s-w1 노드로 라우팅되어 있지 않습니다. 실제 패킷 캡처를 통해 네트워크 통신 여부도 살펴보겠습니다.

 

 

다른 네트워크 대역으로 통신 시 router 를 지나가니, router 노드에서 tcpdump 로 패킷을 스니핑합니다. k8s-ctr 서버에 위치한 curl-pod 로 k8s-w0 에 위치한 webpod 로 통신 시, 정상적으로 통신이 되지 않는 현상을 볼 수 있습니다.

아래 캡쳐된 네트워크 패킷들을 보면, eth1 로 들어왔는데 인터넷 전용 인터페이스인 eth0 으로 빠져나갔습니다. (eth0 인터페이스는 외부에서 쿠버네티스에 접근하기 위한 용도로 k8s 클러스터에서 접근할 일이 없습니다!)

 

통신 불가의 문제를 해결하려면 static routing 을 노드가 생성될 때마다 추가할 수 있지만 수동 처리에는 한계가 있습니다.

BGP, Encapsulation (Overlay Network) 방법들을 통해 문제를 해결합니다.

 

Encapsulation (Overlay Network)

설령 pod 대역 대의 IP 주소를 알지 못 하더라도 라우터는 노드의 IP 주소를 알고 라우팅을 할 수 있기 때문에, 노드의 IP 주소로 한 번 감싸 패킷을 보내면 통신이 가능해집니다.

 

 

여타 다른 CNI 플러그인과 같이 VXLAN 모드, GENEVE 모드를 통해 원본 패킷을 감싸 보낼 수 있습니다. 다른 네트워크 플러그인에서는 Overlay Network 라고 부르는데 Cilium 에서는 encapsulation 이라고 부릅니다.

 

Encapsulation 설정

VXLAN 과 GENEVE 를 활성화하려면 CONFIG_VXLAN 과 CONFIG_GENEVE 커널 설정을 활성화 해야 합니다.

아래와 같이 커널 옵션을 살펴보면 'm' 모듈로 컴파일되어 있어 직접 커널에 로드해서 사용합니다. modprobe 지시자로 원하는 모드를 선택하여 Overlay Network 를 활성화합니다.

 

 

나머지 두 노드에도 똑같이 설정을 해줍니다.

 

 

커널 설정 완료 후 helm routingMode=tunnel 옵션과 tunnelProtocol 옵션을 활성화 하여 cilium 을 rollout 해주면 모든 세팅이 완료됩니다.

 

helm upgrade cilium cilium/cilium --namespace kube-system --version 1.18.0 --reuse-values \
  --set routingMode=tunnel --set tunnelProtocol=vxlan \
  --set autoDirectNodeRoutes=false --set installNoConntrackIptablesRules=false

kubectl rollout restart -n kube-system ds/cilium

 

 

cilium 의 속성을 확인해보면 routing 모드가 tunnel 유형으로 바뀌고 tunnel 프로토콜이 vxlan 으로 변경된 것을 확인할 수 있습니다.

완료 후 변화된 점들을 하나씩 알아보겠습니다. 클러스터에 존재하는 서버들에 cilium_vxlan 인터페이스가 새롭게 생성되었습니다.

 

 

라우팅 테이블도 클러스터의 pod CIDR 대역들이 모두 올라온 것을 확인할 수 있습니다.

 

 

k8s-ctr 서버에서는 podCIDR 대역이 172.20.0.98 로 라우팅 되고, k8s-w1 서버에서는 podCIDR 대역이 172.20.1.11 로 라우팅 되고, k8s-w0 서버에서는 podCIDR 대역이 172.20.2.71 로 라우팅 되는데 이 세 IP 가 cilium 에서 라우팅을 위해 만든 IP 입니다.

 

# cilium 파드 이름 지정
export CILIUMPOD0=$(kubectl get -l k8s-app=cilium pods -n kube-system --field-selector spec.nodeName=k8s-ctr -o jsonpath='{.items[0].metadata.name}')
export CILIUMPOD1=$(kubectl get -l k8s-app=cilium pods -n kube-system --field-selector spec.nodeName=k8s-w1  -o jsonpath='{.items[0].metadata.name}')
export CILIUMPOD2=$(kubectl get -l k8s-app=cilium pods -n kube-system --field-selector spec.nodeName=k8s-w0  -o jsonpath='{.items[0].metadata.name}')
echo $CILIUMPOD0 $CILIUMPOD1 $CILIUMPOD2

# router 역할 IP 확인
kubectl exec -it $CILIUMPOD0 -n kube-system -c cilium-agent -- cilium status --all-addresses | grep router
kubectl exec -it $CILIUMPOD1 -n kube-system -c cilium-agent -- cilium status --all-addresses | grep router
kubectl exec -it $CILIUMPOD2 -n kube-system -c cilium-agent -- cilium status --all-addresses | grep router

 

Encapsulation 통신 과정

샘플 애플리케이션을 활용하여 통신 과정을 살펴보겠습니다.

자기 자신이 누구인지 알려주는 3 개의 webpod 와 컨트롤 노드에만 배치할 curl-pod 를 배포하고, router 노드에서 패킷들을 확인해봅니다.

 

# 샘플 애플리케이션 배포
cat << EOF | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
  name: webpod
spec:
  replicas: 3
  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

 

 

컨트롤 노드의 curl-pod 에서 다른 네트워크 대역인 k8s-w0 노드로 ping 을 보내고, router 노드에서는 tcpdump -i any udp port 8472 -nn 명령어를 통해 VXLAN 패킷을 잡아보겠습니다.

 

 

 

eth1 인터페이스로 k8s-ctr 노드에서 k8s-w0 노드로 통신하는 패킷 요청이 들어왔고, (overlay 라고 표시되어 있음)

내부 파드 IP 호출 흐름이 한 번 표시된 다음 eth2 인터페이스로 나가는 것을 볼 수 있습니다.

 

termshark 로도 확인해보겠습니다.

 

# 반복 접속
kubectl exec -it curl-pod -- sh -c 'while true; do curl -s --connect-timeout 1 webpod | grep Hostname; echo "---" ; sleep 1; done'

# 신규 터미널 [router] 로 저장하고,
tcpdump -i any udp port 8472 -w /tmp/vxlan.pcap
# termshark 로 열어서 확인
termshark -r /tmp/vxlan.pcap -d udp.port==8472,vxlan

 

termshark 가 overlay network 를 인식하지 못하므로 -d upd.port=8472,vxlan 옵션을 통해 decapsulation 합니다.

 

 

마찬가지로 IP Header 가 중복으로 보이며 VXLAN 헤더가 존재하는 것을 볼 수 있습니다.

반응형

'인프라 > 쿠버네티스' 카테고리의 다른 글

[cilium] BGP 설정 방법  (1) 2025.08.15
[cilium] cilium 의 LoadBalancer 서비스  (2) 2025.08.09
[cilium] Routing & Masquerading  (1) 2025.07.31
[cilium] IPAM  (3) 2025.07.31
[cilium] Hubble Exporter  (2) 2025.07.23

+ Recent posts