Skip to content

KVM(Kernel-based Virtual Machine)

KVM은 리눅스 커널 모듈의 일종으로 리눅스 커널 자체를 일종의 하이퍼바이저 역할을 하게 해주는 기술이다.

라고만 들으면 리눅스 커널이 또 엄청난 일들을 하는 것 처럼 느껴지는 데, 그런 것은 아니고

하드웨어에서 가상화 지원을 하지 않으면 사용하지 못하는 기능이다.

가상화란 뭔가

가상화를 한 줄로 정의하자면

게스트한테 자기만의 하드웨어가 있다는 환상을 주면서(추상화), 실제론 호스트가 모든 것을 통제하는 것(격리)

두 가지가 핵심이다.

  • 격리: 게스트가 호스트 / 다른 게스트를 침범하지 못하게 함
  • 추상화: 게스트가 실제 하드웨어 구조를 몰라도 동작하게 만드는 것

내가 진짜 커널이야

게스트 OS의 커널도 소프트웨어이고 프로세스다 근데 CPU는 "이게 게스트 코드야, 호스트 코드야" 를 모름, 그냥 명령어네 실행해야겠다

CPU에는 보호 링 (Prorection Ring) 이라는 권한 레벨이 있다.

bash
 0  커널 (최고 권한, 특권 명령 실행 가능)
 3  유저 애플리케이션

이건 개념적인 게 아니고 CPU 하드웨어에 물리적으로 구현된 부분이다.
CPU가 명령을 실행할 때마다 현재 링을 확인하고 특권 명령을 낮은 링(권한이 낮은=유저 어플리케이션)에서 실행하려하면 트랩(예외)를 발생시킨다.

문제는 게스트 커널을 링 0에서 돌리면 어떻게 되냐

bash
게스트 커널: "나 진짜 커널이야, 특권 명령 써도 돼"

CPU: "링 0이네, 그냥 실행"

호스트 제어권 상실
게스트가 물리 하드웨어 직접 접근 가능
다른 VM 메모리도 들여다볼 있음

커널 위에 커널이 올라가면, 게스트 커널이 자기가 진짜 커널인 줄 알고 특권 명령을 막 날리기 때문에 제어가 안 된다. 이게 가상화의 근본적인 문제다.

세대별 가상화 기법

1세대 소프트웨어 애뮬레이션

가장 단순한 해결책으로 게스트 코드를 CPU에서 직접 실행하지 않는다.

text
소프트웨어가 게스트 명령어를 한 줄씩 읽고 해석해서 실행
for instruction in guest_code:
    if instruction == 일반명령:
        호스트_CPU에서_실행()
    elif instruction == 특권명령:
        소프트웨어_직접_처리()  # CPU에 안 넘기고 가로챔

CPU에 직접 안 넘기고 소프트웨어가 중간에서 다 걸러서 실행하는 방식이다.
안전하지만 명령어 하나 실행할 때마다 해석 과정이 필요하니까 느리다. 네이티브의 5~30% 수준.

2세대: 바이너리 변환 (VMWare , 1999)

x86에는 가상화의 구멍이 있었다.
게스트를 링 1/3으로 강등시키면 일부 특권 명령이 트랩을 발생시키지 않고 조용히 실패하거나 하드웨어 정보를 그대로 노출했다.

VMware가 이걸 소프트웨어로 해결한 방식이 바이너리 변환(BT)이다.

text
게스트 코드 실행 직전에 코드 블록을 스캔

문제 명령어 발견 → 안전한 코드로 교체한 블록을 메모리에 생성

원본 대신 교체된 블록 실행 후 캐시에 저장
  • 원본 파일은 건드리지 않는다. 메모리 위에서만 일어나는 일이다.

3세대: 반가상화

게스트 OS 커널을 수정해서 특권 명령 대신 hypercall 을 사용하도록 한다.

기존: 게스트가 특권 명령 실행 -> VMM(하이퍼바이저)이 가로챔 반가상화: 게스트가 처음부터 hypercall을 사용하여 하이퍼바이저에게 요청함

VMM이 가로챌 이유가 없으니 바이너리 변환 방식보다느 빠름.

  • 단점은 게스트OS를 수정하야한다는 점임

4세대: 하드웨어 가상화

소프트웨어에서 해결하던 문제들을 하드웨어 레벨에서 처리하기 시작함.

기본적인 매커니즘은 아래와 같음

  • CPU에서 게스트/호스트 두가지 동작 모드를 구분한다
  • 기존 보호 링 구조를 없앤 것이 아니라 그위에 차원이 하나더 생김
text
root mode
    → KVM / 호스트가 실행되는 모드, 모든 권한
    └─ 링 0 (호스트 커널 / KVM)
    └─ 링 3 (QEMU 등 호스트 유저)

non-root mode
    → 게스트 OS가 실행되는 모드
    └─ 링 0 (게스트 커널) ← 특권 명령 실행 시 VM Exit 자동 발생
    └─ 링 3 (게스트 앱)
    ```

게스트 커널이 non-root 링 0에서 실행된다.
게스트 입장에선 자기가 진짜 커널인 줄 안다. 근데 non-root이니까 특권 명령을 날리면 CPU 회로(하드웨어)에서 VM Exit을 발생시킴.

그리고 제어권이 VMM으로 이동된다

그래서 사실 KVM은 이러한 하드웨어의 신호를 받아주고 적절히 처리한 뒤 다시 게스트로 돌려보내는 것이 전부임.(KVM이 명령어를 해석하거나 실행하는 게 아니다)