Создание метода клонирования LXC-контейнеров

Немножко предыстории

В конце прошлого года, когда пришло время начинать писать диплом, я наткнулся на статью пользователя am83. Так как я крайне неравнодушен к виртуализации, хотелось придумать что-то относящееся к этой теме. И тут у меня родилась идея по поводу использования общей файловой системы для создания метода, который бы позволил сэкономить дисковое пространство при клонировании контейнеров LXC.

Итак, на основе статьи, написанной am83, я проделал несколько шагов для создания общей файловой системы.
Создание основы файловой системы для контейнеров

Устанавливаем основные компоненты, которые понадобятся для создания общей файловой системы, командой:
$ apt-get install debootstrap lxc lxc-templates lxctl cgroup-lite rsync

Далее включим две управляющие опции.
В конфигурации сети включим сетевой мост для контейнеров:
$ nano /etc/init/lxc-net.conf
USE_LXC_BRIDGE="true"

А для автозапуска контейнеров при старте системы включим:
LXC_AUTO="true"

В файле lxc.conf, командой:
$ nano /etc/init/lxc.conf

Далее отредактируем конфигурационный файл:
$ nano /etc/default/lxc

И добавим в него следующие строки:
Введем переменную:
$ lxcRoot="/lxc"

Создадим каталог /lxc:
$ mkdir -p ${lxcRoot}

Создаем место где хранятся контейнеры и информация по их настройкам, а также место кеширования данных дистрибутивов для ускорения создания множества контейнеров:
$ mkdir /${lxcRoot}/lxclib /${lxcRoot}/lxccache

Удалим старый каталог:
$ rm -rf /var/lib/lxc /var/cache/lxc

Создадим ссылки на каталоги:
$ ln -s /${lxcRoot}/lxclib /var/lib/lxc
$ ln -s /${lxcRoot}/lxccache /var/cache/lxc

Создаем базовый LXC-контейнер на основе Ubuntu с именем hName и с версией Trusty:
$ lxc-create -t ubuntu -n hName -r trusty

Далее приступим к созданию неизменяемой части LXC-контейнера.
Переходим в каталог созданного контейнера:
$ cd /lxc/lxclib/hName/rootfs

В нем создаем каталог с общей частью, назовем его common:
$ mkdir common

Переносим в него неизменяемые каталоги:
$ mv bin lib lib64 sbin usr common/

Создаем символические ссылки на них:
$ ln -s common/bin
$ ln -s common/sbin
$ ln -s common/lib
$ ln -s common/lib64
$ ln -s common/usr

Создание контейнера LXC

После подготовки базового образа системы приступим непосредственно к созданию первого контейнера в системе. Назовем его просто «Node1»:
Создаем каталог для первого контейнера:
$ mkdir -p /lxc/lxclib/Node1/rootfs

Переходим в него:
$ cd /lxc/lxclib/Node1/rootfs

При помощи программы rsync копируем неизменяемую часть в первый контейнер:
$ rsync --exclude=/dev/* --exclude=/common/* -avz /lxc/lxclib/hName/rootfs/* ./

Далее для первого контейнера создаем два каталога для общей части и для устройств:
$ mkdir /lxc/lxclib/Node1/rootfs/common
$ mkdir /lxc/lxclib/Node1/rootfs/dev

Монтируем их при помощи программы Bind:
$ mount --bind /lxc/lxclib/hName/rootfs/dev /lxc/lxclib/Node1/rootfs/dev
$ mount --bind /lxc/lxclib/hName/rootfs/common /lxc/lxclib/Node1/rootfs/common
$ mount -o remount,ro /lxc/lxclib/Node1/rootfs/common

Копируем файл конфигурации и файл fstab из базового контейнера в первый:
$ cp /lxc/lxclib/hName/config /lxc/lxclib/Node1/
$ cp /lxc/lxclib/hName/fstab /lxc/lxclib/Node1/

Меняем имя в конфигурации первого контейнера на Node1, а также MAC-адрес:
$ nano /lxc/lxclib/Node1/config


Метод клонирования


Скрипт, который я написал выглядит следующим образом:
#!/bin/bash
echo "Введите имя нового контейнера: "
read Container
cp -a /lxc/lxclib/Node1 /lxc/lxclib/${Container}
mount --bind /lxc/lxclib/hName/rootfs/dev /lxc/lxclib/${Container}/rootfs/dev
mount --bind /lxc/lxclib/hName/rootfs/common /lxc/lxclib/${Container}/rootfs/common
mount -o remount,ro /lxc/lxclib/${Container}/rootfs/common
sed -i 's/Node1/'$Container'/g' /lxc/lxclib/${Container}/config
echo "Новый контейнер с именем" $Container "создан"


Сравнительные характеристики со стандартным методом lxc-clone


Что это нам дает?
Во-первых я хотел сэкономить дисковое пространство.
Узнаем размер, занимаемый на диске контейнером:
$ du –skh /lxc/lxclib/Имя_контейнера

На рисунке видно, что объем, занимаемый базовым контейнером составляет 395 мегабайт, тогда как объем, занимаемый контейнером, клонированным моим методом, составляет всего 141 мегабайт:





Исходя из вышеперечисленных данных – экономия дискового пространства с каждого контейнера выходит порядка 65%. То есть при применении данного метода, например, на серверной ферме с сотнями контейнеров экономия дискового пространства весьма заметна.

Во-вторых, не слишком впечатляющая, но все же скорость копирования контейнера.
Стандартный способ клонирования выполняется командой:
Замерим скорость клонирования командой time.
Time – выводит на экран время выполнения (в секундах) запускаемой команды. Подставляется перед любой выполняемой командой.
На рисунках представлено время выполнения команды стандартным способом клонирования контейнеров и моим:





Исходя из вышеперечисленных данных видно, что время выполнения клонирования контейнера стандартным способом занимает более 12 секунд, тогда как время выполнения клонирования моим способом, занимает около 6 секунд.

В итоге


Возможно, мою идею и не стоит использовать в продакшене на предприятии, но мне видится использование сего метода на мини-компьютерах. Ведь, поднимая несколько контейнеров на sd-карте, экономия пару сотен мегабайт с одного контейнера будет неплохим выигрышем.

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

    +1
    Хм, docker + UnionFS?
      +4
      docker и так из коробки на aufs работал же.
        0
        Пардон, я это и имелл ввиду. Docker не как конкретная утилита, а как метод создания образов lxc.
        + aufs не совсем обязательно для него.
          0
          Спасибо! Даже не знал, что в Docker уже есть подобная штука.
          Просто на момент продумывания диплома (осень прошлого года) посчитал, что Docker еще сыроват…
            0
            Мне чистый lxc для своих нужд нравиться больше, чем docker, однако у последнего есть чему поучиться в плане модели. Еще вот тут интересная модель расписана.
            В production же docker уже стандарт, по сути.
              0
              > В production же docker уже стандарт, по сути.

              ага, вот только никто его в продашне не юзает.
                0
                Yandex.Cocaine же.
                habrahabr.ru/company/yandex/blog/214069/

                Здесь Яндекс рассказывает в частности, где в их продуктах есть cocaine.
                  0
                  У вас сть данные по всем компаниям в интернете и их инфраструктуре?
                  Помимо уже обозначенного яндекса у гугла есть свои уже готовые темплейты и надстройки на докером. И вот еще список.
        0
        боян
        схожим образом достижимо на openvz и lxc штатными средствами
          0
          А я запихнул /var/lib/lxc в btrfs и клонирую снепшотами

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

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