Orphaned VMs: Running VMs Uninterrupted While Host Kernel Is Offline For Reboots/Updates
고아 VM — 호스트 커널이 재부팅·업데이트 중에도 VM을 계속 실행하기
Google이 주도한 Linux RFC 패치는 호스트 커널이 재부팅이나 업데이트로 내려간 동안에도 VM을 실행하는 ‘Orphaned VM’을 제안합니다. 물리 CPU와 vCPU 상태를 보존하고 Caretaker가 일부 VM exit를 처리하는 구조이며, Intel·AMD·Arm에서 시험했지만 아직 초기 개발 단계입니다.
- 주제
AI 요약
Google이 주도하고 Pasha Tatashin이 이끄는 Linux RFC 패치 시리즈가 호스트 커널의 재부팅과 업데이트 사이에도 가상 머신(VM)을 멈추지 않는 ‘Orphaned VM’을 제안합니다. Live Update Orchestrator(LUO)를 이용해 호스트 Linux 커널이 잠시 오프라인이 되는 동안에도 게스트 실행을 유지하는 방식입니다. 패치 시리즈는 현재 46개 패치로 구성되어 있으며 Intel, AMD, Arm 서버 프로세서에서 시험했습니다. 다만 개발팀은 아직 “very early” 단계의 작업으로 설명하고 있고, 운영 환경에 사용할 수준은 아니라고 밝혔습니다.
호스트 커널이 내려간 동안 VM 실행 유지
일반적인 VM은 게스트 운영체제가 실행되더라도 KVM, QEMU, 호스트 커널 같은 관리 계층에 의존합니다. 호스트 커널을 재부팅하거나 새 커널로 교체하면 VM 실행도 함께 중단됩니다. Orphaned VM은 이 관리 공백을 전제로 설계합니다. 게스트 명령어를 실행하는 물리 CPU와 메모리에 보존한 vCPU 상태를 유지하고, 호스트 커널이 내려간 동안에도 지정된 CPU에서 게스트를 계속 실행합니다.
구현에는 여러 계층이 필요합니다. RAM에 있는 vCPU 상태를 재부팅 이후까지 보존하고, VM이 사용하던 물리 CPU를 호스트의 부팅 과정에서 재설정되지 않도록 보호해야 합니다. CPU 코어 안에서 실행 흐름을 조정하는 on-core scheduling framework와 KVM Caretaker Core 인프라도 추가합니다. RFC가 제시한 구조에서는 호스트 커널과 VMM이 잠시 사라진 동안에도 VM에 필요한 일부 처리를 별도로 남겨 둡니다.
Caretaker가 처리하는 VM exit
제안의 중심에는 ‘Caretaker’라는 특수한 bare-metal primitive interpose layer가 있습니다. Caretaker는 하이퍼바이저의 권한 있는 하드웨어 상태에서 동작하며, 호스트 커널이 오프라인인 동안 일부 VM exit를 가로채 현장에서 처리합니다. 게스트가 계속 실행되려면 모든 명령어를 호스트 커널에 다시 넘길 수 없기 때문에, 관리 계층으로 빠져나오는 상황 중 일부를 Caretaker가 맡는 구조입니다.
RFC 설명은 재부팅 구간에서 vcpufd 구조를 보존하는 방법, 부팅 중 리셋 신호로부터 물리 CPU를 보호하는 방법, 시간 기록의 오차와 예기치 않은 인터럽트, 게스트 간 IPI 라우팅을 다룹니다. 호스트가 내려간 시간 동안 게스트 시계가 얼마나 어긋나는지 관리해야 하고, 새 커널이 부팅되면서 발생하는 인터럽트가 고립된 VM의 CPU를 방해하지 않도록 해야 합니다. 여러 게스트가 서로 IPI를 주고받는 상황도 관리 대상입니다.
실행 조건과 현재 단계
커뮤니티 토론에서는 게스트 명령어 대부분이 할당된 CPU에서 네이티브로 실행되고, VM exit가 발생할 때만 하이퍼바이저의 개입이 필요하다는 점을 중심으로 설명합니다. 게스트가 하이퍼콜로 호스트에 자원을 요청하거나, I/O 같은 하드웨어 동작을 수행하려고 트랩을 일으키면 VM exit가 발생합니다. 일반적인 환경에서는 KVM과 호스트 서비스가 해당 요청을 처리하지만, Orphaned VM에서는 Caretaker가 처리할 수 있는 요청만 남겨야 합니다.
토론에서는 CPU affinity와 격리, 커널의 CPU hotplug, kexec 같은 기존 Linux 기능을 조합하면 이 구조의 기반을 마련할 수 있다는 설명도 나옵니다. 특정 CPU에 VM을 고정하고 다른 작업을 배제한 뒤, kexec로 새 커널을 올리는 동안 해당 CPU와 VM 상태를 보존하는 방식입니다. 다만 댓글 작성자도 실제 코드와 백서를 확인하지 않은 설명이라고 밝혔고, RFC 자체도 아직 신뢰성과 세부 동작을 검증하는 단계입니다.
이 작업은 다음 달 Prague에서 열리는 Linux Plumbers Conference에서 더 논의될 예정입니다.
Reddit 반응
- @u/Single-Virus4935 — 와, NSAH(Nonstop Active Hypervisor)네요.
- @u/TheG0AT0fAllTime — 정말 멋지네요.
- @u/purpleidea — 기술을 아는 분이 더 설명해 주시면 좋겠습니다. 이거 순수 소프트웨어이고 하드웨어 변경은 필요 없는 건가요? 멋지네요! 그러면 GitHub의
mgmt에서 VM 관리가 다음 단계로 올라가겠네요.- @u/Culpirit — 제가 이해한 내용이 맞다면, VM과 하이퍼바이저 사이에 ‘Caretaker’라는 추상화 계층을 두고 호스트 커널과 하이퍼바이저가 재부팅하는 동안에도 Caretaker가 계속 실행되는 구조입니다. 하드웨어 가속 VM이 계속 실행되기 위해 하드웨어에 하이퍼바이저가 반드시 필요한 것은 아닙니다. VM에 할당된 코어에서 게스트 명령어가 네이티브로 실행되고, VM이 고립된 CPU 코어에서 실행된다면 호스트 스케줄러는 그 VM의 작업을 계속 실행하게 둘 수 있습니다. 같은 소켓에서 독립적인 운영체제 두 개가 실행되는 모습과 비슷하며, VM exit가 발생하지 않는 동안은 그렇습니다.
VM exit는 여러 이유로 발생합니다. 반가상화 환경에서는 게스트가 ‘하이퍼콜’을 호출하는 경우가 흔합니다. 프로세스를 게스트 OS로, 커널을 호스트나 하이퍼바이저로 바꾸어 생각하면 시스템 콜과 비슷합니다. 게스트가 호스트에 자원을 요청하면 실행을 양보하고, 하이퍼바이저가 게스트 OS를 대신해 메모리 페이지를 해결하는 같은 작업을 수행한 뒤 VM으로 제어를 돌려줍니다. CPU가 fault를 일으켜 하이퍼바이저에 제어를 넘기는 트랩도 VM exit를 발생시킬 수 있습니다. I/O 같은 하드웨어 동작을 에뮬레이션할 때 이런 방식이 사용됩니다.
이 설계에서는 Linux가 내려가는 동안에도 Caretaker가 자신의 코어에서 계속 동작하고, QEMU와 KVM을 사용할 수 없을 때도 VM과 통신합니다.
↳ @u/purpleidea — 제가 이해한 내용이 맞다면, VM과 하이퍼바이저 사이에 ‘Caretaker’라는 추상화 계층을 두고 호스트 커널과 하이퍼바이저가 재부팅하는 동안에도 Caretaker가 계속 실행되는 구조입니다. 하드웨어 가속 VM이 계속 실행되기 위해 하드웨어에 하이퍼바이저가 반드시 필요한 것은 아닙니다. VM에 할당된 코어에서 게스트 명령어가 네이티브로 실행되고, VM이 고립된 CPU 코어에서 실행된다면 호스트 스케줄러는 그 VM의 작업을 계속 실행하게 둘 수 있습니다. 같은 소켓에서 독립적인 운영체제 두 개가 실행되는 모습과 비슷하며, VM exit가 발생하지 않는 동안은 그렇습니다.
VM exit는 여러 이유로 발생합니다. 반가상화 환경에서는 게스트가 ‘하이퍼콜’을 호출하는 경우가 흔합니다. 프로세스를 게스트 OS로, 커널을 호스트나 하이퍼바이저로 바꾸어 생각하면 시스템 콜과 비슷합니다. 게스트가 호스트에 자원을 요청하면 실행을 양보하고, 하이퍼바이저가 게스트 OS를 대신해 메모리 페이지를 해결하는 같은 작업을 수행한 뒤 VM으로 제어를 돌려줍니다. CPU가 fault를 일으켜 하이퍼바이저에 제어를 넘기는 트랩도 VM exit를 발생시킬 수 있습니다. I/O 같은 하드웨어 동작을 에뮬레이션할 때 이런 방식이 사용됩니다.
이 설계에서는 Linux가 내려가는 동안에도 Caretaker가 자신의 코어에서 계속 동작하고, QEMU와 KVM을 사용할 수 없을 때도 VM과 통신합니다. Linux 자체가 여러 프로세스와 코어를 계속 실행하는 동안 재부팅할 수 있다는 건가요? 어떻게 동작하는지 더 듣고 싶습니다.
↳ @u/Culpirit — 코드를 살펴보거나 백서를 읽지는 않았으니 감안해서 봐 주세요. 일반적인 운영체제에 대한 오해 때문에 이 방식이 유난히 터무니없고 이상하게 들리는 것 같습니다. Linux는 다른 운영체제와 마찬가지로 CPU 시간을 프로세스와 나눠 씁니다. 프로그램이 작업할 때 커널이 동시에 반드시 무언가를 해야 한다는 의미에서 커널이 프로그램 ‘아래’에서 실행되는 것은 아닙니다. 커널은 더 높은 권한을 가지고 실행을 조정하며, 프로그램을 번갈아 실행하고 권한이 필요한 작업을 대신 처리합니다. 하드웨어나 파일시스템에 접근하거나 다른 프로세스와 통신하는 일이 그 예입니다.
원시적인 계산만 수행하는 프로세스는 커널과 거의 통신하지 않습니다. 단순화해서 말하면 Linux는 한 번에 하나의 프로그램이 CPU를 전부 사용하도록 설정하고, 하드웨어 타이머를 걸어 프로그램이 실행할 시간을 제한한 뒤 작업을 맡깁니다. 프로세스는 커널이 프로그램의 상태를 기록하기 위한 추상화에 가깝습니다. 타이머가 만료되거나 프로그램이 커널 또는 하드웨어에 무언가를 요청하거나 스스로 실행을 양보하면 Linux가 개입합니다. 프로세스의 실행을 멈춘 시점에 상태를 저장하고 스케줄러 코드를 실행합니다. 스케줄러는 ‘Completely Fair’ 방식으로 다음 프로세스를 고릅니다. 이전 프로세스의 상태를 복원하고 다른 프로세스에 CPU를 넘깁니다. 이 과정을 컨텍스트 스위치라고 합니다.
현대 시스템에서는 초당 약 1,000번 일어날 수 있지만, 해당 시간 규모에서는 매우 드문 일입니다. 대부분의 시간 동안 프로그램은 CPU에서 혼자 실행됩니다. 최신 Linux는 멀티코어를 지원하므로 CPU 소켓에 여러 코어가 있으면 모든 코어를 사용합니다. 각 CPU에서 Linux 인스턴스가 실행되고, CPU마다 공유하지 않는 자료구조와 모든 CPU가 주 메모리에서 함께 사용하는 자료구조가 존재합니다. Linux는 CPU와 프로세스를 격리하거나 affinity를 지정하는 API도 제공합니다. 프로세스를 하나의 CPU에서만 실행하고, cgroups로 해당 CPU를 격리해 다른 프로세스가 들어오지 못하게 만들 수 있습니다.
특정 플래그를 사용하면 커널이 CPU에서 거의 물러나도록 만들 수도 있습니다. CPU hotplug를 사용하면 실행 중인 커널이 자신이 사용하던 CPU를 반납하고, 실행 중인 프로세스를 다른 곳으로 옮긴 뒤 해당 CPU에서 실행을 끝낼 수 있습니다. 반대로 새로 추가된 CPU를 재부팅 없이 사용하기 시작할 수도 있습니다. kexec라는 기능으로 실행 중인 커널을 재부팅 없이 새 이미지로 교체하는 일도 가능합니다.
기본적으로 커널은 새 커널을 메모리에 올린 뒤 프로세스로 전환하는 대신 새 커널로 전환합니다. 기존 프로세스와 시스템 상태는 남겨 둡니다. 보통 정상적인 종료 절차를 수행한 뒤 사용하므로 하드웨어에 재부팅을 알리지 않는 재부팅과 비슷합니다. 새 커널은 하드웨어의 도움 없이 안전한 상태에 도달하고, 장치를 초기화하며, 새로 시작할 때처럼 자료구조를 초기화해야 합니다.
VM은 특수한 프로세스와 비슷합니다. VM도 가끔 하이퍼바이저에 실행을 넘겨야 합니다. 여기서는 KVM을 거친 Linux 커널과 그 위에서 실행되는 사용자 공간 서비스가 하이퍼바이저 역할을 합니다. 프로세스와 VM을 CPU에서 혼자 실행하고, 커널이 사용할 CPU를 제한하며, 커널을 소프트 재부팅하는 데 필요한 기본 기능은 이미 존재합니다. 이 기능들을 한데 조합하면 됩니다.
↳ @u/Culpirit — RFC에서 ‘kexec and hotplug reclaim’이라는 표현을 봤습니다. 제가 생각한 방향이 맞았던 것 같습니다. 물론 세부 구현이 문제이고, 작동하게 만드는 일부터 안정적으로 만드는 일까지 쉽지 않을 겁니다. 실제 발표를 들으며 어떻게 시연하는지 확인하고 싶습니다.
↳ @u/braaaaaaainworms — VM을 멈추는 대신 VM이 외부와 통신하려는 순간 멈추게 만들 무언가를 그 자리에 두고, 부팅이 끝나면 그 VM의 관리를 다시 넘겨받는 방식이네요.
- @u/EverythingsBroken82 — 궁금해서 묻는 건데, Xen에서도 이미 가능했던 기능인가요?
- @u/GreenFox1505 — 이건 불법처럼 느껴지네요.
원문: Phoronix / 번역·요약: Trawling