BGP 컨트롤 플레인 운영 가이드

BGP 컨트롤 플레인 운영 가이드 (BGP Control Plane Operation Guide)

BGP 컨트롤 플레인을 운영하는 방법을 안내하는 문서예요. cilium bgp CLI로 상태를 확인하는 법, CRD 상태 보고, 에이전트 재시작·노드 종료 같은 일상 운영 작업, 그리고 장애 시나리오별 대처법을 알아볼게요.

출처: BGP Control Plane Operation Guide

본문

이 문서는 BGP 컨트롤 플레인을 운영하는 방법에 대한 안내를 제공합니다.

BGP Cilium CLI

설치

최신 버전의 Cilium CLI를 설치하세요. Cilium CLI는 Cilium 설치, Cilium 설치 상태 확인, 그리고 다양한 기능(예: clustermesh, Hubble)의 활성화/비활성화에 사용할 수 있어요.

LinuxmacOSOther

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{,.sha256sum}
sha256sum --check cilium-linux-${CLI_ARCH}.tar.gz.sha256sum
sudo tar xzvfC cilium-linux-${CLI_ARCH}.tar.gz /usr/local/bin
rm cilium-linux-${CLI_ARCH}.tar.gz{,.sha256sum}
CILIUM_CLI_VERSION=$(curl -s https://raw.githubusercontent.com/cilium/cilium-cli/main/stable.txt)
CLI_ARCH=amd64
if [ "$(uname -m)" = "arm64" ]; then CLI_ARCH=arm64; fi
curl -L --fail --remote-name-all https://github.com/cilium/cilium-cli/releases/download/${CILIUM_CLI_VERSION}/cilium-darwin-${CLI_ARCH}.tar.gz{,.sha256sum}
shasum -a 256 -c cilium-darwin-${CLI_ARCH}.tar.gz.sha256sum
sudo tar xzvfC cilium-darwin-${CLI_ARCH}.tar.gz /usr/local/bin
rm cilium-darwin-${CLI_ARCH}.tar.gz{,.sha256sum}

전체 릴리스 페이지를 참고하세요.

Cilium BGP 상태는 cilium bgp 하위 명령으로 검사할 수 있어요.

# cilium bgp --help
Access to BGP control plane

Usage:
  cilium bgp [command]

Available Commands:
  peers       Lists BGP peering state
  routes      Lists BGP routes

Flags:
  -h, --help   help for bgp

Global Flags:
      --context string             Kubernetes configuration context
      --helm-release-name string   Helm release name (default "cilium")
      --kubeconfig string          Path to the kubeconfig file
  -n, --namespace string           Namespace Cilium is running in (default "kube-system")

Use "cilium bgp [command] --help" for more information about a command.

피어 (Peers)

cilium bgp peers 명령은 Kubernetes 클러스터의 모든 노드에서 현재 피어링 상태를 표시합니다.

다음 예시에서는 클러스터의 두 노드에 대한 피어링 상태를 보여 줘요.

# cilium bgp peers
Node                                   Local AS   Peer AS   Peer Address   Session State   Uptime   Family         Received   Advertised
bgp-cplane-dev-service-control-plane   65001      65000     fd00:10::1     established     33m26s   ipv4/unicast   2          2
                                                                                                    ipv6/unicast   2          2
bgp-cplane-dev-service-worker          65001      65000     fd00:10::1     established     33m25s   ipv4/unicast   2          2
                                                                                                    ipv6/unicast   2          2

이 명령으로 BGP 세션 상태가 established 인지, 그리고 예상되는 수의 경로가 피어에게 광고되고 있는지 검증할 수 있어요.

경로 (Routes)

cilium bgp routes 명령은 로컬 BGP 라우팅 테이블과 피어별 광고된 라우팅 정보에 대한 자세한 정보를 표시합니다.

다음 예시에서는 클러스터의 두 노드에 대한 IPv4/Unicast 주소 패밀리의 로컬 BGP 라우팅 테이블을 보여 줘요.

# cilium bgp routes available ipv4 unicast
Node                                   VRouter   Prefix        NextHop   Age      Attrs
bgp-cplane-dev-service-control-plane   65001     10.1.0.0/24   0.0.0.0   46m45s   [{Origin: i} {Nexthop: 0.0.0.0}]
bgp-cplane-dev-service-worker          65001     10.1.1.0/24   0.0.0.0   46m45s   [{Origin: i} {Nexthop: 0.0.0.0}]

마찬가지로 다음 명령으로 피어별 광고를 검사할 수 있어요.

# cilium bgp routes advertised ipv4 unicast
Node                                   VRouter   Peer         Prefix        NextHop          Age     Attrs
bgp-cplane-dev-service-control-plane   65001     fd00:10::1   10.1.0.0/24   fd00:10:0:1::2   47m0s   [{Origin: i} {AsPath: 65001} {Communities: 65000:99} {MpReach(ipv4-unicast): {Nexthop: fd00:10:0:1::2, NLRIs: [10.1.0.0/24]}}]
bgp-cplane-dev-service-worker          65001     fd00:10::1   10.1.1.0/24   fd00:10:0:2::2   47m0s   [{Origin: i} {AsPath: 65001} {Communities: 65000:99} {MpReach(ipv4-unicast): {Nexthop: fd00:10:0:2::2, NLRIs: [10.1.1.0/24]}}]

구성된 CiliumBGPAdvertisement 리소스에 기반해 BGP 속성이 광고되는지 검증할 수 있어요.

정책 (Policies)

Cilium BGP는 피어별 광고와 BGP 속성을 관리하는 GoBGP 정책을 설치합니다. 이것은 내부 구현 세부 사항이므로 Cilium CLI로 노출되지 않아요. 그러나 디버깅 목적으로 Cilium 에이전트 Pod에서 cilium-dbg CLI를 사용해 설치된 BGP 정책을 검사할 수 있습니다.

/home/cilium# cilium-dbg bgp route-policies
VRouter   Policy Name          Type     Match Peers      Match Prefixes (Min..Max Len)   RIB Action   Path Actions
65001     65000-ipv4-PodCIDR   export   fd00:10::1/128   10.1.0.0/24 (24..24)            accept       AddCommunities: [65000:99]
65001     65000-ipv6-PodCIDR   export   fd00:10::1/128   fd00:10:1::/64 (64..64)         accept       AddCommunities: [65000:99]
65001     allow-local          import                                                    accept

CiliumBGPClusterConfig 상태

CiliumBGPClusterConfig는 런타임에 감지된 일부 구성 오류를 .status.conditions 에 보고할 수 있어요. 현재 다음과 같은 조건이 정의되어 있습니다.

Condition Name Description
cilium.io/NoMatchingNode .spec.nodeSelector 가 어떤 노드도 선택하지 않음.
cilium.io/MissingPeerConfigs spec.bgpInstances[].peers[].peerConfigRef 에 지정된 PeerConfig가 존재하지 않음.
cilium.io/ConflictingClusterConfig 같은 노드를 선택하는 다른 CiliumBGPClusterConfig가 있음.

CiliumBGPPeerConfig 상태

CiliumBGPPeerConfig는 런타임에 감지된 일부 구성 오류를 .status.conditions 에 보고할 수 있어요. 현재 다음과 같은 조건이 정의되어 있습니다.

Condition Name Description
cilium.io/MissingAuthSecret .spec.authSecretRef 에 지정된 Secret이 존재하지 않음.

CiliumBGPNodeConfig 상태

CiliumBGPClusterConfig 노드 셀렉터에 기반해 BGP 컨트롤 플레인이 활성화된 각 Cilium 노드는 연결된 CiliumBGPNodeConfig 리소스를 갖습니다. CiliumBGPNodeConfig 리소스는 노드의 BGP 구성 소스이며, Cilium operator가 관리해요.

CiliumBGPNodeConfig 의 Status 필드는 실시간 BGP 운영 상태를 유지합니다. 이는 자동화나 모니터링 목적으로 사용할 수 있어요.

다음 예시에서는 bgp-cplane-dev-service-worker 노드의 BGP 인스턴스 상태를 볼 수 있어요.

# kubectl describe ciliumbgpnodeconfigs bgp-cplane-dev-service-worker
Name:         bgp-cplane-dev-service-worker
Namespace:
Labels:       <none>
Annotations:  <none>
API Version:  cilium.io/v2
Kind:         CiliumBGPNodeConfig
Metadata:
  Creation Timestamp:  2024-10-17T13:59:44Z
  Generation:          1
  Owner References:
    API Version:     cilium.io/v2
    Kind:            CiliumBGPClusterConfig
    Name:            cilium-bgp
    UID:             f0c23da8-e5ca-40d7-8c94-91699cf1e03a
  Resource Version:  1385
  UID:               fc88be94-37e9-498a-b9f7-a52684090d80
Spec:
  Bgp Instances:
    Local ASN:  65001
    Name:       65001
    Peers:
      Name:          65000
      Peer ASN:      65000
      Peer Address:  fd00:10::1
      Peer Config Ref:
        Group:  cilium.io
        Kind:   CiliumBGPPeerConfig
        Name:   cilium-peer
Status:
  Bgp Instances:
    Local ASN:  65001
    Name:       65001
    Peers:
      Established Time:  2024-10-17T13:59:50Z
      Name:              65000
      Peer ASN:          65000
      Peer Address:      fd00:10::1
      Peering State:     established
      Route Count:
        Advertised:  2
        Afi:         ipv4
        Received:    2
        Safi:        unicast
        Advertised:  2
        Afi:         ipv6
        Received:    2
        Safi:        unicast
      Timers:
        Applied Hold Time Seconds:  90
        Applied Keepalive Seconds:  30
Events:                             <none>

CRD 상태 보고 비활성화

CRD 상태 보고는 트러블슈팅에 유용해서 일반적으로 활성화하는 것이 좋아요. 그러나 노드나 BGP 정책이 많은 대규모 클러스터에서는 CRD 상태 보고가 상당한 API 서버 부하를 더할 수 있습니다. 상태 보고를 비활성화하려면 bgpControlPlane.statusReport.enabled Helm 값을 false 로 설정하세요. 이렇게 하면 상태 보고가 비활성화되고 현재 보고된 상태가 지워져요.

로그

BGP 컨트롤 플레인 로그는 Cilium operator와 Cilium 에이전트 로그에서 찾을 수 있어요.

operator 로그는 subsys=bgp-cp-operator 로 태그됩니다. 이 태그를 사용해 다음 예시처럼 로그를 필터링할 수 있어요:

kubectl -n kube-system logs <cilium operator pod name> | grep "subsys=bgp-cp-operator"

에이전트 로그는 subsys=bgp-control-plane 로 태그됩니다. 이 태그를 사용해 다음 예시처럼 로그를 필터링할 수 있어요:

kubectl -n kube-system logs <cilium agent pod name> | grep "subsys=bgp-control-plane"

메트릭

BGP 컨트롤 플레인이 노출하는 메트릭은 메트릭 문서에 나열되어 있습니다.

에이전트 재시작

Cilium 에이전트를 재시작하면 BGP 스피커가 Cilium 에이전트 안에 통합되어 있기 때문에 BGP 세션이 끊깁니다. Cilium 에이전트가 재시작되면 BGP 세션은 복구됩니다. 그러나 Cilium 에이전트가 내려간 동안 광고된 경로는 BGP 피어에서 제거돼요. 결과적으로 Pod나 Service에 대한 연결이 일시적으로 끊길 수 있습니다. 에이전트 재시작 동안 Pod나 Service로의 트래픽 전달을 계속하려면 Graceful Restart를 활성화할 수 있어요.

Cilium 업그레이드 또는 다운그레이드

Cilium을 업그레이드하거나 다운그레이드할 때는 Cilium 에이전트를 재시작해야 합니다. 에이전트 재시작에 대한 자세한 내용은 에이전트 재시작 섹션을 참고하세요.

BGP 컨트롤 플레인에서는 Cilium을 업그레이드하기 전에 preflight 프로세스를 따라 에이전트 이미지를 미리 받아두는 것이 특히 중요합니다. 이미지 풀은 네트워크 통신을 포함하므로 시간이 걸리고 오류가 발생하기 쉽습니다. 이미지 풀이 더 오래 걸리면 Graceful Restart 시간( restartTimeSeconds )을 초과해 BGP 피어가 경로를 철회하게 될 수 있어요.

노드 종료

유지보수를 위해 노드를 종료해야 한다면 아래 단계를 따라 패킷 손실을 최대한 피할 수 있어요.

  1. 노드를 drain하여 모든 워크로드를 축출합니다. 이렇게 하면 노드의 모든 Pod가 Service 엔드포인트에서 제거되고 externalTrafficPolicy=Cluster 인 Service가 트래픽을 노드로 리다이렉트하지 않게 됩니다.
kubectl drain <node-name> --ignore-daemonsets
  1. Node 객체에서 CiliumBGPClusterConfig 노드 셀렉터 라벨을 수정하거나 제거해 BGP 세션을 재구성합니다. 이렇게 하면 노드의 모든 BGP 세션이 종료됩니다.
# Assuming you select the node by the label enable-bgp=true
kubectl label node <node-name> --overwrite enable-bgp=false
  1. BGP 피어가 노드를 향한 경로를 제거할 때까지 잠시 기다립니다. 이 기간 동안 BGP 피어는 여전히 노드로 트래픽을 보낼 수 있어요. BGP 피어가 경로를 제거할 때까지 기다리지 않고 노드를 종료하면 externalTrafficPolicy=Cluster Service의 진행 중인 트래픽이 끊깁니다.

  2. 노드를 종료합니다.

3단계에서 피어 상태를 확인하지 못할 수 있는데, 실제 피어 상태를 확인하지 않고 특정 시간을 기다리고 싶을 수 있어요. 이 경우 대략적인 시간을 다음과 같이 추정할 수 있습니다:

  • BGP Graceful Restart 기능을 비활성화하면 BGP 피어는 2단계 직후 경로를 철회해야 합니다.
  • BGP Graceful Restart 기능을 활성화하면 두 가지 가능한 경우가 있습니다.
    • BGP 피어가 Notification이 있는 Graceful Restart(RFC 8538)를 지원하면, RFC 8538 4.1절에 정의된 Stale Timer가 만료된 후 경로를 철회합니다.
    • BGP 피어가 Notification이 있는 Graceful Restart를 지원하지 않으면, 노드를 선택 해제할 때 BGP 컨트롤 플레인이 피어에게 BGP Notification을 보내므로 2단계 직후 경로를 철회합니다.

위 추정치는 이론적인 값이며 실제 시간은 항상 BGP 피어의 구현에 따라 달라져요. 이상적으로는 네트워크 관리자와 함께 미리 피어 라우터의 실제 동작을 확인해야 합니다.

Warning

위 단계를 따르더라도, 경로 철회와 ECMP 재해싱 후 트래픽이 다른 노드로 리다이렉트되고 새 노드가 다른 엔드포인트를 선택할 수 있기 때문에 원래 노드로 향하던 일부 진행 중인 Service 트래픽이 리셋될 수 있어요.

실패 시나리오

이 문서는 BGP 컨트롤 플레인을 사용할 때 만날 수 있는 일반적인 실패 시나리오를 설명하고 완화 방법을 제시합니다.

Cilium 에이전트 다운

Cilium 에이전트가 내려가면 BGP 스피커가 Cilium 에이전트 안에 통합되어 있기 때문에 BGP 세션이 끊깁니다. Cilium 에이전트가 재시작되면 BGP 세션은 복구됩니다. 그러나 Cilium 에이전트가 내려간 동안 광고된 경로는 BGP 피어에서 제거돼요. 결과적으로 Pod나 Service에 대한 연결이 일시적으로 끊길 수 있습니다.

완화

이 문제를 해결하는 권장 방법은 Graceful Restart 기능을 활성화하는 것입니다. 이 기능을 사용하면 BGP 피어가 BGP 세션이 끊긴 후 특정 시간 동안 경로를 유지할 수 있어요. 에이전트가 내려가도 데이터패스는 활성 상태이므로 Pod나 Service에 대한 연결 손실을 방지할 수 있습니다.

BGP Graceful Restart를 사용할 수 없을 때는 사용하는 경로의 종류에 따라 다음 조치를 취할 수 있어요:

PodCIDR 경로

PodCIDR 경로를 광고하고 있다면 실패한 노드의 Pod는 외부 네트워크에서 도달할 수 없게 됩니다. 실패가 클러스터 노드의 일부에서만 발생한다면, 비정상 노드를 drain하여 Pod를 다른 노드로 옮길 수 있어요.

Service 경로

Service 경로를 광고하고 있다면 로드 밸런서(KubeProxy 또는 Cilium KubeProxyReplacement)가 외부 네트워크에서 도달할 수 없게 될 수 있어요. 또한 진행 중인 연결은 업스트림 라우터의 ECMP 재해싱으로 인해 다른 노드로 리다이렉트될 수 있습니다. 로드 밸런서가 알 수 없는 트래픽을 만나면 새 엔드포인트를 선택할 거예요. 로드 밸런서의 백엔드 선택 알고리즘에 따라 트래픽이 이전과 다른 엔드포인트로 향할 수 있고, 이로 인해 연결이 리셋될 수 있습니다.

업스트림 라우터가 Resilient Hashing과 함께 ECMP를 지원한다면, 이를 활성화하면 진행 중인 연결이 같은 노드로 계속 전달되도록 유지하는 데 도움이 될 수 있어요. Cilium에서 Maglev Consistent Hashing 기능을 활성화하는 것도 도움이 될 수 있는데, 모든 노드가 같은 플로우에 대해 같은 엔드포인트를 선택할 확률을 높여주기 때문이에요. 하지만 이는 externalTrafficPolicy: Cluster 에서만 동작합니다. Service의 externalTrafficPolicy 가 Local 로 설정되면, 실패한 노드의 엔드포인트와의 모든 진행 중인 연결과 이전과 다른 노드로 전달되는 연결은 리셋되는 것이 불가피합니다.

노드 다운

노드가 내려가면 이 노드의 BGP 세션이 끊깁니다. 피어는 Graceful Restart 설정에 따라 노드가 광고한 경로를 즉시 철회하거나 노드로의 트래픽 전달을 멈추는 데 시간이 걸립니다. 후자의 경우는 externalTrafficPolicy=Cluster Service에 경로를 광고할 때 문제가 됩니다. 피어가 재시작 타이머(기본 120초)가 만료될 때까지 사용할 수 없는 노드로 트래픽을 계속 전달하기 때문이에요.

완화

비자발적 종료

노드가 비자발적으로 종료되면 직접적인 완화 방법이 없습니다. Cilium Pod 재시작 시 graceful restart가 제공하는 안정성과 실패 감지 시간 사이의 트레이드오프에 따라 BGP Graceful Restart 기능을 사용하지 않기로 선택할 수 있어요.

Graceful Restart를 비활성화하면 BGP 피어가 더 빠르게 경로를 철회할 수 있습니다. 노드가 BGP Notification이나 TCP 연결 종료 없이 종료되더라도 피어가 경로를 철회하는 최악의 경우 시간은 BGP hold time입니다. Graceful Restart가 활성화되면 BGP 피어는 노드에서 받은 경로를 철회하는 데 hold time + restart time이 필요할 수 있어요.

자발적 종료

노드를 자발적으로 종료할 때는 노드 종료 섹션에 설명된 단계를 따라 패킷 손실을 최대한 피할 수 있어요.

피어링 링크 다운

BGP 피어 사이의 피어링 링크가 끊어지면 보통 BGP 세션과 데이터패스 연결이 모두 끊깁니다. 그러나 BGP 세션은 유지되고 경로가 여전히 광고되는 동안 데이터패스 연결만 끊기는 기간이 있을 수 있어요. 이로 인해 BGP 피어가 실패한 링크로 트래픽을 보내 패킷이 드롭될 수 있습니다. 이 기간의 길이는 어떤 링크가 끊겼는지와 BGP 구성에 따라 달라져요.

노드에 직접 연결된 링크가 끊기면 Linux 커널이 링크 실패를 감지하고 TCP 세션을 즉시 종료하므로 BGP 세션이 즉시 끊길 가능성이 높아요. 노드에 직접 연결되지 않은 링크가 끊기면 기본값이 90초인 hold 타이머가 만료된 후 BGP 세션이 끊깁니다.

완화

링크 감지 실패를 빠르게 만들려면 BGP 구성에서 holdTimeSeconds 와 keepAliveTimeSeconds 를 더 짧은 값으로 조정할 수 있어요. 그러나 가능한 최소값은 holdTimeSeconds=3 과 keepAliveTimeSeconds=1 입니다. 실패 감지를 더 빠르게 하는 일반적인 접근 방식은 BFD(Bidirectional Forwarding Detection)를 사용하는 것이지만, 현재 Cilium은 이를 지원하지 않아요.

Cilium operator 다운

Cilium operator는 CiliumBGPClusterConfig 를 노드별 CiliumBGPNodeConfig 리소스로 변환하는 역할을 담당합니다. Cilium operator가 내려가면 BGP 컨트롤 플레인의 프로비저닝이 중지됩니다.

마찬가지로 IPAM의 PodCIDR 할당과 LB-IPAM의 LoadBalancer IP 할당도 중지됩니다. 따라서 새 PodCIDR 및 Service VIP 경로의 광고와 이전 경로의 철회도 중지돼요.

완화

BGP 측면에서는 직접적인 완화 방법이 없습니다. 그러나 Cilium Operator를 고가용성 설정으로 실행하면 Cilium Operator가 실패에 더 탄력적으로 대응할 수 있습니다.

Service가 모든 백엔드를 잃음

장애나 구성 실수로 모든 Service 백엔드가 사라지면 BGP 컨트롤 플레인은 Service의 externalTrafficPolicy 와 --enable-no-service-endpoints-routable 플래그에 따라 다르게 동작합니다.

externalTrafficPolicy 가 Cluster 로 설정되면, --enable-no-service-endpoints-routable 이 true(기본값)일 때만 CiliumBGPClusterConfig 가 선택한 모든 노드에서 Service의 VIP가 광고된 상태로 유지됩니다. 플래그가 false 로 설정되면 Service의 VIP가 철회됩니다.

externalTrafficPolicy 가 Local 로 설정되면 광고가 완전히 중지합니다. Service의 VIP는 --enable-no-service-endpoints-routable 값과 무관하게 Service 백엔드가 실행 중인 노드에서만 광고되기 때문이에요.

완화

BGP 측면에서는 직접적인 완화 방법이 없습니다. 일반적으로 PodDisruptionBudget 같은 Kubernetes 기능으로 Service 백엔드가 모두 사라지는 것을 방지해야 합니다.

더 알아보기 (Learn more)