Що таке Docker namespace і cgroups?
Linux namespaces і cgroups це два kernel-механізми, що роблять container можливими. Без них у тебе процеси; з ними у тебе container. Docker переважно це інструмент для налаштування цих фіч на масштабі.
Теорія
TL;DR
- Namespaces відповідають на «що цей процес бачить?». Сім типів: PID, mount, network, IPC, UTS, user, cgroup.
- cgroups відповідають на «що цей процес може використовувати?». Лімітують CPU, пам'ять, I/O, PID.
- Обидва це kernel-фічі, що передували Docker роками (LXC популяризував; Docker зробив mainstream).
- Container концептуально:
unshare()для створення namespaces + cgroups-config +chroot(або pivot_root) у rootfs +exec()твого бінаря. - Сучасний Docker на Linux використовує cgroups v2 (unified hierarchy). Legacy v1 мала окремі ієрархії на controller.
Namespaces — сім типів
| Namespace | Що ізолює |
|---|---|
| PID | process ID — container має свій PID 1 |
| mount (mnt) | mount points — container має свою в'юху filesystem |
| network (net) | мережеві інтерфейси, routing-таблиці, сокети, порти |
| IPC | shared memory, семафори, message queues |
| UTS | hostname і domain name |
| user | UID/GID (з remap) |
| cgroup | в'юха cgroup root (cgroups v2) |
Кожен namespace це kernel-ресурс, до якого можна приєднати процес через unshare(2) або clone(2). Docker їх створює при старті container.
Верифікація namespaces у running container
# Namespaces container (кожен має унікальний inode)
$ docker run -it --rm alpine sh
/ # ls -la /proc/self/ns
lrwxrwxrwx ... cgroup -> 'cgroup:[4026532840]'
lrwxrwxrwx ... ipc -> 'ipc:[4026532838]'
lrwxrwxrwx ... mnt -> 'mnt:[4026532836]'
lrwxrwxrwx ... net -> 'net:[4026532842]'
lrwxrwxrwx ... pid -> 'pid:[4026532839]'
lrwxrwxrwx ... user -> 'user:[4026531837]'
lrwxrwxrwx ... uts -> 'uts:[4026532837]'
# Порівняй з host (різні inode для усього, окрім, можливо, user)
$ ls -la /proc/self/nsРізні inode = різні namespaces = ізольовані в'юхи.
cgroups — що вони лімітують
У cgroups v2 (unified hierarchy, сучасна норма) controllers включають:
cpu — CPU-час (cpus, cpu.weight)
memory — RAM і swap-використання
io — block-I/O bandwidth і IOPS
pids — кількість процесів
rdma — RDMA-bandwidth
hugetlb — huge pages# Всередині container з --memory=256m
$ docker run --rm --memory=256m alpine cat /sys/fs/cgroup/memory.max
268435456 # 256 * 1024 * 1024 байт
$ docker run --rm --cpus=0.5 alpine cat /sys/fs/cgroup/cpu.max
50000 100000 # 50мс quota на 100мс period (= 0.5 CPU)Docker транслює --memory, --cpus тощо у cgroup-файли у /sys/fs/cgroup/....
Як docker run використовує обидва
docker run --memory=256m --cpus=1 myapp
│
├── containerd → runc
│ │
│ ├── unshare(CLONE_NEW{PID,NS,NET,IPC,UTS,USER,CGROUP})
│ │ → 7 свіжих namespaces
│ │
│ ├── write cgroup-файли
│ │ → memory.max=256MB, cpu.max=100000 100000
│ │
│ ├── pivot_root у image rootfs
│ │
│ └── exec(your-binary)
│
└── ти бачиш 'container'Namespaces дають приватні в'юхи; cgroups лімітують, що може робити; pivot_root + image-шари дають кастомну filesystem; exec крутить твій бінар як PID 1 у цьому маленькому світі.
User namespace: security-фронтир
# Дефолт (без user namespace remap): root всередині = root на host (якщо не capability-restricted)
$ docker run --rm alpine id
uid=0(root) gid=0(root)
# Всередині container ти root; kernel знає.
# З userns-remap: root всередині мапиться на non-root UID на host
$ # /etc/docker/daemon.json: { "userns-remap": "default" }
$ docker run --rm alpine id
uid=0(root) gid=0(root)
# Всередині, ще root. Але на host процеси як some-non-root-UID.User namespace remap це одне з найсильніших container-hardening. Container-escape більше не означає root на host.
cgroups v1 vs v2
- v1 (legacy): окремі ієрархії на controller (
/sys/fs/cgroup/memory,/sys/fs/cgroup/cpuтощо). Кожен процес належить одному cgroup на controller. - v2 (modern): єдина unified-ієрархія. Кожен cgroup контролює усі enabled-ресурси. Простіше, послідовніше.
- Більшість сучасних Linux-дистро (Fedora, Debian 11+, Ubuntu 22+) дефолтно v2. Docker обробляє обидві.
Перевір, яка у твого host:
stat -fc %T /sys/fs/cgroup
# 'cgroup2fs' = v2, 'tmpfs' = v1Типові помилки
Сприймати namespaces як security-межі
Namespaces ховають речі від процесу; вони не зупиняють процес з правильними capabilities від break-out. У комбінації з capabilities (default-drop CAP_SYS_ADMIN тощо) і seccomp (syscall-фільтрація) утворюють захист, але самі namespaces не impenetrable. Реальна ізоляція потребує повного Docker security-стеку (або microVM як Kata/Firecracker).
Забути, що cgroups лімітують пам'ять, але не OOM-поведінку
docker run --memory=256m greedy-app
# Коли greedy-app намагається алокувати 257-й MB, kernel OOM-kill.OOM-kill процеси всередині cgroup виходять 137. Твій supervisor / restart-policy вирішує, що далі.
Плутати user namespace з --user
--user 1000:1000= крути процес як конкретний UID всередині user-namespace container (все одно root всередині, якщо не remap).userns-remap= remap UID з container на host. Окрема рукоятка.
Припускати, що PID-namespaces працюють як container скрізь
Kubernetes-pod можуть ділити PID-namespaces між container (флаг shareProcessNamespace: true). У звичайному Docker два docker run container завжди мають окремі PID-namespaces. Інший mental-model.
Реальне застосування
- Кожен container, скрізь. Namespaces і cgroups лежать в основі кожного Docker, Podman, K8s-pod, Lambda-функції (через Firecracker microVM), Cloud Run-task.
- Hardened multi-tenant: user namespace remap + dropped capabilities + seccomp-профіль + read-only filesystem → strong-ish ізоляція.
- Resource governance: cgroup-ліміти запобігають заморюванню одним tenant іншими на shared-infra.
- Debugging container-внутрішнього:
lsns,nsenter,/proc/<pid>/ns/*для inspect або join namespaces ззовні.
Питання для поглиблення
Q: Чи namespaces або cgroups Linux-специфічні?
A: Так. Обидва це Linux kernel-фічі. Docker на Mac/Windows крутить Linux VM під капотом саме тому.
Q: Що таке unshare?
A: Syscall (і CLI-tool), що створює новий namespace і приєднує calling-процес. unshare --pid --fork --mount-proc /bin/bash дає тобі shell у свіжих PID + mount namespaces, найпростіше «побудуй container руками» демо.
Q: Яка різниця між cgroups і ulimits?
A: ulimits (resource-ліміти через PAM, setrlimit) per-process. cgroups застосовуються до дерева процесів і переживають exec. Обидва можуть лімітувати ресурси; cgroups це сучасна, ієрархічна kernel-відповідь.
Q: Чи можу побачити, у якому cgroup host-процес?
A: Так: cat /proc/<pid>/cgroup. Для Docker-процесу це вказує у /sys/fs/cgroup/<docker-cgroup-path>.
Q: (Senior) Як побудувати мінімальний container руками лише через namespaces + cgroups?
A: unshare --pid --net --mount --uts --ipc --user --fork chroot /path/to/rootfs /bin/sh дає тобі процес з ізольованими namespaces і кастомним rootfs, голий кістяк container. Додай cgroups руками, пишучи у /sys/fs/cgroup/<your-cgroup>/.... Це приблизно те, що runc робить за тебе, автоматизовано і OCI-spec-сумісно. Корисна вправа, щоб демістифікувати, що таке container.
Приклади
Демонстрація namespace-ізоляції
# Host
$ ps -ef | wc -l
312
# Всередині container
$ docker run --rm alpine ps -ef | wc -l
2
# Container бачить лише свої процеси (PID 1 + сам ps)Той самий kernel, дві в'юхи, ось і PID-namespace у дії.
Демонстрація cgroups
# Memory-жадібна програма
$ docker run --rm --memory=64m alpine sh -c 'dd if=/dev/zero of=/dev/null bs=1G count=1'
Killed
# Container OOM-kill на 64MB ліміті.
$ docker run --rm --cpus=0.1 alpine sh -c 'time -- timeout 5 sh -c "yes > /dev/null"'
real 0m 5.00s
user 0m 0.50s
sys 0m 0.00s
# user time = 0.5s у 5s wall = 10% CPU = capKernel enforce'їть, Docker лише ставить параметри.
Mapping --user vs userns-remap
# --user: змінює UID всередині (без remap)
$ docker run --rm --user 1000:1000 alpine id
uid=1000 gid=1000
# Зовні все одно UID 1000 (без ізоляції між in/out namespaces).
# З userns-remap (daemon-level config):
# /etc/docker/daemon.json: { "userns-remap": "default" }
$ docker run --rm alpine id
uid=0(root) gid=0(root)
# Всередині root.
$ ps -ef | grep <container-pid>
UID 165536 ...
# Але на host той самий процес UID 165536 (offset).Друге значно сильніша ізоляція. Дуже рекомендовано для multi-tenant кластерів.
Коротка відповідь
Для співбесідиКоротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.
Коментарі
Ще немає коментарів