반응형

podCIDR 대역 BGP 설정

 

지난 시간에 이어, BGP 로 통신하여 네트워크 대역이 다른 문제를 해결해보려고 합니다.

 

 

다른 컴퓨터와 통신하기 위해서는 자신의 IP 를 광고해야 한다고 했는데 네트워크 대역이 다르므로 bgp 를 통해 광고해야 합니다.

k8s 클러스터 내부에서도 bgp 설정이 필요하고, k8s 네트워크에 조인되지 않은 라우터에도 bgp 설정이 필요합니다.

 

먼저 라우터 노드에 frrr 이라는 bgp 소프트웨어를 설치하고, k8s 대역에 있는 노드들을 neighbor 로 등록합니다.

 

cat << EOF >> /etc/frr/frr.conf
  neighbor CILIUM peer-group
  neighbor CILIUM remote-as external
  neighbor 192.168.10.100 peer-group CILIUM
  neighbor 192.168.10.101 peer-group CILIUM
  neighbor 192.168.20.100 peer-group CILIUM 
EOF

systemctl daemon-reexec && systemctl restart frr

 

위와 같이, /etc/frr/frr.conf 파일을 직접 수정해도 되고 아래와 같이 라우터 노드에 접근해서 설정을 해줘도 됩니다.

 

# 1. 터미널 진입
vtysh

# 2. 구성 설정 확인
conf

#3. 라우터 설정
router bgp 65000
neighbor CILIUM peer-group
neighbor CILIUM remote-as external
neighbor 192.168.10.100 peer-group CILIUM
neighbor 192.168.10.101 peer-group CILIUM
neighbor 192.168.20.100 peer-group CILIUM 
end

#4. 메모리 저장
write memory

 

k8s 의 control plane 노드에서도 cilium bgp 설정을 통해 router 노드를 neighbor 로 등록합니다.

먼저, bgp 동작할 노드들을 선정하기 위해서 노드에 label 을 붙여줍니다.

 

kubectl label nodes k8s-ctr k8s-w0 k8s-w1 enable-bgp=true
kubectl get node -l enable-bgp=true

 

이후 CiliumBGPClusterConfig, CiliumBGPPeerConfig, CiliumBGPAdvertisement 설정을 통해 neighbor 를 등록합니다.

 

cat << EOF | kubectl apply -f -
apiVersion: cilium.io/v2
kind: CiliumBGPAdvertisement
metadata:
  name: bgp-advertisements
  labels:
    advertise: bgp
spec:
  advertisements:
    - advertisementType: "PodCIDR"
---
apiVersion: cilium.io/v2
kind: CiliumBGPPeerConfig
metadata:
  name: cilium-peer
spec:
  timers:
    holdTimeSeconds: 9
    keepAliveTimeSeconds: 3
  ebgpMultihop: 2
  gracefulRestart:
    enabled: true
    restartTimeSeconds: 15
  families:
    - afi: ipv4
      safi: unicast
      advertisements:
        matchLabels:
          advertise: "bgp"
---
apiVersion: cilium.io/v2
kind: CiliumBGPClusterConfig
metadata:
  name: cilium-bgp
spec:
  nodeSelector:
    matchLabels:
      "enable-bgp": "true"
  bgpInstances:
  - name: "instance-65001"
    localASN: 65001
    peers:
    - name: "tor-switch"
      peerASN: 65000
      peerAddress: 192.168.10.200  # router ip address
      peerConfigRef:
        name: "cilium-peer"
EOF

 

CiliumBGPClusterConfig

  • 역할: 클러스터 내 bgp 인스턴스들과 neighboor 노드들 간의 peer 설정
  • 특징: nodeSelector 를 통해 특정 노드들을 선택하여 광고 가능 (일관된 BGP 설정 관리)

CiliumBGPPeerConfig

  • 역할: CiliumBGPClusterConfig 에 등록된 클러스터 내 bgp 인스턴스의 BGP 피어링 설정
  • 특징: neighbor 설정과 peering 상세 설정을 분리하여 여러 피어에서 동일한 설정 공유 가능

CiliumBGPAdvertisement

  • 역할: BGP 라우팅 테이블에 주입할 광고 유형 정의 (Pod CIDR, Service IP 등 다양한 타입 지원)

65000 AS 인 192.168.1.200 라우터와 neighboor 설정하고 ipv4의 podCIDR 대역을 홍보하는 설정입니다.

모든 설정이 완료되면, k8s control plane 노드에서 bgp peers 설정을 확인할 수 있습니다.

 

 

라우터 노드에서도 k8s 의 podCIDR 대역이 라우팅 된 것을 확인할 수 있습니다.

 

 

하지만 아직도 다른 네트워크 간 통신이 되지 않고 있습니다. BGP 프로토콜로 인해 다른 neighbor 에 있는 podCIDR 대역을 받아왔지만,

커널 라우팅 테이블에는 자동으로 올라가지 않았습니다. 여전히 라우팅 테이블에 podCIDR 대역이 보이지 않네요.

 

 

Cilium의 BGP는 GoBGP 기반으로 구성되어 있는데 기본적으로 disable-telemetry, disable-fib 상태로 빌드가 되기 때문에, 수신한 경로를 Linux 커널(FIB) 에 바로 주입하지 않는 것으로 추정됩니다. 여러 개의 podCIDR 대역들을 네트워크 장비에 전달하면 그 장비가 직접 라우팅을 진행하면 되기 때문에 Cilium 입장에서는 받을 필요가 없을 수도 있을 것 같습니다.

 

실무 환경에서는 default gateway 가 존재할 것이기 때문에 통신은 무난히 진행될 것으로 생각됩니다. 다만, 실습 환경에서는 k8s 대역을 eth1 인터페이스로, 인터넷을 eth0 인터페이스로 사용하고 있기 때문에 podCIDR 대역을 eth1 통해서 라우팅 될 수 있도록 조정이 필요합니다.

 

# k8s 파드 사용 대역 통신 전체는 eth1을 통해서 라우팅 설정
ip route add 172.20.0.0/16 via 192.168.10.200
sshpass -p 'vagrant' ssh vagrant@k8s-w1 sudo ip route add 172.20.0.0/16 via 192.168.10.200
sshpass -p 'vagrant' ssh vagrant@k8s-w0 sudo ip route add 172.20.0.0/16 via 192.168.20.200

 

 

이제 정상적으로 통신이 되고 있습니다.

 

Service IP BGP 설정

 

지금까지 알아본 BGP 설정은 podCIDR 대역을 홍보한 설정이지만, 저번 시간에 알아본 Service IP (External IP) 는 어떻게 설정해야 할까요?

 

cat << EOF | kubectl apply -f -
apiVersion: "cilium.io/v2"
kind: CiliumLoadBalancerIPPool
metadata:
  name: "cilium-pool"
spec:
  allowFirstLastIPs: "No"
  blocks:
  - cidr: "172.16.1.0/24"
EOF

 

로 IPAM 을 설정하고, 서비스의 ip 를 'LoadBalancer' 타입으로 변경하면 IPAM 에서 IP 를 할당 받습니다.

 

cat << EOF | kubectl apply -f -
apiVersion: cilium.io/v2
kind: CiliumBGPAdvertisement
metadata:
  name: bgp-advertisements-lb-exip-webpod
  labels:
    advertise: bgp
spec:
  advertisements:
    - advertisementType: "Service"
      service:
        addresses:
          - LoadBalancerIP
      selector:             
        matchExpressions:
          - { key: app, operator: In, values: [ webpod ] }
EOF

 

위에서 BGP peering 설정은 완료했으니 "metadata.labels.advertise: bgp" 라벨만 고정으로 해서 Service 유형의 CiliumBGPAdvertisement 를 통해 서비스 IP 를 광고해주면 됩니다.

 

 

정상적으로 router 노드에 Service IP 가 라우팅 되는 것을 확인할 수 있습니다. 로드밸런싱도 정상적으로 수행이 될까요?

 

 

router 노드에서 서비스로 통신 시도 시 트래픽이 골고루 분산되는 것처럼 보입니다. 현재 3개의 replica 구성을 2개의 replica 구성으로 변경해보았습니다.

 

 

2개의 replica 로 줄어들면서 k8s-ctr 노드와 k8s-w0 노드에만 webpod 가 세팅이 되어 있지만, bgp 라우팅에는 3개의 노드가 아직 구성되어 있습니다. 이유는 Service 의 externalTrafficPolicy 속성이 cluster(default) 이기 때문입니다. cluster 타입을 local 로 변경하면 pod 를 가지고 있는 노드만 광고하게 됩니다. (아래 정보에서 2번 방식에서 1번 방식으로 변경된 것입니다.)

 

더보기

(1) BGP(ECMP) + Service(LB EX-IP, ExternalTrafficPolicy:Local) + SNAT + Random

1. Router 에서 BGP ECMP MultiPath 로 인해 파드가 있는 노드로만 전달

2. 해당 노드의 파드가 요청을 처리하고 Router 로 바로 응답 리턴

 

(2) BGP(ECMP) + Service(LB EX-IP, ExternalTrafficPolicy:Cluster) + SNAT → 비권장 방식

 

1. Router 에서 BGP ECMP MultiPath 로 인해 Cilium BGP Peer 중 하나의 노드로 전달
2. 해당 트래픽의 원래 목적지인 k8s-ctr 의 파드로 요청을 전달
3. 해당 노드의 파드가 요청을 처리하고 응답 리턴을 위해서, NAT 를 수행했던 노드(k8s-w1) 로 다시 전달
4. NAT 를 수행했던 연결 정보를 확인해서, Reverse NAT 를 수행해서 최종 응답을 리턴

 

(3) BGP(ECMP) + Service(LB EX-IP, ExternalTrafficPolicy:Cluster) + DSR + Maglev

 

1. Router 에서 BGP ECMP MultiPath 로 인해 Cilium BGP Peer 중 하나의 노드로 전달
2. 해당 트래픽의 원래 목적지인 k8s-ctr 의 파드로 요청을 전달

이 때, Router 로 바로 리턴하기 위해서(DSR) 최초 접속했던 클라이언트의 정보를 GENEVE 헤더에 감싸 전달

(클라이언트의 세션에 대한 유지를 위해서 Maglev 알고리즘을 사용)

3. 해당 노드의 파드가 요청을 처리하고 GEVEVE 헤더 정보를 활용하여 Reverse NAT 을 수행해서 응답을 바로 리턴

 

kubectl patch service webpod -p '{"spec":{"externalTrafficPolicy":"Local"}}'

 

 

pod 가 있는 노드만 라우팅 설정된 것을 볼 수 있습니다. 하지만, 아직도 부하 분산이 되지 않고 있습니다. 한 쪽에 있는 pod 에만 트래픽이 몰리고 있는데요. 이는 리눅스에서 네트워크 분산을 책임지는 ECMP Hash 정책이 기본적으로 L3(목적지 IP 기반) 해시를 사용하기 때문입니다.

 

 

정교한 부하분산을 원한다면 L4 해시 (IP + 포트) 기반으로 설정해야 합니다.

 

sudo sysctl -w net.ipv4.fib_multipath_hash_policy=1

 

 

부하 분산이 정상적으로 되는 것을 확인할 수 있습니다. replica 를 다시 3개로 증가시켜 부하 분산이 되는지 마지막으로 체크해보겠습니다.

 

kubectl scale deployment webpod --replicas 3

 

 

라우팅도 바로 원복되고, 부하 분산도 잘 되고 있습니다.

반응형

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

[cilium] Ingress / Gateway API  (0) 2025.08.23
[cilium] cluster mesh  (2) 2025.08.15
[cilium] cilium 의 LoadBalancer 서비스  (2) 2025.08.09
[cilium] Overlay Network  (1) 2025.08.09
[cilium] Routing & Masquerading  (1) 2025.07.31

+ Recent posts