Курс СРС SRS01
до ЛР1 рівень 2 → «4»↔ Лабораторна 1↔ Лекція 1⌨️ команди 8
Самостійна робота · ~2.5 год

Простори імен Linux (PID, NET, MNT, UTS, IPC, USER): що ізолює кожен

🌌 Шість Вартових на брамах: що кожен бреше процесові — С.І.Д. обожнює цю тему й радо проведе тебе за руку: розберися, що саме кажуть процесові шість Вартових на брамах капсули — PID, мережа, файли, хостнейм, IPC, cgroup — і чому сьома брама, USER, за замовчуванням стоїть навстіж, тож root усередині капсули — це той самий root і зовні.

📚 ТЕОРЕТИЧНІ ВІДОМОСТІ

Що таке простір імен

Простір імен (namespace) — це механізм ядра Linux, який обмежує видимість певного класу глобальних системних ресурсів для групи процесів. Це не віртуалізація в сенсі гіпервізора: процеси контейнера виконуються на тому самому ядрі, що й процеси хоста, просто ядро підмінює їм «вид» на систему. Контейнер Docker технічно — звичайний процес Linux, якому під час clone() або unshare() передали набір прапорців CLONE_NEW*.

Сучасне ядро підтримує вісім типів просторів імен, з яких Docker на сучасному хості (cgroups v2, напр. Ubuntu 24.04 чи Codespaces) вмикає шість базових за замовчуванням:

  • PID — власна нумерація процесів; перший процес контейнера отримує PID 1 у своєму просторі, хоча на хості в нього звичайний, «зовнішній» PID.
  • NET — власний мережевий стек: інтерфейси, таблиці маршрутизації, порти. Контейнери з окремим NET-простором з'єднуються через віртуальні veth-пари й міст docker0.
  • MNT — власне дерево точок монтування; контейнер бачить власну кореневу файлову систему, змонтовану через pivot_root, і не бачить монтувань хоста.
  • UTS — власні hostname і domainname (звідси контейнер може мати інше ім'я хоста, ніж машина, на якій він працює).
  • IPC — окремий простір для System V IPC (черги повідомлень, семафори, спільна пам'ять) і POSIX-черг повідомлень.
  • CGROUP — власний корінь ієрархії cgroups: контейнер бачить свої cgroup-шляхи як корінь, а не реальну гілку /sys/fs/cgroup хоста. Саме CGROUP, а не USER, доповнює п'ятірку класичних просторів до шістки, яку Docker створює без додаткових прапорців.

Ще два типи існують, але до цієї шістки за замовчуванням не входять:

  • USER — відображення (mapping) UID/GID усередині простору на інші UID/GID зовні; Docker не вмикає його без --userns-remap, тобто root у контейнері за замовчуванням відповідає root на хості. Це найважливіший для безпеки простір — і водночас єдиний із «камер», що лишається ввімкненою: доки USER не задіяно, внутрішній root видно ззовні як справжній root.
  • TIME (найновіший, з ядра 5.6) — підмінює видимість системного годинника; у типовому docker run не активується.

Ключова відмінність PID-простору від решти — ієрархічність: процес, що створив новий PID namespace, бачить процеси й свого, і всіх вкладених просторів (з їхніми «зовнішніми» PID), а процеси всередині — лише себе й таких самих «сусідів» у своєму просторі. Саме тому ps aux на хості показує всі процеси контейнерів, а ps aux усередині контейнера — лише свої.

Для дослідження просторів імен зручні дві утиліти: lsns виводить таблицю всіх активних просторів у системі з їхніми NS-ідентифікаторами (це номери inode спеціальних псевдофайлів), а /proc/<pid>/ns/ містить символьні посилання виду pid:[4026531836] для кожного простору, у якому виконується процес. Якщо два процеси мають однакове число в дужках — вони перебувають в одному й тому самому просторі імен, навіть якщо формально належать різним контейнерам (це трапляється, коли контейнери запущені з --network container:<інший> — вони свідомо ділять NET-простір). Команда nsenter -t <pid> -n ... дозволяє «увійти» в простір імен уже запущеного процесу з боку хоста — це основний інструмент діагностики мережі контейнера ззовні.

📖 ОПРАЦЮВАТИ

Прочитати namespaces(7) (man-pages) і розділ Docker docs «Namespaces in Docker»; на своїй машині виконати lsns і порівняти список просторів імен хоста зі списком усередині docker run -it ubuntu:24.04 bash; додатково переглянути символьні посилання /proc//ns/*.

🖥️ ТЕРМІНАЛ — СПРОБУЙ САМ
🎯 ЗАВДАННЯ
  1. Виконати lsns на хості до й після docker run -d nginx; знайти в списку новий рядок PID/NET/MNT/UTS/IPC-простору саме цього контейнера й записати його NS-ідентифікатори.
  2. Усередині запущеного контейнера і на хості паралельно виконати ls -la /proc/self/ns/ і порівняти номери inode для кожного простору імен; пояснити, які збігаються, а які — ні.
  3. Виконати вручну unshare --pid --fork --mount-proc bash поза Docker і переконатися, що echo $$ також повертає 1 — довести, що ізоляція PID не є унікальною фічею саме Docker, а базовим механізмом ядра.
  4. Запустити два контейнери з прапорцем --network container:<ім'я_першого> у другого і переконатися через nsenter -t -n ip addr та nsenter -t -n ip addr, що NET-простори в них ідентичні, а PID-простори — різні.
  5. Перевірити, чи root у контейнері (id -u усередині) відповідає root на хості за відсутності --userns-remap: створити в контейнері файл від root і подивитися його власника (UID) з боку хоста через docker inspect --format '{{.GraphDriver.Data.MergedDir}}' або bind-mount.
❓ КОНТРОЛЬНІ ПИТАННЯ
  1. Скільки типів просторів імен підтримує сучасне ядро Linux, і які шість із них Docker використовує за замовчуванням?
  2. Чому PID усередині контейнера дорівнює 1, хоча реальний PID цього самого процесу на хості інший?
  3. Що станеться з рештою процесів контейнера, якщо процес із PID 1 у ньому аварійно завершиться?
  4. Як за допомогою /proc/<pid>/ns/ визначити, чи перебувають два процеси в одному просторі імен?
  5. Чим mount namespace принципово відрізняється від класичного chroot?
  6. Чому USER namespace вважають найважливішим для безпеки серед усіх, і чи вмикає його Docker без додаткових налаштувань?
  7. Яку задачу вирішує команда nsenter і чим вона відрізняється від docker exec?
✅ САМОПЕРЕВІРКА

Який з шести просторів імен відповідає за те, що echo $$ усередині контейнера повертає 1, а не реальний PID процесу на хості, і що покаже /proc/1/ns/pid зсередини контейнера й ззовні?

🥚 ПАСХАЛКА
Номери просторів імен у lsns — це inode, і роздає їх Диспетчер, не питаючи нікого. Але С.І.Д. присягається, що на списаній машині в класі PID-простір його найпершої капсули мав номер, який закінчувався на 3101, — і що Пиксель у той момент сидів на клавіатурі. «Збіг, ранере? Я перевіряв: 0xC1D збігом не буває».
⌨️ КОМАНДИ НА ЦІЙ СТОРІНЦІ 8

Кожна команда терміналу з цієї сторінки — одним реченням. Позначка нове — команда зустрічається в курсі вперше; далі вважаємо її знайомою.

docker run
Створює й запускає контейнер з образу (docker run -it ubuntu:24.04 bash — інтерактивно з терміналом; -d — у фоні; --rm — видалити після виходу; -p 8080:80 — прокинути порт).
docker
Клієнт Docker: усі дії з образами й контейнерами — через його підкоманди (docker <підкоманда> --help — довідка).
lsns
Перелічує простори імен процесу (lsns -p <PID>) — показує, у яких «кімнатах» ядра він живе.
docker inspect
Друкує повний JSON-опис контейнера чи образу; -f '{{.State.Pid}}' — витягнути одне поле.
docker exec
Виконує команду всередині вже запущеного контейнера (docker exec -it storage sh).
sudo
Виконує команду від імені адміністратора (root); потрібно для змін у ядрі — просторів імен, мережевих інтерфейсів.
unshare
Запускає програму в нових просторах імен (namespaces) ядра — те, з чого «зшитий» контейнер (unshare --pid --fork --mount-proc bash).
ps
Список процесів; ps aux — усі процеси з користувачем, PID і командою (у контейнері видно лише його власні).

💡 Прочитати README прямо в терміналі: cat README.md (виведе весь файл) або less README.md (посторінково; вихід — клавіша q).
Довідка з будь-якої команди: man curl (повний посібник, вихід — q) або коротко curl --help; для підкоманд — docker run --help, cargo build --help.

усі темиSRS02 →