Стаття також доступна російською (перейти до перегляду).

Зміст:
- Загальні відомості
- Що таке namespaces
- API namespaces
- Приклади роботи із Namespaces
- Що таке Cgroups (control groups)
Для розробки, доставки та запуску багатокомпонентних розподілених додатків широко використовуються такі інструменти контейнеризації, як Docker, Podman, Kubernetes та інші, котрі забезпечують умови роботи середовища виконання. Однак, не всі знають, що вказані інструменти не є абсолютно незалежними, а використовують для своєї роботи влаштовані у ядро ОС Linux засоби контейнеризації, зокрема, Namespaces та Cgroup.Саме вони дають змогу працювати із контейнерами, котрі можна порівняти із полегшеними віртуальними машинами. Пряме використання влаштованих засобів контейнеризації дає можливість створити ізольоване середовище для запуску та виконання будь-якого процесу, зокрема, завдання адміністрування Linux. Розглянемо методи створення та управління ізольованими Runtime-середовищами за допомогою влаштованих засобів ядра Linux.
Загальні відомості
Що таке контейнери насправді
Контейнери є одним з основних механізмів віртуалізації середовища виконання додатків Runtime, котрий розвинувся, як результат пошуку ефективних рішень для оптимізації роботи напрямку DevOps.
Запит на пошук методів віртуалізації завжди був пов'язаний із необхідністю оптимізації ресурсних витрат – машинних та фінансових. На даний час можна виділити три базових типа організації Runtime середовища – фізичний (Traditional), віртуальний (Virtualized) та контейнерний (Container) (див. Мал. 1).

Малюнок 1. Базові типи організації Runtime середовища.
Для першого, фізичного типу відсутня будь-яка віртуалізація і тому ресурсні витрати тут максимальні. Прикладом застосування може бути фізичний виділений сервер (Dedicated Server) для забезпечення потреб хостингу – дуже вартісне та неефективне рішення у сучасних умовах для більшості завдань.
Віртуальний тип заснований на використанні, так званих, віртуальних машин VM (Virtual Machine) – ізольованого псевдо комп’ютера із окремою ОС та власними ресурсами. Віртуалізація забезпечується на апаратному рівні. Машини утворюються на базі проміжного шару – гіпервізору (Hypervisor), котрий ізолює їх від ОС та «заліза» фізичної машини. Перевагами використання технології є економія ресурсів порівняно із фізичним типом та можливість запуску на кожній із VM будь-якої ОС. Недоліки – мала щільність розміщення VM у межах одного комп'ютеру та велика інерційність (час запуску вимірюється кількома секундами). Приклади реалізації – Xen, KVM(Kernel-based Virtual Machine).
Контейнерне середовище виконання функціонує на базі створених у Container Runtime окремих контейнерів для запуску ізольованих завдань. Воно має багато спільних рис із VM, однак на відміну від останнього віртуалізація тут забезпечується на рівні ОС – всі контейнери запускаються у межах одного віртуального простору на базі єдиного Linux-ядра. По суті, контейнери є окремими процесами із власним простором імен. Переваги – велика щільність розміщення, мала інерційність (час запуску у межах кількох мс), динамічність виділення та споживання ресурсів. В результаті, на одній фізичній машині може бути запущене набагато більше додатків, ніж у попередніх двох типах Runtime-простору. Недоліки – підвищена увага до питань безпеки та необхідність використання лише одного з Linux-дистрибутивів для всіх контейнерів. Приклади реалізації – FreeBSD jail, Solaris Containers, Linux-Vserver, OpenVZ, Docker.
Історія появи ізольованих контейнерних середовищ виконання
Runtime-простір на основі контейнерів з'явився набагато раніше, ніж його сучасні аналоги – Docker та Kubernetes.
Однією з перших платформ віртуалізації контейнерного типу стала OpenVZ компанії Parallels, Inc, перша версія якої побачила світ ще у 2005 році. Нині вона є основою для системи Virtuozzo, котрашироко використовується хостинг-компаніями для створення віртуального середовища для роботи віртуальних приватних серверів VPS (Virtual Private Servers). За даними розробників, такі сервери забезпечують продуктивність роботи на тому ж рівні, що і звичайні Linux-сервери – падіння складає лише 2-3 %.
Підсистема контейнеризації LXC (Linux Containers) однієї з французських компаній також розрахована на роботу із окремими екземплярами ОС для кожного контейнеру на базі єдиного ядра Linux. Її поява датується початком серпня 2008 року. Вона була використана для організації роботи сервісу Heroku – одного з перших в світі хмарних PaaS-майданчиків. Перші версії платформи Docker спиралися саме на неї, доки не перейшли на власні бібліотеки.
OpenVZ та LXC використовують можливості влаштованих засобів контейнеризації. Саме це забезпечило їх успіх та надало можливість розвиватися й надалі. Технології Solaris Containers, Linux-Vserver та FreeBSD jail так само використовують внутрішні засоби Linux для організації простору виконання програм контейнерного типу.
Що таке namespaces
Як вже зазначалося, функціонування Container Runtime-простору платформ контейнеризації стало можливим завдяки наявності влаштованих механізмів ядра Linux. Одним з них є простір імен Namespaces. Його основне призначення – забезпечити ізольоване використання ресурсів процесами. Реалізується це шляхом створення окремих екземплярів системних ресурсів для кожного процесу.
Namespaces був відсутній у перших версіях ядра, а був введений, починаючи з версії 2.6.29. Його розробка тривала більше десяти років і була завершена у лютому 2013 року із закінченням розробки одного з його видів – простору імен користувача. Завершений варіант Namespaces був реалізований у Linux-ядрі версії 3.18.
Використовується для платформ контейнеризації, для ізоляції мережевих ресурсів, для тестування ядра та нового програмного забезпечення.
Види namespaces
Наявність різних типів системних ресурсів обумовило розподіл простору імен на різні види. На даний час підтримується шість видів Namespaces:
-
mnt (точки монтування);
-
net (мережевий стек);
-
pid (процеси);
-
uts (ім'я хоста);
-
ipc (System V IPC);
-
user (UID).
Mnt – дозволяє ізолювати файлові системи, тобто кожен процес буде мати «власні» точки монтування, недоступні іншим процесам. Вкажемо на декотрі особливості організації вказаного виду простору:
-
При створенні нового простору усі попередні монтування будуть доступними для перегляду;
-
З моменту створення простору всі операції монтування / размонтування стають прихованими для всіх інших процесів;
-
Операції монтування / размонтування, виконані у глобальному просторі імен, будуть доступними для перегляду в новому просторі.
Net – забезпечує ізоляцію мережевих ресурсів для кожного з процесів. За логікою є окремою копією мережевого стеку із власними таблицями ARP, мережевими пристроями, SNMP-статистикою,/procfs та /sysfs записами, сокетами та правилами файрволу.
Особливості організації для поточного моменту часу:
-
Мережевий пристрій належить єдиному простору імен;
-
Вихідний мережевий Net-простір об'єднує в собі всі фізичні пристрої, loopback-пристрій, мережеві таблиці тощо;
-
Сокет належить єдиному простору імен;
-
Кожний новий Net-простір має у своєму складі лише loopback-пристрій.
Pid – забезпечує ізоляцію ідентифікаторів процесів. Має наступні особливості організації:
-
Процеси в різних Pid-просторах можуть мати однакові ідентифікатори;
-
Перший процес у новому Pid-просторі буде мати ідентифікатор під номером 1;
-
При закритті будь-якого процесу, для всіх його «нащадків» буде встановлений «батьківський» процес, для якого Pid=1;
-
Процес із Pid=1 неможиво завершити за допомогою сигналу SIGKILL;
-
Простір може мати до 32-х рівнів вкладеності.
Uts (Unix Time-Sharing) – ізолює відомостіпро хост і домен та дозволяє кожному ізольованому процесу мати власні значення відповідних параметрів. Надає можливість отримати інформацію про систему за допомогою команд hostname та uname.
Ipc (Inter-Process Communication) – Забезпечує ізоляцію засобів взаємодії між окремими процесами, до яких, зокрема, належать: черги повідомлень, загальна пам'ять тощо. Організація простору підпорядковується тим самим правилам, що і для Uts-простору.
User – дозволяє процесам мати у єдиному просторі імен власні значення ідентифікаторів UID та GID. Це, зокрема, дозволяє не root користувачу створювати процеси, у яких він буде мати права root.
API namespaces
Для можливості роботи із Namespaces було створено ряд інструментів, до яких належать системні виклики та шість прапорців CLONE_NEW..., котрі використовуються у системних викликах у якості додаткових опцій для формування простору імен визначеної конфігурації.
APINamespaces включає три системні виклики:
clone() – створює новий процес разом із простором імен за допомогою операції клонування. Може забезпечити лише загальний доступ до ресурсів для всіх процесів.
unshare() – створює новий простір імен та під'єднує до нього процес, котрий викликається. Він відміняє встановлений за замовчуванням загальний доступ до ресурсів. Його використання дозволяє розділити між процесами простір імен без необхідності застосування операції клонування, що ускладнило б цей процес та зробило б його більш ресурсозатратним.
setns() – під'єднує до Namespaces процес, котрий викликається.
Додатково використовуються функції fork() та exit() длястворення та завершення процесів.
Прапорці для кожного з видів Namespaces:
CLONE_NEWNS CLONE_NEWNET CLONE_NEWIPC CLONE_NEWPID CLONE_NEWUTS CLONE_NEWUSER
Кожному простору при його створенні присвоюється унікальний номер inode. Закриття Namespaces відбувається лише після закриття всіх процесів при умові, якщо його inode не утримується якоюсь із функцій.
Приклади роботи із Namespaces
При створенні нових процесів всі вони за замовчуванням будуть додаватися до вже існуючих просторів імен кожного виду. Для того, щоб змінити ситуацію, необхідно скористатися засобами створення нового Namespaces для визначеного процесу. Але для цього треба знати його PID. Його можна знайти за допомогою утиліти htop:
$ htop

Продемонструємо зміну UTS-простору імен для копії процесу bash. Спочатку переглянемо всі Namespaces, котрим належить процес. Вони виводяться у вигляді файлів у каталозі /proc/<pid>/ns для процесу із вказаним значенням pid. Для bash значення pid виражається через символи $$.
Введемо в терміналі:
$ ls -l /proc/$$/ns

Вихід:
lrwxrwxrwx 1 root root 0 May 5 14:26 cgroup -> 'cgroup:[4026531835]' lrwxrwxrwx 1 root root 0 May 5 14:26 ipc -> 'ipc:[4026531839]' lrwxrwxrwx 1 root root 0 May 5 14:26 mnt -> 'mnt:[4026531841]' lrwxrwxrwx 1 root root 0 May 5 14:26 net -> 'net:[4026531840]' lrwxrwxrwx 1 root root 0 May 5 14:26 pid -> 'pid:[4026531836]' lrwxrwxrwx 1 root root 0 May 5 14:26 pid_for_children -> 'pid:[4026531836]' lrwxrwxrwx 1 root root 0 May 5 14:26 time -> 'time:[4026531834]' lrwxrwxrwx 1 root root 0 May 5 14:26 time_for_children -> 'time:[4026531834]' lrwxrwxrwx 1 root root 0 May 5 14:26 user -> 'user:[4026531837]' lrwxrwxrwx 1 root root 0 May 5 14:26 uts -> 'uts:[4026531838]'
Відкриємо другий термінал та перевіримо, які Namespaces виділяються:
$ ls -l /proc/$$/ns

Можна переконатися, що виділяються ті ж самі простори імен.
Тепер створимо окремий UTS-простір імен для копії процесу bash. Для цього введемо:
$ sudo unshare -u bash

Перевіримо номера Namespaces:
$ ls -l /proc/$$/ns

Вихід:
lrwxrwxrwx 1 root root 0 May 5 14:50 cgroup -> 'cgroup:[4026531835]' .............................................................................................. lrwxrwxrwx 1 root root 0 May 5 14:50 uts -> 'uts:[4026532211]'
Можна переконатися, що простір UTS змінився, а всі інші залишилися ті ж самі. Це говорить про те, що копія процесу bash виконується у новому UTS-просторі. Тепер ми маємо можливість змінити ім’я хоста у другому терміналі, а в першому воно залишиться без змін.
Перевіримо це за допомогою команди зміни назви хоста:
$ hostname newdedicated

З’ясуємо поточне ім’я хоста:
$ hostname

Вихід: newdedicated
У першому терміналі та сама команда дасть інший результат:
$ hostname

Вихід: dedicated
Так само ми можемо створити ізольований PID-простір для виконання будь-якого процесу.
Для прикладу, запустимо команду, котра створить PID-простір для виконання програми для виведення інформації про поточний процес.
Введемо в терміналі:
$ sudo unshare --fork --pid --mount-proc readlink /proc/self
Тут опція --fork – забезпечує виконання команди у дочірньому процесі; параметр --mount-proc – створює Namespaces для монтування та водночас монтує файлову систему proc;утиліта readlink – виводить системну інформацію про процес, котра міститься у proc.

Вихід: «1». Це означає, що у новому просторі імен процес має PID = 1.
Після завершення виконання програми readlink, новий простір імен буде автоматично видалений.
Що таке Cgroups (control groups)
Це підсистема управління ресурсами (облік та відслідковування), котра надає загальну структуру групування процесів у відповідності до існуючих для них обмежень. Контролюються такі ресурси, як ЦП, пам’ять, мережа тощо. Заснована на механізмі «bean counters» із OpenVZ. Вперше з'явилася у Linux-ядрі версії 2.6.24.
Підсистема для своєї роботи не вимагає системного виклику, а використовує віртуальну файлову систему VFS або cgroupfs. Це означає, що всі її дії виконуються через операції файлової системи – запис / читання файлів, монтування / размонтування об’єктів, створення / видалення каталогів тощо.
Для початку роботи із cgroups необхідно змонтувати VFS. Як і будь-яка інша файлова система VFS може бути змонтована із використанням будь-якого шляху в файловій системі, але системна служба Systemd використовує шлях /sys/fs/cgroup.
Cgroups має одинадцять контроллерів, котрі можна під’єднати під час монтування за допомогою параметру -о.
Основні з контроллерів:
-
Memory – встановлює обмеження на використання ОП та Swap;
-
CPU – контролює виділення процесорного часу;
-
PIDs – встановлює обмеження на кількість процесів у групі;
-
IO – регулює ввід-вивід для блочних пристроїв;
-
Devices – обмежує доступ до фізичних пристроїв.
Приклад:
$ mount -t cgroup –o pids none /sys/fs/cgroup/pids
Тут монтується файлова система cgroupfs із використанням контроллеру pids.
Розгортання на сервері
Для демонстрації декотрих можливостей по управлінню ресурсами, встановимо на VPS-сервер під управлінням ОС Debian 12, механізм cgroup.
Оновлюємо індекс пакетів нашої системи:
$ sudo apt update

Встановлюємо пакет libcgroup-dev:
$ sudo apt install libcgroup-dev

Вихід:
Setting up libcgroup2:amd64 (2.0.2-2) Setting up libcgroup-dev:amd64 (2.0.2-2)
Отже, cgroup версії v2розгорнуто. Можна починати роботу із задачами.
Приклади обмеження CPU та пам’яті
Сконфігуруємо механізм cgroup у ручному режимі через ієрархію sysfs.
Створимо директорію для групи задач із ім’ям test_group:
$ sudo mkdir /sys/fs/cgroup/test_group

Встановимо ліміт використання пам’яті у 10 Mb для всіх задач створеної групи:
$ echo $((10*1024*1024)) | sudo tee /sys/fs/cgroup/test_group/memory.max

Обмежимо використання процесорних ресурсів до 10 відсотків:
$ echo "10000 100000" | sudo tee /sys/fs/cgroup/test_group/cpu.max
Тут 10000 – квота в мс.

Додамо поточну задачу (інтерпретатор bash) до нашої групи:
$ echo $$ | sudo tee /sys/fs/cgroup/test_group/cgroup.procs

Після цього всі запущені у bash команди будуть потрапляти до списку наших задач, для котрих були встановлені обмеження.
Створення ізольованого Runtime-середовища
Після встановлення обмежень нам залишається лише налаштувати механізм ізоляції між завданнями.
Як вже зазначалося, забезпечити створення окремих просторів імен для кожного з процесів можна лише за допомогою утиліти unshare, запущеної із відповідними параметрами.
Команда буде виглядати наступним чином:
$ sudo unshare --fork --pid --mount --uts --ipc --net --user --map-root-user --mount-proc /proc /bin/bash
Тут опція --fork – створює копію процесу для нового Namespaces; --map-root-user – забезпечує маршрутизацію в новому Namespaces для root-користувача;--mount-proc – монтує /proc у створеному Mount-просторі.
Після виконання команди ізольоване середовище буде готовим для використання. За своїми характеристиками воно буде мало чим відрізнятися від Container Runtime відомих систем контейнеризації.
Підписуйтесь на наш телеграм-канал https://t.me/freehostua, щоб бути в курсі нових корисних матеріалів.
Дивіться наш канал Youtube на https://www.youtube.com/freehostua.
Ми у чомусь помилилися, чи щось пропустили?
Напишіть про це у коментарях, ми з задоволенням відповімо та обговорюємо Ваші зауваження та пропозиції.
|
Дата: 07.05.2025 Автор: Олександр Ровник
|
|

Авторам статті важлива Ваша думка. Будемо раді його обговорити з Вами:
comments powered by Disqus