По ходу работы над CoreOS и Kubernetes мне приходилось часто воспроизводить окружения пользователей, чтобы помочь им решить проблему. Согласитесь, что при запуске OS при помощи контейнера, не всегда можно добиться полного функционала OS, т.к. часто приходилось решать вопросы, связанные с systemd.
Так и родилась идея написать костыли, которые с легкостью помогут мне поднять кластер из почти любой оперционной системы, эдакий OpenStack в миниатюре. В настоящий момент в качестве гостевых полностью поддерживаются следующие OS:
- Ubuntu
- Debian
- CentOS 6/7 + atomic
- Fedora + atomic
- CoreOS
Частично:
- FreeBSD (требуется ручная настройка сети и ssh ключей)
- openSUSE (требуется ручная настройка сети и ssh ключей)
- Windows (в консоль не попадёшь, но при помощи virt-manager можно пользоваться графическим интерфейсом)
Публикации поспособствовал коллега, который случайно увидел, как я тестирую код. А теперь о преимуществах перед Vagrant. Первое преимущество — время. Например, три виртуальные машины создаются всего за 20-30 секунд.
На момент начала работы над скриптами Vagrant под Linux мог запускать образы исключительно используя VirtualBox, поддержка libvirt/qemu была еще сырая. Для VirtualBox приходилось искать специально подготовленные образы и перезапуск кластера из виртуальных машин занимал значительное время.
В настоящий момент большинство разработчкиов операционных систем предоставляют образы, подготовленные для работы в окружении OpenStack ("cloud" образы). Эти образы очень удобно настраивать благодаря наличию в них cloud-init
. С помощью cloud-init
на этапе первой загрузки можно с легкостью внедрять в образ публичные ключи SSH и настраивать сеть.
QEMU умеет работать с образами виртуальной машины как со слоями (spanshots, почти как Docker). Мы можем скачать официальный "cloud" образ и использовать его как базовый для всех виртуальных машин из кластера. В этом случае все изменения на диске будут записываться как разность между базовым образом и текущим состоянием (как LVM snapshots). Этот способ также позволяет с легкостью удалить все машины и пересоздать их в течение нескольких секунд.
Удаляем уже созданный кластер из 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. Полагаю я не единственный, кто придумал что-то подобное. Буду признателен ссылкам не более зрелые решения.