Контейнерні утиліти Linux Containers (LXC)

Контейнери ефективно розділяють ресурси, керовані єдиною операційною системою, на ізольовані групи, для досягнення кращого балансу між конфліктуючими запитами на використання ресурсів. На відміну від віртуалізації, тут не потрібно ні емуляція на командному рівні, ні компіляція "на льоту" (just-in-time compilation). Контейнери можуть виконувати прямі процесорні команди, не вдаючись до механізмам інтерпретації. Також відпадають складності паравіртуалізаціі і перетворення системних викликів.


Надаючи засоби для створення і використання контейнерів, ОС дає додаткам можливість працювати як би на окремій машині, при цьому спільно використовуючи безліч базових ресурсів. Наприклад, кешування сторінок загальних файлів – наприклад, glibc – можна ефективно використовувати спільно, тому що всі контейнери використовують один і той же ядро і, в залежності від налаштувань контейнера, звичайно одну і ту ж бібліотеку libc. Часто таке спільне використання поширюється і на інші файли та папки, які не відбувається запис.


Економія від спільного використання ресурсів у поєднанні з наданої ізоляцією призводить до того, що контейнери вимагають значно менших накладних витрат, ніж справжня віртуалізація.


Контейнерні технології існують вже досить тривалий час. В якості прикладів контейнерів з інших Unix-систем слід назвати Solaris Zones і BSD jails. У контейнерних технологій в Linux також давні традиції: Linux-Vserver, OpenVZ і FreeVPS. Хоча кожна з цих технологій є цілком зрілої, рішучих кроків з інтеграції підтримки їх контейнерних можливостей в основну гілку ядра Linux не робилося.


У статті Сержа Халліна (Serge Hallyn) "Модулі безпеки Linux: Рецепти для роботи з контейнерами" (developerWorks, лютий 2009 р.), розповідається, як можна підсилити безпеку легких контейнерів за допомогою політик SELinux і Smack.


Проект Linux Resource Containers, навпаки, спрямований на реалізацію контейнерів у співпраці з розробниками основної гілки ядра Linux. Одночасно цей внесок може бути корисний і для більш зрілих контейнерних Linux-рішень, надаючи для них загальний внутрішній інтерфейс. Дана стаття містить короткий вступ до використання утиліт, створених проектом LXC.


Для кращого розуміння статті необхідно впевнено почувати себе в командному рядку в роботі з такими програмами, як make, gcc, і patch, а також бути знайомим з процесом розпакування тарболов (файлів з розширенням. tar.gz).


Отримання, складання та встановлення LXC


Проект LXC складається з патча для ядра Linux і утиліт, що працюють у просторі користувача. Утиліти використовують нову функціональність, що додається патчем в ядро, і пропонують спрощений набір інструментів для управління контейнерами.


Перш ніж почати використовувати LXC, необхідно завантажити вихідний код ядра Linux, встановити відповідний LXC-патч, потім зібрати, встановити і завантажити нове ядро. Далі необхідно завантажити, зібрати і встановити інструментарій LXC.


Ми використовували пропатчені ядро Linux 2.6.27. Швидше за все, lxc-патч для ядра 2.6.27 не підійде для вихідного коду ядра вашого улюбленого дистрибутива, і в той же час версії ядра Linux 2.6.27 старше можуть вже містити значну частину функціональності, представленої в патчі. Тому настійно рекомендується використовувати останні версії патча і ядра з основної гілки. Також замість завантаження вихідного коду ядра і встановлення на нього патча можна отримати код, використовуючи git:






 git clone git: / / git.kernel.org/pub/scm/linux/kernel/git/daveh/linux-2.6-lxc.git

Інструкції по накладенню патчів, налаштуванню, збірці, інсталяцію та запуск ядра можна знайти на сайті kernelnewbies.org.


Для LXC необхідні деякі специфічні налаштування в ядрі. Найпростіший спосіб правильно налаштувати ядро для роботи з LXC – це використовувати make menuconfig і включити Container support. Це, у свою чергу, автоматично включить набір інших опцій, що залежать від можливостей, які підтримуються ядром.


Відчуваємо LXC-середовища

На додаток до ядра, що підтримує контейнери, нам знадобляться інструменти для спрощення запуску та управління контейнерами. Основними засобами управління в цій статті є утиліти з бібліотеки liblxc. У цьому розділі обговорюються:



Утиліта liblxc


Скачайте і розпакуйте liblxc, потім виконайте з папки liblxc команду:






./configure –prefix=/
make
make install

Якщо вам зручніше збирати з SRPM, такий пакет також є.


Утиліта iproute2


Для управління мережевими інтерфейсами всередині контейнерів необхідний пакет iproute2 версії 2.6.26 або старше. Якщо у вашому дистрибутиві він відсутній, то скачайте, налаштуйте, зберіть і встановіть його, дотримуючись інструкцій з архіву з вихідним кодом.


Налаштування мережі


Ще один ключовий компонент багатьох функціональних контейнерів – мережевий доступ. Найкращим способом підключення контейнера до мережі в даний час є поєднання сегментів Ethernet мережевим мостом таким чином, що вони виглядають єдиним сегментом мережі. Готуючись до використання LXC, ми створимо мережевий міст і з його допомогою з'єднаємо наш справжній мережний інтерфейс і мережевий інтерфейс контейнера.


Створюємо мережевий міст з ім'ям br0:






brctl addbr br0
brctl setfd br0 0

Тепер підніміть інтерфейс мосту з вашим IP від вже існуючого інтерфейсу (у цьому прикладі 10.0.2.15): ifconfig br0 10.0.2.15 promisc up. Додайте в міст існуючий інтерфейс (у нашому прикладі eth0) І приберіть його прямий зв'язок з IP-адресою:






brctl addif br0 eth0
ifconfig eth0 0.0.0.0 up

Будь-який інтерфейс, доданий до мосту br0, Буде відповідати IP-адресою мосту. Наостанок переконайтеся, що пакети прямують до шлюзу через правильний маршрут за замовчуванням: route add -net default gw 10.0.2.2 br0. Пізніше, під час налаштування контейнера, ми вкажемо br0 як шлях у зовнішній світ.


Заповнення файлової системи контейнера


Крім мережі, контейнерів часто потрібна власна файлова система. Існує кілька способів заповнити її в залежності пропонованих вимог. Обговоримо два з них:



Зібрати власний Debian-контейнер найпростіше з допомогу команди debootstrap:






 debootstrap sid rootfs http://debian.osuosl.org/debian/

Якщо робиться велика кількість контейнерів відразу, то можна заощадити час, попередньо скачавши пакети і об'єднавши їх в тарбол: debootstrap – make-tarball sid.packages.tgz sid http://debian.osuosl.org/debian/. Команда з цього прикладу збере tar-файл розміром близько 71 МБ (52 МБ в стислому вигляді), в той час як кореневий каталог займе приблизно 200 МБ. Тепер все готово до збірки кореневої папки в rootfs: debootstrap –unpack-tarball sid.packages.tgz sid rootfs. (Man-сторінка debootstrap містить більш повну інформацію по збірці контейнерів меншого розміру або розміру, більш підходящого вам за іншими параметрами.


У результаті ми отримуємо середу, надзвичайно надлишкову по відношенню до основного хост-контейнера.


Запуск SSH-контейнера дозволяє дуже істотно знизити обсяг дискового простору, що виділяється виключно під файлову систему контейнера. Наприклад, даний спосіб використовує лише кілька кілобайт, щоб включити безліч ssh-демонів з різних контейнерів, що працюють на порту 22. Контейнер робить це, використовуючи монтування "тільки для читання" (read-only bind mounts), таких важливих кореневих папок, як / bin, / sbin, / lib та інші, для спільного доступу до вмісту пакета sshd з існуючої системи Linux. При цьому використовується мережний простір імен і створюється дуже невелике змінюване вміст.


Методи, використані вище для створення легких контейнерів, в основному такі ж, які використовуються для створення chroot-середовищ. Різниця лише у використанні синонімів "тільки для читання" (read-only bind mounts) і у використанні просторів імен для підвищення ізольованості chroot-середовища до такого ступеня, що вона стає ефективним контейнером.


Далі нам необхідно вибрати спосіб підключення до контейнера.


Підключення до контейнера


Наступний крок – підключення до контейнера. Тут, в залежності від налаштувань контейнера, можливо кілька способів:



Підключення через SSH добре підходить для тих випадків, коли контейнера не потрібно графічний інтерфейс. У цьому випадку цілком достатньо простого з'єднання ssh. Перевага цього методу, заснованого на IP-адресації, в можливості створювати довільну кількість контейнерів.


Якщо ssh-з'єднання очікує введення пароля занадто довго, то широкомовний демон Avahi служби DNS / Service Discovery при запиті до DNS може зупинити роботу по тайм-ауту.


Підключення через віддалений доступ до робочого столу (VNC) дозволить використовувати контейнер з графічним інтерфейсом.


Для запуску X-сервера, що обслуговує тільки VNC-клієнтів, використовуйте vnc4server. Встановлений vnc4server необхідно буде запустити з файлу / etc / rc.local контейнера таким чином: echo "/ usr/bin/vnc4server: 0-geometry 1024×768-depth 24">> rootfs / etc / rc.local. У результаті при старті контейнера буде створений екран з роздільною здатністю 1024 * 768 пікселів і глибиною кольору 24 біта. Тепер для підключення досить ввести:






vncviewer <ip>:<display>

Підключення через VT: tty (текстовий режим) зручно, коли контейнер ділить tty з основною машиною (хостом). У цьому випадку для підключення до контейнера можна використовувати Linux Virtual Terminals (VT). Найпростіше використання VT починається з авторизації в одному з пристроїв tty, які зазвичай збігаються з віртуальними терміналами Linux. Процес, що відповідає за авторизацію, називається getty. Щоб використовувати VT 8, вводимо:






 echo "8:2345: respawn: / sbin / getty 38400 tty8"
>> rootfs/etc/inittab

Тепер при запуску контейнера буде запускатися getty на tty8, що дасть користувачам можливість авторизуватися в контейнері. Аналогічний прийом можна використовувати для перезапуску контейнера за допомогою утиліт LXC.


Цей метод не дозволяє використовувати графічний інтерфейс контейнера. Більше того, оскільки до tty8 в кожен момент часу може підключитися лише один процес, для підключення декількох контейнерів потрібні додаткові налаштування.


Підключення через VT: X дозволить запустити графічний інтерфейс. Для запуску GNOME Display Manager (gdm) на VT 9, відредагуйте rootfs / usr / share / gdm / defaults.conf, замінивши значення FirstVT=7 на FirstVT=9, І VTAllocation=true на VTAllocation=false.


Хоча тепер ми отримали графічний режим, ми використовуємо один термінал з обмеженої кількості віртуальних Linux-терміналів.


Запуск утиліт LXC

Тепер, коли у нас працює задовольняє вимогам ядро, встановлені утиліти LXC і є робоче середовище, настав час навчитися керувати примірниками середовища. (Порада: більш докладний опис багатьох необхідних дій міститься у файлі LXC README.)


Для управління контейнерами LXC використовує файлову систему cgroup. Перше, що потрібно зробити, – це змонтувати її: mount -t cgroup cgroup /cgroup. Файлову систему cgroup можна монтувати куди завгодно. LXC буде використовувати першу змонтовану cgroup з файлу / etc / mtab.


Далі у статті наводяться деякі базові відомості по LXC, конкретні зауваження та огляд низькорівневого доступу.


Основи LXC


Тут ми розглянемо такі питання:



Створення контейнера пов'язує ім'я з файлом налаштувань. Ім'я буде використано для управління одиничним контейнером:






lxc-create -n name -f configfile

Це дозволяє безлічі контейнерів використовувати один і той же файл настройок. У конфігураційному файлі задаються атрибути контейнера, такі як ім'я хоста, налаштування мережі, коренева файлова система і точки монтування в fstab. Після запуску скрипта lxc-sshd (що створює для нас конфігурацію) конфігурація ssh-контейнера буде виглядати так:






lxc.utsname = my_ssh_container
lxc.network.type = veth
lxc.network.flags = up
lxc.network.link = br0
lxc.network.ipv4 = 10.0.2.16/24
lxc.network.name = eth0
lxc.mount = ./fstab
lxc.rootfs = ./rootfs

Незалежно від файлу налаштувань контейнери, що запускаються утилітами LXC, по-своєму бачать процеси системи і доступні ресурси між процесами взаємодії (IPC), а також мають власне дерево точок монтування (mount tree).


Крім того, при запуску контейнера мається на увазі, що будь-які ресурси, не вказані у файлі конфігурації, використовуються спільно з хостом. Це дозволяє адміністраторам компактно описувати ключові відмінності між хостом і контейнером, а також забезпечує переносимість налаштувань.


Виведення інформації про існуючі контейнерах – ключовий момент в управлінні ними. Перегляд стану конкретного контейнера:






lxc-info -n name

Перегляд процесів, що належать контейнера:






lxc-ps

Запуск
У LXC розрізняють два типи контейнерів: системні контейнери і контейнери додатків. Системні контейнери схожі на віртуальні машини. Але, на відміну від справжньої віртуалізації, вони створюють менші накладні витрати за рахунок меншої ізольованості. Це прямий наслідок того, що всі контейнери використовують одне і теж ядро. Як і віртуальна машина, системний контейнер запускається так само, як Linux-дистрибутив, через запуск процесу init:






lxc-start -n name init

Навпаки, контейнер додатків лише створює окремий простір імен, необхідне для ізоляції одиничного додатки. Запуск контейнера додатків:






lxc-execute -n name cmd

Подача сигналів
Подаємо сигнал всім процесам всередині контейнера:






lxc-kill -n name -s SIGNAL

Призупинення
Призупинення контейнера по суті схожа на відправлення сигналу SIGSTOP всіх процесів в контейнері. Однак відправка надлишкових сигналів SIGSTOP може заплутати деякі програми. Тому LXC використовує "заморажіватель" процесів (Linux process freezer), доступний через інтерфейс cgroup:






lxc-freeze -n name

Відновлення
Для "розмороження" контейнера:






lxc-unfreeze -n name

Зупинка
Зупинка очищає контейнер, завершуючи всі запущені в ньому процеси:






lxc-stop -n name

Знищення
Знищення контейнера видаляє конфігураційні файли і метадані, які були пов'язані з його ім'ям при створенні lxc-create:






lxc-destroy -n name

Інші зауваження


Ось кілька практичних моментів, які можуть здаватися корисними (деякі з них стосуються моніторингу).


Перегляд і налаштування пріоритету контейнера:






lxc-priority -n name
lxc-priority -n name -p priority

Безперервне спостереження за станом і зміною пріоритету контейнера:






lxc-monitor -n name

Натисніть Ctrl-C щоб зупинити спостереження.


Чекаємо, поки контейнер не увійде в один з множин станів, розділених /:






lxc-wait -n name -s states

Чекаємо стану, крім RUNNING:






 lxc-wait-n name-s "STOPPED / STARTING / STOPPING / ABORTING / FREEZING / FROZEN"

Ця команда, зрозуміло, призведе до негайного повернення управління. Виключаючи непередбачені помилки, можна очікувати, що команда lxc-wait завершиться тільки коли контейнер увійде до вказаний стан.


Низькорівневий доступ


Для управління контейнерами LXC використовує файлову систему cgroup. За допомогою LXC можливо переглядати і робити певні дії з частинами файлової системи cgroup. Використання процесора кожним контейнером можна регулювати зчитуванням і регулюванням параметра cpu.shares:






lxc-cgroup -n name cpu.shares
lxc-cgroup -n name cpu.shares howmany

Висновок

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


Цей матеріал грунтується на роботі, підтриманої Агентством передових оборонних дослідницьких проектів (DARPA), в рамках Угоди HR0011-07-9-0002.

Схожі статті:


Сподобалася стаття? Ви можете залишити відгук або підписатися на RSS , щоб автоматично отримувати інформацію про нові статтях.

Коментарів поки що немає.

Ваш отзыв

Поділ на параграфи відбувається автоматично, адреса електронної пошти ніколи не буде опублікований, допустимий HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*

*