KVM 가상화시스템 탐방 [2]

KVM은 리눅스에 현존하는 커널과 사용자 모드에 새로운 프로세스 모드를 추가한다. 이 새로운 모드는 게스트라고 부르며, 이름이 의미하는 바와 같이 (최소한 일부만이라도) 게스트 운영체제 코드 수행에 사용된다. 커널 모드는 코드 수행에 있어 특권 모드를 대표하며, 사용자 모드는 (커널 외부에서 동작하는 프로그램을 위한) 비 특권 모드를 대표한다는 사실을 기억하자. 실행 모드는 무엇이 동작하고, 목적이 무엇이냐에 따라 다양한 목적을 위해 정의된다. 게스트 모드는 I/O가 없는 게스트 운영체제 코드를 수행하기 위해 존재한다. 게스트 모드 내부에 표준 모드가 두 가지 존재하므로 게스트 모드로 동작하는 게스트 운영체제는 커널과 사용자 영역 응용 프로그램을 위해 표준 커널과 사용자 모드를 지원한다. 게스트 운영체제의 사용자 모드는 독립적으로 관리되는 I/O를 수행한다.
게스트 운영체제에서 I/O 수행은 QEMU가 제공한다. QEMU는 (디스크, 그래픽 카드, 네트워크 디바이스를 포함하여) 전체 PC 환경의 가상화를 허용하는 플랫폼 가상화 해법이다. 게스트 운영체제가 요청한 I/O를 가로채어 QEMU 프로세스가 에뮬레이션하도록 사용자 영역으로 전달한다.
KVM은 /dev/kvm 디바이스를 통해 메모리 가상화를 제공한다. 각 게스트 운영체제는 게스트를 새로 하나 생성할 때 사상된 독자적인 주소 영역을 확보한다. 게스트 운영체제에 사상된 물리적인 메모리는 실제로 프로세스 내부로 사상된 가상 메모리다. 게스트 물리 주소에서 호스트 물리 주소로 변환을 지원하기 위해 그림자 페이지 테이블 집합을 관리한다. 프로세서는 또한 사상되지 않은 메모리 위치에 접근할 때 하이퍼바이저(호스트 커널)를 사용하도록 메모리 변환 프로세스를 지원한다.
새로운 게스트 생성하기
새로운 게스트 운영체제 생성은 kvm이라는 유틸리티가 맡는다. 이 유틸리티는 kvm 모듈과 함께 동작해 /dev/kvm을 사용해서 게스트를 메모리에 올리고, 가상 디스크(호스트 운영체제에 있는 일반 파일)를 붙인 다음 동작을 개시한다.
/dev/kvm 디바이스에 수행하는 ioctl 집합을 통해 제어 기능을 지원한다. 디바이스 파일이 처음으로 열리면, 새로운 VM 객체가 생성되어 가상 CPU와 연결된다. 그리고 나서 여러 ioctl을 사용해 가상 CPU를 생성하고, kvm 버전을 점검하고, 메모리 영역을 생성하고, 그리고 나서 가상 CPU를 시작한다. 명령어 kvm으로 이런 작업을 할 수 있다. 다음에 이어지는 절에서 kvm 명령어를 살피고 지원되는 몇 가지 ioctl 에제를 보여주겠다.
KVM 활용
하드웨어가 지원하기만 하면 KVM 활용은 상당히 단순하다. 가상화를 지원하는 프로세서가 필요하다. /proc/cpuinfo를 살펴보면 시스템이 가상화를 지원하는지 확인할 수 있다. 이 파일은 vmx(인텔), svm(AMD) 확장을 지원하는지 알려준다.
다음으로 KVM 지원을 활성화한 리눅스 커널이 필요하다. ‘Device Driver > Virtualization’ 커널 환경 설정에서 활성화가 가능하다. 또한 환경을 위한 프로세서 지원을 활성화한다. 또한 kvm과 qemu 사용자 영역 응용 프로그램도 필요하다. 세부 사항은 참고자료 항목을 참조하기 바란다.
가상화 지원이 활성화된 커널을 사용해서, 다음 단계로 게스트 운영체제를 위한 디스크 이미지 생성 과정을 밟는다. 다음에 소개하듯이 qeumu-img로 이미지를 만든다. 이미지 크기는 4GB이지만 QEMU에서 제공하는 qcow(copy-on-write format)를 사용하므로, 파일은 완전히 4GB를 가득 채우는 대신 필요한만큼 용량이 늘어난다.
$ qemu-img create -f qcow vm-disk.img 4G
            
가상 디스크를 만들었다면, 여기에 게스트 운영체제를 올리자. 다음 예제는 게스트 운영체제가 CD-ROM에 담겨있다고 가정한다. CD-ROM ISO 이미지로 가상 디스크를 만들었다면, 완료 후에 만들어진 이미지로 부팅해야 한다.
$ kvm -no-acpi -m 384 -cdrom guestos.iso -hda vm-disk.img -boot d
            
Ari Kivity는 완벽한 디바이스 모델 없이도 KVM을 테스트하는 테스트 도구 집합을 만들었다. (kvm-12/user/main.c에서 따온) 다음 코드 조각은 VM을 시작하는 고차원적인 코드 개요를 보여준다(Listing 1 참조). 제어 기능은 커널에서 ioctl이 제공한다(특히 ./linux-2.6.20/drivers/kvm/kvm_main.c 파일을 살펴본다).
kvm_init를 호출하면 /dev/kvm 디바이스를 열고, (KVM 커널 모듈이 외부에 공개한) 버전 번호를 점검하고, 그리고 나서 KVM 문맥 객체를 할당하고 몇 가지 콜백 함수를 채운다. kvm_create 함수는 두 메모리 영역을 설정하고 사상한 다음에 ioctl(KVM_CREATE_VCPU)로 가상 CPU(VCPU)를 생성한다.
load_file 함수는 이미지를 주어진 VM을 위한 주소 영역으로 올리고, (ioctl KVM_RUN으로) kvm_run을 호출해서 실행한다. 단순하지만, 이런 과정은 새로운 게스트 운영체제를 KVM으로 생성하는 방법을 보여준다.
Listing 1. KVM 하이퍼바이저 테스트를 위한 응용 프로그램 일부
                
int main()
{
       void *vm_mem;
       kvm = kvm_init(&test_callbacks, 0);
       if (!kvm) {
           fprintf(stderr, “kvm_init failed\n”);
           return 1;
       }
       if (kvm_create(kvm, 128 * 1024 * 1024, &vm_mem) < 0) {
           kvm_finalize(kvm);
           fprintf(stderr, “kvm_create failed\n”);
           return 1;
       }
       if (ac > 1)
           if (strcmp(av[1], “-32”) != 0)
              load_file(vm_mem + 0xf0000, av[1]);
           else
              enter_32(kvm);
       if (ac > 2)
           load_file(vm_mem + 0x100000, av[2]);
       kvm_show_regs(kvm, 0);
       kvm_run(kvm, 0);
       return 0;
}
마무리
KVM은 가상화 문제를 해결하는 흥미로운 해법이며, 처음으로 리눅스 커널에 들어간 가상화 기법이기에 서버 가상화를 위해 급속도로 지지 세력을 얻을 것임을 상상하기란 어렵지 않다. 다른 메서드는 (UML과 Xen처럼) 상당히 오랜 기간 동안 커널로 들어가려고 팽팽하게 밀고 당기기를 했지만, 다른 메서드를 제치고 KVM이 선택된 이유는 상당히 명확하다. 변경을 최소로 하고 표준 커널을 하이퍼바이저로 변환하는 특성 때문이다.
KVM을 채택함으로써 얻어지는 또 다른 장점은, KVM이 커널 자신이므로 커널 최적화와 개선을 활용할 수 있다. 이는 다른 독립적인 하이퍼바이저 해법과 비교해서 미래를 내다보는 접근 방법이다. KVM에는 새로운 가상화 기능을 탑재한 프로세서와 I/O 가상화를 제공하기 위한 사용자 영역 QEMU 프로세스를 요구한다는 두 가지 커다란 단점이 있다. 하지만 좋든 나쁘든 KVM은 커널에 들어갔으며, 현존하는 다른 가상화 기법과 비교해서 한발짝 앞서나가게 되었다

서진우

슈퍼컴퓨팅 전문 기업 클루닉스/ 상무(기술이사)/ 정보시스템감리사/ 시스존 블로그 운영자

You may also like...

페이스북/트위트/구글 계정으로 댓글 가능합니다.