Кластер, который всегда с собой

    lxcЗахотелось странного.
    Во-первых, взгромоздить кучу виртуальных машин прямо на свой ноутбук.
    А во-вторых, раскурить одну виртуализацию внутри другой.

    Речь пойдет про использование контейнеров LXC, причем внутри другой виртуальной машины.



    WTF! На кой это нужно?


    Прежде всего, для экспериментов с различными инструментами:
    • Распределенные базы данных, файловые системы, параллельные вычисления и т.д.
    • Системы управления инфраструктурой (типа Chef, Puppet, Fabric и т.п.)
    • Тестирование и сборка в разных окружениях
    • Ваш вариант (пишите в комментариях)

    При этом хочется иметь доступ к этой лаборатории всегда, вне зависимости от доступности интернета. Ну почему бы где-нибудь в дороге не раскурить какой-нибудь Hadoop? :-)

    Думаю, эта заметка будет полезна как тем, у кого на десктопе Windows или Mac OS X, так и тем, у кого Linux (часть про LXC).


    Задача


    Запустить на среднем ноутбуке 10-20 виртуальных машин, которые
        – могут ходить в интернет (через NAT)
        – видят друг друга и хост-компьютер (то есть, наш ноут)
        – доступны с хост-компьютера (то есть по ssh можно зайти на любую из этих виртуальных машин)


    Решение


    1. На компьютере (с Windows или Mac OS X) запустить VirtualBox
    2. Установить на нем Linux
    3. Внутри Linux-а наделать кучу LXC-контейнеров с независимыми Linux-ами

    Собственно, на этом можно было бы поставить точку.
    Ниже приведена просто пошаговая шпаргалка (использовался Ubuntu), как все это настроить быстро.



    1. Устанавливаем VirtualBox и систему на виртуальную машину


    Здесь особо и описывать нечего.
    После установки системы — не забыть поставить Guest Additions.


    2. Настраиваем сетевые интерфейсы в VirtualBox


    У виртуальной машины должно быть два сетевых интерфейса:
    • Тип подключения NAT (он создается по умолчанию). Через него наши виртуалки смогут ходить в интернет (например, чтобы скачивать пакеты).
    • Тип подключения Host-only networking (по-русски это называется «Виртуальный адаптер хоста»).
    Для того чтобы добавить Host-only интерфейс сначала идем в общие настройки Virtualbox и добавляем Host-only адаптер на хостовой машине. Затем в конфигурации виртуальной машины добавляем второй интерфейс.

    Важно! Нужно разрешить «Promiscuous mode» («Неразборчивый режим») на Host-only интерфейсе. Это позволит контейнерам видеть хост-машину и друг друга.

    Virtual box - Promiscuous mode


    3. Настраиваем сетевые интерфейсы


    В гостевой системе нужно сконфигурировать bridge-интерфейсы. Они нам потребуются для работы сети в контейнерах. Для этого нужно установить пакет bridge-utils (# apt-get install bridge-utils) и внести изменения в файл /etc/network/interfaces (см. man bridge-utils-interfaces).
    Должно получиться что-то похожее:
    Было Стало
    auto eth0
    iface eth0 inet dhcp
    
    auto br0
    iface br0 inet dhcp
        bridge_ports eth0
        bridge_fd 0
    
    auto br1
    iface br1 inet static
        address 192.168.56.2
        netmask 255.255.255.0
        bridge_ports eth1
        bridge_fd 0
    IP-адрес на br0 (eth0) пусть назначается самим VirtualBox-ом по DHCP, нам этот адрес и знать-то не нужно. А на br1 (eth1) назначим IP-адрес руками — так удобнее, потом на него по ssh будем ходить с хост-машины.

    Перезапускаем виртуальную машину чтобы убедиться, что оба интерфейса внутри виртуальной машины поднимаются, сама виртуальная машина доступна по адресу 192.168.56.2 (через Host-only интерфейс) и внутри неё доступен интернет (через NAT-интерфейс).


    4. Монтируем файловую систему cgroup


    Для работы LXC-контейнеров нужна служебная файловая система cgroup. Точка монтирования не важна - можно смонтировать куда угодно.

    Добавляем строчку в /etc/fstab:
    cgroup  /var/local/cgroup  cgroup  defaults  0  0

    и монтируем
    mkdir /var/local/cgroup
    mount cgroup
    
    В Ubuntu 11.10 (oneiric) cgroup руками монтировать не нужно. Пакет lxc зависит от пакета cgroup-lite, который монтирует cgroup в /sys/fs/cgroup/

    5. Устанавливаем пакеты для работы с LXC


    apt-get install lxc
    apt-get install debootstrap

    Пакет lxc содержит утилиты для управления и скрипты для создания контейнеров. Пакет debootstrap — это утилита, которая скачивает нужные пакеты и разворачивает минимальную базовую систему (ubuntu или debian). Кроме того, есть пакет febootstrap — он скачивает и разворачивает Fedora.
    Самый быстрый способ изучить lxc: набрать lxc- и нажать два раза "Tab"

    6. Создаем первый LXC-контейнер


    В каталоге /usr/lib/lxc/templates/ есть файлы вида lxc-debian, lxc-natty, lxc-oneiric, lxc-fedora и т.п. Это так называемые «шаблоны». На самом деле это скрипты, которые создают соответствующее рабочее окружение.

    Создаем контейнер (c Ubuntu 11.04)
    lxc-create -n node01 -t natty

    Наш контейнер появится в каталоге /var/lib/lxc/node01/.
    Во создаваемом окружении у пользователя root пароль "root". Не забудьте поменять!
    В Ubuntu 11.10 (oneiric) пакет lxc посвежее: шаблону "ubuntu" можно передать параметры, в том числе желаемую версию дистрибутива. Чтобы узнать, какие параметры принимает шаблон, выполните lxc-create --template ubuntu --help

    7. Настраиваем сеть в контейнере


    7.1. Сетевые интерфейсы


    В конфигурационном файле контейнера не хватает параметров сети – их нужно добавить руками. Потом можно будет использовать шаблонный конфиг или просто клонировать контейнер.

    Открываем файл
    vi /var/lib/lxc/node01/config

    и добавляем такие строчки (ставим нужные нам MAC- и IP-адреса):
    lxc.network.type = veth
    lxc.network.flags = up
    lxc.network.link = br0        <- это реальный интерфейс
    lxc.network.name = eth0       <- это интерфейс внутри контейнера
    lxc.network.hwaddr = ac:de:48:00:00:01
    lxc.network.ipv4 = 10.0.2.101/24
    
    lxc.network.type = veth
    lxc.network.flags = up
    lxc.network.link = br1
    lxc.network.name = eth1
    lxc.network.hwaddr = ac:de:48:00:ff:01
    lxc.network.ipv4 = 192.168.56.101/24
    

    Здесь 10.0.2.101/24 – это сеть, которая обычно используется для NAT-интерфейсов в VirtualBox. Через этот интерфейс контейнер будет выходить в интернет.
    192.168.56.101/24 – это наша Host-Only сеть. Через этот интерфейс контейнер будет общаться с локальной сетью и другими контейнерами.

    Рекомендую устанавливать MAC-адрес и IP-адрес вручную. Это делать не обязательно, но удобно. Например, когда нужно послушать сетевой трафик. Я во всех номерах ставлю одинаковую последнюю цифру (node01 – 10.0.2.101 – ac:de:48:00:00:01).

    Обратите внимание, файл конфигурации интерфейсов /etc/network/interfaces внутри контейнера не нужно трогать. Интерфейсы достаточно настроить снаружи.


    7.2. DNS в контейнере


    Добавляем что-нибудь осмысленное в /etc/resolv.conf, чтобы заработал DNS:
    echo "nameserver 8.8.8.8" > /var/lib/lxc/node01/rootfs/etc/resolv.conf
    Для локального разрешения адресов можно обойтись /etc/hosts. Файл /etc/hosts можно сделать общим для всех контейнеров, если смонтировать его с опцией bind.


    8. Запускаем и проверяем контейнер


    Запускаем контейнер
    lxc-start --logfile /tmp/lxc-node01.log --logpriority DEBUG --name node01

    Заходим (root/root) и проверяем, что сеть доступна во все стороны.
    Чтобы запустить контейнер в фоновом режиме надо добавить ключ "--daemon"

    9. Клонируем контейнеры


    Для клонирования контейнеров достаточно скопировать его целиком
    cp -a node01 node02

    и поправить конфигурационные файлы (пути, MAC- и IP-адреса):
    vi node02/config
    vi node02/fstab
    vi node02/rootfs/etc/hostname
    Начиная с версии lxc 0.7.5 появилась утилита lxc-clone. Она корректно правит пути и hostname, но IP-адреса все равно нужно отредактировать руками

    10. Автозапуск контейнеров


    В пакет lxc входит скрипт /etc/init.d/lxc, который запускает определенные контейнеры при старте системы. В файле /etc/default/lxc нужно перечислить, какие контейнеры запускать. Этот скрипт ожидает, что конфигурационные файлы контейнеров лежат в /etc/lxc и имеют расширение *.conf.
    Я просто наделал симлинков:
    /var/lib/lxc/nodeXX/config -> /etc/lxc/nodeXX.conf


    11. Как еще можно облагородить эту кухню


    • Написать скрипты, которые автоматизируют рутину по созданию контейнеров (шаблонный конфиг, установка IP-адресов, создание пользователей, настройка ssh по ключам и т.п.)
    • Установить прокси apt-cacher-ng, чтобы не качать одни и те же пакеты по нескольку раз
    • Смонтировать каталоги и файлы (с помощью опции bind), так чтобы некоторые файлы были общими
    • Поставить контейнеры под управление libvirt (Я не пробовал. Возможно, это тема для отдельной заметки)
    • Попробовать aufs для запуска “наложенных” (overlay) контейнеров, когда неизменяемые файлы могут быть общими для всех контейнеров (а также утилиту lxc-start-ephemeral).
    Поделиться публикацией
    Похожие публикации
    Реклама помогает поддерживать и развивать наши сервисы

    Подробнее
    Реклама
    Комментарии 58
    • +13
      Давно я такого на хабре не видел. Образцово-показательный пример того, как правильно писать и оформлять статьи.
      • +19
        Вы бы знали, друзья, как я натрахался с хабровским редактором. Чтобы хоть как-то смотрелось читаемо, пришлось натыкать 100500 <br>. Так еще и preview показывает не то, что будет в действительности.
        • +4
          Превью они сломали. Даже сложные комменты приходится «отлаживать» через сохранённый черновик поста.
      • +2
        Хорошая статья. А по производительности не сравнивали контейнеры и виртуализацию?
        • 0
          У LXC производительность должна быть такой же как у OpenVZ. Важным отличием является то, что lxc есть в ванильной ветке и не является набором хаков и кривых патчей на ядро.
          • НЛО прилетело и опубликовало эту надпись здесь
            • +1
              +1
              Насколько мне известно OpenVZ с удовольствием перенесли бы свои патчи в ядро и с успехом это делают (LXC во многом их работа). Только вот протолкнуть патч в ядро это весьма и весьма сложная задача, причём далеко не только техническая.
              • –1
                Любые патчи в ядро могут привести к внезапной неработе чегонибудь. + Вы ограничены набором ядер, на которых это хоть как-то тестировалось.
                • НЛО прилетело и опубликовало эту надпись здесь
              • НЛО прилетело и опубликовало эту надпись здесь
                • 0
                  Я так подозреваю, в ванильной ветке будет дополнительный функционал в namespaces и cgroups.

                  После этого, lxc и openvz будут их одинаково использовать, возможно предоставляя различные интерфейсы в userspace.

                  Ведь на самом деле, в ядре нет ни lxc, ни kvm ни т.д. — там есть несколько другие вещи, которые могут использоваться множеством продуктов.
              • 0
                Предложите общедоступный тест и сравним :)
              • 0
                >>В создаваемом окружении у пользователя root пароль «root». Не забудьте поменять!
                А если разворачиваем ubuntu/natty, в юбунтах ведь нет юзера root вроде?
                • 0
                  Есть, но он без пароля. По этому вход им невозможен.
                  • 0
                    Ну я это и имел ввиду, что не возможно с него залогиниться… Отсюда вопрос автору топика, о дефолтных данных логина в юбунте…
                    • 0
                      Если вы ставите пароль для root в Ubuntu то без проблем на него логинетесь.
                  • +1
                    root есть везде. Это такая штука, которая в ядро вшита намертво.
                    • +1
                      На самом деле уже практически нет. Сравнений типа euid == 0 не осталось эдак с средних версий Linux 2.2.
                    • 0
                      есть, но пока ему не выставить пароль руками, под него не зайти… и правильно… используем sudo
                      • 0
                        Ага, спасибо, теперь понял…
                      • 0
                        В контейнер разворачивается система не задавая вопросов, в том числе про пользователя.Поэтому у вас будет только root с паролем root. Это не проблема, пока вы об этом помните.

                        Как я писал, «шаблон» lxc-контейнера — это просто shell скрипт, так что если нужно, можно это скрипт доработать и добавить туда все что угодно, в том числе создание обычного пользователя.
                      • 0
                        Хорошая статья. Как время появится, попробую с её помощью «поиграть» с контейнерами.
                        Автору — спасибо!
                        • +1
                          А можно ещё небольшое сравнение OpenVZ vs LXC?

                          Поверхностный поиск показал, что полноценных виртуалок на нём пока не сделать — нет возможности выставлять ограничения по RAM и ограничивать нагрузку на CPU.
                          Т.е. LXC фактически — значительно улучшенный вариант обычного chroot'а.

                          Всё действительно так и есть?
                          • 0
                            Как я понял, LXC это не просто chroot, но и еще независимые сетевые стеки. Но по факту всё исполняется на текущем ядре ОС, только чуть изолировано.
                            • НЛО прилетело и опубликовало эту надпись здесь
                              • 0
                                Да, коллеги. Обязательно прочитайие эту заметку, чтобы лучше понять, что такое OpenVZ и LXC.
                                • 0
                                  Кое-где Колышкин лукавит.
                                  Особенно о том чего нет в LXC.
                                  К примеру впрыгнуть в контейнер там можно без проблем.
                                  Лучше бы рассказал что там есть по сравнению с OVZ.
                                  К примеру нормальные контроллеры io.
                                  Хороший сетевой стек, который почти полностью абстрагируется от хостового.
                                  etc
                              • 0
                                LXC не предназначен для распродажи виртуалок хостерами. Это програмно-изолированный контейнер со своим пространством процессов (нельзя по pid стучаться между виртуалками), имеющий свой сетевой стек, etc. Что-то типа jail в BSD-системах. Какие либо решения с ограничением ресурсов lxc-контейнеров на текущий момент носят характер костылей.
                                • 0
                                  Зачем же сразу продавать?
                                  Если у меня есть DNS сервер и я чётко понимаю его потребности в RAM, то есть смысл (на всякий случай) ему подобные лимиты выставить жестко.
                                  Аналогично с другим софтом.

                                  Но в принципе понятно, спасибо.
                                  • 0
                                    Ну если так, то можно использовать cgroup.
                                  • 0
                                    FirstVDS (и не только они) уже много лет продает виртуалки на FreeBSD jail и прекрасно себя чувствует.
                                • 0
                                  Статья очень хорошая, сам недавно бился над вопросом связанным с созданием mongodb кластера. По этому приходилось запускать несколько копий дебиана на виртуалке. А этот подход упрощает всё в корне.
                                  • +2
                                    Я вот буду краток.
                                    lxc.tl/
                                    Идем туда и радостно админим lxc в стиле «я привык к openvz и не люблю думать». Проект пишут 3 сисадмина из Яндекса.
                                    • 0
                                      О, спасибо. Я привык к openvz и я не люблю думать.
                                      • 0
                                        Это не обидно, кстати. Если сисадмину на рутинной работе приходится думать — значит сисадмин неправильно работает. А управление виртуалками — это вполне себе рутина.
                                        • 0
                                          Абсолютно согласен
                                          • 0
                                            Не любить и не уметь — две большие разницы же.
                                      • 0
                                        tnx, завтра буду опробую :)
                                        • 0
                                          Слово «кухня» прочёл правильно с третьего раза :-)
                                          • 0
                                            мм… можно и так :)
                                          • 0
                                            Все прекрасно, но поправьте пожалуйста «Promiscuous mode» («Неразборчивый режим»)
                                            Все же это «смешанный» режим.
                                            • 0
                                              Это не перевод термина. Я всего лишь имел ввиду, что так написано в VirtualBox в русском интерфейсе.
                                              • 0
                                                И правда, не сразу заметил, прошу прощения. Ужас какой-то >_<
                                            • 0
                                              > Установить прокси apt-cacher-ng, чтобы не качать одни и те же пакеты по нескольку раз
                                              А может вариант сделать общий /var/cache/apt/archives/?
                                              Меньше сервисов )
                                              • 0
                                                Да, можно. Я так и сделал в итоге.
                                              • 0
                                                Следовал по инструкции вроде и получил следующее:
                                                root@sicness:/usr/lib/lxc/templates# lxc-start -n node02
                                                lxc-start: cgroup is not mounted
                                                lxc-start: failed to spawn 'node02'
                                                lxc-start: cgroup is not mounted
                                                хотя
                                                root@sicness:/var/lib/lxc/node02# mount | grep cgr
                                                none on /cgroup type cgroup (rw)
                                                Не произошел chroot, наверное потому что в том fstab не указан корень:
                                                root@sicness:/var/lib/lxc/node02# cat fstab
                                                proc /var/lib/lxc/node02/rootfs/proc proc nodev,noexec,nosuid 0 0
                                                sysfs /var/lib/lxc/node02/rootfs/sys sysfs defaults 0 0

                                                Подскажите, пожалуйста, где ошибся.
                                                • 0
                                                  С fstab все впорядке. Откуда будет «расти» корень контейнера — задается в конфиге в lxc.rootfs.
                                                  Неплохо бы запустить скрипт lxc-checkconfig (проверяет конфигурацию ядра).

                                                  Если не разобрался — пиши в личку или почту.
                                                  • 0
                                                    Перезагрузился. Ввел mount /cgroup сказал что уже. Ввел umount /cgroup скажал что не примонтирован. Ввел еще раз mount /cgroup сработало. Все стартануло.
                                                    Толи система проключила, то ли я :)
                                                    Спасибо за статью, весьма юзабилити.
                                                • 0
                                                  По поводу облагораживания здесь кое-что можно подчерпнуть.
                                                  • 0
                                                    В Ubuntu 11.10 Server поставил LXC

                                                    Не смотря на то что в файле /etc/default/lxc параметр указывающий путь конфиг файлов контейнеров для автостарта CONF_DIR=/etc/lxc

                                                    Файлы .conf всё-же нужно располагать в /etc/lxc/auto/
                                                    Может кому пригодиться.
                                                    • 0
                                                      Здравствуйте. Как быть, если дополнительные адреса для виртуалок настоящие «белые» и по ним контейнеры должны быть видны снаружи из мира?

                                                      То есть имеется железный сервак на Hetzner, а на нём требуется развернуть пару виртуалок для изолированных задач. Текущий конфиг сети хоста такой:

                                                      auto lo
                                                      iface lo inet loopback
                                                      
                                                      auto  eth0
                                                      iface eth0 inet static
                                                       address   176.9.51.109
                                                       broadcast 176.9.51.127
                                                       netmask   255.255.255.224
                                                       gateway   176.9.51.97
                                                      
                                                      up route add -net 176.9.51.96 netmask 255.255.255.224 gw 176.9.51.97 eth0

                                                      Есть два дополнительных адреса (Hetzner их даёт из другой подсети почему-то):

                                                      176.9.69.13
                                                      176.9.69.14

                                                      Создал через LXC гостевую машину vm1 с помощью lxc-create. Машина завелась, но сеть в ней по дефолту не работает (как и ожидалось, в общем-то).

                                                      А надо в итоге сделать две виртуальных гостевых машины (vm1 и vm2) доступными из вне по 176.9.69.13 и 176.9.69.14, соответственно. Текущий IP хоста 176.9.51.109 при этом никак с пользой дела использовать не требуется (пусть остаётся исключительно для хост-машины).

                                                      В связи с чем три вопроса:

                                                      1. Чего понаписать в конфиге хоста /etc/network/interfaces (как его изменить, чтобы начались слушаться два дополнительных IP и их можно было прокинуть к виртуалькам)?

                                                      2. Чего добавить в /var/lib/lxc/vm1/config (какие имена интерфейсов, какой IP)?

                                                      3. Чего написать в конфиг /etc/network/interfaces на гостевой виртуальной машине?

                                                      Буду очень признателен за конкретные указания.
                                                      • 0
                                                        1. На хост-машине нужно настроить бридж br0 и связать его с интерфейсом eth0:

                                                        auto br0
                                                        iface br0 inet static
                                                        address 176.9.51.109
                                                        netmask 255.255.255.224
                                                        gateway 176.9.51.97
                                                        bridge_ports eth0
                                                        bridge_fd 0
                                                        К слову, «up route add», по-моему, здесь не нужен.

                                                        2. В конфиге /var/lib/lxc/vm1/config нужно указать ваш IP-адрес (176.9.69.13) и маску (в формате /NN)
                                                        lxc.network.link = br0
                                                        lxc.network.name = eth0
                                                        lxc.network.ipv4 = 176.9.69.13/NN

                                                        3. В контейнере в /etc/network/interfaces нужно тоже указать ваш IP-адрес (176.9.69.13), маску (в формате 255.255.255.MMM)
                                                        и шлюз, который сказал провайдер.
                                                        • 0
                                                          Огромное спасибо! Буду пробовать и позже расскажу, что получилось (или не получилось).

                                                          > К слову, «up route add», по-моему, здесь не нужен.

                                                          Это дефолтная настройка от самого Hetzner, они её там комментируют вот так:
                                                          # default route to access subnet
                                                          • 0
                                                            Всё заработало! Спасибо вам.

                                                            /NN посчитал этим калькулятором (вышло /29), а шлюз и маску Hetzner высылает в письме с подтверждением о выделение дополнительного IP, ищите соответствующие письма по теме «Additional IP address for server...» (это примечание для тех, кто также как и я безуспешно попытается найти реквизиты сетей в веб-интерфейсе robot`а).
                                                        • 0
                                                          Скажите, я правильно понимаю, что root в контейнере = root в хосте?
                                                          • 0
                                                            нет, не правильно
                                                          • 0
                                                            Отличная статья. Спасибо! Но проясните один момент: зачем интерфейсы eth* заменяются на br*. Я не силен в конфигурировании сетей, особенно под Linux, а быстрый поиск мне не помог. Кстати у меня на Ubuntu 12.04 после перезагрузки интерфейсы eth* сохранились (в выводе ifconfig) и мешали запустить контейнеры (сообщение близко к тексту):
                                                            Coudn't rename <...> into eth0: File already exists

                                                            Причем ifdown почему-то их не выключал. Пришлось в конфигурации контейнеров использовать eth2 и eth3. После этого заработало.
                                                            • 0
                                                              К слову, OpenVZ тоже без проблем работает внутри VirtualBOX виртуалки.

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