Namespaces
Пространства имен
Пространства имен - это механизм ядра операционной системы, который обеспечивает изоляцию ресурсов процессов. Каждое пространство имен представляет собой логическую группу ресурсов, таких как сеть, файловая система, процессы, IPC (межпроцессное взаимодействие) и другие.
Пространства имен обеспечивают процессы собственным системным представлением, тем самым изолируя независимые процессы друг от друга.
Другими словами, пространства имен определяют набор ресурсов, которые может использовать процесс (нельзя взаимодействовать с тем, что не видно). На высоком уровне они позволяют тонко разделять глобальные ресурсы операционной системы, такие как точки монтирования, сетевой стек и утилиты межпроцессного взаимодействия.
Пространства имен позволяют создавать отдельные изолированные экземпляры ресурсов для каждого процесса или группы процессов, что обеспечивает логическую и физическую изоляцию между процессами и предотвращает конфликты ресурсов.
Виды пространства имён
Linux-система при старте инициализирует один экземпляр каждого типа пространства имён, кроме пространства имён файловой системы. После инициализации можно создать или объединить дополнительные пространства имён.
Все пространства имён поддерживают вложенность, то есть между ними можно установить связь «родитель — потомок». Таким образом некоторые пространства наследуют все свойства от своего родительского пространства имён. Однако это верно не для всех пространств.
Функциональные возможности пространства имён одинаковы для всех типов: каждый процесс связан с пространством имён и может видеть или использовать только ресурсы, связанные с этим пространством имён, и, где это применимо, — с его потомками. Таким образом, каждый процесс (или его группа) может иметь уникальное представление о ресурсе. Изолированный ресурс зависит от типа пространства имён, созданного для данной группы процессов.
На текущий момент в Linux поддерживается шесть типов пространств имён:
| Пространство имён | Что изолирует |
|---|---|
| PID | PID процессов |
| NETWORK | Сетевые устройства, стеки, порты и т.п. |
| USER | ID пользователей и групп |
| MOUNT | Точки монтирования |
| IPC | SystemV IPC, очереди сообщений POSIX |
| UTS | Имя хоста и доменное имя NIS |
| Time | Время |
PID: изоляция PID процессов
Исторически в ядре Linux поддерживалось только одно дерево процессов. Дерево процессов представляет собой иерархическую структуру, подобную дереву каталогов файловой системы. С появлением механизма namespaces стала возможной поддержка нескольких деревьев процессов, полностью изолированных друг от друга.
При загрузке в Linux сначала запускается процесс с идентификационным номером (PID) 1. В дереве процессов он является корневым. Он запускает другие процессы и службы. Механизм namespaces позволяет создавать отдельное ответвление дерева процессов с собственным PID 1. В результате не только systemd (PID=1), но и другие процессы могут воспринимать себя как корневые, перемещаясь в вершину поддерева и получая в нем PID=1. Процесс, который создаёт такое ответвление, являются частью основного дерева, но его дочерний процесс уже будет корневым в новом дереве.
Процессы в новом дереве никак не взаимодействуют с родительским процессом и даже не «видят» его. В то же время процессам в основном дереве доступны все процессы дочернего дерева.
Можно создавать несколько вложенных пространств имён PID: один процесс запускает дочерний процесс в новом пространстве имён PID, a тот в свою очередь порождает новый процесс в новом пространстве и т.п.
Один и тот же процесс может иметь несколько идентификаторов PID (отдельный идентификатор для отдельного пространства имён).
Для создания новых пространств имён PID используется системный вызов clone() c флагом CLONE_NEWPID. С помощью этого флага можно запускать новый процесс в новом пространстве имён и в новом дереве.
NET: изоляция сетей
Благодаря пространству имён NET мы можем выделять для изолированных процессов собственные сeтевые интерфейсы. Даже loopback-интерфейс для каждого пространства имён будет отдельным.
Если приложение выполняется в процессе с отдельным net namespace, то мы можем гарантировать полную сетевую изоляцию от всей остальной системы и взаимодействие только через специально выделенные для этого интерфейсы.
Сетевые пространства имён можно создавать с помощью системного вызова clone() с флагом CLONE_NEWNET. Также это можно сделать с помощью iproute2: ip netns add netns1
Как можно помещать процессы в новое сетевое пространство имён?
- Во-первых, процесс, создавший новое пространство имён, может порождать другие процессы, и каждый из этих процессов будет наследовать сетевое пространство имён родителя.
- Во-вторых, в ядре имеется специальный системный вызов —
setns(). С его помощью можно поместить вызывающий процесс или тред в нужное пространство имён. Для этого требуется файловый дескриптор, который на это пространство имён ссылается.
Сетевое пространство имён нельзя удалить при помощи какого-либо системного вызова. Оно будет существовать, пока его использует хотя бы один процесс.
Связывание двух пространств имен
Для того, чтобы сделать процесс внутри нового сетевого пространства имен достижимым из другого аналогичного пространства, нам потребуется пара виртуальных интерфейсов. Эти интерфейсы связаны виртуальным кабелем – то, что поступает на один его конец, передается на другой (подобно конвейеру в Linux). Значит, если мы хотим связать одно пространство имен (N1) с другим (N2), то нужно поместить один из виртуальных интерфейсов в сетевой стек N1, а другой в сетевой стек N2.
Соединение нескольких пространств имен (создание LAN)
Для создания виртуальной LAN мы используем другую утилиту виртуализации – мост. Мост в Linux действует подобно реальному сетевому коммутатору второго уровня – перенаправляет пакеты между подключенными к нему интерфейсами, используя MAC-таблицу.
USER namespace
Все процессы в мире Linux кому-то принадлежат. Существуют привилегированные и непривилегированные процессы, что определяется их пользовательским ID (UID). В зависимости от этого UID процессы получают разные привилегии в ОС. Пользовательское пространство имен – это функционал ядра, позволяющий выполнять виртуализацию этого атрибута для каждого процесса.
По сути, это означает, что процесс имеет полные привилегии для операций внутри его текущего пользовательского пространства имен, но вне него является непривилегированным.
Когда создается user namespace, первый процесс в нем получает полный набор возможностей для данного namespace. Это позволяет ему выполнять любые необходимые инициализации до создания других процессов в этом namespace. Причем несмотря на то, что новый процесс имеет весь набор возможностей в новом user namespace, в родительском namespace он их не имеет совсем. Это верно независимо от полномочий и возможностей процесса, вызывающего clone(). В частности, даже если корень задействует clone(CLONE_NEWUSER), результирующий дочерний процесс не будет иметь возможностей в родительском namespace.
MOUNT: изоляция файловой системы
С помощью пространств имён MOUNT можно создавать полностью независимые файловые системы, ассоциируемые с различными процессами.
Сначала дочерний процесс «видит» те же точки монтирования, что и родительский. Как только дочерний процесс перенесён в отдельное пространство имён, к нему можно примонтировать любую файловую системы, и это никак не затронет ни родительский процесс, ни другие пространства имён.
Linux поддерживает структуру данных для всех различных файловых систем, смонтированных в системе. Эта структура является индивидуальной для каждого процесса, а также пространства имен. В нее входит информация о том, какие разделы дисков смонтированы, где они смонтированы и тип монтирования (RO/RW).
UTS namespace
Пространство имен UTS изолирует имя хоста системы для определенного процесса.
Большая часть взаимодействия с хостом выполняется через IP-адрес и номер порта. Однако для человеческого восприятия все сильно упрощается, когда у процесса есть хоть какое-то имя. К примеру, выполнять поиск по файлам журналов гораздо проще, когда определено имя хоста. Не в последнюю очередь это связано с тем, что в динамической среде IP могут изменяться.
Итак, пространство имен UTS предоставляет разделение имен хостов среди процессов. Таким образом, становится проще взаимодействовать со службами в закрытой сети и инспектировать их логи на хосте.
IPC namespace
Пространство имен IPC предоставляет изоляцию для механизмов взаимодействия процессов, таких как семафоры, очереди сообщений, разделяемая память и т.д. Обычно, когда процесс ответвляется, он наследует все IPC, открытые его родителем. Процессы внутри IPC namespace не могут видеть или взаимодействовать с ресурсами IPC вышестоящего пространства имен.
CGROUP namespace
Cgroup (контрольная группа) — это технология, контролирующая потребляемый процессом объем аппаратных ресурсов (RAM, HDD, блок ввода-вывода).
По умолчанию CGroup создаются в виртуальной файловой системе /sys/fs/cgroup. Создание другого CGroup namespace, по сути, перемещает корневой каталог CGroup. Если CGroup размещалось, например, в /sys/fs/cgroup/mycgroup, то новое CGroup namespace могло использовать его в качестве корневого каталога. Хост может видеть /sys/fs/cgroup/mycgroup/{group1,group2,group3}, но создание нового CGroup namespace будет означать, что новое namespace увидит только {group1,group2,group3}.
nsenter
nsenter — это утилита, которая позволяет выполнять команду, входя в пространства имен других процессов.
# Запустить команду в сетевом пространстве имён уже запущенного процесса:
nsenter -t {{pid}} -n {{command}} {{command_arguments}}
# Запустить новую команду в пространстве имён PID уже запущенного процесса:
nsenter -t {{pid}} -p {{command}} {{command_arguments}}
# Запустить новую команду в пространстве имён IPC уже запущенного процесса:
nsenter -t {{pid}} -i {{command}} {{command_arguments}}
Контейнеры
Пространства имен активно используются для виртуализации ресорсов ПК с помощью контейнеров