Контейнеры линукс что это

Обновлено: 05.07.2024

Пришло время научиться работать с Linux Containers, более известными под названием LXC. Далее мы будем рассматривать LXC в контексте Debian и Ubuntu, но написанное во многом будет применимо и для других дистрибутивов Linux. Мы коснемся не только основ использования LXC, но и узнаем, как настроить bridged сеть, ограничить количество ресурсов, используемых контейнером, и даже осилим unprivileged containers.

Коротко о главном

Control Groups, они же cgroups, позволяют организовывать процессы в группы и для каждой группы задавать лимиты. Например, лимиты на использование CPU, объем используемой памяти и дисковый ввод-вывод.

Примечание: Кстати, в заметке Начало работы с Vagrant и зачем он вообще нужен рассказывается, как работать с LXC через Vagrant. Использование LXC через Vagrant кому-то может показаться удобнее, чем работа с LXC напрямую.

Установка

Как было отмечено выше, все необходимое уже есть в ядре. Тем не менее, для хождения в ядро понадобятся некоторые дополнительные утилиты. Также не повредит обновить до последней версии кое-какие, казалось бы, не особо связанные с LXC пакеты.

sudo apt-get update
sudo apt-get install lxc lxc-templates systemd-services cgroup-bin \
bridge-utils debootstrap

Очень важно реально сделать update, чтобы поставились наиболее свежие версии указанных пакетов. И, не поверите, но реально лучше сразу сделать reboot . Иначе, работая с LXC, вы в какой-то момент можете получить странную ошибку вроде такой:

call to cgmanager_create_sync failed: invalid request

Свои данные LXC хранит в следующих местах:

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

Основные команды

Создание контейнера с именем test-container из шаблона Ubuntu:

Увидим что-то вроде:

Посмотреть список доступных шаблонов можно так:

Список скачанных шаблонов:

Удалить шаблон можно просто удалив соответствующий ему каталог.

Запуск контейнера в бэкграунде:

Подробная информация о контейнере:

Заходим в контейнер:

Создание клона контейнера (test-container должен быть остановлен):

sudo lxc-clone -o test-container -n test-container-clone sudo lxc-freeze -n test-container
sudo lxc-unfreeze -n test-container

Создать снапшот (контейнер должен быть остановлен):

Восстановление из снапшота:

Если нужно пошарить каталог, проще всего сделать это при помощи sshfs:

Пока ничего сложного.

Автозапуск

Чтобы контейнер запускался при старте системы, в конфиг контейнера (в нашем случае это файл /var/lib/lxc/test-container/config) дописываем:

Если все было сделано верно, команда sudo lxc-ls -f покажет YES в колонке autostart.

Ограничение на использование ресурсов

Попробуем ограничить количество памяти, которое может отъедать контейнер.

Затем правим /var/lib/lxc/test-container/config:

sudo lxc-start -d -n test-container -l debug -o test.log
cat test.log | grep -i memory

Должны увидеть что-то вроде:

lxc-start 1449237148.829 DEBUG lxc_cgmanager - cgmanager.c:
cgm_setup_limits:1385 - cgroup 'memory.limit_in_bytes' set to '256M'

Проверяем, что настройки применились:

sudo lxc-cgroup -n test-container memory.limit_in_bytes

Можно менять лимиты на лету, но они потеряются с рестартом:

sudo lxc-cgroup -n test-container memory.limit_in_bytes 100M

Также можно следить, сколько ресурвов потребляет контейнер прямо сейчас:

Вот еще интересные параметры:

Ограничение на использование дискового пространства

Эту задачу можно решить несколькими способами. Например, многие советуют использовать LVM. И хотя LVM, бесспорно, крутая штука, использовать его для решения такой простой задачи мне лично кажется оверкилом. Предлагаю пойти более простым путем.

Допустим, мы хотим создать контейнер с именем new-container, который будет занимать на диске не более 10 Гб.

sudo truncate -s 10G / var / lib / lxc / new-container.img
sudo mkfs.ext4 -F / var / lib / lxc / new-container.img
sudo mkdir / var / lib / lxc / new-container
sudo mount -t ext4 -o loop / var / lib / lxc / new-container.img \
/ var / lib / lxc / new-container

Теперь создаем контейнер, как обычно:

Заходим внутрь контейнера, и через df видим, что отъесть от диска он может только 10 Гб.

Чтобы не приходилось каждый раз монтировать раздел руками, в /etc/fstab дописываем:

/var/lib/lxc/new-container.img /var/lib/lxc/new-container ext4 loop 0 0

Вы можете заметить, что количество loop-устройств в системе ограничено. В Ubuntu, например, их по умолчанию только 8. Если попытаться создать много контейнеров описанным выше образом, вы получите ошибку:

Эту проблему можно решить следующим скриптом:

Чтобы loop-устройства создавались при загрузке системы, создаем файл /etc/init.d/more-loop-devices следующего содержания:

PATH = / sbin: / usr / sbin: / bin: / usr / bin

sudo chmod a+x / etc / init.d / more-loop-devices
sudo update-rc.d more-loop-devices defaults

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

Настройка bridged сети

Ранее в заметке Контейнерная виртуализация при помощи OpenVZ мы научились настраивать bridged сеть под CentOS. Настало время узнать, как то же самое делается в Debian и Ubuntu.

Далее, если у вас DHCP:

auto br0
iface br0 inet dhcp
bridge_ports eth0
bridge_stp off
bridge_fd 0
bridge_maxwait 0

Если же у вас используются статические адреса:

auto br0
iface br0 inet static
address 192.168.0.123
network 192.168.0.0
netmask 255.255.255.0
broadcast 192.168.0.255
gateway 192.168.0.1
bridge_ports eth0
bridge_stp off
bridge_fd 0
bridge_maxwait 0

Далее останавливаем контейнер и правим /var/lib/lxc/(container)/config:

Если хотим присвоить контейнеру статический IP, также дописываем:

Запускаем контейнер. Если все было сделано правильно, в контейнер можно будет ходить из локалки и sudo lxc-ls -f покажет у него соответствующий IP.

Резервное копирование и восстановление

Как уже отмечалось, все лежит в /var/lib/lxc. Поэтому просто нужно аккуратно заархивировать все данные оттуда. Тут каждый использует, что ему больше нравится. Для примера рассмотрим решение задачи при помощи tar.

Останавливаем контейнер, под рутом делаем:

cd / var / lib / lxc / test-container
tar -cvzf backup.tgz . /

Резервная копия готова! Для восстановления же говорим:

Теперь контейнер виден в lxc-ls и может быть запущен через lxc-start .

Если же вы ограничиваете место на диске, которое может занимать контейнер, как это было описано выше, то резервное копирование и восстановление делается еще проще.

Непривилегированные контейнеры

Оказывается, что контейнерами можно управлать и под самыми обыкновенными пользователями, не под рутом. Как минимум, это намного безопаснее.

При этом каталоги немного меняются:

Первым делом говорим:

sudo usermod --add-subuids 100000 - 165536 eax
sudo usermod --add-subgids 100000 - 165536 eax
sudo chmod +x / home / eax

Копируем /etc/lxc/default.conf в

/.config/lxc/default.conf и дописываем в конце:

lxc.id_map = u 0 100000 65536
lxc.id_map = g 0 100000 65536

В файл /etc/lxc/lxc-usernet пишем:

Создаем контейнер (как видите, без sudo):

lxc-create -t download -n test-container -- -d ubuntu \
-r trusty -a amd64

Заметьте, как это работает. Мы указали тип контейнера download, которому передали в качестве аргумента название дистрибутива, релиза и архитектуры CPU. Все эти три параметра обязательны при создании непривилегированных контейнеров.

Теперь запускаем контейнер, как обычно:

В случае возникновения проблем:

lxc-start -d -n test-container --logfile t.log --logpriority debug

Дополнение: Чтобы непривилегированные контейнеры заработали, может потребоваться перезагрузка. Если вы используете encfs, команды sudo и ping могут не работать. Это баг. Здесь рассказывается, как примерно можно его обойти. Идея в том, чтобы при помощи симлинков положить контейнеры и конфиги за пределы encfs.

Ну вот, а в остальном все как обычно.

Заключение

Не могу не отметить ряд косяков в LXC:


При упоминании словосочетания «контейнерная виртуализация», многим на ум сразу же приходят Virtuozzo и OpenVZ, а также Docker. Ассоциируется же это все, в первую очередь, с хостингом, VPS и другими подобными вещами.

Дома, на личных компьютерах многие используют виртуальные машины: в основном, пожалуй, Virtualbox. Как правило, для того, чтобы работая под Linux, иметь под рукой Windows или наоборот. Однако, при наличии множества родственных Linux-операционок, я стал замечать, что использование виртуальных машин — это, мягко говоря, нерационально.

В первую очередь, очень быстро расходуется дисковое пространство. Каждой виртуальной машине нужно место, даже если несколько из них отличаются только конфигами. Особенно критично это на невеликих размеров SSD лаптопа. В принципе, Virtualbox умеет работать с raw-девайсами и, теоретически, машинам можно назначать rw LVM-снапшот, но тут опять же встают вопросы с изменением размера файловой системы в дальнейшем, автоматизацией клонирования, переноса, удаления и тому подобное.

Во вторую — это больший расход оперативной памяти. В третью — не самые удобные инструменты взаимодействия…

Потому, возникла идея опробовать в домашних условиях контейнерную виртуализацию. OpenVZ отмел сразу, по причине необходимости возиться с кастомным ядром. Выбор же пал на LXC, поставляющийся в репозитарии стабильного Debian'a.

Что такое контейнеры и чем это все отличается от виртуализации? В случае контейнеров, не создается виртуальное аппаратное окружение, а используется изолированное пространство процессов и сетевого стека. Скажем так, получается chroot с расширенными возможностями.

Зачем это нужно:

— Для сборки ПО при нежелании захламлять разномастными *-dev пакетами основную рабочую систему.
— Потребность в другом дистрибутиве для запуска каких-либо специфических программ и, опять же, сборки.
— Изоляция потенциально небезопасного софта, вроде того же скайпа совершающего разные непонятные действия в домашнем каталоге пользователя и всяких сомнительных веб-технологий: уязвимость во флеше, в java, в обработчике pdf — это только то, что плавает на поверхности.
— Анонимность. Эдак можно банально остаться залогиненым в своей любимой социалочке, забыть подчистить куки или оказаться незнакомым с очередной новой веб-технологией вроде этой webrtc. Можно, конечно, держать несколько профилей браузера, но от перечисленных выше дыр и технологий это не защитит.

Итак, рассмотрим плюсы и минусы LXC:

+ Работает на ванильном ядре
+ Простота проброса устройств и каталогов хоста, так как работает это все через cgroups
+ Очень нетребовательно к ресурсам, в отличии от виртуальных машин типа Virtualbox или qemu

— Контейнеры будут работать на том же ядре, что и хост, хотя — это скорей особенность контейнерной виртуализации в целом.
— Некоторая недоделанность идущих в комплекте утилит.

Развертывание и настройка контейнера

В первую очередь, ставим пакет lxc и все необходимые утилиты:


Смотрим доступные группы томов LVM:


Указываем использовать LVM в качестве системы хранения, Volume Group ( в моем случае — nethack-vg) и размер 2 гигабайта, иначе по умолчанию будет создан одногиговый том. Хотя, если вдруг стало тесновато, можно будет сделать lvresize.


Видим, что у нас появился том deb_test.

Типовой конфиг, созданный скриптом:




Залогинимся с указанным паролем. Для запуска в headless-режиме используется ключ -d, а рутовую консоль можно получить с помощью команды

Пока у нас ни сети, ни нужных для работы программ. Для этого на хосте поднимаем мост, задаем IP, заворачиваем трафик из подсети виртуалки, при отключении интерфейса разрушаем мост.

На хосте прописываем в /etc/network/interfaces


В конфиг контейнера дописываем:


Понятно, что mac-адрес произвольный, на любой вкус.
Чтобы сразу получить рабочую сеть и возможность установки пакетов apt'ом, допишем

Понятно, что 192.168.18.1 — IP моего DNS.

Установим нужные пакеты:


Дальше либо на хосте, либо на другой рабочей виртуалке можно получить список установленных пакетов и установить их все в нашем новом контейнере:


Теперь можно по-человечески настроить сетевой интерфейс в контейнере, использовав любимый текстовый редактор:


Впрочем, это можно было сделать с хост-системы, например, смонтировав логический том. Способов много.

В принципе, в качестве DNS можно указать любой публичный, если не опасаетесь за свою приватность. Например, гугловские 8.8.8.8 и 8.8.4.4.

По доступу к устройствам хост-системы, я придерживаюсь политики «все, что не разрешено, запрещено». Добавим для этого следующую строчку в конфиг:

Попробуем подключиться через OpenVPN. Сразу же получаем ошибку:



Система пишет, что интерфейсы TUN/TAP недоступны по причине их отсутствия. Очевидно, что нужно разрешить гостевой системе использовать устройства хоста. Открываем конфигурационный файл контейнера, /var/lib/lxc/deb_test/config и добавляем туда строчку:


В контейнере выполняем:


Обратим внимание на 10:200 — это идентификатор типа устройств. Если выполним на хосте:


То увидим идентификаторы 10, 200. По ним и будем ориентироваться, разрешая доступ к устройства, например камере — video0.

Точно также добавляем остальные нужные устройства:

Для функционирования иксов и возможности их проброса через ssh, нужно добавить точку монтирования:


По аналогии можно примонтировать и другие, нужные каталоги и файлы:


Для воспроизведения звука, можно разрешить доступ к звуковому устройству, если карта многопоточная (с однопоточной при использовании dmix возникают проблемы с блокировкой):


А можно настроить pulseaudio на воспроизведение звука по сети, как это описано здесь. Кратко:

Отредактировать на хосте /etc/pulse/default.pa, дописав туда:


В итоге у нас получается вот такой конфиг:

Контейнер готов к использованию.

Использование

Доустановим, например, i2p с Tor'ом, если не сделали этого ранее, и сходу настроим privoxy:

Запускать графические приложения вроде браузера удобнее всего через ssh:


Также, разумеется, LXC предоставляет средства для клонирования контейнеров и снятия снапшотов.

Так, например, склонировать контейнер, файловая система которого будет являться LVM-снапшотом можно командой:



Будет создан контейнер deb_test2 с файловой системой, размещенной на LVM-снапшоте размером 200MB (под хранение diff'ов). Это будет точная копия deb_test, над которой можно провести пару экспериментов и, например, безболезненно удалить.

А вот lxc-snapshot с LVM в качестве хранилища, на версии lxc-1.0.6 почему-то не работает:


Проблема описывается и обсуждается здесь. Потому, снимки придется делать по старинке:


В данном случае создали read-only снапшот с именем deb_test_before_rm_rf размером 100MB. Что с ним делать дальше? Например, его можно сдампить посредством dd, перенести на другую машину вместе с конфигами контейнера, создать там том нужного размера и пролить тем же dd (cp, cat, итд) — эдакая «живая миграция».

Как писалось выше, областей применения контейнерам можно найти массу. Но главной, при домашнем использовании, на мой взгляд, является изоляция приложений.

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

LXC можно расценивать как что-то среднее между изолированным окружением chroot и полноценной технологией виртуализации Qemu, Xen, KVM или VirtualBox. Поскольку все программы выполняются на реальном железе, без использования виртуализации, то вы не теряете производительность, в отличие от случая если бы вы использовали VirtualBox. Вы можете очень легко запустить параллельно несколько контейнеров в своей системе, даже при очень низких аппаратных ресурсах, чего нельзя сделать с полноценными технологиями виртуализации.

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

Что такое контейнеры LXC?

Перед тем как перейти к настройке давайте рассмотрим что из себя представляют контейнеры Linux. Как я уже сказал, это не совсем виртуализация, потому что все программы, которые выполняются внутри контейнера - работают на реальном железе и почти не теряют в производительности. Используется, только одно ядро, а для разграничения наборов процессов между собой применяются виртуальные окружения.

Виртуальные окружения создаются с помощью встроенных в ядро механизмов. Это в первую очередь улучшенный механизм chroot, который изолирует файловую систему контейнера от основной файловой системы. Но, как вы знаете в chroot есть один недостаток, вы не можете запустить систему инициализации, поскольку программа с таким PID уже существует, но это необходимо для управления процессами и службами.

Для решения этой проблемы используются пространства имен PID, с помощью этого механизма PID процессов контейнера не зависят от основной системы и других контейнеров, а поэтому мы можем очень просто запустить систему инициализации. Ну и наконец нужно управлять ресурсами, для этого используется механизм cgroups.

Благодаря всему этому потеря производительности при использовании контейнеров LXC Linux составляет не более 1%. Теперь, когда вы знаете как все это работает, перейдем к описанию процесса установки LXC.

Установка и настройка LXC

В этой инструкции мы будем настраивать LXC в Ubuntu, поскольку это самая популярная операционная система, но все эти команды подойдут для всех других дистрибутивов. Отличие составляет только команда установки. Сначала нужно установить все необходимое программное обеспечение. Установка LXC на Ubuntu выполняется командой:

sudo apt install lxc lxc-templates uidmap

lxc

Дальше нужно задать базовые настройки, которые будут применяться для создания сети в контейнерах и установки других параметров. Сначала создаем папку с конфигурацией:

Настроим пользовательские пространства имен. Первая цифра означает первый UID пользователя linux в контейнере, вторая отвечающий ему UID пользователя в основной системе:

echo "lxc.id_map = u 0 100000 65536" >>

/.config/lxc/default.conf
echo "lxc.id_map = g 0 100000 65536" >>

lxc1

Дальше настраиваем сеть в контейнере:

echo "lxc.network.type = veth" >>

/.config/lxc/default.conf
echo "lxc.network.link = lxcbr0" >>

/.config/lxc/default.conf
echo "lxc.network.flags = up" >>

Затем в файле /etc/lxc/lxc-usernet нужно разрешить использовать сетевые интерфейсы текущему пользователю, чтобы получить возможность запускать контейнер без root прав:

echo "$USER veth lxcbr0 2" | sudo tee -a /etc/lxc/lxc-usernet

Для того чтобы пространства имен пользователей linux в контейнере работали нужно присвоить своему пользователю подпространство UID и GID 100000-165536:

sudo usermod --add-subuids 100000-165536 $USER
sudo usermod --add-subgids 100000-165536 $USER

И даем права на использование данного пользователя в cgm:

sudo cgm create all user
sudo cgm chown all user $(id -u) $(id -g)
cgm movepid all user $$

Теперь первоначальная настройка завершена и мы готовы перейти к загрузке и установке образа контейнера. Для установки в интерактивном режиме наберите такую команду, здесь ubu1, это имя будущего контейнера:

lxc-create --template download --name ubu1

lxc2

В этом списке вам предстоит выбрать нужную операционную систему. Просто введите необходимые параметры, имя, релиз и архитектура, выбрав их из списка доступных, например, для Ubuntu Yakkety Yak 64 бит:

lxc3

Затем начнется загрузка уже готового, настроенного образа из интернета. Это может занять довольно много времени если у вас медленный интернет.

Также вы можете использовать не интерактивный режим и указать все необходимые параметры сразу в командной строке:

lxc-create -t download -n ubu1 -- --dist ubuntu --release xenial --arch amd64

lxc4

После завершения загрузки контейнера первоначальная установка будет завершена и мы можем перейти дальше.

Использование контейнеров LXC

После всех проделанных выше действий мы можем перейти к запуску контейнера. Для этого используйте команду lxc-start с именем вашего контейнера, например:

lxc-start -n ubu1 -d

Опция -n задает имя контейнера, в нашем случае - ubu1, а -d говорит утилите запуска, что нужно выполнять программу в фоновом режиме. Вы можете убедиться, что контейнер запущен с помощью такой команды:

lxc5

Тут опция -f включает более подробный вывод, в списке вы увидите только что установленный контейнер и его состояние будет запущен.

Подключение к контейнеру

Чтобы подключиться к терминалу контейнера используйте команду lxc-attach:

lxc-attach -n ubu1

lxc6

После подключения вы получаете полный root доступ к файлам в контейнере, дальше рекомендуется задать пароль root и создать пользователя:

lxc7

lxc8

Настройка системы или установка программ выполняется точно так же, как и в обычной системе, например установка программ:

apt install wget openssh-server htop tmux nano iptables

Выключение контейнера

Когда вы завершили все работы в контейнере, его можно выключить, чтобы он не отнимал системные ресурсы. Для этого выполните:

lxc9

Эта команда проведет правильное завершение работы контейнера и он больше не будет потреблять ресурсов системы, кроме дискового пространства.

Клонирование контейнеров

После того как вы установили все необходимые программы в контейнере и настроили его как нужно, можно создать несколько его копий для упрощения настройки новых контейнеров и экспериментов. Для этого есть команда clone, которая создает полную копию контейнера:

Для примера давайте создадим клон контейнера ubu1 с именем ubu2. Сначала нужно остановить контейнер:

Затем можно клонировать. Опция -n указывает контейнер источник, а -N - имя нового контейнера:

lxc-copy -n ubu1 -N ubu2

Затем вы опять можете использовать lxc-ls, чтобы убедится, что контейнер был создан:

lxc11

Моментальные снимки

Затем используйте команду lxc-snapshot для создания снимка:

lxc-snapshot -n ubu1

Будет создан снимок с именем snap0, следующие снимки для этой же машины будут называться snap1, snap2, и так далее. Вы можете восстановить состояние контейнера до снимка в любой момент, для этого используйте опцию -r:

lxc-snapshot -r snap0 -n ubu1

Вам нужно указать имя снимка и имя контейнера.

Запуск контейнера при старте системы

Вы можете настроить запуск контейнера автоматически при старте системы, например, для запуска веб-сервера. Для этого откройте файл конфигурации контейнера и добавьте такие строки:

lxc.start.auto = 1
lxc.start.delay = 5

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

Решение проблем

Если у вас возникнут проблемы с запуском контейнеров, первое что нужно сделать, это попытаться запустить контейнер lxc с опцией -F, запуск не будет отправлен в фоновый режим и вы увидите все ошибки:

lxc-start -n ubu1 -F

lxc12

sudo vi /etc/lxc/lxc-usernet

losst veth lxcbr0 5

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

Выводы

Контейнеры Linux можно использовать для решения огромного количества задач. Начиная от средства тестирования настроек или нового программного обеспечения и до изоляции своих приложений для обеспечения максимальной безопасности системы. Обратите внимание, что вы даже можете запускать приложения с графическим интерфейсом с помощью контейнеров.

Установка и настройка LXC Linux полностью рассмотрена и я надеюсь, теперь вам стало понятнее как работать с этой технологией. Ее полезность ограничена только вашей фантазией, так что не бойтесь экспериментировать. Если остались вопросы по настройке контейнеров, спрашивайте в комментариях!

На завершение видео с конференции LinuxPiter, где рассказывается подробно что такое контейнеры Linux и действительно ли они настолько безопасны:



Отличие контейнеров от виртуальных машин (виртуализации на уровне ОС)

LXC (Linux Containers) — механизм виртуализации на уровне операционной системы, позволяющий исполнять множество изолированных Linux-систем (контейнеров) в одной системе.

Ядро Linux может изолировать ресурсы (процессор, память, ввод/вывод, сеть и так далее) при помощи cgroups, не прибегая для этого к использованию виртуальных машин. Посредством cgroups изолируются так же деревья процессов, сеть, пользователи и файловые системы.

LXC комбинирует cgroups и пространства имён (namespace).

На данный момент использует LXC следующие возможности ядра:

  • Kernel namespaces (ipc, uts, mount, pid, network and user)
  • Apparmor and SELinux profiles
  • Seccomp policies
  • Chroots (using pivot_root)
  • Kernel capabilities
  • CGroups (control groups)


LXC используется в разнообразных проектах, в том числе в Docker.

LXC можно воспринимать как что-то среднее между chroot и полноценной виртуальной машиной, такой chroot на стероидах.

Содержание

1. Инсталлируем сразу все необходимые пакеты:

2. Монтирование cgroup. Пакет lxc зависит от пакета cgroup-lite, который монтирует каждую cgroup подсистему отдельно в /sys/fs/cgroup/ (в Debian и Ubuntu cgroup вручную монтировать не нужно), но если cgroup все же не смонтирован, то:

добавляем строку в /etc/fstab:

В принципе, точка монтирования не важна -- можно создать любой каталог (например, sudo mkdir /cgroup) и сохранить соответствующую запись в /etc/fstab:


3. Проверяем правильность установки:

lxc-create создать новый контейнер LXC lxc-start запустить контейнер LXC lxc-console подключиться к консоли указанного контейнера lxc-attach запустить указанную программу внутри контейнера - (NOT SUPPORTED) Run a command in a running container lxc-destroy lxc-stop остановить процесс, работающий внутри контейнера lxc-execute выполнить указанную команду внутри контейнера (в чём отличие от lxc-attach?) lxc-monitor мониторить состояние контейнеров lxc-wait ждать определённого состояния контейнера; завершаться, когда состояние достигнуто lxc-cgroup управление cgroup-группами контейнера lxc-ls показать список контейнеров в системе lxc-ps показать список процессов внутри определённого контейнера lxc-info показать информацию о заданном контейнере lxc-freeze заморозить все процессы указанного контейнера lxc-unfreeze разморозить все процессы указанного контейнера

Реализуется через выполнение шаблонов, командой: lxc-create -t <название шаблона> -n <название контейнера>:

Файлы доступных шаблонов (для debian) находятся в каталоге /usr/share/lxc/templates/

После загрузки и инсталляции пакетов, контейнеры будут размещаться в /var/lib/lxc/<название контейнера>. В данном примере -- это каталог /var/lib/lxc/test_01, в котором:

Файл config -- файл конфигурации контейнера, а rootfs -- каталог, в котором развернута файловая система ubuntu.

В команду lxc-create можно передать параметры, в том числе желаемую версию дистрибутива. Чтобы узнать, какие параметры принимает шаблон -- следует выполнить lxc-create --template <название шаблона> --help:

Например, скачивание и установка шаблона ubuntu может быть выполнена следующим образом:

Выполняется командой lxc-start -n <название контейнера>:

В данном случае будет запущен контейнер с ubuntu и мы сразу же попадаем в консоль этой системы. Как правило, логин root, а пароль генерируется случайный:

Читать вывод на консоль в последней строке запуска контейнера (иногда логин и пароль root:root либо ubuntu:ubuntu. ). После входа рекомендуется его сменить командой passwd.

Согласно документации, отключиться от консоли можно комбинацией клавиш ctrl-a q (в некоторых случая, например при использовании терминальных менеджеров типа tmux или screen, может не работать! в этом случае нужно проверить тип терминала и попробовать с терминалом TERM=vt100).

Если запустить контейнеры с ключом -d, контейнер будет работать в фоновом режиме без подключения к консоли:

Выполняется командой lxc-console -n <название контейнера>:

Для более комфортной работы, настроим доступ по ssh. Изначально командой lxc-console заходим на консоль контейнера и устанавливаем sshd (в случае выхода во внешнюю сеть, возможно потребуется скопировать содержимое /etc/resolv.conf из хост-машины), а также создаем нового пользователя user:

Впоследствии, для доступ к запущенному контейнеру достаточно:

Изнутри остановить контейнер можно обычным способом, через shutdown, poweroff или reboot, извне -- командой lxc-stop -n <название контейнера>:

При этом контейнер нормально завершит свою работу (с сохранениями изменений во всех открытых файлах).

Рекомендуется использовать команду lxc-clone -o <название базового контейнер> -n <название нового контейнера>

Хотя вместо lxc-clone можно воспользоваться обычным копированием каталогов (с последующим изменением файлов конфигурации - пути, hostname, MAC- и IP-адреса. )

Согласно документации, существует 5 способов виртуализации сети:

Если в конфигурационном файле контейнера укажем настройки, наподобие:

То после старта, у виртуальной машины будет настроен только loopback interface:

Если конфигурационный файл контейнера привести к виду:

то получим, по сути, проброс физического сетевого интерфейса (после старта контейнера, интерфейс eth1 исчезнет в хост-машине, а сеть перейдет под управление eth0 в виртуальной машине).

Данная схема используется по умолчанию. При запуске контейнера с таким типом сети, на хост-машине создается специальный виртуальный интерфейс (в примере ниже, он называется veth-*). Этот виртуальный интерфейс фактически и использует контейнер для взаимодействия с внешней средой.

Рассмотрим несколько типовых случаев.

NAT уместно использовать в случае, когда на хост-машине имеется один статический ip (например, 192.168.0.186 на интерфейсе eth0) и несколько контейнеров, которым нужен выход в сеть через данный интерфейс. Условно, это можно проиллюстрировать следующей схемой:


Создадим сеть 10.0.0.0, в которой разместим виртуальные машины. Будем использовать пакет bridge-utils.

1. На хост-машине редактируем файл /etc/network/interfaces, дописывая блок настроек br0:

Для того, чтобы изменения были приняты, выполняем:

Внимание! В случае каких-либо ошибок, может пропасть сеть.

2. Правим файл /var/lib/lxc/test_01/config, дописывая блок настроек сети:

3. Добавляем в таблицу nat правило:

4. Запускаем контейнер test_01. В результате, данный хост должен получить при старте ip=10.0.0.10 и через шлюз 10.0.0.1, и далее через 192.168.0.186 -- выход в сеть.

Пункты 2-4 выполняем по аналогии для всех контейнеров сети.

Этот вариант уместно использовать, когда у каждого контейнера должен быть постоянный выделенный ip (и, соответственно, возможность заходить из инета внутрь контейнера напрямую).

Для настройки сети нужно создать bridge br0, который будет включать с одной стороны eth0 хост-машины, а с другой - виртуальные интерфейсы контейнеров:


1. На хост-машине отредактируем файл /etc/network/interfaces, дописывая блок настроек br0:

2. Правим файл /var/lib/lxc/test_01/config, дописывая блок настроек сети:

В результате будем иметь следующую картину (на хост-машине):

Результат вывода ifconfig внутри контейнера test_01:

Пункт 2 выполняем по аналогии для всех контейнеров сети.

  • Контейнеры с такими параметрами смогут взаимодействовать с внешним миром напрямую, как отдельно стоящие машины.
  • В идеале, вместо eth0 на хост-машине следует завести отдельный физический интерфейс для сетевого трафика контейнеров.

Сеть может быть настроена как статически в контейнерах, так и динамически и помощью DHCP-сервера, запущенного на хост-машине. Такой DHCP-сервер должен быть сконфигурирован для ответа на запросы на интерфейсе br0:

1. Устанавливаем и настраиваем DHCP-сервер

2. Файл /etc/network/interfaces, примет вид:

3. В файле /var/lib/lxc/test_02/config, удаляем или комментируем все статические настройки сети:

При использовании схемы veth, все запущенные контейнеры, принадлежащие одной сети, видны и доступны друг-другу. Например, можно из хост-системы по ssh подсоединиться к машине 10.0.0.10, а из консоли этой машины -- попасть на консоль 10.0.0.20 и т.д.

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

Для демонстрации, на хост-машине редактируем файл /etc/network/interfaces, дописывая блок настроек br0:

Файлы конфигурации каждого контейнера приводим к виду:

После запуска контейнеров можно убедиться в их статусе:

При использовании macvlan следует указать один из режимов:

Чтобы ограничить выделяемую контейнеру память, необходимо в его конфигурационном файле добавить следующий параметр:

Как вариант, можно те же действия выполнить из командной строки (перечень всех параметров -- см. в man lxc-cgroup):

Более подробно, см.:

Есть два параметра описывающих лимит процессора:

  • lxc.cgroup.cpuset.cpus -- выделение конкретного ядра/ядер
  • lxc.cgroup.cpu.shares -- приоритет (по умолчанию равно 1024)

В конфигурационном файле контейнера (выделяем под контейнер первых два ядра процессора):

Или то же из-под консоли:

Более подробно, см.:

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

  • файле (через loopback-устройство);
  • томе LVM;
  • томе btrfs;
  • быть дисковым разделом;
  • быть полноценным диском.

Последние два варианта, как правило, не используются из-за недостаточной их гибкости, хотя в некоторых случаях они вполне могут найти своё применение. Использование файлов считается более медленным чем непосредственное использование LVM или btrfs, посколько вводит дополнительный слой (файловую систему, на которой располагается сам файл), с другой стороны этот способ является наиболее гибким.

Использование LVM и btrfs помимо прочих преимуществ обладает ещё тем, что позволяет создавать снэпшоты устройств, а в случае с btrfs ещё и снэпшоты со снэпшотов, что облегчает задачу клонирования контейнеров.

Ниже подробно рассматривается, как можно использовать файл для хранения файловой системы LXC.

Создаем файл определенного размера (в примере ниже он называется disk и имеет размер 600Мб), форматируем его и монтируем средствами хост-машины. А далее в этот каталог (/var/fs) устанавливаем контейнер:

Естественно, команду монтирования можно прописать в /etc/fstab. Ну и следует не забывать указывать ключ lxcpath при работе с контейнером, например:

Принципиально данный способ не отличается от предыдущего: изначально подготавливается логический том требуемого размера, в который далее инсталлируется контейнер LXC.

Подробнее об использовании LVM: LVM.

Для начала проверим, куда смонтирована cgroup (по умолчанию -- в /sys/fs/cgroup):

Данные по использованию памяти, процессора и пр., находятся в /<точка монтирования cgroup>/lxc/<название запущенного контейнера>/<файл параметров>:

Что произойдёт с процессом если он превысит отведённые ему лимиты памяти? Как проверить? Проверить можно очень просто, можно просто создать процесс, который запрашивает необходимое количество памяти:

Видно, что программа занимает чуть больше запрошенных 100 мегабайтов (пятая колонка, первый ряд).

Конфигурация контейнера находится в файле

Конфигурация контейнера описывает всевозможные аспекты его существования, начиная от доменного имени, IP-адреса и заканчивая ограничениями всех ресурсов, которые он использует.

Устанавливаем внутри контейнера графическую оболочку и софт для работы с удаленным рабочим столом по протоколу RDP:

Если сеть настроена для работы с NAT, то на хосте приводим правила iptables к следующему виду (10.0.0.100 -- ip контейнера, 192.168.0.186 -- статический ip хост-машины, 3389 -- порт по умолчанию для работы xrdp):

В Windows заходим в «Пуск» -> «Все программы» -> «Стандартные» -> «Подключение к удаленному рабочему столу», вводим ip хост-машины; во время подключения -- выбираем модуль «sesman-Xvnc» и вводим логин/пароль пользователя контейнера.

Функционал LXC фактически представлен механизмами ядра Linux и утилиты lxc, работающие в пространстве пользователя (userspace). Это означает, что контейнеры LXC в полной мере могут использоваться и без утилит lxc. Естественно, что в этом случае потребуется какая-то другая программа/система, выполняющая управление ими.

libvirt LXC-драйвер не использует никакие утилиты LXC и никак не зависит от них.

Возможности ядра, необходимые для работы LXC:

  • control groups (требуемые контроллеры: cpuacct, memory, devices; рекомендуемые: cpu, freezer, blkio);
  • namespaces (требуются mount, ipc, pid и uts; если используется собственная сеть в контейнере, то ещё требуется net).

Подробнее о возможностях драйвера контейнеров LXC библиотеки libvirt:

Хотя и немного устаревшую, но всё же полезную информацию на эту тему можно найти здесь:

Читайте также: