← Назад к вопросам

Что такое namespaces и cgroups в Linux? Как они связаны с контейнерами?

2.0 Middle🔥 231 комментариев
#Docker и контейнеризация

Комментарии (1)

🐱
deepseek-v3.2PrepBro AI6 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Namespaces и cgroups: фундамент контейнеризации в Linux

Этот вопрос затрагивает саму суть технологии контейнеров, таких как Docker и Kubernetes. Namespaces и cgroups — это два фундаментальных механизма ядра Linux, которые в совокупности создают изоляцию и контроль ресурсов, необходимые для работы контейнеров. Они не были созданы специально для контейнеров, но стали их технологическим фундаментом.

Linux Namespaces: изоляция процессов

Namespaces — это механизм ядра Linux для изолирования и виртуализации системных ресурсов для группы процессов. Каждый namespace создаёт собственный, изолированный взгляд на систему. Основные типы namespace:

  • PID (Process ID): Изолирует дерево процессов. Процессы в одном PID namespace видят только свои и дочерние процессы. PID 1 в контейнере — это его init-процесс, а не системный systemd или init.
  • Network (net): Создаёт изолированное сетевое стек (интерфейсы, таблицы маршрутизации, правила iptables). Контейнер получает свой собственный loopback-интерфейс (lo) и, при необходимости, виртуальные сетевые интерфейсы (например, eth0 внутри контейнера, привязанный к veth-паре на хосте).
  • Mount (mnt): Изолирует точки монтирования файловых систем. Процесс в контейнере "видит" только своё собственное корневое дерево файлов (rootfs), а не всю файловую систему хоста.
  • UTS (Unix Timesharing System): Позволяет контейнеру иметь собственное имя хоста (hostname) и доменное имя (domainname), независимое от хостовой системы.
  • IPC (Inter-Process Communication): Изолирует ресурсы межпроцессного взаимодействия, такие как очереди сообщений (message queues), сегменты разделяемой памяти и семафоры.
  • User: Изолирует пространство UID/GID. Пользователь с UID 1000 внутри контейнера может быть отображён на UID 10000 на хосте, что повышает безопасность.
  • Cgroup: Изолирует представление о cgroup (появился позже).

Пример создания простой изоляции с помощью namespaces:

# Запуск новой оболочки (sh) в новых PID, UTS, IPC и Mount namespaces.
# unshare - это утилита для создания namespaces.
sudo unshare --pid --uts --ipc --mount --fork /bin/sh
# В этой новой оболочке:
hostname mycontainer  # Меняем hostname только внутри этого namespace
mount -t tmpfs none /tmp  # Монтируем tmpfs, видимый только здесь
ps aux  # Увидим очень ограниченный список процессов

Это примитивный "контейнер", изолированный от основной системы.

Linux Control Groups (cgroups): управление и лимитирование ресурсов

Если namespaces отвечают на вопрос "Что я вижу?", то cgroups отвечают на вопрос "Сколько ресурсов я могу использовать?".

Cgroups (control groups) — это механизм ядра для ограничения, учёта и изоляции потребления ресурсов (CPU, память, диск, сеть) группой процессов. Основные подсистемы (controllers) cgroups v1/v2:

  • cpu / cpuacct: Ограничивает использование процессорного времени и ведёт его учёт. Позволяет назначать shares, quotas и periods (например, через CFS).
  • memory: Устанавливает лимиты на использование оперативной памяти и подкачки (swap), контролирует кэш.
  • blkio: Ограничивает ввод-вывод на блочных устройствах (дисках).
  • pids: Ограничивает количество процессов в группе.
  • devices: Управляет доступом к устройствам (разрешён/запрещён).
  • net_cls / net_prio: Помечает сетевые пакеты для управления трафиком (например, через tc).

Пример использования cgroups для ограничения памяти:

# Создаём новую cgroup в подсистеме memory
sudo mkdir /sys/fs/cgroup/memory/my_container_group
# Устанавливаем лимит в 100 МБ
echo "100M" | sudo tee /sys/fs/cgroup/memory/my_container_group/memory.limit_in_bytes
# Запускаем процесс и помещаем его PID в эту cgroup
echo $$ | sudo tee /sys/fs/cgroup/memory/my_container_group/cgroup.procs
# Теперь процесс и его потомки не смогут использовать больше 100 МБ RAM.

Связь с контейнерами (Docker, containerd, Podman)

Современные среды выполнения контейнеров (runc, containerd) используют namespaces и cgroups как строительные блоки.

  1. Создание изолированной среды: При запуске контейнера docker run, среда выполнения (например, runc) через системный вызов clone() или unshare() создаёт новый набор namespaces для будущих процессов контейнера. Спецификация OCI Runtime явно определяет, какие namespaces должны быть созданы.

  2. Настройка ограничений ресурсов: На основе флагов --memory, --cpus, --blkio-weight среда выполнения создаёт и настраивает cgroup для контейнера (обычно в /sys/fs/cgroup/...), помещая в неё PID основного процесса контейнера (PID 1 внутри namespace). Это обеспечивает соблюдение лимитов.

  3. Иерархия и композиция: Контейнер — это не один namespace или cgroup, а их композиция. Каждый контейнер имеет свой набор изолированных namespaces и принадлежит к своей управляющей cgroup. Инструменты вроде docker exec используют системные вызовы (setns()) для "вхождения" в namespaces существующего контейнера.

  4. Образ и файловая система: Механизм mount namespace в сочетании с pivot_root или chroot позволяет смонтировать корневую файловую систему образа контейнера (например, слои OverlayFS) в изолированное окружение.

Таким образом, контейнер в Linux — это, по сути, процесс (или группа процессов), запущенный в собственном наборе namespaces и ограниченный cgroups. Docker и другие движки предоставляют удобный пользовательский интерфейс, управление образами, сетевыми слоями и оркестрацией поверх этих низкоуровневых примитивов ядра. Понимание namespaces и cgroups критически важно для глубокой отладки, профилирования и обеспечения безопасности контейнерных сред.

Что такое namespaces и cgroups в Linux? Как они связаны с контейнерами? | PrepBro