DockerSeniorTechnical
Что такое namespaces и cgroups, и при чём они тут? (На senior без этого вопроса не уходят.)
Namespaces изолируют то, что видит процесс (PID, сеть, FS, hostname), а cgroups ограничивают, сколько ресурсов он потребляет (CPU, RAM, I/O). Вместе они образуют контейнер без виртуальной машины.
Namespaces и cgroups — основа изоляции контейнеров
Docker не использует никакой магии виртуализации. Контейнер — это просто обычный Linux-процесс, изолированный с помощью двух механизмов ядра: namespaces (изоляция видимости) и cgroups (ограничение ресурсов).
Namespaces — что видит процесс
Namespace делает так, что процесс видит только свою «версию» системного ресурса. Docker использует 7 типов namespace:
- pid — контейнер видит свои процессы начиная с PID 1 (entrypoint). На хосте они имеют реальные PID.
- net — своя сетевая стека: интерфейсы, IP, маршруты, порты. Поэтому два контейнера могут оба слушать порт 8080.
- mnt — своё дерево файловой системы (union FS поверх образа).
- uts — своё имя хоста (hostname). Команда
hostnameвнутри контейнера вернёт container ID. - ipc — изоляция очередей сообщений и разделяемой памяти.
- user — маппинг UID/GID: root (0) внутри контейнера = непривилегированный UID на хосте.
- cgroup (v2) — скрывает cgroup-иерархию хоста.
# Посмотреть namespaces процесса контейнера
CID=$(docker inspect my-container --format '{{.State.Pid}}')
ls -la /proc/$CID/ns/
# Войти в namespace контейнера вручную
nsenter --target $CID --mount --uts --ipc --net --pid -- bash
cgroups — сколько ресурсов потребляет процесс
Control Groups ограничивают CPU, память, I/O, количество процессов. Без cgroups один контейнер может «съесть» всю RAM хоста.
# Запустить контейнер с ограничениями
docker run -d \
--memory=512m \
--memory-swap=512m \
--cpus=1.5 \
--pids-limit=200 \
--name limited-app \
my-app:latest
# Проверить текущие ограничения
docker stats limited-app --no-stream
# Напрямую через cgroup v2
cat /sys/fs/cgroup/system.slice/docker-$(docker inspect limited-app --format '{{.Id}}').scope/memory.max
Связь с Docker-сетями
Когда Docker создаёт контейнер, он:
- Создаёт новый
netnamespace. - Создаёт виртуальный Ethernet-пару (veth): один конец в контейнере (
eth0), другой на хосте (vethXXXX). - Подключает хостовый конец к bridge-интерфейсу (
docker0или пользовательский). - Настраивает iptables/nftables-правила для NAT и фильтрации.
# Посмотреть veth-пары на хосте
ip link show type veth
# Посмотреть bridge docker0
brctl show docker0
# iptables-правила для NAT
iptables -t nat -L DOCKER --line-numbers
Почему это важно для senior-уровня
Понимание namespaces объясняет:
- Почему
--network hostнебезопасен — контейнер разделяетnetnamespace с хостом. - Почему
--privilegedопасен — снимает ограничения namespace и даёт доступ к устройствам. - Как работает
docker exec— процесс присоединяется к существующим namespace контейнера. - Почему контейнер нельзя «убежать» без уязвимости — он ограничен своим namespace.
Подводные камни
- cgroups v1 и v2 — разный путь и API; Ubuntu 22+ и RHEL 9 используют v2 по умолчанию, некоторые старые инструменты ожидают v1.
- Без
--memory-swapконтейнер может использовать своп неограниченно даже при заданном--memory. - User namespace не включён по умолчанию в Docker (требует настройки userns-remap в daemon.json) — root внутри = root снаружи без него.
--pid=hostдаёт контейнеру доступ ко всем процессам хоста — критическая уязвимость.--privilegedмонтирует все устройства и отключает seccomp/AppArmor — эквивалентно полному root на хосте.- PID limit по умолчанию не задан — fork-bomb в контейнере убьёт хост. Используйте
--pids-limit. - Ядро одно на всех: уязвимость ядра (container escape) обходит все namespace. Это принципиальное отличие от VM.
- Namespace изолируют ресурсы, но не файловую систему
/procполностью — некоторые пути видны из контейнера и раскрывают информацию о хосте.
Common mistakes
- Путать изоляцию видимости namespaces с ограничением ресурсов cgroups.
- Забывать, что контейнер всё равно использует ядро хоста.
- Не связывать cgroups с OOM, docker stats и resource limits.
What the interviewer is testing
- Называет основные namespaces и объясняет хотя бы PID/network/mount.
- Различает resource accounting и resource isolation.
- Умеет применить модель к debugging сети, процессов и памяти.