Мгновенный запуск почти любой OS под Linux используя libvirt + qemu

    По ходу работы над CoreOS и Kubernetes мне приходилось часто воспроизводить окружения пользователей, чтобы помочь им решить проблему. Согласитесь, что при запуске OS при помощи контейнера, не всегда можно добиться полного функционала OS, т.к. часто приходилось решать вопросы, связанные с systemd.


    Так и родилась идея написать костыли, которые с легкостью помогут мне поднять кластер из почти любой оперционной системы, эдакий OpenStack в миниатюре. В настоящий момент в качестве гостевых полностью поддерживаются следующие OS:


    • Ubuntu
    • Debian
    • CentOS 6/7 + atomic
    • Fedora + atomic
    • CoreOS

    Частично:



    Публикации поспособствовал коллега, который случайно увидел, как я тестирую код. А теперь о преимуществах перед Vagrant. Первое преимущество — время. Например, три виртуальные машины создаются всего за 20-30 секунд.


    image

    На момент начала работы над скриптами Vagrant под Linux мог запускать образы исключительно используя VirtualBox, поддержка libvirt/qemu была еще сырая. Для VirtualBox приходилось искать специально подготовленные образы и перезапуск кластера из виртуальных машин занимал значительное время.


    В настоящий момент большинство разработчкиов операционных систем предоставляют образы, подготовленные для работы в окружении OpenStack ("cloud" образы). Эти образы очень удобно настраивать благодаря наличию в них cloud-init. С помощью cloud-init на этапе первой загрузки можно с легкостью внедрять в образ публичные ключи SSH и настраивать сеть.


    QEMU умеет работать с образами виртуальной машины как со слоями (spanshots, почти как Docker). Мы можем скачать официальный "cloud" образ и использовать его как базовый для всех виртуальных машин из кластера. В этом случае все изменения на диске будут записываться как разность между базовым образом и текущим состоянием (как LVM snapshots). Этот способ также позволяет с легкостью удалить все машины и пересоздать их в течение нескольких секунд.


    Пример редеплоя 3-х debian машин

    Удаляем уже созданный кластер из Debian и пересоздаём его с нуля, используя скачанный официальный образ debian-8.5.0-openstack-amd64.qcow2


    $ virsh list 
     Id    Name                           State
    ----------------------------------------------------
     12    debian1                        running
     13    debian2                        running
     14    debian3                        running
    ./remove_cluster.sh debian
    Are you sure to remove 'debian1 debian2 debian3 '? (Type 'y' when agree) y
    Domain debian1 destroyed
    
    Domain debian1 has been undefined
    
    Vol debian1.qcow2 deleted
    
    # Host debian1 found: line 8
    /home/user/.ssh/known_hosts.debian updated.
    Original contents retained as /home/user/.ssh/known_hosts.debian.old                                                                                                                                                  
    Domain debian2 destroyed                                                                                                                                                                                             
    
    Domain debian2 has been undefined                                                                                                                                                                                    
    
    Vol debian2.qcow2 deleted                                                                                                                                                                                            
    
    # Host debian2 found: line 9                                                                                                                                                                                         
    /home/user/.ssh/known_hosts.debian updated.                                                                                                                                                                           
    Original contents retained as /home/user/.ssh/known_hosts.debian.old                                                                                                                                                  
    Domain debian3 destroyed                                                                                                                                                                                             
    
    Domain debian3 has been undefined                                                                                                                                                                                    
    
    Vol debian3.qcow2 deleted                                                                                                                                                                                            
    
    Host debian3 not found in /home/user/.ssh/known_hosts.debian                                                                                                                                                          
    Pool debian destroyed                                                                                                                                                                                                
    
    Pool debian has been undefined
    
    $ date && time ./deploy_vms_cluster.sh -o debian -s 3 && date
    Thu Aug 25 10:26:15 CEST 2016 # <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
    Using default 8.5.0 channel for debian
    Using default current release for debian
    Will use following path to SSH public key: /home/user/.ssh/id_rsa.pub
    Pool debian created
    
    Pool debian defined from /dev/stdin
    
    Formatting '/home/user/libvirt_images/debian/debian1.qcow2', fmt=qcow2 size=2147483648 backing_file=/home/user/libvirt_images/debian/debian-8.5.0-openstack-amd64.qcow2 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
    Pool debian refreshed
    
    Total translation table size: 0
    Total rockridge attributes bytes: 763
    Total directory bytes: 4458
    Path table size(bytes): 40
    Max brk space used 22000
    187 extents written (0 MB)
    Pool debian refreshed
    
    Starting install...
    Creating domain...                                                                                                                                                                            |    0 B  00:00:00     
    Domain creation completed.
    Pool debian defined from /dev/stdin
    
    Formatting '/home/user/libvirt_images/debian/debian2.qcow2', fmt=qcow2 size=2147483648 backing_file=/home/user/libvirt_images/debian/debian-8.5.0-openstack-amd64.qcow2 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
    Pool debian refreshed
    
    Total translation table size: 0
    Total rockridge attributes bytes: 763
    Total directory bytes: 4458
    Path table size(bytes): 40
    Max brk space used 22000
    187 extents written (0 MB)
    Pool debian refreshed
    
    Starting install...
    Creating domain...                                                                                                                                                                            |    0 B  00:00:00     
    Domain creation completed.
    Pool debian defined from /dev/stdin
    
    Formatting '/home/user/libvirt_images/debian/debian3.qcow2', fmt=qcow2 size=2147483648 backing_file=/home/user/libvirt_images/debian/debian-8.5.0-openstack-amd64.qcow2 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
    Pool debian refreshed
    
    Total translation table size: 0
    Total rockridge attributes bytes: 763
    Total directory bytes: 4458
    Path table size(bytes): 40
    Max brk space used 22000
    187 extents written (0 MB)
    Pool debian refreshed
    
    Starting install...
    Creating domain...                                                                                                                                                                            |    0 B  00:00:00     
    Domain creation completed.
    Use following command to connect to your cluster: 'ssh -i "/home/user/.ssh/id_rsa" debian@debian1'
    
    real    0m4.916s
    user    0m2.112s
    sys     0m0.268s
    Thu Aug 25 10:26:20 CEST 2016 # <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
    $ ssh debian1
    Warning: Permanently added 'debian1,192.168.122.30' (ECDSA) to the list of known hosts.
    
    The programs included with the Debian GNU/Linux system are free software;
    the exact distribution terms for each program are described in the
    individual files in /usr/share/doc/*/copyright.
    
    Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
    permitted by applicable law.
    debian@debian1:~$ date
    Thu Aug 25 08:26:38 UTC 2016 # <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

    Виртуальные машины готовы к использованию уже через 20 секунд (ноутбук с SSD), на HDD приблизительно на 10 секунд дольше.


    Так выглядит содержимое директории ~/libvirt_images/debian


    $ find ~/libvirt_images/debian -ls
      4456467      4 drwxrwxr-x   5 user      user          4096 Aug 25 11:13 /home/user/libvirt_images/debian
      4853836      4 drwxrwxr-x   3 user      user          4096 Aug 25 11:13 /home/user/libvirt_images/debian/debian2
      4853838      4 -rwxrwxr-x   1 user      user           157 Aug 25 11:13 /home/user/libvirt_images/debian/debian2/rebuild_iso.sh
      4853837    376 -rw-rw-r--   1 libvirt-qemu kvm        382976 Aug 25 11:13 /home/user/libvirt_images/debian/debian2/cidata.iso
      4985097      4 drwxrwxr-x   3 user          user          4096 Aug 25 11:13 /home/user/libvirt_images/debian/debian2/openstack
      4985103      4 drwxrwxr-x   2 user          user          4096 Aug 25 11:13 /home/user/libvirt_images/debian/debian2/openstack/latest
      4985104      4 -rw-rw-r--   1 user          user           574 Aug 25 11:13 /home/user/libvirt_images/debian/debian2/openstack/latest/user_data
      4985105      4 -rw-rw-r--   1 user          user           152 Aug 25 11:13 /home/user/libvirt_images/debian/debian2/openstack/latest/meta_data.json
      4456468   7752 -rw-r--r--   1 libvirt-qemu kvm       7995392 Aug 25 11:13 /home/user/libvirt_images/debian/debian1.qcow2
      4456470   7752 -rw-r--r--   1 libvirt-qemu kvm       7995392 Aug 25 11:13 /home/user/libvirt_images/debian/debian3.qcow2
      4722884      4 drwxrwxr-x   3 user          user          4096 Aug 25 11:13 /home/user/libvirt_images/debian/debian1
      4722886      4 -rwxrwxr-x   1 user          user           157 Aug 25 11:13 /home/user/libvirt_images/debian/debian1/rebuild_iso.sh
      4722885    376 -rw-rw-r--   1 libvirt-qemu kvm        382976 Aug 25 11:13 /home/user/libvirt_images/debian/debian1/cidata.iso
      4853832      4 drwxrwxr-x   3 user          user          4096 Aug 25 11:13 /home/user/libvirt_images/debian/debian1/openstack
      4853833      4 drwxrwxr-x   2 user          user          4096 Aug 25 11:13 /home/user/libvirt_images/debian/debian1/openstack/latest
      4853834      4 -rw-rw-r--   1 user          user           574 Aug 25 11:13 /home/user/libvirt_images/debian/debian1/openstack/latest/user_data
      4853835      4 -rw-rw-r--   1 user          user           152 Aug 25 11:13 /home/user/libvirt_images/debian/debian1/openstack/latest/meta_data.json
      4985106      4 drwxrwxr-x   3 user          user          4096 Aug 25 11:13 /home/user/libvirt_images/debian/debian3
      4985112      4 -rwxrwxr-x   1 user          user           157 Aug 25 11:13 /home/user/libvirt_images/debian/debian3/rebuild_iso.sh
      4985111    376 -rw-rw-r--   1 libvirt-qemu kvm        382976 Aug 25 11:13 /home/user/libvirt_images/debian/debian3/cidata.iso
      4985107      4 drwxrwxr-x   3 user          user          4096 Aug 25 11:13 /home/user/libvirt_images/debian/debian3/openstack
      4985108      4 drwxrwxr-x   2 user          user          4096 Aug 25 11:13 /home/user/libvirt_images/debian/debian3/openstack/latest
      4985109      4 -rw-rw-r--   1 user          user           574 Aug 25 11:13 /home/user/libvirt_images/debian/debian3/openstack/latest/user_data
      4985110      4 -rw-rw-r--   1 user          user           152 Aug 25 11:13 /home/user/libvirt_images/debian/debian3/openstack/latest/meta_data.json
      4456469   7752 -rw-r--r--   1 libvirt-qemu kvm       7995392 Aug 25 11:13 /home/user/libvirt_images/debian/debian2.qcow2
      4456471 474092 -rw-rw-r--   1 libvirt-qemu kvm      485465600 Aug 25 10:18 /home/user/libvirt_images/debian/debian-8.5.0-openstack-amd64.qcow2

    Сеть и DNS настраиваются с помощью dnsmasq и send host-name "<hostname>". На этапе конфигурации сети мы присваиваем виртуальной машине hostname, затем она запрашивает IP адрес по DHCP и отправляет свой hostname в dnsmasq, dnsmasq прописывает hostname во внутренний DNS. Используя dnsmasq как резолвер мы получаем IP новой виртуальной машины.


    Я также запускал виртуальные машины внутри виртуальных машин. Вложенная (nested) виртуализация KVM работает вполне нормально, но возможно потребуется дополнительная конфигурация.


    Недостатки:


    • Скрипты написаны на bash
    • Необходимо заранее настроить окружение libvirt
    • Нет гибкости, которую предоставляют Vagrantfile или Dockerfile, после деплоя придётся запускать свой любимый puppet/chef/ansible/etc.
    • Пока нет поддержки PXE boot образов, чтобы эмулировать/тестировать deploy с нуля таких провайдеров как Hetzner/OVH/etc.
    • Требуется помощь по улучшению.
    • Требуется придумать красивое название.
    • В планах добавить поддержку FreeBSD и bhyve.

    Ну и сам репозиторий здесь: https://github.com/kayrus/scripts. Там же информация по настройке окружения libvirt.


    В качестве бонуса в репозитории уже есть скрипт деплоя кластера Kubernetes под CoreOS.


    P.S. Полагаю я не единственный, кто придумал что-то подобное. Буду признателен ссылкам не более зрелые решения.

    • +11
    • 19,4k
    • 5
    Поделиться публикацией

    Похожие публикации

    Комментарии 5

      +2

      Cкрипты определенно получились у вас довольно классные и свою задачу выполняют, спасибо.
      Но в вашем случае я бы использовал OpenNebula.
      В отличие от OpenStack эта платформа очень легковестна, и ее с легкостью можно использовать к для больших датацентров, так и всего на одном компьютере. При этом она сохраняет всю свою гибкость и многофункциальность.
      Среди функций есть так же свой Marketplace с популярными образами операционных систем и автоматическое конфигурирование виртуальных машин посредством, так называемой, контекстулизации. Все машины создаются как и у вас из базового образа.
      В вашем случае для ее работы вам хватит того же самого libvirt с lvm или zfs.

        0
        Ну не знаю, Nutanix CE тоже бы подошёл. Всё никак не могу на него перейти, надо SSD обзавестись.
        0
        Хмм. Может я конечно ничего не понимаю но: а что мешает поднимать это-же все в LXC контейнерах? НУ к примеру тем-же docker (нужно облако — берем docker-swarm)?
        Оно еще и тормозить не будет так отчянно как через паравиртуализацию… и поднимается 1ой коммандой и описание всего что надо в ось поставить и вообще все что сделать после установи оси надо — декларатиное и легко ложиться под системы контроля версий.
          0

          Низкоуровневые тесты необходимо проводить в полной изоляции.


          1) LXC у меня вешал ядро и засорял файловую систему. Виртуальная машина если и зависнет, то с малой долей вероятности повесит хост, а значи рабочему процессу не помешает.
          2) Первоначально разрабатывалось только для CoreOS, а CoreOS просто так в Docker не запустишь. Там система обновления, базирующася на GPT, readonly /usr раздел и прочие тонкости.

          0

          Я тоже делал похожие кастыли (packer+libvirt+python-script+dhpcd) ну и время старта квм-виртуалки на нормальном железе это секунды… но по хорошему cobbler решает большинство вопросов, а также его можно использовать как dynamic inventory для ansible.

          Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

          Самое читаемое