지식

[OpenStack] disabled 컴퓨트 노드에 VM을 강제로 띄우는 시대는 끝났다 — force_hosts 필터 우회의 소멸

OpenStack 클러스터를 운영하다 보면 특정 컴퓨트 노드들을 스케줄러에서 빼두고 싶을 때가 있다. 우리는 GPU 장착 노드들을 준비 작업(드라이버 전환·디스크 재구성) 동안 리부트가 잦을 것으로 보고, 일반 VM이 그 노드들에 배치되지 않도록 nova-compute 서비스를 전부 disable 상태로 상주시키는 정책을 운영하고 있었다.

문제는 그 다음이었다. 기반 작업이 끝나 "이 노드에서 GPU VM이 정말 뜨는가"를 실증해야 하는데, 노드는 disabled다. 괜찮다고 생각했다 — admin이니까 노드를 지정해서 강제로 띄우면 되겠지. 안 됐다. 이 글은 그 실측 기록이다: 최신 nova에서는 disabled 노드에 VM을 착지시키는 강제 지정 경로가 전부 막혀 있다.

증상 — 세 가지 강제 지정, 세 번의 NoValidHost

소모성 VM으로 세 경로를 차례로 시도했다. 첫째, microversion 2.74의 --host 지정:

openstack --os-compute-api-version 2.74 server create \
  --flavor tiny --image <image-id> --nic none \
  --host compute-gpu-1 --wait probe-vm
# → ERROR

둘째와 셋째, 가용영역 강제 문법 두 변형 — host 강제와 node 강제:

openstack server create ... --availability-zone nova:compute-gpu-1  probe-vm   # host 강제
openstack server create ... --availability-zone nova::compute-gpu-1 probe-vm  # node 강제

세 번 모두 결과가 똑같았다. fault를 열어 보면:

{'code': 500, 'message': 'No valid host was found. ',
 'details': '... File ".../nova/scheduler/manager.py", line 278, in select_destinations
    raise exception.NoValidHost(reason="")
 nova.exception.NoValidHost: No valid host was found.'}

주목할 부분은 예외가 터진 위치다 — scheduler/manager.pyselect_destinations. 강제 지정을 했는데도 요청이 스케줄러의 필터 파이프라인을 통과하고 있었다.

원인 — 강제 지정은 더 이상 필터를 우회하지 않는다

nova 스케줄러의 ComputeFilter는 "서비스가 살아 있고(enabled·up) 운영 가능한 호스트"만 통과시킨다. disabled 서비스는 여기서 무조건 탈락한다. 그러니 질문은 하나로 좁혀진다: 강제 지정이 필터를 우회하느냐.

  • --host(2.74)는 원래부터 우회가 아니다. 이 방식은 요청에 "희망 목적지(requested destination)"를 실어 보내고, 스케줄러는 후보를 그 호스트 하나로 좁힌 뒤 필터를 그대로 적용한다. disabled면 후보 1개가 0개가 되고, NoValidHost다.
  • 진짜 반전은 AZ 강제(zone:host·zone::node) 쪽이다. 구세대 nova에서 이 문법은 force_hosts/force_nodes라는 내부 플래그로 번역되어 필터를 건너뛰는 뒷문이었다. 오래된 운영 블로그·사내 위키들이 "disabled 노드엔 AZ 강제로 띄우면 된다"고 적어둔 근거가 이것이다. 그런데 우리가 운영하는 버전(2026.1)에서 실측한 결과, 이 경로도 동일하게 select_destinations에서 기각됐다 — AZ 강제 역시 요청 목적지로 취급되어 필터를 탄다.

정리하면 이렇다:

경로 구세대 동작 현행 실측 (2026.1)
2.74 --host 필터 적용 필터 적용 → disabled 기각
--availability-zone zone:host 필터 우회 (force_hosts) 필터 적용 → disabled 기각
--availability-zone zone::node 필터 우회 (force_nodes) 필터 적용 → disabled 기각

우리를 헷갈리게 한 함정이 하나 더 있었다. 몇 주 전 같은 클러스터에서 --host 지정 배치를 성공시킨 선례가 있었던 것이다. 다시 확인해 보니 그때는 대상 노드가 enabled 상태였다 — 성공의 원인은 강제 지정이 아니라 노드 상태였는데, 우리는 "강제 지정이 통했다"로 기억하고 있었다. 검증 절차의 전제는 실측으로 다시 깔아야 한다는 걸 재확인했다.

해법 — 우회로가 없으면 정공법: enable 창

이 버전에서 disabled 노드에 새 VM을 앉히는 API 경로는 존재하지 않는다(콜드/라이브 마이그레이션의 강제 플래그도 최신 microversion에서는 제거됐다). 남는 정공법은 하나 — 짧은 enable 창을 열고 닫는 표준 절차를 만드는 것이다. 핵심은 disable에 실려 있던 사유 문자열을 잃지 않는 것이다:

# 1) 현재 disable reason 원문을 캡처해 둔다
openstack compute service list --long -f json \
  | jq -r '.[] | select(.Host=="compute-gpu-1") | ."Disabled Reason"'

# 2) enable → 실증 VM 착지·검증 → 삭제
openstack compute service set --enable compute-gpu-1 nova-compute
openstack --os-compute-api-version 2.74 server create --host compute-gpu-1 ... probe-vm
# ... 검증 ...
openstack server delete probe-vm --wait

# 3) 즉시 disable 복원 — 캡처했던 사유 원문 그대로
openstack compute service set --disable \
  --disable-reason "<캡처한 원문>" compute-gpu-1 nova-compute

창은 노드당 몇 분이면 충분하고, 스크립트라면 trap으로 어떤 실패 경로에서도 disable 복원이 실행되게 걸어두는 편이 안전하다. 우리는 이 절차를 운영 결정 문서에 표준으로 박아, "실증 목적의 enable 창"과 "그 외 enable 금지"를 명시적으로 분리했다.

교훈

  1. "force"라는 단어를 믿지 말고 예외가 터진 위치를 봐라. fault 트레이스에 select_destinations가 보이면, 그 요청은 필터를 탔다는 뜻이다 — 어떤 강제 옵션을 줬든.
  2. 구세대 우회 지식은 만료된다. force_hosts 시절의 답변·블로그가 검색 상위에 여전히 많다. 버전이 다르면 실측이 유일한 근거다.
  3. 성공 선례는 조건까지 함께 기억해야 한다. "그때 됐는데"의 그때는 노드가 enabled였다.
  4. 정책(disable 상주)과 검증(실증 VM)이 충돌하면, 우회를 찾기보다 예외 절차를 표준화하는 쪽이 결국 싸다 — 사유 캡처·복원까지 포함해서.
조회 1댓글 0

댓글

아직 댓글이 없습니다. 첫 댓글을 남겨보세요.