Таблица снизу это обзор текущих систем виртуализации с позиции того, насколько большую часть хост системы виртуальные машины используют напрямую:
Матрешка виртуализации
==========================================================================================
Используется Название Примеры:
совместно
с хостом
==========================================================================================
ничего Эмуляция QEMU, Boсsh
——————————————————————————————
CPU Виртуализация KVM, VmWare, XEN, Hyper-V
——————————————————————————————
Аппаратура Intel VT-d, SR-IOV Может использоваться совместно
с системой виртуализации (kvm)
——————————————————————————————
Драйвера Паравиртуализация XEN, VirtIO, VMWare tools
——————————————————————————————
Ядро OS Контейнеры LXC, Solaris Zones, OpenVZ, Linux VServer
==========================================================================================
В первой графе — слои системы «компьютер + ОС» — чем ниже, тем более высокий уровень (что-то типа уровней ISO для сетевого стека ). Средняя графа — название модели виртуализации. Третья графа — типичные примеры. Чем ниже, тем больше компонентов гостевые системы используют от хост-системы напрямую, тем меньше нагрузка на гипервизор и тем выше скорость работы.
Я немного расскажу о контейнерах вообще и LXC (LinuX Containers) в частности. Контейнеры (или виртуализация уровня операционной системы)- это группы процессов, изолированные от остальной системы, возможно с наложенными ограничениями, и имеющие доступ только к некоторой части ресурсов. Процессы из контейнера «видят» и могут напрямую взаимодействовать только с процессами из того же контейнера, им доступна только часть аппаратуры, а корень файловой системы контейнера с помощью chroot сдвинут в глубь файловой системы хоста (например, в /var/lib/lxc/my_container_1). Виртуализация всех необходимых подсистем ядра (таблицы монтирования, PID, маршруты IP, etc) позволяет контейнеру выглядеть как «нормальная» виртуалка.
Какие же плюсы и минусы есть у контейнера по сравнению с «полноценной» vm? Начнем с минусов — все контейнеры и хост система делять одну копию ядра и из этого вытекают очевидные недостатки:
- Безопасность — компрометация ОС в контейнере равноценна компрометации и хост ОС
- Ограниченость вариантов окружения — только та же ОС, только та же версия ядра, даже запустить другой дистрибутив — может быть проблемой, поскольку часто дистрибутивы имеют модифицированные версии ядра, а родные утилиты и glibc могут полагаться на наличие в ядре определенных изменений.
- Поддержка миграции, точек восстановления и сброса состояния на диск отсутствует в некоторых контейнерах, поскольку требует совсем другого типа взаимодействия с приложениями.
Ко всему этому LXC добавляет проблемы с user id. root в контейнере имеет UID == 0, т.е. совпадает с root в хост системе. В некоторых случаях это создает проблемы безопасности, о чем я скажу еще раз ниже.
Теперь о плюсах:
- Не нужна аппаратная поддержка виртуализации (вообще никакая). Т.е. все это работает «из коробки» на любом процессоре ( а объем работы для портирования кода на новую архитектуру несравнимо меньше объема работы по портированию туда-же гипервизора типа KVM/XEN, KVM вот уже тянут на ARM 3 года). В частности это означает, что контейнеры работаю внутри виртуальных машин. Все, кто хотели попробовать Linux виртуализацию, но не хотели ставить Linux «на голое железо» — LXC это для вас; LXC будет работать в Linux’е, установленном в vmWare.
- Возможна вложенная виртуализация. Даже, например, LXC в КVM/XEN в LXC и т.д. (если процессор «умеет» KVM). Главное, что нативная виртуализация не должна встречаться более одного раза (если она не поддерживает вложенность).
- Быстрый (доли секунды) запуск. Фактически запускаются только необходимые для работы контейнера приложения. Ядро, драйвера, инициализация железа, etc — это все не нужно. Так же быстро он и гасится.
- Нет потерь производительности CPU и дисковых операций — почти все, что доступно в контейнере, работает со скоростью хост системы. Несмотря на некоторые потери по скорости в сетевом стеке, связанные с избыточным копированием данных и невозможностью tcp offload для veth, в целом все несравнимо лучше, чем в xen/kvm (правда из тестов не ясно — использовалась ли там virtio, по идее kvm c ним не должен так сильно проседать по скорости). Где-то там в ядре есть, конечно, какие-то проверки или индексации массивов по номеру контейнера, но это все мелочь. То-же относится и к вложенным контейнерам.
- Не нужно выделять оперативную память под ядро ОС и всё прилагающееся (видеопамять, дисковые буферы, etc). Из «лишних» потребителей остаются init и другие стартовые сервисы.
- Нет дополнительных виртуальных устройств(таймеры, монитор, другое), вызывающих постоянное пробуждение гостевых драйверов, съедающих несколько процентов CPU на пустом месте.
- Поддерживается запуск в контейнере отдельных приложений, а не полной системы — «chroot на стероидах» (по меньшей мере это умеет LXC).
По итогу контейнеры позволяют поднять на весьма стандартном десктопе несколько сотен виртуальных машин c ssh и apache, сохраняя достаточную производительность.
Чем же особенно интересен LXC? Как можно понять из приведенного описания для реализации контейнера нужно внести в ядро OC очень значительные изменения. Именно поэтому долгое время в базовом ядре (vanilla kernel) контейнеров не было. И это не смотря на то, что OpenVZ/VServer появились не менее 6 лет назад и очень широко использовались (и использутся) VPS провайдерами. Все они, хотя и являются на сегодня более полноценной реализацией контейнеров чем LXC, не используют другие подсистемы ядра, а изобретают свои велосипеды (хотя благодаря LXC ситуация и у них улучшается). Видимо именно высокий уровень повторного использования кода привел к тому что LXC находится в основной ветке ядра уже достаточно давно (2.6.29+).
LXC является относительно небольшой надстройкой над cgroups, namespaces и capabilities. В итоге процессы из контейнера доступны для управления из хост системы всеми стандартными средствами и утилитами. С пользовательской позиции LXC несравнимо удобнее интеграцией в основное ядро линукс и (как результат) доступностью «из коробки» во всех дистрибутивах и(почти) всех ядрах без мороки с патчами, компиляцией и перезагрузками.
Из минусов конткретно LXC — его нужно аккуратно настраивать, иначе в него могут попасть «лишние» устройства и тогда он «распорядится» ими по своему усмотрению. Остались еще проблемы в безопасности, связанные с тем, что не все участки ядра Linux переведены на capabilities, и местами остались сравнения вида 0 == uid. Из-за этого криво настроенный контейнер при старте может погасить XServer или выключить звук (udev постарается). Так-же есть проблема безопасности с sysfs. Из некритичного — dmesg общий с хостом и прочие мелочи. Также иногда разобраться «чего ему надо» требует больше времени, чем следовало бы.
Но все это временное — LXC серьезно продвигается Canonical, уже есть поддержка в openstack, на сайтах всех основных дистрибутивов есть примеры по созданию контейнеров.
Немного про технологии, лежащие в основе LXC. cgroups позволяет ограничить ресурсы, доступные процессу — процессорные ядра, процессорное время, ОЗУ, нагрузку на сеть, диски и другое; namespaces виртуализирует системные ресурсы — таблицу монтирования, PID, средства межпроцессного взаимодействия, сетевые интерфейсы, таблицы маршрутизации и прочее; capabilities — это система ролевого доступа, которая позволяет разделить абсолютные административные привилегии пользователя root на отдельные части (например: право использовать RAW сокеты, право загружать модули и т.д. ) и выдавать только те права, которые реально нужно приложению. Все эти возможности/ограничения наследуются дочерними процессами, а доступные через cgroups ресурсы делятся между ними.
Практика
О создании контейнеров можно подробно прочитать в сети, отдельно стоит отметить эту статью — она будет особенно полезна windows пользователям, остальные могут смело пролистывать процесс создания Linux VM в VirtualBox. Ссылки из сети — 1, 2, debian, 3, запуск X, ubuntu. Так что подробно останавливаться на установке не буду (все примеры для ubuntu 11.10):
# oneiric.cfg
lxc.utsname = test
lxc.network.type = veth
lxc.network.flags = up
lxc.network.link = virbr0 # воспользуемся default сетью из libvirt
# для этого libvirt должна быть установлена
# см посты "облако на коленке"
lxc.network.hwaddr = 00:44:01:61:78:22
lxc.network.ipv4 = 192.168.122.190/24
lxc.network.name = test_vm
Без подсветки синтаксиса
# # lxc-create использует debootstrap для создания минималистического
# # образа ОС в /var/lib/lxc/test/rootfs
# lxc-create -n test -f oneiric.cfg -t ubuntu — —release oneiric
debootstrap is /usr/sbin/debootstrap
Checking cache download in /var/cache/lxc/oneiric/rootfs-amd64 …
Copy /var/cache/lxc/oneiric/rootfs-amd64 to /var/lib/lxc/test/rootfs …
Copying rootfs to /var/lib/lxc/test/rootfs …Please change root-password !
Reading package lists… Done
Building dependency tree… Done
The following NEW packages will be installed:
lxcguest
# # ……..
Setting up lxcguest (0.7.5-0ubuntu8) …
‘ubuntu’ template installed
‘test’ created
# ls /var/lib/lxc/test/rootfs/
bin boot dev etc home lib lib64 media mnt opt proc root run sbin selinux srv sys tmp usr var
# # lxc-create использует debootstrap для создания минималистического
# # образа ОС в /var/lib/lxc/test/rootfs
# lxc-create -n test -f oneiric.cfg -t ubuntu — —release oneiric
debootstrap is /usr/sbin/debootstrap
Checking cache download in /var/cache/lxc/oneiric/rootfs-amd64 …
Copy /var/cache/lxc/oneiric/rootfs-amd64 to /var/lib/lxc/test/rootfs …
Copying rootfs to /var/lib/lxc/test/rootfs …Please change root-password !
Reading package lists… Done
Building dependency tree… Done
The following NEW packages will be installed:
lxcguest
# # ……..
Setting up lxcguest (0.7.5-0ubuntu8) …
‘ubuntu’ template installed
‘test’ created
# ls /var/lib/lxc/test/rootfs/
bin boot dev etc home lib lib64 media mnt opt proc root run sbin selinux srv sys tmp usr var
Мы получили в /var/lib/lxc/test/rootfs корень файловой системы нашего контейнера. В принципе можно сделать туда chroot и провести все приготовления для старта. lxc-create по умолчанию помещает все контейнеры в /var/lib/lxc, из соображений удобства примеров мы их там и оставим.
Также в /var/lib/lxc/test есть два полезных файла — config и fstab. Первый содержит конфигурацию контейнера, а второй — описание точек монтирования. Часть конфурации скопирована из oneiric.cfg, а часть заполнена lxc-create параметрами по умолчанию:
Показать код
# скопированно из oneiric.cfg
lxc.network.type = veth
lxc.network.flags = up
lxc.network.link = virbr0
lxc.network.hwaddr = 11:b2:c3:d4:e5:f7
lxc.network.ipv4 = 192.168.122.190/24
lxc.network.name = test_vm
lxc.utsname = test
# значения по умолчанию
lxc.tty = 4
lxc.pts = 1024
lxc.rootfs = /var/lib/lxc/test/rootfs
lxc.mount = /var/lib/lxc/test/fstab
lxc.arch = amd64
# устройства, которые будут доступны из контейнера
lxc.cgroup.devices.deny = a
# Allow any mknod (but not using the node)
lxc.cgroup.devices.allow = c *:* m
lxc.cgroup.devices.allow = b *:* m
# /dev/null and zero
lxc.cgroup.devices.allow = c 1:3 rwm
lxc.cgroup.devices.allow = c 1:5 rwm
# consoles
lxc.cgroup.devices.allow = c 5:1 rwm
lxc.cgroup.devices.allow = c 5:0 rwm
#lxc.cgroup.devices.allow = c 4:0 rwm
#lxc.cgroup.devices.allow = c 4:1 rwm
# /dev/{,u}random
lxc.cgroup.devices.allow = c 1:9 rwm
lxc.cgroup.devices.allow = c 1:8 rwm
lxc.cgroup.devices.allow = c 136:* rwm
lxc.cgroup.devices.allow = c 5:2 rwm
# rtc
lxc.cgroup.devices.allow = c 254:0 rwm
#fuse
lxc.cgroup.devices.allow = c 10:229 rwm
Отдельно интересна группа с пробросом устройств — модифицируя ее можно выдавать контейнеры разнообразные возможности. Например для того чтобы разрешить использование kvm из контейнера нужно «пропустить» в него /dev/kvm
Без подсветки синтаксиса
# ls -l /dev/kvm
crw-rw----+ 1 root k
vm 10, 232 2012-01-11 21:14 /dev/kvm
# #/dev/kvm это символьное устройство с id (10, 232)
# mknod /var/lib/lxc/test/rootfs/dev/kvm c 10 232
# ls -l /dev/kvm
crw-rw----+ 1 root kvm 10, 232 2012-01-11 21:14 /dev/kvm
# #/dev/kvm это символьное устройство с id (10, 232)
# mknod /var/lib/lxc/test/rootfs/dev/kvm c 10 232
Теперь дописываем в config строку
lxc.cgroup.devices.allow = c 10:232 rwm
Обратите внимание — это должно быть сделано до первого запуска контейнера. После первого запуска пробросить устройства уже не получится (по крайней мере этим способом).
Не забываем убрать из контейнера запуск udev. Устройства в нем будут управляться хостовым udev демоном, а локальный будет только пакостить. В ubuntu для этого делаем rm %CONTAINER_ROOT%/etc/init/udev.conf (привет, upstart).
Запускаем контейнер и смотрим, что вышло:
Показать код
Без подсветки синтаксиса
# lxc-start -d -n test
# lxc-ls
kvm_in_lxc oneiric oneiric_br test # вообще все доступные контейнеры
test
# ip addr show
# #…..
# # это сетевой адаптер, ведущий в контейнер
22: vethcSEf3D: <broadcast,MULTICAST,PROMISC,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast master virbr0 state UP qlen 1000
link/ether d2:ea:5e:ba:3f:1b brd ff:ff:ff:ff:ff:ff
inet6 fe80::d0ea:5eff:feba:3f1b/64 scope link
valid_lft forever preferred_lft forever
# brctl show
bridge name bridge id STP enabled interfaces
br0 8000.000000000000 no
virbr0 8000.d2ea5eba3f1b yes vethcSEf3D
# ps -eo pid,cgroup,user,args | grep cpuset:/test
# # показываем все процессы с информацией о cgroup
# # и фильтруем только те, что относятся в группе test типа cpuset
22526 6:cpuset:/test?5:freezer:/ root /sbin/init
22562 6:cpuset:/test?5:freezer:/ root /sbin/plymouthd —mode=boot —attach-to-session
22593 6:cpuset:/test?5:freezer:/ root /usr/sbin/sshd -D
22594 6:cpuset:/test?5:freezer:/ syslog rsyslogd -c5
22617 6:cpuset:/test?5:freezer:/ root sshd: root@pts/1
22630 6:cpuset:/test?5:freezer:/ root -bash
22715 6:cpuset:/sysdefault?5:fre root grep —color=auto cpuset:/test
# # это процессы из контейнера, обратите внимание на PID
# # логинимся в контейнер
# ssh root@192.168.122.190
root@192.168.122.190’s password:
Welcome to Ubuntu 11.10 (GNU/Linux 3.1.3-030103-generic x86_64)
* Documentation: https://help.ubuntu.com/
Last login: Thu Jan 12 22:08:53 2012 from 192.168.122.1
root@test:~# # мы в контейнере
root@test:~# ps -eo pid,cgroup,user,args
PID CGROUP USER COMMAND
1 6:cpuset:/test?5:freezer:/ root /sbin/init
11 6:cpuset:/test?5:freezer:/ root /sbin/plymouthd —mode=boot —attach-to-session
42 6:cpuset:/test?5:freezer:/ root /usr/sbin/sshd -D
43 6:cpuset:/test?5:freezer:/ syslog rsyslogd -c5
49 6:cpuset:/test?5:freezer:/ root sshd: root@pts/1
61 6:cpuset:/test?5:freezer:/ root -bash
81 6:cpuset:/test?5:freezer:/ root ps -eo pid,cgroup,user,args
# # PID виртуализированы, а вот cgroup — нет
root@test:~# ip addr
24: test_vm: <broadcast,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
link/ether 00:44:01:61:78:22 brd ff:ff:ff:ff:ff:ff
inet 192.168.122.190/24 brd 192.168.122.255 scope global test_vm
inet6 fe80::244:1ff:fe61:7822/64 scope link
valid_lft forever preferred_lft forever
26: lo: <loopback,UP,LOW ER_UP> mtu 16436 qdisc noqueue state UNKNOWN
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
# # сетевые интерфейсы тоже только те, что нужно
# lxc-start -d -n test
# lxc-ls
kvm_in_lxc oneiric oneiric_br test # вообще все доступные контейнеры
test
# ip addr show
# #…..
# # это сетевой адаптер, ведущий в контейнер
22: vethcSEf3D: <broadcast,MULTICAST,PROMISC,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast master virbr0 state UP qlen 1000
link/ether d2:ea:5e:ba:3f:1b brd ff:ff:ff:ff:ff:ff
inet6 fe80::d0ea:5eff:feba:3f1b/64 scope link
valid_lft forever preferred_lft forever
# brctl show
bridge name bridge id STP enabled interfaces
br0 8000.000000000000 no
virbr0 8000.d2ea5eba3f1b yes vethcSEf3D
# ps -eo pid,cgroup,user,args | grep cpuset:/test
# # показываем все процессы с информацией о cgroup
# # и фильтруем только те, что относятся в группе test типа cpuset
22526 6:cpuset:/test?5:freezer:/ root /sbin/init
22562 6:cpuset:/test?5:freezer:/ root /sbin/plymouthd —mode=boot —attach-to-session
22593 6:cpuset:/test?5:freezer:/ root /usr/sbin/sshd -D
22594 6:cpuset:/test?5:freezer:/ syslog rsyslogd -c5
22617 6:cpuset:/test?5:freezer:/ root sshd: root@pts/1
22630 6:cpuset:/test?5:freezer:/ root -bash
22715 6:cpuset:/sysdefault?5:fre root grep —color=auto cpuset:/test
# # это процессы из контейнера, обратите внимание на PID
# # логинимся в контейнер
# ssh root@192.168.122.190
root@192.168.122.190’s password:
Welcome to Ubuntu 11.10 (GNU/Linux 3.1.3-030103-generic x86_64)
* Documentation: https://help.ubuntu.com/
Last login: Thu Jan 12 22:08:53 2012 from 192.168.122.1
root@test:~# # мы в контейнере
root@test:~# ps -eo pid,cgroup,user,args
PID CGROUP USER COMMAND
1 6:cpuset:/test?5:freezer:/ root /sbin/init
11 6:cpuset:/test?5:freezer:/ root /sbin/plymouthd —mode=boot —attach-to-session
42 6:cpuset:/test?5:freezer:/ root /usr/sbin/sshd -D
43 6:cpuset:/test?5:freezer:/ syslog rsyslogd -c5
49 6:cpuset:/test?5:freezer:/ root sshd: root@pts/1
61 6:cpuset:/test?5:freezer:/ root -bash
81 6:cpuset:/test?5:freezer:/ root ps -eo pid,cgroup,user,args
# # PID виртуализированы, а вот cgroup — нет
root@test:~# ip addr
24: test_vm: <broadcast,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
link/ether 00:44:01:61:78:22 brd ff:ff:ff:ff:ff:ff
inet 192.168.122.190/24 brd 192.168.122.255 scope global test_vm
inet6 fe80::244:1ff:fe61:7822/64 scope link
valid_lft forever preferred_lft forever
26: lo: <loopback,UP,LOWER_UP> mtu 16436 qdisc noqueue state UNKNOWN
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
# # сетевые интерфейсы тоже только те, что нужно
В итоге мы получили изолированную виртуальную машину. Ради интереса — по информации от free весь контейнер вместе с залогиненным ssh клиентом занимает «аж» 4М ОЗУ. Останавливается контейнер через ‘lxc-stop’/’lxc-destroy’.
Хранение образов
О файловой системе: LXC критикуют за отсутствие дисковых квот для контейнеров, но эта проблема легко решается с помощью LVM, а возможность overcommita обеспечивает thin provisioning, который появился в 3.2 ядре. А вот возможность копирования при записи, которая очень полезна для VM, требует дополнительных телодвижений. Хочется то же, что qcow2 формат дает виртуальным машинам kvm/xen — вместо полного образа на каждую VM — один большой базовый образ с установленной системой и множество маленьких diff’ов, по одному на виртуалку.
- использовать qcow2 через qemu-nbd
- модифицируемые снимки а btrfs
- модифицируемые снимки в LVM2
- наслаиваемые файловые системы — aufs
Первый вариант достаточно простой для тех, кто уже использовал qcow2 в kvm/xen, но неудобен по производительности. Второй и третий вариант похожи — и lvm2 и btrfs умеют создавать модифицируемые снимки, описывающие состояние файловой системы на некоторый момент времени. На каждую виртуальную машину можно делать отдельный снимок с базового образа. При этом все изменения будут записываться в снимок, а оригинальный образ модифицироваться не будет. В случае с LVM также можно модифицировать оригинальный образ, не затрагивая снимки.
Без подсветки синтаксиса
# lvcreate -s -n disk-snapshot /dev/vg0/disk -L 5G
# lvcreate -s -n disk-snapshot /dev/vg0/disk -L 5G
Эта команда создает снимок /dev/vg0/disk-snapshot с LVM раздела /dev/vg0/disk, где 5Гб места зарезервировано под хранение измененных, по отношению к /dev/vg0/disk, блоков. В дальнейшем количество свободного месте можно изменить
командой lvextend. Если на /dev/vg0/disk была установлена система, то, после монтирования, /dev/vg0/disk-snapshot может использоваться для старта виртуалки.
Еще один вариант — наслаиваемые файловые системы — aufs и другие, я рассмотрю только aufs. Она позволяет примонтировать в одну точку несколько файловых систем, называемых ветками. В отличии от стандартного поведения, когда смонтированная позднее файловая система полностью закрывает смонтированную ранее, aufs позволяет «видеть» нижние ветки, если файлы из них не были перекрыты файлами с такими-же именами в более поздних ветках. При этом чтение будет производиться из самой верхней ветки, имеющей данный файл, а запись — в зависимости от настроек при монтировании. Если ветка, в которой найден необходимый файл, защищена от записи, то файл будет скопирован в первую вверх ветвь, в которую можно писать. Фактически это cow на уровне файлов, а не блоков. Из очевидные минусов — даже небольшие изменения объемного файла приведут к его полному дублированию.
aufs не управляет хранением файлов на блочных устройствах, а использует для этого драйверы файловых систем веток, перераспределяя между ними запросы и копируя при необходимости файлы. Так что aufs монтируют не блочные устройства, а папки.
Без подсветки синтаксиса
# mkdir /tmp/rw
# mount -t aufs -o br=/tmp/rw=rw:/home/user=ro none /tmp/aufs
# mkdir /tmp/rw
# mount -t aufs -o br=/tmp/rw=rw:/home/user=ro none /tmp/aufs
Эта команда монтирует папки /home/user и /tmp/rw в папку /tmp/aufs. /tmp/user монтируется в режиме «только для чтения», так в /tmp/aufs будет видна домашняя папка, но все изменения будут попадать в /tmp/rw. P.S. aufs не включена в основную ветку ядра, и модулей для 3.1 в ubuntu еще нет, так что пользователям последней ubuntu этот вариант попробовать не удастся.
libvirt
Формально libvirt поддерживает LXC, но работоспособность этого решения и полнота поддержки оставляет желать лучшего. Libvirt не использует стандартные утилиты LXC, а создает контейнеры самостоятельно. В итоге на некоторых комбинациях ядер/libvirt запущенные контейнеры оказываются полностью не работоспособными (хотя lxc-start работает «на ура») Нашел у себя ошибку, так что остался без примера:
#/var/log/libvirt/lxc/test.log
......
01:48:38.544: 28327: error : lxcFdForward:289 : read of fd 9 failed: Input/output error
... и тут еще сотни тысяч таких записей .......
Фикс для этой ошибки вроде как был внесен еще год назад, но она раз за разом проявляется снова. Также контейнер, запущенный с помощью lxc-start при попытке последующих запусков из libvirt вообще не создает сетевые интерфейсы. libvirt полуофициально не поддерживает старт с /sbin/init — необходимо использовать собственные скрипты; нет поддержки нормального проброса устройств, установки адреса и параметров на сетевой адаптер и др. Все это, естественно, следует читать как «у меня не получилось», хотя масса не отвеченных вопросов говорит, что не только у меня.
Пример конфигурации для запуска lxc из libvirt:
Показать код
Без подсветки синтаксиса
<domain type="lxc">
test
1048576
exe
/sbin/init
1
<clock offset="utc"/>
destroy
restart
destroy
/usr/lib/libvirt/libvirt_lxc
<filesystem type="mount">
<source dir="/var/lib/lxc/test/rootfs" />
<target dir="/" />
<interface type="network">
<source network="default" />
<forward mode="nat" />
<target dev="vnet7" />
<mac address="00:44:01:61:78:22" />
<console type="pty" />
test
1048576
exe
/sbin/init
1
destroy
restart
destroy
/usr/lib/libvirt/libvirt_lxc
Записываем это в %CONTAINER_ROOT%/etc/init/mylxc.conf:
# %CONTAINER_ROOT%/etc/init/mylxc.conf
description "startup ifconfig"
start on filesystem or runlevel [2345]
pre-start script
# стартовый ip для адаптеров
now_ip=192.168.122.190
all_links=`ip link | grep ‘^[0-9][0-9]*:’ | awk -F: ‘{print $2}’ | grep -v lo`
for eth in $all_links ; do
ifconfig $eth $now_ip/24 up
now_ip=`echo $now_ip | awk -F. ‘{print $1 «.» $2 «.» $3 «.» $4 + 1}’`
done
end script
exec ps
Запуск контейнера через virsh:
Показать код
Без подсветки синтаксиса
# virsh -c lxc:/// create lxc.xml
Domain test created from lxc.xml
# virsh -c lxc:/// list
Id Name State
———————————-
21834 test running
# ip addr show
…….
10: virbr0: <broadcast,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP
link/ether 8e:05:b2:bb:be:f2 brd ff:ff:ff:ff:ff:ff
inet 192.168.122.1/24 brd 192.168.122.255 scope global virbr0
16: veth0: <broadcast,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast master virbr0 state UP qlen 1000
link/ether 8e:05:b2:bb:be:f2 brd ff:ff:ff:ff:ff:ff
inet6 fe80::8c05:b2ff:febb:bef2/64 scope link
valid_lft forever preferred_lft forever
# virsh -c lxc:// list
Id Name State
———————————-
13261 test11 running
# ssh root@192.168.122.190
root@192.168.122.190’s password:
root@192.168.122.190’s password:
Welcome to Ubuntu 11.10 (GNU/Linux 3.1.3-030103-generic x86_64)
* Documentation: https://help.ubuntu.com/
Last login: Tue Jan 17 03:50:29 2012 from 192.168.122.1
root@test11:~# # мы в контейнере
# virsh -c lxc:/// create lxc.xml
Domain test created from lxc.xml
# virsh -c lxc:/// list
Id Name State
———————————-
21834 test running
# ip addr show
…….
10: virbr0: <broadcast,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP
link/ether 8e:05:b2:bb:be:f2 brd ff:ff:ff:ff:ff:ff
inet 192.168.122.1/24 brd 192.168.122.255 scope global virbr0
16: veth0: <broadcast,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast master virbr0 state UP qlen 1000
link/ether 8e:05:b2:bb:be:f2 brd ff:ff:ff:ff:ff:ff
inet6 fe80::8c05:b2ff:febb:bef2/64 scope link
valid_lft forever preferred_lft forever
# virsh -c lxc:// list
Id Name State
———————————-
13261 test11 running
# ssh root@192.168.122.190
root@192.168.122.190’s password:
root@192.168.122.190’s password:
Welcome to Ubuntu 11.10 (GNU/Linux 3.1.3-030103-generic x86_64)
* Documentation: https://help.ubuntu.com/
Last login: Tue Jan 17 03:50:29 2012 from 192.168.122.1
root@test11:~# # мы в контейнере
libvirt позволяет удобнее програмно контролировать контейнеры, чем lxc-xxx.
Без подсветки синтаксиса
#!/bin/env python
# -*- coding:utf8 -*-
import time
import socket
import libvirt
c = libvirt.open(«lxc:///»)
dom = open(«lxc.xml»).read()
t = time.time()
c.createXML(dom, 0)
print «Time 1», time.time() — t
try:
while True:
try:
socket.socket().connect((«192.168.122.190», 22))
print «SSH available after», time.time() — t, «seconds»
break
except:
# на самм деле будет спать больше
time.sleep(0.001)
finally:
vm = c.lookupByName(‘test11’)
vm.destroy()
#!/bin/env python
# -*- coding:utf8 -*-
import time
import socket
import libvirt
c = libvirt.open(«lxc:///»)
dom = open(«lxc.xml»).read()
t = time.time()
c.createXML(dom, 0)
print «Time 1», time.time() — t
try:
while True:
try:
socket.socket().connect((«192.168.122.190», 22))
print «SSH available after», time.time() — t, «seconds»
break
except:
# на самм деле будет спать больше
time.sleep(0.001)
finally:
vm = c.lookupByName(‘test11’)
vm.destroy()
Этот quick-and-dirty скрипт дает время старта контейнера — 0.1±0.02сек, полной загрузки до готовности ssh сервера — 0.9±0.05сек на core i7-2630QM @ 2.00GHz (ноутбучный процессор). Примерно в 1.5 раза меньше времени нужно для старта на Core i5-650 @ 3.20GHz.
footer
И напоследок о другой стороне контейнеров — запуск отдельных приложений в изолированных окружениях ( a-la FreeBSD jail). Практически бесплатность создания контейнера (порядка десятка системных вызовов) создает интересные возможности. Например можно вынести в контейнеры исполнение потенциально опасного кода, отдельных сервисов и проч. Уже есть реализация подобной идеи — arkose. Он позволяет запускать потенциально опасные приложения в отдельных контейнерах, например браузер.
Подведем итоги — по сумме характеристик LXC очень серьезный конкурент для классической виртуализации (KVM/XEN). Пока его промышленное применение сдерживается некоторым объемом недоработок (но перспективы весьма радужные), но для «домашнего» использования он уже вполне готов.
Ссылки:
lxc.sourceforge.net
tr.opensu
se.org/OpenVZ_virtualization#Density
eos.aristanetworks.com/2011/06/linux-namespaces-at-arista
en.wikipedia.org/wiki/Cgroups
linux.die.net/man/7/capabilities
en.gentoo-wiki.com/wiki/LXC#MAJOR_Temporary_Problems_with_LXC_-_READ_THIS
code.launchpad.net/~zulcss/nova/nova-lxc
wiki.debian.org/LXC
en.gentoo-wiki.com/wiki/LXC
habrahabr.ru/blogs/virtualization/130522
lxc.sourceforge.net/man/lxc.html
lxc.teegra.net
nigel.mcnie.name/blog/a-five-minute-guide-to-linux-containers-for-debian
help.ubuntu.com/community/LXC
www.markus-gattol.name/ws/linux_containers.html
blog.mraw.org/2011/04/05/Running_X_from_LXC
libvirt.org/drvlxc.html
kernelnewbies.org/Linux_3.2#head-782dd8358611718f0d8468ee7034c760ba5a20d3
koder-ua.blogspot.com/2012/01/libvirt-co-3.html
www.iip.net.pl/sites/default/files/41/Benchmarking%20the%20performance%20of%20virtualized%20routers.pdf
launchpad.net/arkose
en.wikipedia.org/wiki/FreeBSD_jail
lists.ubuntu.com/archives/ubuntu-server-bugs/2011-February/051503.html
www.redhat.com/archives/libvir-list/2010-January/msg00218.html
libvirt.org/drvlxc.html
upstart.ubuntu.com
en.wikipedia.org/wiki/TCP_offload_engine
wiki.openvz.org/Virtual_Ethernet_device
wiki.ncl.cs.columbia.edu/wiki/KVMARM:MainPage
Исходники этого и других постов со скриптами лежат тут — github.com/koder-ua. При использовании их, пожалуйста, ссылайтесь на koder-ua.blogspot.com.
Автор: konstantin danilov