Stein 오픈스택 클라우드 분석(6) - 오픈스택 시스템 내부에서 이미지와 가상머신을 생성하고 관리하는 방법

blog post 

 

 

이번 포스트에서는 오픈스택 시스템 내부에서 이미지와 가상머신을 어디에 생성하고 어떻게 관리하는지 살펴보겠습니다. 사실 이번 포스트에서 네트워킹까지 함께 다루려 했으나, 네트워크 부분은 얘기가 길어질 것 같아서 별도로 포스팅 하겠습니다. 

 

 

1. 가상머신 이미지 관리

 

 

우선 가상머신 이미지부터 살펴보겠습니다. 지난 포스트에서 인스턴스를 생성하기 위해 우선 QCOW2 기반의 윈도우 이미지를 업로드 했습니다. [해당 포스트 보기]

 

이 이미지가 어디에 저장될까요?

 

혹시 기억나실지 모르겠네요, 지난번 이미지 서비스 설치 및 구성 포스트에서 /etc/glance/glance-api.conf 설정 파일을 통해 "filesystem_store_datadir = /var/lib/glance/images/" 옵션을 설정했습니다. 이 디렉토리가 바로 이미지 저장소 입니다.

 

해당 디렉토리를 보면 다음과 같이 파일 하나가 있는 것을 볼 수 있습니다.

 

[root@Controller ~]# ls /var/lib/glance/images/
15c04942-1027-4b82-a9e9-8411a47ddb2c

 

 

파일의 타입을 확인해보니 QCOW2 타입의 이미지라는 것을 확인할 수 있습니다.

 

[root@Controller images]# file 15c04942-1027-4b82-a9e9-8411a47ddb2c
15c04942-1027-4b82-a9e9-8411a47ddb2c: QEMU QCOW Image (v3), 32212254720 bytes

 

 

또한 이미지 명을 보니 오픈스택에서 자주 사용되는 id 포맷 처럼 보입니다. 오픈스택의 image list를 보면 알 수 있습니다.

 

[root@Controller ~]# openstack image list
+--------------------------------------+-----------+--------+
| ID                                   | Name      | Status |
+--------------------------------------+-----------+--------+
| 15c04942-1027-4b82-a9e9-8411a47ddb2c | windows10 | active |
+--------------------------------------+-----------+--------+
[root@Controller ~]# openstack image show 15c04942-1027-4b82-a9e9-8411a47ddb2c | egrep "disk_format|name"
| disk_format      | qcow2
| name             | windows10

 

이를 통해 glance 이미지 서비스가 사용자로부터 받은 이미지의 파일명을 id로 변경하여 사용자가 지정한 컨트롤러 노드의 특정 경로에 저장한다는 것을 알 수 있습니다.

 

다음으로 인스턴스는 이 이미지를 사용하여 어떻게 생성되는지 살펴보겠습니다.

 

 

2. 인스턴스(VM)의 디스크 생성

 

 

이전에 컴퓨트 서비스 포스트에서(3. Nova 컴포넌트 구조 참고) 설명한 것과 같이 nova-compute 서비스가 인스턴스를 생성하고 관리하는 역할을 담당한다고 했습니다. 즉 우리가 오픈스택 대시보드에서 인스턴스 정보를 입력하고 가상머신 생성 버튼을 클릭하면 그 정보가 message queue를 통해 nova-compute로 전달됩니다(가상머신 이미지 업로드 및 인스턴스 생성 포스트의 3번 과정 참고).

 

그 다음으로 컴퓨트 노드에서 /var/log/nova/nova-compute.log 파일을 살펴보면, 아래와 같이 사용자로부터 입력 받은 정보를 컴퓨트 노드에서 받아오는 로그가 보입니다. 사용자가 입력한 인스턴스 스펙을 우선 전달하고 컴퓨트 노드에서 스펙 할당 가능 여부를 체크한다는 것을 이 로그를 통해 예상할 수 있습니다.

 

2020-02-14 18:23:20.005 23339 INFO nova.compute.claims ...생략... [instance: 88888f8f-3cd4-41dd-9d67-f2229b055b9c] Attempting claim on node Compute0: memory 4096 MB, disk 50 GB, vcpus 1 CPU

2020-02-14 18:23:20.006 23339 INFO nova.compute.claims ...생략... [instance: 88888f8f-3cd4-41dd-9d67-f2229b055b9c] Total memory: 7772 MB, used: 512.00 MB

2020-02-14 18:23:20.007 23339 INFO nova.compute.claims ...생략... [instance: 88888f8f-3cd4-41dd-9d67-f2229b055b9c] memory limit not specified, defaulting to unlimited

2020-02-14 18:23:20.007 23339 INFO nova.compute.claims ...생략... [instance: 88888f8f-3cd4-41dd-9d67-f2229b055b9c] Total disk: 218 GB, used: 0.00 GB

2020-02-14 18:23:20.008 23339 INFO nova.compute.claims ...생략... [instance: 88888f8f-3cd4-41dd-9d67-f2229b055b9c] disk limit not specified, defaulting to unlimited

2020-02-14 18:23:20.008 23339 INFO nova.compute.claims ...생략... [instance: 88888f8f-3cd4-41dd-9d67-f2229b055b9c] Total vcpu: 2 VCPU, used: 0.00 VCPU

2020-02-14 18:23:20.009 23339 INFO nova.compute.claims ...생략... [instance: 88888f8f-3cd4-41dd-9d67-f2229b055b9c] vcpu limit not specified, defaulting to unlimited

2020-02-14 18:23:20.011 23339 INFO nova.compute.claims ...생략... [instance: 88888f8f-3cd4-41dd-9d67-f2229b055b9c] Claim successful on node Compute0

 

 

이어서 아래의 로그와 같이 이미지 디스크를 생성(Creating image)을 하는데 그 이후에 openvswitch로 부터 포트를 하나 할당받아서 이를 vm의 인터페이스로 사용하는 것을 볼 수 있습니다. 포트 생성 및 VM에 인터페이스 연결까지 약 11분이 소요된 것을 볼 수 있습니다.

 

 

* 참고

시스템 상태에 따라 이미지 생성 시간은 차이가 큽니다.

 

2020-02-14 18:23:23.725 23339 INFO nova.virt.libvirt.driver ...생략... [instance: 88888f8f-3cd4-41dd-9d67-f2229b055b9c] Creating image

2020-02-14 18:34:38.592 23339 INFO os_vif ...생략... Successfully plugged vif VIFOpenVSwitch(active=False,address=xx:xx:xx:xx:xx:xx,bridge_name='br-int',has_traffic_filtering=True,id=9102106c-dad0-4644-ba6c-f449b5d4131f,network=Network(585040c0-8dea-43f0-ba73-001955f59ce1),plugin='ovs',port_profile=VIFPortProfileOpenVSwitch,preserve_on_delete=False,vif_name='tap9102106c-da')

 

이 11분 동안 실질적으로 원본 이미지로 부터 인스턴스 디스크로 이미지를 복사하는 과정에 들어갑니다.

 

 

출처: Openstack Foundation

  

중요한건 앞서 본 것과 같이 원본 이미지 파일은 현재 컨트롤러 노드 (/var/lib/glance/qemu/15c04942-1027-4b82-a9e9-8411a47ddb2c)에 있다는 것입니다. 노드 간 복사가 이뤄진다는 점에서 시간이 다소 소요될 수 밖에 없습니다.

 

어찌됐든, "Creating Image" 단계에 들어가면 nova-compute는 컨트롤러 노드로부터 이미지를 다음 경로로 복사합니다: /var/lib/nova/instances/_base/

 

[root@Compute0 ~]# ll -h /var/lib/nova/instances/_base/
합계 9.3G
-rw-r--r--. 1 qemu qemu 30G  2월 16 01:01 2b45dbd3be0df1d1b9798ff08b325bbfbe772ce7

 

 그리고 이 _base에 저장된 이미지 파일을 backing file로 삼아 인스턴스의 디스크 이미지를 생성합니다. 아래 결과를 보시다시피 instances 디렉토리에 새로 생성 될 인스턴스의 id를 디렉토리로 만들고 disk를 만듭니다. 

 

[root@Compute0 ~]# ll -h /var/lib/nova/instances/88888f8f-3cd4-41dd-9d67-f2229b055b9c/
합계 5.4G
-rw-------. 1 root root    0  2월 15 20:12 console.log
-rw-r--r--. 1 qemu qemu 5.4G  2월 16 01:43 disk
-rw-r--r--. 1 nova nova   79  2월 14 18:23 disk.info

 

qemu-img 명령을 통해 이 disk 파일이 QCOW2 포맷이고, _base 디렉토리의 2b45dbd3be0df1d1b9798ff08b325bbfbe772ce7 파일을 backing file로 하여 복사 생성되었다는 것을 확인할 수 있습니다.

 

즉, 이 disk 이미지가 실제 인스턴스에 마운트 될 QCOW2 포맷의 disk 이미지 입니다.

 

[root@Compute0 88888f8f-3cd4-41dd-9d67-f2229b055b9c]# qemu-img info -U disk
image: disk
file format: qcow2
virtual size: 50G (53687091200 bytes)
disk size: 5.3G
cluster_size: 65536
backing file: /var/lib/nova/instances/_base/2b45dbd3be0df1d1b9798ff08b325bbfbe772ce7
Format specific information:
    compat: 1.1
    lazy refcounts: false
    refcount bits: 16
    corrupt: false

 

 

그렇다면, 컨트롤러 노드에 원본 이미지가 있는데도 불구하고, 굳이 왜 원본 이미지를 _base에 또 저장하고 이 이미지로 인스턴스 disk를 만드는 걸까요? _base 이미지를 바로 인스턴스 디스크로 마운트해서 사용하면 되지 않을까요?

 

물론 _base 이미지를 바로 마운트해서 사용할 수도 있겠지만, disk파일로 복사해서 마운트 하는 이유는 인스턴스를 빠르게 프로비저닝하기 위해서 입니다.

 

저는 소규모의 오픈스택 시스템을 구축해서 테스트 하는 입장이라 크게 상관은 없으나, 컴퓨트 노드를 수십대씩 구축해서 사용하는 대규모 프라이빗 클라우드 환경을 생각해 보면 답이 나옵니다. 사용자가 인스턴스를 생성할 때마다 매번 컨트롤러 노드에서 이미지를 가져와서 인스턴스를 사용하면 네트워크 트래픽이 증가하고 이는 곧 시스템 성능에 영향을 미칠 것입니다. 인스턴스 생성 요청 횟수 자체도 굉장히 많을 수 있습니다. 이런 사항들을 고려하면 매번 컨트롤러 노드에서 이미지를 복사해 와서 인스턴스에 디스크를 마운트 하는 것은 비효율적인 방법일 수 있습니다.

 

따라서 nova-compute 서비스는 인스턴스를 처음 생성할 때만 _base로 복사해 옵니다. 이후 인스턴스 생성 요청시에는 같은 컴퓨트 노드에 있는 _base 이미지 파일을 backing file로 하여 디스크 이미지를 생성함으로써 프로비저닝 성능을 높입니다. 불필요한 이미지 서버 접근과 복사를 줄이는 것이죠.

 

그럼 실제로 같은 이미지로 두 번째 인스턴스 생성시, 시간이 얼마나 단축되는지 잠시 확인해 보겠습니다.

 

 

보이시나요? 같은 이미지로 추가 인스턴스를 생성해 본 결과, 위와 같이 1분도 채 걸리지 않아서 Running 상태로 바뀐 것을 볼 수 있습니다. 로그를 보니 대략 3초만에 디스크 이미지가 생성되었네요.

 

 

2020-02-16 02:25:02.661 1810 INFO nova.virt.libvirt.driver ...생략... [instance: 98c1920c-1de6-4aac-bca3-0c2a2f6bad2e] Creating image

2020-02-16 02:25:05.638 1810 INFO os_vif ...생략... Successfully plugged vif VIFOpenVSwitch(active=False,address=xx:xx:xx:xx:xx:xx,bridge_name='br-int',has_traffic_filtering=True,id=ed2e156a-f97b-4a1f-8a29-2da8864bf88b,network=Network(585040c0-8dea-43f0-ba73-001955f59ce1),plugin='ovs',port_profile=VIFPortProfileOpenVSwitch,preserve_on_delete=False,vif_name='taped2e156a-f9')

 

새로 생성된 인스턴스의 디스크 역시 기존 인스턴스와 같은 _base의 이미지를 Backing File로 삼고 있는 것을 볼 수 있습니다.

 

[root@Compute0 98c1920c-1de6-4aac-bca3-0c2a2f6bad2e]# qemu-img info -U disk
image: disk
file format: qcow2
virtual size: 50G (53687091200 bytes)
disk size: 4.6G
cluster_size: 65536
backing file: /var/lib/nova/instances/_base/2b45dbd3be0df1d1b9798ff08b325bbfbe772ce7
Format specific information:
    compat: 1.1
    lazy refcounts: false
    refcount bits: 16
    corrupt: false

 

 

3. 인스턴스(VM) 생성

 

 

그럼 다시 "Creating Image" 로그로 돌아가서, 이제 인스턴스에 사용할 디스크가 이 단계에서 생성되었고 다음으로 openvswitch 기반의 네트워크 포트를 생성해서 인스턴스에 할당하는 로그를 볼 수 있습니다. (자세한 네트워크 관련 분석은 다음 포스트에서 하도록 하겠습니다)

 

네트워크 포트까지 생성했으면 이제 인스턴스를 생성할 것입니다.

 

현재 인스턴스는 KVM/QEMU 기반으로 만들어지고 있습니다. KVM/QEMU는 오픈스택에서 가장 최적화된 하이퍼바이저 타입이고, 가상화를 지원하는 에뮬레이터입니다. 이 하이퍼바이저의 특징은 물리 자원의 가상화만 지원할 뿐, 우리가 잘 아는 VirtualBox처럼 사용자로부터 실제 인스턴스(가상머신, VM)를 생성하고 관리하지는 않는다는 점입니다. 실제 명령은 libvirt가 수행합니다. 

 

libvirt 기반의 컨트롤러인 virsh 명령을 통해 인스턴스 리스트를 확인해 보겠습니다.

 

[root@Compute0 qemu]# virsh list
 Id    이름                         상태
----------------------------------------------------
 1     instance-0000000d              실행중
 2     instance-0000000e              실행중

 

* 참고

인스턴스, 가상머신 용어를 혼용하고 있지만 사실상 같은 의미입니다.

 

방금 만든 가상머신까지 총 2개의 가상머신이 현재 동작중인 것을 볼 수 있습니다. 문제는 어떤 인스턴스가 기존의 것이고 방금 생성한 것인지 구분이 잘 되지 않습니다. 다음과 같이 인스턴스의 이미지를 확인하면 됩니다.

 

[root@Compute0 ~]# virsh domblklist 1
대상     소스
------------------------------------------------
vda        /var/lib/nova/instances/88888f8f-3cd4-41dd-9d67-f2229b055b9c/disk

[root@Compute0 ~]# virsh domblklist 2
대상     소스
------------------------------------------------
vda        /var/lib/nova/instances/98c1920c-1de6-4aac-bca3-0c2a2f6bad2e/disk

 

 현재 동작중인 이미지 디스크가 가상머신의 운영체제에서 vda 볼륨에 마운트 된 것까지 확인할 수 있습니다.

 

 

 

물론 아래와 같이 디스크 뿐만 아니라 인스턴스에 필요한 정보를 확인할 수 있습니다.

 

[root@Compute0 ~]# virsh edit 1

<domain type='kvm'>
  <name>instance-0000000d</name>
  <uuid>88888f8f-3cd4-41dd-9d67-f2229b055b9c</uuid>
  <metadata>
    <nova:instance xmlns:nova="http://openstack.org/xmlns/libvirt/nova/1.0">
      <nova:package version="19.0.3-1.el7"/>
      <nova:name>myWindows10</nova:name>
      <nova:creationTime>2020-02-15 11:11:58</nova:creationTime>
      <nova:flavor name="windows_flavor">
        <nova:memory>4096</nova:memory>
        <nova:disk>50</nova:disk>
        <nova:swap>0</nova:swap>
        <nova:ephemeral>0</nova:ephemeral>
        <nova:vcpus>1</nova:vcpus>
      </nova:flavor>
      <nova:owner>
        <nova:user uuid="5320950663e34daf8d22fa2e5b7e696f">user1</nova:user>
        <nova:project uuid="e725a918191b4b649023644c006376b1">New_Project</nova:project>
      </nova:owner>
      <nova:root type="image" uuid="15c04942-1027-4b82-a9e9-8411a47ddb2c"/>
    </nova:instance>
  </metadata>
...
  <memory unit='KiB'>4194304</memory>
  <currentMemory unit='KiB'>4194304</currentMemory>
  <vcpu placement='static'>1</vcpu>
...
  <sysinfo type='smbios'>
    <system>
      <entry name='manufacturer'>RDO</entry>
      <entry name='product'>OpenStack Compute</entry>
      <entry name='version'>19.0.3-1.el7</entry>
      <entry name='serial'>88888f8f-3cd4-41dd-9d67-f2229b055b9c</entry>
      <entry name='uuid'>88888f8f-3cd4-41dd-9d67-f2229b055b9c</entry>
      <entry name='family'>Virtual Machine</entry>
    </system>
  </sysinfo>
  <os>
    <type arch='x86_64' machine='pc-i440fx-rhel7.6.0'>hvm</type>
    <boot dev='hd'/>
    <smbios mode='sysinfo'/>
  </os>

...
    <disk type='file' device='disk'>
      <driver name='qemu' type='qcow2' cache='none'/>
      <source file='/var/lib/nova/instances/88888f8f-3cd4-41dd-9d67-f2229b055b9c/disk'/>
      <target dev='vda' bus='virtio'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/>
    </disk>
...

<interface type='bridge'>
      <mac address='xx:xx:xx:xx:xx:xx'/>
      <source bridge='br-int'/>
      <virtualport type='openvswitch'>
        <parameters interfaceid='9102106c-dad0-4644-ba6c-f449b5d4131f'/>
      </virtualport>
      <target dev='tap9102106c-da'/>
      <model type='virtio'/>
      <mtu size='1450'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>
    </interface>
...

 

인스턴스 생성 과정에서 필요한 메모리, cpu, 네트워크 인터페이스, 시스템 아키텍처 정보 등이 작성된 것을 볼 수 있습니다. 물론 우리가 방금 본 disk 파일도 보입니다.

 

실제 이 xml 포멧의 스펙 파일은 다음 경로에 위치합니다: /etc/libvirt/qemu/

 

[root@Compute0 ~]# ls /etc/libvirt/qemu/
instance-0000000d.xml  instance-0000000e.xml  networks

 

이처럼 nova-compute 서비스가 인스턴스 생성 요청을 받으면 우선 디스크를 local에 생성하고 인스턴스의 스펙파일까지 생성하는 것을 볼 수 있습니다. 그 다음 이 xml 스펙 파일을 기반으로 인스턴스를 만들고 실행합니다. 이 역시 nova-compute 로그를 통해서 확인할 수 있습니다.

 

2020-02-14 13:10:41.488 23339 INFO nova.compute.manager ...생략... [instance: 316a16df-8107-46e4-93a5-70d2a43e6366] VM Started (Lifecycle Event)
2020-02-14 13:10:41.533 23339 INFO nova.compute.manager ...생략... [instance: 316a16df-8107-46e4-93a5-70d2a43e6366] VM Paused (Lifecycle Event)
2020-02-14 13:10:41.610 23339 INFO nova.compute.manager ...생략... [instance: 316a16df-8107-46e4-93a5-70d2a43e6366] During sync_power_state the instance has a pending task (spawning). Skip.
2020-02-14 13:10:43.698 23339 INFO nova.compute.manager ...생략... [instance: 316a16df-8107-46e4-93a5-70d2a43e6366] VM Resumed (Lifecycle Event)
2020-02-14 13:10:43.724 23339 INFO nova.virt.libvirt.driver [-] [instance: 316a16df-8107-46e4-93a5-70d2a43e6366] Instance spawned successfully.
2020-02-14 13:10:43.725 23339 INFO nova.compute.manager ...생략... [instance: 316a16df-8107-46e4-93a5-70d2a43e6366] Took 642.26 seconds to spawn the instance on the hypervisor.
2020-02-14 13:10:43.812 23339 INFO nova.compute.manager ...생략... [instance: 316a16df-8107-46e4-93a5-70d2a43e6366] During sync_power_state the instance has a pending task (spawning). Skip.
2020-02-14 13:10:43.861 23339 INFO nova.compute.manager ...생략... [instance: 316a16df-8107-46e4-93a5-70d2a43e6366] Took 645.10 seconds to build instance.
2020-02-14 13:10:43.880 23339 INFO nova.compute.manager [-] [instance: 316a16df-8107-46e4-93a5-70d2a43e6366] During sync_power_state the instance has a pending task (spawning). Skip.

 

nova-compute 서비스가 인스턴스 실행에 문제가 없는 것으로 판단하면 정상적으로 인스턴스 스폰을 마쳤다는 메시지를 출력합니다. 끝으로 전체 인스턴스 빌드 시간까지 보여주면서 인스턴스 생성을 마치는 것을 볼 수 있습니다.

 

이상으로 오픈스택 내에서 어떻게 이미지를 생성하고 복사하고 인스턴스를 생성하는지 분석해 보았습니다. 물론 오픈스택 시스템이 실제 동작하는 것은 이것보다 훨씬 복잡합니다. 실시간으로 api 메시지를 전달하며 서비스간 유기적으로 통신하는 과정을 통해 인스턴스를 생성하죠. 따라서 이번 포스트에서는 너무 깊게 들어가기 보다는 최대한 로그를 추적하며 일반 사용자(혹은 관리자) 입장에서 그 과정을 이해할 수 있는 수준으로 접근해 보았습니다.

 

다음 포스트에서는 이 인스턴스가 어떻게 인터넷에 접근하고, 또 호스트 시스템에서 네트워크 인터페이스는 어떻게 구성되는지 분석해 보겠습니다.

 

TAGS.

Comments