Зачем нужны namespaces
Контейнеры - это не виртуальные машины. У них одно ядро с хостом. Изоляцию даёт связка двух механизмов:
- cgroups - лимит «сколько ресурсов можно тратить»
- namespaces - лимит «что видно процессу»
Семь типов
| namespace | что изолирует | флаг unshare/clone |
|---|---|---|
| mnt | mount points (свой набор смонтированных FS) | CLONE_NEWNS |
| net | интерфейсы, маршруты, ARP, сокеты, файрвол | CLONE_NEWNET |
| pid | дерево PID; PID 1 в ns ≠ PID 1 на хосте | CLONE_NEWPID |
| user | UID/GID; root внутри = unprivileged снаружи | CLONE_NEWUSER |
| uts | hostname, domainname | CLONE_NEWUTS |
| ipc | System V IPC, shared memory | CLONE_NEWIPC |
| cgroup | view на cgroup-tree (видишь только своё поддерево) | CLONE_NEWCGROUP |
| time | CLOCK_MONOTONIC offset (Linux 5.6+) | CLONE_NEWTIME |
Как создаются
Три способа:
clone()/unshare()syscall - программа просит у ядра новый namespaceip netns add NAME- создаёт network namespace, монтирует/run/netns/NAMEчтобы можно было сослаться (см. veth-pair)unshare CMD- обёртка которая делаетunshare()+exec()
Что видно в /proc/<pid>/ns/
Каждый процесс - это набор namespace handle'ов в /proc/<pid>/ns/:
ls -l /proc/self/ns/
# net -> 'net:[4026531992]'
# mnt -> 'mnt:[4026531840]'
# pid -> 'pid:[4026531836]'
# ...
Число в скобках - inode-id namespace'а. Если у двух процессов одинаковый ID
для net - они в одном network namespace. Это первичный способ диагностики
«в каком ns я нахожусь».
Перейти в существующий namespace другого процесса - nsenter:
sudo nsenter -t <pid> -n -p ip addr # выполнить ip addr в net+pid ns процесса <pid>
Связь с Docker
Когда ты делаешь docker run image, Docker:
unshare()со всеми флагами кромеtime- Создаёт veth-pair, один конец оставляет на хосте в bridge, другой кладёт в новый net-namespace
- Mount'ит overlay-FS как корень процесса
- Помещает процесс в cgroups для лимитов
exec-нул бинарь из image
Всё. Никакой VM, никакого гипервизора - только namespaces + cgroups.