본문으로 바로가기 본문 바로가기
WIKI 기술 지식 베이스

OpenStack VM 라이브 마이그레이션

원문 보기 위키 갱신

OpenStack VM을 라이브 마이그레이션할 때 네트워크 중단을 최소화하는 방법을 다뤄요. Felix가 대상 노드에 높은 우선순위 라우트를 프로그래밍하는 방식을 이해하고, BIRD iBGP/eBGP 설정으로 라우트 우선순위 정보가 노드 사이에 제대로 전파되게 만드는 절차를 안내해요. Nova의 live_migration_wait_for_vif_plug 옵션과 마이그레이션 진행 상황 모니터링까지 함께 다뤄요.

출처: 문서

본문

큰 그림

Calico는 네트워크 중단을 최소화하면서 OpenStack VM 라이브 마이그레이션을 지원해요. 라이브 마이그레이션 중에 Calico의 Felix 에이전트는 대상 노드에 높은 우선순위로 라우트를 프로그래밍해서, 네트워크 트래픽이 가능한 한 빨리 새 노드로 수렴하도록 만들어요. 멀티 노드 배포에서 이것이 최적으로 동작하려면 BGP 구성이 노드 사이에 라우트 우선순위 정보를 전파해야 해요.

개념

라이브 마이그레이션 중 라우트 우선순위

Felix가 대상(목적지) 노드에서 라이브 마이그레이션 중인 VM을 처리할 때는 VM의 라우트를 더 높은 우선순위의 메트릭(값이 낮을수록 우선순위가 높음)으로 프로그래밍해요. 기본값은 다음과 같아요:

  • 일반 우선순위는 메트릭 값 1024
  • 높은 우선순위는 메트릭 값 512

필요하다면 FelixConfiguration 리소스나 /etc/calico/felix.cfg의 다음 설정으로 이 값들을 바꿀 수 있어요:

설정 기본값 설명
IPv4NormalRoutePriority 1024 일반 VM IPv4 라우트의 커널 라우트 메트릭
IPv4ElevatedRoutePriority 512 라이브 마이그레이션 중 VM IPv4 라우트의 커널 라우트 메트릭
IPv6NormalRoutePriority 1024 일반 VM IPv6 라우트의 커널 라우트 메트릭
IPv6ElevatedRoutePriority 512 라이브 마이그레이션 중 VM IPv6 라우트의 커널 라우트 메트릭

기본값에서 바꾼다면 아래 BIRD 구성 예시의 해당 값도 함께 조정하세요.

라이브 마이그레이션 중인 VM의 IP에 대해 소스 노드와 대상 노드가 동시에 라우트를 광고하는 겹침 구간 동안에는, 원격 노드(그리고 중간 라우터)가 대상 노드 쪽 라우트를 선호해야 해요. 높은 우선순위 메트릭이 이 역할을 하지만, BGP 구성이 우선순위 정보를 노드 사이에 올바르게 전파할 때만 그렇게 돼요. 아래 섹션에서 iBGP와 eBGP 두 경우 모두에 대해 BIRD 구성으로 이를 수행하는 예시를 보여줘요.

SECONDARY: 동일한 원칙은 Kubernetes 클러스터의 KubeVirt VM 라이브 마이그레이션에도 적용되며, 이는 KubeVirt 라이브 마이그레이션을 위한 BGP 라우팅에서 별도로 문서화되어 있어요. OpenStack과 KubeVirt의 고려 사항 차이는 다음과 같아요.

  • OpenStack에서는 Calico가 BGP 구성을 생성·유지하지 않으므로 고객이 직접 책임져요. 반면 Kubernetes에서는 Calico가 BGP 구성을 생성·유지해요.

  • KubeVirt 문서에서 언급하는 "라우트 집계" 세부 사항은 OpenStack에는 적용되지 않아요. OpenStack IPAM은 노드 어피니티를 사용하지 않기 때문에 VM 라우트는 항상 개별 /32(IPv4) 또는 /128(IPv6) 라우트로 전파돼요.

BIRD 속성과 필터

Calico for OpenStack에서는 VM 라우트를 노드 사이에 전파하기 위해 어떤 BGP 구현이든 사용할 수 있고, 심지어 다른 라우팅 프로토콜도 가능해요. 그중 BIRD가 널리 쓰이는 선택이라 iBGP와 eBGP 피어로 라우트 우선순위를 전파하는 BIRD 구성 예시를 아래에 제공해요.

krt_metric

BIRD 필터에서 krt_metric 속성을 읽으면 Felix가 로컬 Linux 커널에 프로그래밍한 라우트의 메트릭 값을 볼 수 있고, 값을 설정하면 BIRD가 가져온(import) 라우트를 로컬 커널에 프로그래밍할 때 사용할 메트릭 값을 제어할 수 있어요.

  • krt_metric을 읽는 것은 로컬에 프로그래밍된 라우트, 즉 BIRD가 BGP 피어로 내보낼(export) 라우트를 처리할 때 의미가 있어요. 자연스럽게는 BGP export 필터에서 처리해요.

  • krt_metric을 설정하는 것은 BGP 피어에서 받아 로컬에 프로그래밍할 라우트를 처리할 때 의미가 있어요. 안타깝게도 가장 직관적으로 보이는 BGP import 필터에서는 동작하지 않고, 대신 라우트 출처가 RTS_BGP일 때만 게이트된 커널 export 필터에서 코딩해야 해요.

BGP 프로토콜 속성으로 변환하기

일반적인 접근은 라우트를 내보낼 때 krt_metric을 BGP 와이어 프로토콜 상의 우선순위 표현으로 변환하고, 라우트를 가져올 때 와이어 표현에서 krt_metric으로 역변환하는 거예요.

iBGP 피어라면 와이어 상에서 가장 좋은 옵션은 BGP LOCAL_PREF 속성이에요. bgp_local_pref 속성은 BIRD 필터 코드에서 읽고 설정할 수 있어요. LOCAL_PREF 값이 높을수록 우선순위가 높다는 의미로 정의되어 있는데, Linux의 우선순위/메트릭 값과는 반대예요. 그래서 krt_metric과 bgp_local_pref 사이에 다음과 같은 변환이 필요해요:

bgp_local_pref = 2^31-1 - krt_metric
krt_metric     = 2^31-1 - bgp_local_pref

Calico는 메트릭 값을 1..2^31-2 범위로 제한하기 때문에 bgp_local_pref 값도 그 범위 안에 있어요.

eBGP 피어라면 와이어 상에서 좋은 옵션은 다음 두 가지예요:

  1. BGP 커뮤니티 값으로 "높은 우선순위"를 표시하기
  2. BGP AS path에 추가해 높은 우선순위가 아닌 모든 라우트의 우선순위를 낮추기

(1)이 선호돼요. 라이브 마이그레이션 중 사용되는 특정 높은 우선순위 라우트에만 BGP 수정이 필요한 반면, (2)는 정상 동작 중인 라우트에도 BGP 수정이 필요하기 때문이에요.

방법

라우트 우선순위 전파를 위한 BIRD 구성 (iBGP)

하나의 AS 안에서 라우트를 전파할 때는 라우트 우선순위를 BGP LOCAL_PREF 속성으로 표현하는 게 가장 좋아요.

BIRD 구성(/etc/bird/bird.conf)에 다음과 같은 필터 코드를 추가해요:

filter export_bgp {
  ...
  if (!defined(krt_metric)) then { krt_metric = 1024; }
  bgp_local_pref = 2147483647 - krt_metric;
  ...
}

filter import_bgp {
  ...
  if (defined(bgp_local_pref)&&(bgp_local_pref > 2147482623)) then
    preference = 200;
  ...
}

filter export_kernel {
  ...
  if (defined(source) && (source = RTS_BGP) && !defined(krt_metric)) then {
    krt_metric = 1024;
    if (defined(bgp_local_pref)) then {
      krt_metric = 2147483647 - bgp_local_pref;
    }
    if (krt_metric < 1024) then {
      preference = 200;
    }
  }
  ...
}

이 코드는 다음과 같이 동작해요:

  • export_bgp: BGP 피어로 라우트를 내보낼 때 커널 라우트 메트릭(krt_metric)을 bgp_local_pref로 변환해요. 메트릭이 없는 라우트는 1024(일반 우선순위)를 기본값으로 사용해요.

  • import_bgp: BGP 피어에서 라우트를 가져올 때 그 라우트가 높은 우선순위인지(bgp_local_pref > 2147482623, 즉 krt_metric < 1024에 해당) 확인해요. 그렇다면 BIRD의 preference를 200으로 설정해서 같은 목적지의 로컬 라우트보다 이 원격 라우트를 선호하게 만들어요. VM이 그 VM에 대한 활성 연결을 가진 노드에서 다른 곳으로 마이그레이션할 때 중요해요.

  • export_kernel: BGP로 학습한 라우트를 Linux 커널에 프로그래밍할 때 bgp_local_pref를 다시 krt_metric으로 변환해요. 높은 우선순위 라우트에 대해서는 import_bgp와 같은 이유로 preference = 200도 설정해요. 이 변환을 import_bgp가 아니라 여기서 하는 이유는 BGP import 필터에서 krt_metric을 설정해도 효과가 없기 때문이에요.

커널 프로토콜 블록이 export_kernel 필터를 사용하도록 업데이트하세요(아직 없다면):

protocol kernel {
  ...
  export filter export_kernel;
  ...
}

각 iBGP 피어 정의에 export_bgp와 import_bgp 필터를 사용해요:

protocol bgp 'peer1' {
  ...
  import filter import_bgp;
  export filter export_bgp;
  ...
}

IPv6라면 bird6.conf에서 같은 변경을 하세요.

라우트 우선순위 전파를 위한 BIRD 구성 (eBGP)

eBGP 피어로 라우트를 전파할 때는 라우트 우선순위를 BGP 커뮤니티 값으로 표현하는 게 가장 좋아요. BGP 커뮤니티 값은 표준화된 의미가 없어서, 값의 선택과 해석은 네트워크 내부의 문제예요. 이 예시에서는 더 높은 우선순위 라우트를 나타내는 값으로 (65000, 100)을 선택해요.

  • 그 커뮤니티 값이 있는 라우트는 더 높은 우선순위로 간주되고 krt_metric 512에 매핑돼요.

  • 그 커뮤니티 값이 없는 라우트는 일반 우선순위로 간주되고 krt_metric 1024에 매핑돼요.

BIRD 구성(/etc/bird/bird.conf)에 다음과 같은 필터 코드를 추가해요:

filter export_bgp {
  ...
  if (!defined(krt_metric)) then { krt_metric = 1024; }
  if (krt_metric < 1024) then {
    bgp_community.add((65000, 100));
  }
  ...
}

filter import_bgp {
  ...
  if (((65000, 100) ~ bgp_community)) then
    preference = 200;
  ...
}

filter export_kernel {
  ...
  if (defined(source) && (source = RTS_BGP) && !defined(krt_metric)) then {
    krt_metric = 1024;
    if (((65000, 100) ~ bgp_community)) then {
      krt_metric = 512;
    }
    if (krt_metric < 1024) then {
      preference = 200;
    }
  }
  ...
}

이 필터들은 다음과 같이 동작해요:

  • export_bgp: 더 높은 우선순위 라우트에 커뮤니티를 붙여요. 높은 우선순위 라우트(메트릭 < 1024)는 커뮤니티 (65000, 100)을 받아요.

  • import_bgp: 들어오는 라우트에서 높은 우선순위 커뮤니티를 확인하고, 있으면 BIRD의 preference를 200으로 설정해요.

  • export_kernel: BGP로 학습한 라우트를 Linux 커널에 프로그래밍할 때 커뮤니티를 읽어 올바른 krt_metric을 결정해요. 높은 우선순위 커뮤니티가 있는 라우트는 메트릭 512를 받고, 나머지는 모두 1024를 기본값으로 사용해요.

커널 프로토콜 블록이 export_kernel 필터를 사용하도록 업데이트하세요(아직 없다면):

protocol kernel {
  ...
  export filter export_kernel;
  ...
}

각 eBGP 피어 정의에 export_bgp와 import_bgp 필터를 사용해요:

protocol bgp 'peer1' {
  ...
  import filter import_bgp;
  export filter export_bgp;
  ...
}

IPv6라면 bird6.conf에서 같은 변경을 하세요.

Nova 옵션 live_migration_wait_for_vif_plug = True 구성

Nova 옵션 live_migration_wait_for_vif_plug는 "라이브 마이그레이션의 컴퓨트 쪽, 즉 VM 상태를 소스 노드에서 대상 노드로 복사하는 작업을, Neutron과 네트워크 드라이버가 대상 노드에서 VM을 위한 네트워킹이 준비됐다고 알릴 때까지 미룬다"는 의미예요. 이 옵션은 True로 설정하기를 권장해요. True가 기본값이기 때문에 명시적으로 설정할 필요는 없어요. 다만 예전 Calico 버전 중에는 이 설정이 False여야 하는 경우가 있었으니, 예전 버전에서 업그레이드했다면 nova.conf를 검토해서 예전 False 설정을 지우거나 True로 바꾸는 걸 고려하세요.

Calico 네트워크 드라이버는 대상 노드에서 VM을 위한 인터페이스 구성, ipset, iptables가 모두 갖춰지면 준비됐음을 알려줘요. 복잡한 네트워크 정책을 가진 클러스터에서는 ipset과 iptables 프로그래밍이 눈에 띄는 시간이 걸릴 수 있고, 가끔 수십 초까지 걸리기도 해요. live_migration_wait_for_vif_plug = True이면 라이브 마이그레이션 타임라인이 다음과 같이 진행돼요:

  1. VM에 라이브 마이그레이션이 요청돼요.

  2. Calico가 대상 노드에서 네트워킹을 준비해요. VM은 여전히 소스 노드에서 살아 있고 트래픽은 소스 노드로 오가고 있어요.

  3. Calico와 Neutron이 네트워킹이 준비됐음을 알려줘요. Nova가 라이브 마이그레이션의 컴퓨트 쪽을 시작해요.

  4. 컴퓨트 전송이 완료되고 VM이 대상 노드에서 살아있게 돼요. Calico가 라우팅을 갱신해서 트래픽이 이제 대상 노드로 오가요.

반면 live_migration_wait_for_vif_plug = False이면 (2)와 (3)이 병렬로 실행되고, 컴퓨트 쪽(3)이 네트워킹 쪽(2)보다 먼저 끝나는 일이 가능해요. 그러면 VM은 대상 노드에서 살아 있는데 그 노드에서 VM으로 오가는 트래픽이 아직 올바르게 흐르지 못하는 상황이 생길 수 있어요. 그래서 True 설정을 권장해요.

라이브 마이그레이션 진행 상황 모니터링

Calico는 라이브 마이그레이션 작업의 상세 진행 상황과 시간을 추적하는 데 쓸 수 있는 INFO 수준 로그 메시지를 내보내요. 이 메시지들은 다음 컴포넌트에서 나타나요.

이 로그들 모두에서 <id>는 개별 라이브 마이그레이션 작업을 고유하게 식별하며, Neutron 드라이버 로그와 소스·대상 노드의 Felix 로그를 서로 연결하는 데 사용할 수 있어요.

Neutron 드라이버

Calico Neutron 드라이버(networking_calico)는 다음 이벤트를 로그로 남겨요:

로그 메시지 의미
Live migration <id>: pre-migrate port <port> from <source> to <target> Nova가 라이브 마이그레이션을 시작했어요. Calico가 대상 노드에서 네트워킹을 준비하고 있어요.
Live migration <id>: destination port <port> active on <target>, notifying Nova 대상 노드에서 네트워킹이 준비됐어요. Calico가 진행하라고 Nova에 신호를 보내고 있어요.
Live migration <id>: succeeded, port <port> migrated from <source> to <target> 마이그레이션이 완료됐어요. 소스 노드의 네트워킹이 정리됐어요.

예시:

2026-03-27 13:31:11.386 INFO networking_calico [...] Live migration b7ce174c-...: pre-migrate port 480eb297-... from compute2 to compute3
2026-03-27 13:31:13.600 INFO networking_calico [...] Live migration b7ce174c-...: destination port 480eb297-... active on compute3, notifying Nova
2026-03-27 13:31:15.229 INFO networking_calico [...] Live migration b7ce174c-...: succeeded, port 480eb297-... migrated from compute2 to compute3

소스 노드의 Felix

Felix는 마이그레이션을 감지하고 해당 엔드포인트에 SOURCE 역할을 맡을 때 로그를 남겨요:

LiveMigrationCalculator: LiveMigration created/updated ... source=...compute2... target=...compute3... uid=<id>
LiveMigrationCalculator: emitting role for WEP role=SOURCE uid=<id> ...

대상 노드의 Felix

Felix는 마찬가지로 마이그레이션을 감지하고 해당 엔드포인트에 TARGET 역할을 맡을 때 로그를 남겨요:

LiveMigrationCalculator: LiveMigration created/updated ... source=...compute2... target=...compute3... uid=<id>
LiveMigrationCalculator: emitting role for WEP role=TARGET uid=<id> ...

추가로 Felix는 대상 노드에서 상세 라이브 마이그레이션 처리에 관여하는 상태 머신 전이를 로그로 남겨요:

전이 의미
Base → Target Felix가 대상 노드에서 VM을 위한 네트워킹 설정을 시작해요.
Target → Live Felix가 VM의 GARP(Gratuitous ARP)를 감지해서 대상 노드에서 VM이 살아 있음을 확인하고, 이 노드에서 VM으로의 높은 우선순위 라우트 광고를 시작해요.
Live → TimeWait OpenStack이 마이그레이션이 완료됐음을 알렸어요. 인접 네트워크가 소스 노드에서 VM이 삭제되는 걸 인지할 시간을 주기 위해 높은 우선순위 라우트 광고가 계속돼요.
TimeWait → Base 충분한 시간이 지났어요. VM의 라우트 광고가 일반 우선순위로 되돌아가요.

예를 들면:

13:31:11.393 [INFO] felix/live_migration.go: Live migration state transition from=Base ... input=Target migrationUid=<id> to=Target
13:31:14.042 [INFO] felix/live_migration.go: Live migration state transition from=Target ... input=GARPDetected migrationUid=<id> to=Live
13:31:15.229 [INFO] felix/live_migration.go: Live migration state transition from=Live ... input=NoRole migrationUid=<id> to=TimeWait
13:31:24.607 [INFO] felix/live_migration.go: Live migration state transition from=TimeWait ... input=Deleted migrationUid=<id> to=Base

이 전이들의 타임스탬프로 각 단계가 얼마나 걸리는지 측정할 수 있어요. 예를 들어 Target과 Live 전이 사이의 시간(위 예시에서 약 2.6초)은 네트워킹이 준비된 뒤 VM이 대상 노드에서 실행을 시작하기까지 걸린 시간을 나타내요.

더 알아보기 (Learn more)

핵심은 라이브 마이그레이션 중 대상 노드의 라우트가 메트릭 512로 프로그래밍되어 트래픽이 새 노드로 빠르게 수렴한다는 점이에요. iBGP에서는 LOCAL_PREF 변환, eBGP에서는 커뮤니티 (65000, 100)으로 우선순위를 전파하는 BIRD 필터 예시를 그대로 가져다 쓸 수 있어요. KubeVirt VM의 경우 BGP 구성을 Calico가 관리하니 별도 문서를 참고하세요.