Namespaces и cgroups

Материал из llmdocs — справочник разработчика
Namespaces и cgroups
Подсистемаядро Linux
Namespacesс 2002 (mount), полный набор к 2013 (user), cgroup ns 2016, time ns 2020
cgroupsGoogle (2006), в ядре с 2.6.24 (2008)
cgroup v2стабильна с ядра 4.5 (2016)
Видов namespaces8 (mnt, pid, net, ipc, uts, user, cgroup, time)
Утилитыunshare, nsenter, lsns, systemd-cgls, systemd-cgtop

Namespaces (пространства имён) и cgroups (control groups, контрольные группы) — два механизма ядра Linux, из которых собирается то, что мы называем контейнером. Пространства имён отвечают на вопрос «что процесс видит»: свой список процессов, свою сеть, свою файловую систему, своё имя хоста. Контрольные группы отвечают на вопрос «сколько процесс может потребить»: процессорного времени, памяти, операций ввода-вывода. Контейнер — это обычный процесс, запущенный в отдельных namespaces и помещённый в свою cgroup; никакой виртуальной машины при этом нет.

История

Первым в 2002 году появилось пространство имён точек монтирования (mount namespace, ядро 2.4.19), вдохновлённое ОС Plan 9. Остальные добавлялись постепенно, и набор, достаточный для полноценных контейнеров, сложился к ядру 3.8 (2013) с появлением user namespaces.[6] Механизм cgroups инженеры Google начали разрабатывать в 2006 году под названием «process containers»; в ядро он вошёл в 2.6.24 (2008). Из-за запутанной иерархии первой версии была создана cgroup v2 с единым деревом, стабильная с ядра 4.5 (2016).[3] На этих механизмах построены LXC (2008), Docker (2013) и все современные среды выполнения.

Пространства имён

Каждый процесс принадлежит одному пространству имён каждого вида; по умолчанию — общим «корневым».[1]

Вид Флаг Что изолирует
mnt CLONE_NEWNS дерево точек монтирования (своя корневая ФС)
pid CLONE_NEWPID номера процессов: внутри контейнера приложение — PID 1
net CLONE_NEWNET сетевые интерфейсы, маршруты, правила iptables, порты
ipc CLONE_NEWIPC очереди сообщений и разделяемую память System V / POSIX
uts CLONE_NEWUTS имя хоста и домена
user CLONE_NEWUSER UID/GID: root внутри может быть обычным пользователем снаружи
cgroup CLONE_NEWCGROUP видимую часть дерева cgroups
time CLONE_NEWTIME смещения часов CLOCK_MONOTONIC и CLOCK_BOOTTIME

Пространства создаются системными вызовами clone() и unshare(), присоединиться к существующему можно через setns(). Они видны как файлы в /proc/<PID>/ns/.

User namespaces особенно важны для безопасности: они позволяют запускать контейнеры без прав root на хосте (rootless-режим Podman и Docker).[4]

Контрольные группы

cgroup — это узел иерархии в виртуальной файловой системе /sys/fs/cgroup, к которому привязаны процессы и контроллеры ресурсов.[2] В cgroup v2 основные контроллеры такие:

  • cpu — веса (cpu.weight) и жёсткие квоты (cpu.max, например 50000 100000 = половина ядра);
  • memory — лимит (memory.max); при его превышении внутри группы срабатывает OOM killer;
  • io — ограничение пропускной способности и IOPS для блочных устройств;
  • pids — максимальное число процессов (защита от fork-бомбы);
  • cpuset — привязка к конкретным ядрам и NUMA-узлам.

В современных дистрибутивах деревом cgroups управляет systemd: каждая служба, пользовательская сессия и контейнер получают свою группу. Kubernetes переводит requests и limits из описания Pod в настройки cgroup на узле; начиная с версии 1.25 поддержка cgroup v2 стабильна, а cgroup v1 объявлена устаревшей.[5]

Попробовать вручную

# новая оболочка в отдельных pid-, mount- и uts-пространствах
sudo unshare --pid --fork --mount-proc --uts bash
hostname sandbox; ps aux          # видны только процессы этой оболочки

# пространства имён процесса и вход в них (как docker exec)
lsns -p <PID>
sudo nsenter -t <PID> -n ip addr   # сеть контейнера

# cgroups
systemd-cgls                       # дерево групп
systemd-run --scope -p MemoryMax=200M -p CPUQuota=50% ./heavy_job
cat /sys/fs/cgroup/system.slice/nginx.service/memory.current

Изоляция и её пределы

Все контейнеры на хосте делят одно ядро. Уязвимость в ядре или опасные привилегии (--privileged, монтирование сокета Docker, лишние capabilities) позволяют выбраться из контейнера. Поэтому namespaces и cgroups дополняют другими механизмами: capabilities (дробление прав root), seccomp (фильтр системных вызовов), AppArmor и SELinux. Для более жёсткой изоляции применяют песочницы вроде gVisor и микро-VM вроде Kata Containers и Firecracker.

См. также

Источники

  1. man 7 namespaces — overview of Linux namespaces
  2. man 7 cgroups — Linux control groups
  3. Linux kernel docs — Control Group v2
  4. man 7 user_namespaces
  5. Kubernetes Docs — About cgroup v2
  6. LWN — Namespaces in operation (series, 2013)