BGP 컨트롤 플레인 리소스

BGP 컨트롤 플레인 리소스 (BGP Control Plane Resources)

Cilium BGP 컨트롤 플레인은 커스텀 리소스 집합으로 관리돼요. 피어, 정책, 광고를 유연하게 구성할 수 있게 해 주죠. 이 글에서는 각 리소스의 역할과 클러스터·피어·광고 구성 방법을 예시와 함께 알아볼게요.

출처: BGP Control Plane Resources

본문

Cilium BGP 컨트롤 플레인은 BGP 피어, 정책, 광고를 유연하게 구성할 수 있는 커스텀 리소스 집합으로 관리됩니다.

BGP 컨트롤 플레인을 관리하는 데 사용되는 리소스는 다음과 같아요:

  • CiliumBGPClusterConfig : 여러 노드에 적용되는 BGP 인스턴스와 피어 구성을 정의합니다.
  • CiliumBGPPeerConfig : 공통으로 사용하는 BGP 피어링 설정 집합. 여러 피어에서 함께 사용할 수 있어요.
  • CiliumBGPAdvertisement : BGP 라우팅 테이블에 주입되는 접두사를 정의합니다.
  • CiliumBGPNodeConfigOverride : 더 세밀한 제어를 위해 노드별 BGP 구성을 정의합니다.

여러 리소스 간의 관계는 아래 다이어그램에 나타나 있습니다.

BGP 클러스터 구성

CiliumBGPClusterConfig 리소스는 nodeSelector 필드에 기반해 클러스터의 하나 이상의 노드에 대한 BGP 구성을 정의하는 데 사용됩니다. 각 CiliumBGPClusterConfig 는 하나 이상의 BGP 인스턴스를 정의하며, 각 인스턴스는 name 필드로 고유하게 식별돼요.

BGP 인스턴스는 하나 이상의 피어를 가질 수 있습니다. 각 피어는 name 필드로 고유하게 식별돼요. 피어 자율 시스템 번호와 피어 주소는 각각 peerASN 과 peerAddress 필드로 정의됩니다. 피어의 구성은 피어 구성 리소스를 참조하는 peerConfigRef 필드로 정의되고, peerConfigRef 의 Group 과 kind 는 선택 사항이며 각각 cilium.io 와 CiliumBGPPeerConfig 로 기본 설정됩니다.

기본적으로 BGP 컨트롤 플레인은 각 라우터 인스턴스를 수신 포트 없이 인스턴스화합니다. 즉 BGP 라우터는 구성된 피어로의 연결만 시작할 수 있고, 들어오는 연결은 받아들일 수 없어요. BGP 컨트롤 플레인은 같은 노드에서 다른 BGP 라우터(예: Bird)가 실행되는 환경에서 동작하도록 설계됐기 때문에 이것이 기본 동작입니다. 들어오는 연결을 받아들여야 한다면 localPort 필드로 수신 포트를 지정할 수 있어요.

Warning

기본 BGP 포트(179)에서 수신하려면 CAP_NET_BIND_SERVICE 가 필요합니다. 기본 포트를 사용하고 싶다면 securityContext.capabilities.ciliumAgent Helm 값으로 CAP_NET_BIND_SERVICE 권한을 부여해야 해요.

다음은 instance-65000 이라는 BGP 인스턴스와 이 인스턴스 아래 구성된 두 피어를 가진 CiliumBGPClusterConfig 의 예시 구성입니다.

apiVersion: cilium.io/v2
kind: CiliumBGPClusterConfig
metadata:
  name: cilium-bgp
spec:
  nodeSelector:
    matchLabels:
      rack: rack0
  bgpInstances:
  - name: "instance-65000"
    localASN: 65000
    localPort: 179
    peers:
    - name: "peer-65000-tor1"
      peerASN: 65000
      peerAddress: fd00:10:0:0::1
      peerConfigRef:
        name: "cilium-peer"
    - name: "peer-65000-tor2"
      peerASN: 65000
      peerAddress: fd00:11:0:0::1
      peerConfigRef:
        name: "cilium-peer"

자동 발견 (Auto-Discovery)

Cilium BGP 컨트롤 플레인은 BGP 피어의 자동 발견도 지원해요.

활성화되면 자동 발견 기능이 BGP 피어의 IP 주소를 자동으로 구성합니다. 특정 주소의 선택은 활성화된 mode 에 따라 달라져요.

Cilium BGP 컨트롤 플레인은 현재 CiliumBGPClusterConfig 의 autoDiscovery 필드 아래에서 DefaultGateway 모드를 지원합니다.

기본 게이트웨이 자동 발견

기본 게이트웨이 자동 발견 모드는 Cilium이 지정된 주소 패밀리에 대해 기본 게이트웨이(보통 Top-of-Rack(ToR) 스위치)를 자동으로 발견하고 BGP 세션을 수립할 수 있게 해 줍니다.

기본 게이트웨이 자동 발견을 활성화하려면 피어 구성에 autoDiscovery 필드를 구성하세요:

peers:
- name: "tor-switch"
  peerASN: 65000
  autoDiscovery:
    mode: "DefaultGateway"
    defaultGateway:
      addressFamily: ipv6  # Can be "ipv4" or "ipv6"
  peerConfigRef:
    name: "cilium-peer"

ToR 스위치 BGP 구성 요구사항은 다음과 같습니다:

  • ToR 스위치는 동적 BGP 이웃을 지원하도록 "bgp listen range"로 구성해야 합니다. 이 구성은 특정 IP 접두사 범위에서 오는 연결을 수신하여 Cilium 노드의 BGP 세션을 받아들이도록 ToR 스위치를 설정하며, 각 Cilium 노드의 정확한 피어 주소를 알 필요가 없게 해 줘요.
  • 자세한 내용은 FRR 문서를 참고하세요.
  • 클러스터의 모든 노드에서 Cilium 구성이 일관되도록 각 ToR 스위치를 동일한 로컬 ASN(자율 시스템 번호)으로 구성하세요.

예를 들면:

router bgp 65100
  neighbor CILIUM peer-group
  neighbor CILIUM local-as 65000 no-prepend replace-as
  bgp listen range fd00:10:0:1::/64 peer-group CILIUM

이 구성이 적용되면:

  • Cilium이 각 노드에서 지정된 주소 패밀리의 기본 게이트웨이를 결정합니다
  • 발견된 게이트웨이와 자동으로 BGP 세션을 수립합니다
  • 세션 매개변수에 peerConfigRef 가 참조하는 피어 구성을 사용합니다

Warning

기본 게이트웨이로 링크-로컬 주소는 지원되지 않습니다.

기본 게이트웨이 자동 발견과 멀티호밍

멀티호밍 설정에서 Cilium 노드는 두 개의 서로 다른 Top-of-Rack 스위치에 연결됩니다. 두 기본 게이트웨이를 모두 발견하지만, BGP 세션을 수립하려면 더 낮은 메트릭을 가진 기본 경로를 선택해요. Cilium은 한 번에 주소 패밀리당 하나의 BGP 세션만 생성한다는 점을 기억하세요. 더 낮은 메트릭의 기본 경로에 실패하거나 변경되면 조정(reconciliation)이 트리거되어 다른 기본 경로의 기본 게이트웨이와 BGP 세션을 수립합니다.

구성 예시:

bgpInstances:
- name: "65001"
  localASN: 65001
  peers:
  - name: "instance-65001"
    peerASN: 65000
    autoDiscovery:
      mode: "DefaultGateway"
      defaultGateway:
        addressFamily: ipv6
    peerConfigRef:
      name: "cilium-peer"
검증

자동 발견된 피어와 BGP 세션이 수립됐는지 확인하려면 cilium bgp peers 명령을 사용하세요:

$ cilium bgp peers
Local AS   Peer AS   Peer Address         Session       Uptime   Family         Received   Advertised
65001      65000     fd00:10:0:1::1:179   established   21m55s   ipv4/unicast   2          2
                                                                 ipv6/unicast   2          2
한계

멀티호밍 설정에서 DefaultGateway 모드의 자동 발견은 같은 주소 패밀리에 대해 여러 BGP 세션을 만드는 데 사용할 수 없어요. 현재로선 각 피어의 주소를 수동으로 구성하는 것만이 해결 방법입니다.

BGP 피어 구성

CiliumBGPPeerConfig 리소스는 BGP 피어 구성을 정의하는 데 사용됩니다. 여러 피어가 같은 구성을 공유하고 공통 CiliumBGPPeerConfig 리소스를 참조할 수 있어요.

CiliumBGPPeerConfig 리소스는 다음에 대한 구성 옵션을 포함합니다:

다음은 CiliumBGPPeerConfig 리소스의 예시 구성입니다. 다음 섹션에서 각 구성 옵션을 하나씩 살펴볼게요.

apiVersion: cilium.io/v2
kind: CiliumBGPPeerConfig
metadata:
  name: cilium-peer
spec:
  timers:
    holdTimeSeconds: 9
    keepAliveTimeSeconds: 3
  authSecretRef: bgp-auth-secret
  ebgpMultihop: 4
  gracefulRestart:
    enabled: true
    restartTimeSeconds: 15
  families:
    - afi: ipv4
      safi: unicast
      advertisements:
        matchLabels:
          advertise: "bgp"

MD5 비밀번호

CiliumBGPPeerConfig 의 AuthSecretRef 는 이 구성을 참조하는 BGP 피어와의 세션에 RFC-2385 TCP MD5 비밀번호를 구성하는 데 사용할 수 있어요.

authSecretRef 설정 예시:

apiVersion: cilium.io/v2
kind: CiliumBGPPeerConfig
metadata:
  name: cilium-peer
spec:
  authSecretRef: bgp-auth-secret

AuthSecretRef 는 BGP 시크릿 네임스페이스의 시크릿 이름을 참조해야 합니다 (Helm 차트를 사용한다면 기본값은 kube-system). 시크릿은 password 라는 이름의 키를 포함해야 해요.

BGP 시크릿은 각 Cilium 에이전트 인스턴스에 필요한 권한을 최소화하기 위해 구성된 네임스페이스로 제한됩니다. Helm 차트는 기본적으로 Cilium이 그곳을 읽을 수 있도록 구성해 줍니다.

시크릿 생성 예시:

$ kubectl create secret generic -n kube-system --type=string secretname --from-literal=password=my-secret-password

네임스페이스를 변경하려면 bgpControlPlane.secretNamespace.name Helm 차트 값을 설정하면 됩니다. 네임스페이스를 자동으로 생성하려면 bgpControlPlane.secretNamespace.create Helm 차트 값을 true 로 설정하세요.

TCP MD5 비밀번호는 패킷의 헤더에 서명하기 때문에 세션이 Cilium에 의해 주소 변환되면 사용할 수 없어요 (즉, BGP 피어가 보는 주소가 Cilium 에이전트의 Pod IP 주소여야 합니다).

비밀번호가 틀리거나 헤더가 변경되면 TCP 연결은 성공하지 않습니다. 이는 Cilium 에이전트 로그에서 더 구체적인 오류 메시지 대신 dial: i/o timeout 으로 나타날 거예요.

Cilium이 찾을 수 없는 authSecretRef 가 있는 CiliumBGPPeerConfig 가 배포되면, BGP 세션은 빈 비밀번호를 사용하고 에이전트는 다음 예시와 같은 오류를 기록합니다:

level=error msg="Failed to fetch secret \"secretname\": not found (will continue with empty password)" component=manager.fetchPeerPassword subsys=bgp-control-plane

타이머

BGP 컨트롤 플레인은 다음 BGP 타이머 매개변수 수정을 지원합니다. 각 타이머 매개변수에 대한 자세한 설명은 RFC4271을 참고하세요.

Name Field Default
ConnectRetryTimer connectRetryTimeSeconds 120
HoldTimer holdTimeSeconds 90
KeepaliveTimer keepAliveTimeSeconds 30

Kubernetes 클러스터가 배포된 데이터센터 네트워크에서는 더 빠른 장애 감지를 위해 HoldTimer 와 KeepaliveTimer 를 더 낮은 값으로 설정하는 것이 일반적으로 권장됩니다. 예를 들어 최소 가능 값인 holdTimeSeconds=9 와 keepAliveTimeSeconds=3 을 설정할 수 있어요.

피어와의 연결이 끊긴 후 빠른 재연결을 보장하려면 connectRetryTimeSeconds 를 줄이세요 (예: 5 이하). 구성된 값에 내부적으로 무작위 지터(jitter)가 적용되므로 실제 사용되는 ConnectRetryTimer 값은 [ConnectRetryTimeSeconds, 2 * ConnectRetryTimeSeconds) 구간 안에 있습니다.

apiVersion: cilium.io/v2
kind: CiliumBGPPeerConfig
metadata:
  name: cilium-peer
spec:
  timers:
    connectRetryTimeSeconds: 5
    holdTimeSeconds: 9
    keepAliveTimeSeconds: 3

EBGP 멀티홉

기본적으로 eBGP에서 BGP 패킷의 IP TTL은 1로 설정됩니다. 일반적으로 TTL을 변경하지 않는 것이 권장되지만, 경우에 따라 TTL 값을 변경해야 할 수 있어요. 예를 들어 BGP 피어가 Route Server이고 다른 서브넷에 있는 경우 TTL 값을 1보다 크게 설정해야 할 수 있습니다.

apiVersion: cilium.io/v2
kind: CiliumBGPPeerConfig
metadata:
  name: cilium-peer
spec:
  ebgpMultihop: 4 # <-- specify the TTL value

Graceful Restart

Cilium BGP 컨트롤 플레인은 graceful restart Restarting Speaker 로 동작하도록 구성할 수 있어요. graceful restart를 활성화하면 BGP 세션이 재시작되고 BGP OPEN 메시지에 "graceful restart" 능력(capability)이 광고됩니다.

Cilium 에이전트가 재시작되면 피어링하고 있는 BGP 라우터는 Cilium BGP 컨트롤 플레인에서 받은 경로를 즉시 철회하지 않아요. 에이전트 재시작 동안 데이터패스는 계속 트래픽을 전달하므로 트래픽 중단이 없습니다.

선택적으로 restartTimeSeconds 매개변수를 사용할 수 있어요. RestartTime 은 재시작 후 Cilium BGP 컨트롤 플레인이 BGP 세션을 재수립할 것으로 예상되는 시간으로 피어에게 광고됩니다. RestartTime 이 만료되면 피어는 Cilium BGP 컨트롤 플레인이 이전에 광고한 경로를 제거해요.

apiVersion: cilium.io/v2
kind: CiliumBGPPeerConfig
metadata:
  name: cilium-peer
spec:
  gracefulRestart:
    enabled: true
    restartTimeSeconds: 15

Cilium 에이전트가 재시작되면 BGP TCP 소켓을 닫아 TCP FIN 패킷을 보냅니다. 이 TCP FIN을 받으면 피어는 BGP 상태를 Idle 로 변경하고 RestartTime 타이머를 시작해요.

Cilium 에이전트 부팅 시간은 배포에 따라 다릅니다. RestartTime 을 사용한다면, Cilium 에이전트가 부팅하는 데 걸리는 시간보다 큰 기간으로 설정해야 해요.

RestartTime 의 기본값은 120초입니다. graceful restart와 RestartTime 에 대한 자세한 내용은 RFC-4724와 RFC-8538에서 찾을 수 있어요.

전송 (Transport)

CiliumBGPPeerConfig 의 전송 섹션은 피어 BGP 세션의 연결 설정을 조정하는 데 사용할 수 있어요.

기본적으로 BGP가 active 모드(Cilium 에이전트가 TCP 연결을 시작)로 동작할 때, 목적지 포트는 179이고 소스 포트는 임시(ephemeral)입니다. peerPort 필드로 사용자 지정 목적지 포트를 구성할 수 있어요.

BGP 세션의 소스 IP 주소는 기본적으로 egress 인터페이스에 기반해 자동 감지됩니다. sourceInterface 필드로 이를 제공된 네트워크 인터페이스에 적용된 IP 주소로 재정의할 수 있어요. 인터페이스는 주소 패밀리당 하나를 초과하는 비-루프백, 비-멀티캐스트, 비-링크-로컬-IPv6 주소를 가져선 안 됩니다.

전송 구성 설정 예시:

apiVersion: cilium.io/v2
kind: CiliumBGPPeerConfig
metadata:
  name: cilium-peer
spec:
  transport:
    peerPort: 179
    sourceInterface: lo

주소 패밀리

families 필드는 AFI(주소 패밀리 식별자), SAFI(후속 주소 패밀리 식별자) 쌍과 광고 셀렉터의 목록입니다. 현재 지원되는 AFI/SAFI 옵션은 {afi: ipv4, safi: unicast} 와 {afi: ipv6, safi: unicast} 뿐입니다.

기본적으로 주소 패밀리를 지정하지 않으면 BGP 컨트롤 플레인은 IPv4 Unicast와 IPv6 Unicast Multiprotocol Extensions Capability (RFC-4760)를 모두 피어에게 보냅니다.

각 주소 패밀리에서 advertisements 라벨 셀렉터를 통해 경로 발행을 제어할 수 있어요. 다양한 광고 유형은 여기에 정의되어 있습니다.

Note

일치하는 광고가 없으면 어떤 접두사도 피어에게 광고되지 않습니다. 기본 구성은 어떤 접두사도 광고하지 않는 것입니다.

apiVersion: cilium.io/v2
kind: CiliumBGPPeerConfig
metadata:
  name: cilium-peer
spec:
  families:
    - afi: ipv4
      safi: unicast
      advertisements:
        matchLabels:
          advertise: "bgp"
    - afi: ipv6
      safi: unicast
      advertisements:
        matchLabels:
          advertise: "bgp"

BGP 광고

CiliumBGPAdvertisement 리소스는 다양한 광고 유형과 관련 속성을 정의하는 데 사용됩니다. 피어 구성의 families 필드에 정의된 advertisements 라벨 셀렉터는 하나 이상의 CiliumBGPAdvertisement 리소스와 일치할 수 있어요.

BGP 속성

advertisements[*] 의 attributes 필드를 사용해 Cilium BGP 컨트롤 플레인이 광고하는 접두사의 BGP 경로 속성을 구성할 수 있어요. 광고할 수 있는 경로 속성 유형은 Communities 와 LocalPreference 두 가지입니다.

다음은 커뮤니티 값 "65000:99"와 로컬 프리퍼런스 99로 pod 접두사를 광고하는 CiliumBGPAdvertisement 리소스의 예시 구성입니다.

apiVersion: cilium.io/v2
kind: CiliumBGPAdvertisement
metadata:
  name: bgp-advertisements
  labels:
    advertise: bgp
spec:
  advertisements:
    - advertisementType: "PodCIDR"
      attributes:
        communities:
          standard: [ "65000:99" ]
        localPreference: 99

Community

Communities 는 지원되는 BGP Communities 경로 속성에서 광고되는 커뮤니티 값 집합을 정의합니다.

값은 세 가지 유형일 수 있어요:

  • Standard : "standard" 32비트 BGP Communities 속성(RFC-1997)의 값을 4바이트 10진수 또는 콜론으로 구분된 두 개의 2바이트 10진수(예: 64512:100 )로 나타냅니다.
  • WellKnown : "standard" 32비트 BGP Communities 속성(RFC-1997)의 값을 숫자 값에 대한 잘 알려진 문자열 별칭으로 나타냅니다. 허용된 값과 숫자 값으로의 매핑은 다음 표에 표시됩니다.
Well-Known Value Hexadecimal Value 16-bit Pair Value
internet 0x00000000 0:0
planned-shut 0xffff0000 65535:0
accept-own 0xffff0001 65535:1
route-filter-translated-v4 0xffff0002 65535:2
route-filter-v4 0xffff0003 65535:3
route-filter-translated-v6 0xffff0004 65535:4
route-filter-v6 0xffff0005 65535:5
llgr-stale 0xffff0006 65535:6
no-llgr 0xffff0007 65535:7
blackhole 0xffff029a 65535:666
no-export 0xffffff01 65535:65281
no-advertise 0xffffff02 65535:65282
no-export-subconfed 0xffffff03 65535:65283
no-peer 0xffffff04 65535:65284
  • Large : BGP Large Communities 속성(RFC-8092)의 값을 콜론으로 구분된 세 개의 4바이트 10진수(예: 64512:100:50 )로 나타냅니다.

로컬 프리퍼런스

LocalPreference 는 BGP Local Preference 경로 속성에서 광고되는 프리퍼런스 값을 정의합니다. Local Preference는 iBGP 피어에게만 유효하므로, 이 값은 eBGP 피어에게는 무시됩니다 (Local Preference 경로 속성이 광고되지 않아요).

광고 유형

Cilium이 지원하는 광고 유형은 다음과 같습니다:

Pod CIDR 범위

BGP 컨트롤 플레인은 노드의 Pod CIDR 접두사를 광고할 수 있어요. 이렇게 하면 로드 밸런서나 NAT 없이 BGP 피어와 연결된 네트워크가 직접 Pod에 도달할 수 있습니다. IPAM 모드 설정에 따라 PodCIDR을 광고하는 두 가지 방법이 있어요.

Note

Cilium BGP 컨트롤 플레인은 전체 범위가 아니라 노드에 할당된 pod CIDR을 광고합니다.

Kubernetes 및 ClusterPool IPAM

Kubernetes 또는 ClusterPool IPAM을 사용할 때 광고 유형을 PodCIDR 로 설정하세요.

apiVersion: cilium.io/v2
kind: CiliumBGPAdvertisement
metadata:
  name: bgp-advertisements
  labels:
    advertise: bgp
spec:
  advertisements:
    - advertisementType: "PodCIDR"

이 구성으로 노드의 BGP 인스턴스는 로컬 노드에 할당된 Pod CIDR 접두사를 광고해요.

MultiPool IPAM

MultiPool IPAM을 사용할 때는 advertisementType 필드를 CiliumPodIPPool 로 지정하세요. selector 필드는 지정된 .matchLabels 또는 .matchExpressions 와 일치하는 CiliumPodIPPool 을 선택하는 라벨 셀렉터입니다.

apiVersion: cilium.io/v2
kind: CiliumPodIPPool
metadata:
  name: default
  labels:
    pool: blue
apiVersion: cilium.io/v2
kind: CiliumBGPAdvertisement
metadata:
  name: pod-ip-pool-advert
  labels:
    advertise: bgp
spec:
  advertisements:
    - advertisementType: "CiliumPodIPPool"
      selector:
        matchLabels:
          pool: "blue"

이 구성은 선택된 Cilium pod IP 풀에서 할당된 PodCIDR 접두사를 광고합니다. CIDR이 CiliumNode 리소스에 할당되어야 한다는 점을 기억하세요.

클러스터 안의 모든 CiliumPodIPPool CIDR을 광고하려면 더미 키와 값을 가진 NotIn 일치 표현식을 다음과 같이 사용할 수 있어요:

apiVersion: cilium.io/v2
kind: CiliumBGPAdvertisement
metadata:
  name: pod-ip-pool-advert
  labels:
    advertise: bgp
spec:
  advertisements:
    - advertisementType: "CiliumPodIPPool"
      selector:
        matchExpressions:
        - {key: somekey, operator: NotIn, values: ['never-used-value']}

라벨 대신 name 및/또는 namespace 메타데이터에 기반해 CiliumPodIPPools를 일치시키는 특수 목적 셀렉터 필드가 두 개 있습니다:

Selector Field
io.cilium.podippool.namespace .meta.namespace
io.cilium.podippool.name .meta.name

CiliumPodIPPools에 대한 추가 세부 사항은 Multi-Pool 섹션을 참고하세요.

기타 IPAM 유형

다른 IPAM 유형을 사용할 때 BGP 컨트롤 플레인은 PodCIDR 광고를 지원하지 않으며 advertisementType: "PodCIDR" 를 지정해도 효과가 없어요.

Service 가상 IP

Kubernetes에서 Service는 .spec.clusterIP , .spec.clusterIPs , .status.loadBalancer.ingress[*].ip 또는 .spec.externalIPs 같은 여러 가상 IP 주소를 가질 수 있어요.

BGP 컨트롤 플레인은 Service의 가상 IP 주소를 BGP 피어에게 광고할 수 있습니다. 이렇게 하면 클러스터 외부에서 Service에 직접 접근할 수 있어요.

Note

Cilium BGP 컨트롤 플레인은 VIP에 대한 정확한 경로(/32 또는 /128 접두사)를 광고합니다.

Service 가상 IP를 광고하려면 advertisementType 필드를 Service 로, service.addresses 필드를 LoadBalancerIP , ClusterIP 또는 ExternalIP 으로 지정하세요.

.selector 필드는 지정된 .matchLabels 또는 .matchExpressions 와 일치하는 Service를 선택하는 라벨 셀렉터입니다.

apiVersion: cilium.io/v2
kind: CiliumBGPAdvertisement
metadata:
  name: bgp-advertisements
  labels:
    advertise: bgp
spec:
  advertisements:
    - advertisementType: "Service"
      service:
        addresses:
          - ClusterIP
          - ExternalIP
          - LoadBalancerIP
      selector:
        matchExpressions:
          - { key: bgp, operator: In, values: [ blue ] }

업스트림 라우터가 ECMP(Equal Cost Multi Path)를 지원하면, 여러 노드에서 동일한 가상 IP를 광고해 이 기능으로 여러 노드에 걸쳐 Service로의 트래픽을 로드 밸런싱할 수 있어요.

Warning

많은 라우터는 라우팅 테이블에 보관할 수 있는 ECMP 경로 수에 제한이 있습니다 (Juniper). 많은 노드에서 Service VIP를 광고하면 이 제한을 초과할 수 있어요. 이 기능을 사용하기 전에 네트워크 관리자에게 제한 값을 확인하는 것을 권장합니다.

ExternalIP

kubeProxyReplacement 기능과 함께 사용하려면 ( kube-proxy 없는 Kubernetes 문서 참고), ExternalIP 지원이 활성화되어 있는지 확인하세요.

Service의 .spec.externalIPs 만 광고하고 싶다면 service.addresses 필드를 ExternalIP 로 지정할 수 있어요.

apiVersion: cilium.io/v2
kind: CiliumBGPAdvertisement
metadata:
  name: bgp-advertisements
  labels:
    advertise: bgp
spec:
  advertisements:
    - advertisementType: "Service"
      service:
        addresses:                  # <-- specify the service types to advertise
          - ExternalIP
      selector:                     # <-- select Services to advertise
        matchExpressions:
          - { key: bgp, operator: In, values: [ blue ] }
ClusterIP

kubeProxyReplacement 기능과 함께 사용하려면 ( kube-proxy 없는 Kubernetes 문서 참고), 특정 BPF 매개변수를 활성화해야 해요. 활성화 방법은 ClusterIP 서비스에 대한 외부 접근 섹션을 참고하세요.

Service의 .spec.clusterIP 와 .spec.clusterIPs 만 광고하고 싶다면 virtualRouters[*].serviceAdvertisements 필드를 ClusterIP 로 지정할 수 있어요.

apiVersion: cilium.io/v2
kind: CiliumBGPAdvertisement
metadata:
  name: bgp-advertisements
  labels:
    advertise: bgp
spec:
  advertisements:
    - advertisementType: "Service"
      service:
        addresses:          # <-- specify the service types to advertise
          - ClusterIP
      selector:             # <-- select Services to advertise
        matchExpressions:
          - { key: bgp, operator: In, values: [ blue ] }
Load Balancer IP

ingress IP를 광고하려면 먼저 할당해야 합니다. 기본적으로 Kubernetes는 Service에 ingress IP를 할당하는 방법을 제공하지 않아요. ingress IP를 할당하는 컨트롤러를 준비하는 것은 클러스터 관리자의 책임입니다. Cilium은 Load Balancer IPAM 기능으로 ingress IP 할당을 지원해요.

apiVersion: cilium.io/v2
kind: CiliumBGPAdvertisement
metadata:
  name: bgp-advertisements
  labels:
    advertise: bgp
spec:
  advertisements:
    - advertisementType: "Service"
      service:
        addresses:          # <-- specify the service types to advertise
          - LoadBalancerIP
      selector:             # <-- select Services to advertise
        matchExpressions:
          - { key: bgp, operator: In, values: [ blue ] }

이 설정은 .selector 와 일치하는 모든 Service의 ingress IP를 광고합니다.

클러스터 안의 모든 서비스를 광고하려면 더미 키와 값을 가진 NotIn 일치 표현식을 다음과 같이 사용할 수 있어요:

apiVersion: cilium.io/v2
kind: CiliumBGPAdvertisement
metadata:
  name: bgp-advertisements
  labels:
    advertise: bgp
spec:
  advertisements:
    - advertisementType: "Service"
      service:
        addresses:          # <-- specify the service types to advertise
          - LoadBalancerIP
      selector:             # <-- select all services
        matchExpressions:
         - {key: somekey, operator: NotIn, values: ['never-used-value']}

라벨이 아니라 .meta.name 이나 .meta.namespace 같은 다른 메타데이터를 기준으로 일치시키는 특수 목적 셀렉터 필드가 몇 가지 있습니다.

Selector Field
io.kubernetes.service.namespace .meta.namespace
io.kubernetes.service.name .meta.name
Load Balancer Class

Cilium은 loadBalancerClass를 지원합니다. 로드 밸런서 클래스가 io.cilium/bgp-control-plane 로 설정되거나 지정되지 않으면 Cilium은 Service의 ingress IP를 광고합니다. 그 외의 경우 Cilium은 Service의 ingress IP를 광고하지 않아요.

ExternalTrafficPolicy/InternalTrafficPolicy

로드 밸런서 ingress IP 또는 외부 IP 광고의 경우, Service가 externalTrafficPolicy: Cluster 이면 BGP 컨트롤 플레인은 선택된 Service의 IP를 무조건 광고합니다. Service가 externalTrafficPolicy: Local 이면 BGP 컨트롤 플레인은 로컬 노드의 서비스 엔드포인트를 추적하고 로컬 엔드포인트가 없으면 광고를 중지해요.

마찬가지로 internalTrafficPolicy 는 ClusterIP 광고에 고려됩니다.

Note

service.addresses 를 ClusterIP 로 구성하면 BGP 컨트롤 플레인이 일치하는 서비스의 .spec.internalTrafficPolicy 구성만 고려하고 .spec.externalTrafficPolicy 구성은 무시한다는 점을 기억하세요. ExternalIP 와 LoadBalancerIP 의 경우 서비스의 .spec.externalTrafficPolicy 구성만 고려하고 .spec.internalTrafficPolicy 구성은 무시해요.

겹치는 광고

CiliumBGPAdvertisement 를 구성할 때 두 개 이상의 광고가 같은 Service와 일치할 수 있어요. Cilium 1.18 이전에는 겹치는 일치가 예상되지 않았고 마지막 순차 일치가 사용됐습니다. 오늘날에는 겹치는 광고 셀렉터가 지원됩니다. 겹침 처리 방식은 속성에 따라 다릅니다:

  • Communities: 모든 일치에서 요소의 합집합을 취합니다
  • Local Preference: 가장 큰 값을 선택합니다

예를 들어 아래에는 각각 셀렉터 일치를 정의하는 두 개의 광고가 있습니다. 하나는 vpc1 라벨에서, 다른 하나는 vpc2 에서 일치해요.

apiVersion: cilium.io/v2
kind: CiliumBGPAdvertisement
metadata:
  name: bgp-advertisements
  labels:
    advertise: bgp
spec:
  advertisements:
    - advertisementType: "Service"
      service:
        addresses:
          - LoadBalancerIP
      selector:
        matchExpressions:
          - { key: vpc1, operator: In, values: [ "true" ] }
      attributes:
        communities:
          large: [ "1111:1111:1111" ]
    - advertisementType: "Service"
      service:
        addresses:
          - LoadBalancerIP
      selector:
        matchExpressions:
          - { key: vpc2, operator: In, values: [ "true" ] }
      attributes:
        communities:
          large: [ "2222:2222:2222" ]

LoadBalancer Service를 노출하는 hello-world 배포가 있다고 해 볼게요. 처음에는 구성된 라벨이 없었습니다. 그래서 일치 항목도, BGP 광고도 없었어요.

kubectl get deployment
NAME          READY   UP-TO-DATE   AVAILABLE   AGE
hello-world   1/1     1            1           42m

kubectl get service hello-world --show-labels
NAME          TYPE           CLUSTER-IP   EXTERNAL-IP   PORT(S)          AGE   LABELS
hello-world   LoadBalancer   10.2.65.71   <pending>     8080:30569/TCP   43m   app=hello-world

그런 다음 라벨을 다음과 같이 구성했습니다:

kubectl label service hello-world vpc1=true
kubectl label service hello-world vpc2=true

결과적으로 BGP 광고는 1111:1111:1111 과 2222:2222:2222 커뮤니티를 모두 설정했어요. 모든 조합의 커뮤니티( Standard , Large , WellKnown )가 지원됩니다. Local Preference가 설정됐다면 모든 일치에서 관찰된 가장 큰 값이 됐을 거예요. 이는 "더 높은 프리퍼런스 정도가 선호되어야 한다(The higher degree of preference MUST be preferred)"고 명시한 RFC4271과 일치합니다.

접두사 집계 (Prefix Aggregation)

기본적으로 Cilium BGP 컨트롤 플레인은 서비스 VIP에 대한 정확한 경로(/32 또는 /128 접두사)를 광고해요. 다음 예시처럼 .service.aggregationLengthIPv4 및/또는 .service.aggregationLengthIPv6 필드(각각 IPv4 및/또는 IPv6 접두사에 대한)로 광고되는 접두사 길이를 수정할 수 있습니다.

apiVersion: cilium.io/v2
kind: CiliumBGPAdvertisement
metadata:
  name: bgp-advertisements
  labels:
    advertise: bgp
spec:
  advertisements:
    - advertisementType: "Service"
      service:
        aggregationLengthIPv4: 24
        aggregationLengthIPv6: 120
        addresses:
          - ClusterIP
          - ExternalIP
          - LoadBalancerIP
      selector:
        matchExpressions:
          - { key: bgp, operator: In, values: [ blue ] }

Note

.service.aggregationLengthIPv4 / .service.aggregationLengthIPv6 필드는 externalTrafficPolicy: Local 인 서비스의 ExternalIP 또는 LoadBalancerIP 를 광고할 때 무시됩니다. 마찬가지로 internalTrafficPolicy: Local 인 서비스의 ClusterIP 를 광고할 때도 무시돼요.

이 기능을 사용할 때 알려진 문제가 몇 가지 있습니다:

  • 접두사 집계는 일반적으로 데이터패스가 잘 처리할 수 없는 경로를 광고할 때 블랙홀이나 라우팅 루프를 만들 위험이 있어요. Cilium에는 Service에 할당되지 않은 VIP 범위로 트래픽을 보내면 라우팅 루프를 일으키는 알려진 문제가 있습니다 (자세한 내용은 이 이슈 참고). 즉 집계된 접두사를 광고하고 주소 범위의 일부가 Service에 할당되지 않으면 그 주소로 보내는 트래픽은 라우팅 루프에 빠지게 됩니다.
  • 여러 Service 광고가 집계를 통해 같은 접두사를 서로 다른 경로 속성으로 광고하게 되면 동작이 정의되지 않습니다. 업데이트는 이 이슈에서 추적할 수 있어요.

인터페이스 IP

BGP 컨트롤 플레인은 로컬 인터페이스에 할당된 임의의 IP 주소를 BGP 피어에게 광고할 수 있어요. 이는 예를 들어 멀티호밍 설정에서 유용할 수 있는데, 공통 노드의 루프백 주소를 여러 다른 네트워크 인터페이스의 여러 BGP 세션으로 광고할 수 있죠.

인터페이스 IP는 정확한 경로( /32 또는 /128 접두사)로 광고됩니다. 루프백, 멀티캐스트, IPv6 링크-로컬 및 IPv4-매핑 IPv6 주소 범위의 IP 주소는 광고되지 않아요.

Note

IP 주소를 광고하려면 인터페이스가 관리적으로 활성화되고 운영상 up 또는 unknown 상태여야 합니다.

다음 예시는 lo 라는 이름의 로컬 인터페이스에 할당된 IP 주소를 광고하는 데 사용할 수 있어요:

apiVersion: cilium.io/v2
kind: CiliumBGPAdvertisement
metadata:
  name: bgp-advertisements
  labels:
    advertise: bgp
spec:
  advertisements:
    - advertisementType: "Interface"
      interface:
        name: lo

Note

Cilium은 임의의(Cilium이 소유하지 않은) 로컬 인터페이스의 IP 주소를 관리하지 않으므로, 노드 관리자가 직접 구성해야 합니다.

BGP 구성 오버라이드

CiliumBGPNodeConfigOverride 리소스는 자동 생성된 구성의 일부를 노드 단위로 오버라이드하는 데 사용할 수 있어요.

다음은 bgp-cplane-dev-multi-homing-worker 라는 이름의 노드에서 각 피어에 사용되는 Router ID, 로컬 주소, 로컬 자율 시스템 번호를 설정하는 CiliumBGPNodeConfigOverride 리소스의 예시입니다.

apiVersion: cilium.io/v2
kind: CiliumBGPNodeConfigOverride
metadata:
  name: bgp-cplane-dev-multi-homing-worker
spec:
  bgpInstances:
    - name: "instance-65000"
      routerID: "192.168.10.1"
      localPort: 1790
      localASN: 65010
      peers:
        - name: "peer-65000-tor1"
          localAddress: fd00:10:0:2::2
        - name: "peer-65000-tor2"
          localAddress: fd00:11:0:2::2

Note

CiliumBGPNodeConfigOverride 리소스의 이름은 구성이 의도된 노드의 이름과 일치해야 합니다. 마찬가지로 BGP 인스턴스와 피어의 이름은 CiliumBGPClusterConfig 아래에 정의된 것과 일치해야 해요.

이것은 노드별 구성입니다.

RouterID

Router ID가 어떻게 할당되는지를 규정하는 bgpControlPlane.routerIDAllocation.mode Helm 차트 값이 있습니다. 현재 default 와 ip-pool 이 지원됩니다. 기본 할당 모드는 default 입니다.

default 모드에서 Cilium이 IPv4 단일 스택 또는 이중 스택에서 실행될 때, BGP 컨트롤 플레인은 노드에 할당된 IPv4 주소를 BGP Router ID로 사용할 수 있어요. Router ID가 32비트 길이이므로 IPv4 주소의 고유성을 신뢰해 Router ID를 고유하게 만들 수 있기 때문이죠. IPv6 단일 스택에서 실행할 때는 cilium_host 인터페이스 MAC 주소의 하위 32비트를 Router ID로 사용합니다.

ip-pool 모드에서는 bgpControlPlane.routerIDAllocation.ipPool Helm 값을 통해 10.0.0.0/24 같은 IPv4 IP 풀을 Cilium에 제공해야 합니다. Cilium은 구성된 풀에서 BGP 인스턴스에 Router ID를 할당해요.

Router ID의 자동 할당을 원하지 않으면 수동으로 정의해야 합니다. 사용자 지정 Router ID를 구성하려면 IPv4 주소 형식으로 routerID 필드를 설정하면 됩니다. default 모드에서는 어떤 Router ID든 수동으로 설정할 수 있고 Cilium은 검증하지 않아요. ip-pool 모드에서 Router ID가 풀 범위 안에 있으면 다른 것과 충돌하지 않도록 확인해야 합니다. Router ID가 풀 밖에 있으면 자유롭게 설정할 수 있습니다.

수신 포트

CiliumBGPClusterConfig 의 localPort 필드로 수신 포트를 지정할 수 있어요. 노드 단위로 오버라이드하고 싶다면 CiliumBGPNodeConfigOverride 리소스에 localPort 필드를 설정할 수 있습니다. 이는 CiliumBGPClusterConfig 에 localPort 필드가 설정되지 않은 경우에도 동작해요.

로컬 피어링 주소

BGP 컨트롤 플레인이 이웃과 피어링을 설정하기 위해 사용하는 소스 인터페이스와 주소는 CiliumBGPClusterConfig 에 정의된 피어 주소의 경로 조회에 기반해 결정됩니다. 노드에 여러 링크가 있고 BGP 피어링이 어느 링크에서 설정될지 더 정밀하게 제어하려는 사용 사례가 있을 수 있어요.

소스 주소를 구성하려면 peers[*].localAddress 필드를 설정할 수 있습니다. 이는 노드의 링크 중 하나에 구성된 주소여야 해요.

로컬 ASN

CiliumBGPNodeConfigOverride 리소스의 LocalASN 필드를 사용해 노드의 자율 시스템 번호(ASN)를 오버라이드할 수 있습니다. 이 필드가 정의되지 않으면 일치하는 CiliumBGPClusterConfig 의 LocalASN 이 노드의 로컬 ASN으로 사용됩니다. 이 사용자 지정을 통해 네트워크 설계에서 요구할 때 개별 노드가 다른 ASN으로 동작할 수 있어요.

샘플 구성

Cilium 저장소의 contrib/containerlab 아래 컨테이너 랩 예시를 참고하세요.

더 알아보기 (Learn more)