Именни пространства и c-групи в Linux: истинската основа на контейнерите

Последна актуализация: 24 на февруари 2026
Автор: TecnoDigital
  • Контейнерите в Linux разчитат на пространства от имена, за да изолират какво могат да виждат процесите, и на cgroups, за да ограничат колко ресурси могат да използват.
  • Съществуват различни видове именни пространства (PID, NET, MNT, UTS, IPC, USER, cgroup, time) и cgroup контролери (CPU, памет, I/O, pids), които се комбинират в зависимост от случая.
  • Docker, Kubernetes и systemd разчитат на тези примитиви на ядрото, за да създават изолирани среди, да прилагат политики за ресурси и да управляват услугите по единен начин.
  • Мониторингът на показателите на cgroup и разбирането на топологията на именните пространства са от съществено значение за диагностициране на OOM-и, проблеми с производителността и осигуряване на солидна изолация в производствения процес.

linux контейнери cgroups именни пространства

Ако работите с Docker, Kubernetes или която и да е друга контейнерна платформа, рано или късно ще се наложи да се задълбочите във вътрешните механизми на системата. Зад „магията“ на стартирането на контейнери за секунди се крият два ключови компонента на ядрото на Linux: пространства от имена и cgroups, дуото, отговорно за изолацията и фино настроеното управление на ресурсите . Разбирането им прави цялата разлика между простото използване на инструменти и проектирането на инфраструктурата.

В цялата статия спокойно, но без да навлизаме в прекалено много подробности, ще разгледаме как работят те пространства от имена (какво може да вижда даден процес) и cgroups (какво може да използва даден процес)Как Docker и Kubernetes се възползват от тях; как можете да ги променяте на ниско ниво, използвайки команди като unshare, ip netns или писане директно в /sys/fs/cgroupИ какви трикове са полезни за производителност, сигурност и отстраняване на проблеми в производствена среда.

Какво всъщност прави един контейнер в Linux?

Когато изпълнявате нещо подобно docker runне се създава магическа виртуална машина; Това, което получавате, е Linux процес (или група от процеси) със силна изолация и ограничени ресурси.„Трикът“ се основава на четири механизма на ядрото:

  • Пространствата от именаТе контролират какво вижда процесът (PID-ове, мрежа, файлова система, име на хост и т.н.).
  • C-групиТе контролират колко може да използва процесът (CPU, RAM, I/O, PID...).
  • Chroot / rootfs изолирани: те дават на процеса собствена файлова система.
  • Нормални Linux процесиВ крайна сметка всичко се свежда до PID-овете на хоста, управлявани от ядрото.

С други думи, контейнерът е просто процес, изпълняващ се с набор от нови пространства от имена, вложени в една или повече cgroups, и със персонализирана файлова система . Останалото се обработва от инструмента (Docker, container, runc и др.) с автоматизация и лесни за ползване API.

Именни пространства в Linux: изолиране на това, което всеки процес може да вижда

Именните пространства са слой на абстракция на ядрото, който създава отделни „светове“ за групи процеси . Процесът вижда само ресурсите в своето именно пространство; останалата част от системата е все още там, но е невидима за него.

В момента Linux има няколко вида пространства от имена, всяко от които е фокусирано върху специфична част от системата. Комбинирани, те позволяват контейнерът да бъде възприеман като независима операционна система, въпреки че споделя ядро ​​с хоста.

Основни типове именни пространства

Всеки тип именно пространство изолира различно измерение. Обичайна практика е в „сериозен“ контейнер да се използват няколко от тях едновременно. Това са най-важните:

  • PID пространство от имена: изолира пространството на идентификатора на процеса. В контейнера основният процес обикновено е PID 1.дори ако хостът има различен номер. Процесите от различни пространства от имена могат да имат един и същ PID, без да си пречат, и не могат да си изпращат сигнали, освен ако не е изрично разрешено от хоста.
  • Именуване на мрежа (NET): създава независим мрежов стек със собствени интерфейси, маршрути, правила за защитна стена, сокети и др. Всеки контейнер има собствен обратен цикъл, собствени IP адреси и собствено маршрутизиране.По този начин можете да използвате повторно един и същ IP адрес в различни пространства от имена без конфликт и да прилагате изолирани правила за iptables.
  • Именуване на Mount (MNT): разделя изгледа от точките на монтаж. Процесите виждат само файловата йерархия на своето пространство от именаВъпреки че отдолу има свързващи монтирания, споделени томове, наслагвания и т.н. Това позволява на контейнера да изглежда сякаш има свой собствен "/", без да докосва действителния корен на хоста.
  • UTS пространство от имена: контролира името на хоста и NIS домейна. В рамките на UTS пространство от имена, Можете да промените името на хоста, без да засягате хост систематаМного полезно за разграничаване на контейнери или симулиране на възли в тестови среди.
  • IPC пространство от имена: изолира опашките от съобщения, семафорите и споделената памет на System V. Предотвратяване на смущенията в IPC от различни процеси на контейнери поради инцидент или лош дизайн.
  • Потребителско пространство от именаВероятно най-деликатният. Той позволява Съпоставяне на вътрешни UID и GID на пространствата от имена с други идентификатори на хостовеТова прави възможно „root“-ът в контейнера да бъде съпоставен с непривилегирован потребител на хоста, което значително намалява риска от ескалация на привилегиите и подобрява... сигурност на контейнера.
  • Cgroup именно пространство: предоставя виртуализиран изглед на /proc/self/cgroup и йерархията на cgroups. От вътрешността на контейнера се виждат само неговите собствени групи.Това скрива действителната структура на гостоприемника и засилва изолацията.
  • Именуване на време: позволява предлагането различни възприятия за време (часовници като CLOCK_MONOTONIC или CLOCK_BOOTTIME) за различни групи процеси. Полезно е за тестови сценарии или много фина изолация.
  5-те най-често срещани операционни системи днес

Всички тези пространства от имена са изложени в /proc/<pid>/ns/и може да бъде създаден или комбиниран с инструменти като unshare y nsenterКогато последният процес, принадлежащ към дадено именно пространство, завърши работа, това именно пространство се унищожава автоматично.

Експериментиране с пространства от имена от командния ред

Командата unshare Това е едно от основните правила за експериментиране: създава дъщерен процес с едно или повече нови пространства от именаНапример, за да тествате изолирано пространство от имена на PID:

unshare --pid --fork --mount-proc bash
ps aux
echo $$

Вътре ще виждате само процесите от това пространство от имена и вашата обвивка ще се показва там като PID 1, въпреки че хостът все още ще има всичките си обичайни процеси. Това е основно скелетът на това, което ще прави OCI средата за изпълнение, когато се стартира контейнер.

Подробности за мрежовите именни пространства

Мрежовият аспект е един от най-гъвкавите. При създаването на NET пространство от имена с ip netns addПолучавате празен стек, с изключение на стека за обратна връзка. Оттам можете:

  • Свържете това пространство от имена с хоста с чифт veth (два виртуални интерфейса, свързани чрез логически кабел).
  • Създаване на мостове тип br0 и свържете няколко пространства от имена към този мост, така че те да могат да се виждат взаимно, използвайки частни IP адреси.
  • NAT и пренасочване да се даде достъп до интернет на тези „домашно приготвени контейнери“ с iptables и /proc/sys/net/ipv4/ip_forward.

Точно така, на много ниско ниво, това прави Docker с моста docker0 и техните мрежи по подразбиране: Той настройва мрежови пространства от имена, veth peers, мостове и NAT правила. така че контейнерите да могат да общуват помежду си и да излизат навън.

Монтиране и потребителски пространства от имена за rootfs и сигурност

С `mount namespace` можете да експериментирате със създаването на файлова система от контейнери, без да използвате Docker. Типичният модел е:

  • За да сглобите или подготвите минимални rootfs (например, мини-роотфс файл на Alpine, изтеглен от wget и разархивирано в директория).
  • Създайте пространство от имена за монтиране и го направете pivot_root o chroot към тази директория.
  • планина /proc, /sys и други псевдосистеми в рамките на новия корен.

С това вашата обвивка ще вижда само тази файлова система, но Вие оставате нормален хост процес, с вашия реален PID и контролируем от администратора.Ако използвате и потребителско пространство от имена с --map-root-userМожете да имате "root" вътре, който е извън потребител без привилегии.

Cgroups: колко ресурси може да изразходва всеки процес

Докато пространствата от имена определят какво може да вижда даден процес, cgroups ограничават колко системни ресурси може да консумира една група от процеси . Те бяха въведени в ядрото 2.6.24 и сега са от съществено значение за всяка съвременна контейнерна платформа.

На концептуално ниво, c-групата е директория в /sys/fs/cgroup с файлове, които описват ограничения, приоритети и показателиКогато добавите PID към съответния файл (например, cgroup.procs), този процес е предмет на тези правила.

Контролери на ресурси в cgroups

C-групите са съставени от контролери (подсистеми), които действат върху специфични ресурси. Сред най-често използваните са:

  • процесор: контролира разпределеното време на процесора. С акции определя относителния приоритет; с квоти твърди ограничения (напр. 50 ms време за изчакване на процесора за период от 100 ms); с CPU комплекти Вие фиксирате процесите към конкретни ядра.
  • памет: ограничава RAM паметта и swap-а. Позволява Твърди и меки ограничения, OOM killer настройки, статистика и натоварване на паметтаМного полезно за предотвратяване на използването на целия сървър от дадена услуга.
  • Блоков вход/изход (blkio / io): ограничава честотната лента и IOPS на устройство. Можете задайте пропорционално тегло или задайте точни ограничения в байтове/сек. операции/сек..
  • мрежаСъществуват механизми за ограничаване на честотната лента и пакетите, въпреки че поддръжката е по-слабо развита и обикновено се комбинира с tc и QoS.
  • PID-овемаркирайте максимален брой процеси/нишки което може да създаде група, смекчавайки форк бомбите или грешките в кода, които задействат нишки.

Практическата идея е много проста: поставяте приложението си в контролна група (cgroup) и задавате максимален брой процесори (CPU), памет, входно-изходни данни (I/O) и PID-ове . Оттам нататък ядрото се грижи за прилагането на правилата.

cgroups v1 срещу cgroups v2

В продукционната среда ще откриете два вида cgroups и е важно да сте наясно на коя територия стъпвате:

  • cgroup v1Всеки контролер има своя собствена независима йерархия. Имате маршрути като /sys/fs/cgroup/cpu/..., /sys/fs/cgroup/memory/...И др Гъвкав е, но сложен за управление в голям мащаб.Много класически дистрибуции и платформи все още го използват или го поддържат за съвместимост.
  • cgroup v2групира всичко под едно унифицирана йерархия en /sys/fs/cgroupОграниченията се конфигурират чрез файлове като cpu.max, memory.max, io.max и други подобни. Опростява управлението и подобрява фината настройка на ресурситеСъвременните дистрибуции са склонни да използват v2 по подразбиране, понякога с хибриден режим.
  Как да изтриете сигурно файлове, така че да не могат да бъдат възстановени

En /proc/cgroups Можете да видите кои контролери са активирани, колко активни cgroups има и дали сте във v1 или v2 (във v2 ще видите унифицирана йерархия с ID 0). Командата mount | grep cgroup Той също така ви казва типа на файловата система (cgroup2fs предполага v2, tmpfs (обикновено сочи към v1).

Ръчно създаване на c-групи и типични ограничения

За да разберете напълно какво прави Docker „под капака“, си струва да създадете cgroups ръчно. Общият модел е:

  • Създайте директория cgroup.
  • Конфигуриране на файлове с ограничения/приоритет (процесор, памет, входно/изходни устройства, PID контролери…).
  • Добавете PID-ове към cgroup, като въведете cgroup.procs o tasks (във версия 1).

Например, в cgroups v2, може да имате нещо подобно за процесора и паметта:

mkdir /sys/fs/cgroup/test_app
echo "+cpu +memory +io +pids" > /sys/fs/cgroup/cgroup.subtree_control
echo "50000 100000" > /sys/fs/cgroup/test_app/cpu.max
echo "512M" > /sys/fs/cgroup/test_app/memory.max
echo $$ > /sys/fs/cgroup/test_app/cgroup.procs

С това настоящият процес е ограничен до 50% от ядрото и 512 MB RAMАко започнете нещо интензивно (а dd към /dev/null, например), ще видите, че системата не се побърква. В cgroups v1 схемата е подобна, но с файлове като cpu.shares, cpu.cfs_quota_us, memory.limit_in_bytesи т.н., всяко в собствената си йерархия.

Как Docker, Kubernetes и ядрото се стекат

Над пространствата от имена и c-групите има няколко софтуерни слоя, които си прехвърлят отговорността, докато стигнат до ядрото. Дори ако името на инструмента се промени, крайният резултат винаги е един и същ: ядрото извършва повиквания за създаване на пространства от имена, конфигуриране на c-групи и монтиране на файлови системи.

Типичният „стек“ от контейнери днес изглежда горе-долу така:

  • Оркестрационен слойKubernetes, Docker Swarm, Nomad… Те управляват жизнения цикъл на pod/услугата, планирането, мащабирането и поддръжката. архитектури на микросървиси.
  • среда за изпълнение на контейнери на високо нивоDocker Engine, контейнеризиран, CRI-O. Те получават заповедите на оркестратора и ги превръщат в конкретни действия. (изтегляне на изображения, създаване на контейнери, управление на моментни снимки и др.).
  • Ниско ниво на изпълнение на OCIRunc, crun и подобни инструменти имплементират OCI спецификацията и са пряко отговорни за нейното внедряване. те се обаждат clone(), unshare(), mount() и компания да материализира контейнера.
  • Linux ядроТой предоставя пространства от имена, cgroups, OverlayFS и всички други примитиви. Тук се случва истинската „магия“.

Когато хвърлите docker runПътят е: CLI клиент → dockerd → containerd → runc → kernel calls. По този път се създават именни пространства, присвояват се cgroups, rootfs се монтира с OverlayFS плюс томове и се свързват мрежовите интерфейси и bridge. Това, което виждате като „контейнер“, за ядрото е шепа процеси с определени флагове и специални пътища..

Изисквания и предварителни проверки в системата

Преди да започнете да се занимавате с именни пространства и c-групи на сървър, е добре да се уверите, че хардуерът и ядрото отговарят на разумни минимални изисквания , особено ако планирате да настроите нещо подобно на производствена среда.

Като ориентир, обикновено се препоръчват поне 2 логически процесора, 4 GB RAM (за предпочитане 8 GB или повече) , около 20 GB свободно дисково пространство и ядро ​​3.10 или по-нова версия (в идеалния случай 4.x или 5.x, за да има всички предимства на cgroups v2 и съвременни функции).

За да проверите дали ядрото поддържа именни пространства и cgroups, просто проверете конфигурационния файл на използваната версия:

grep -E "CONFIG_.*_NS" /boot/config-$(uname -r)
grep -E "CONFIG_CGROUP" /boot/config-$(uname -r)

Опции като тези би трябвало да се появят там CONFIG_NAMESPACES, CONFIG_PID_NS, CONFIG_NET_NS, CONFIG_CGROUPS, CONFIG_MEMCG, CONFIG_CGROUP_SCHED маркиран като =yБез това няма да имаш кой знае каква игра.

Друг практичен детайл е дали системата позволява създаване на потребителски пространства от имена без да сте rootТова е много полезно за тестване и някои инструменти. Контролира се със sysctl. kernel.unprivileged_userns_cloneАко е на 0, ще трябва да го активирате (или да използвате потта си навсякъде).

Изследване на c-групи и именни пространства на „реални“ машини

Доста лесен начин да се усвоят тези концепции е да се разгледа как самата система и вашите контейнери ги използват . Някои полезни съвети:

  • ls /proc/self/ns/ Показва ви именните пространства, към които принадлежи текущата ви обвивка (cgroup, ipc, mnt, net, pid, user, uts…).
  • systemd-cgtop Показва използването на процесора, паметта и входно/изходните операции от cgroup, много подобно на top но групирани по услуги и контейнери.
  • En /sys/fs/cgroup Можете да намерите cgroups, които Docker или Podman създават за всеки контейнер, обикновено използвайки идентификатора на контейнера в пътя. Вътре, cgroup.procs Избройте свързаните PID-ове.
  • /proc/<pid>/cgroup Той ви казва към кои cgroups е присвоен даден процес, което е идеално за проследяване на проблемно приложение.
  Новини за операционните системи: пълен и актуален преглед

Ще видите, че контейнерите са просто друг клон на йерархията на cgroups, със своите ограничения за процесор, памет, blkio и други, точно както бихте могли да ги създадете ръчно . Хубавото на Docker е, че прави това автоматично и с лесен за ползване API.

Стратегии за производителност, NUMA и афинитет

В сценарии с високо натоварване (големи бази данни, интензивна обработка, стрийминг и др.), простото „стартиране на контейнери“ не е достатъчно. Начинът, по който разпределяте процесора и паметта за всяка услуга, оказва значително влияние върху производителността.

С драйвера cpuset можете да присвоите процеси или услуги на специфични набори от процесори и NUMA възли. Толкова е просто:

mkdir /sys/fs/cgroup/cpuset/dedicated_cpus
echo "4-7" > /sys/fs/cgroup/cpuset/dedicated_cpus/cpuset.cpus
echo "0" > /sys/fs/cgroup/cpuset/dedicated_cpus/cpuset.mems
echo 1 > /sys/fs/cgroup/cpuset/dedicated_cpus/cpuset.cpu_exclusive

Това ви позволява да резервирате група ядра за конкретна услуга и да предотвратите смущения от останалата част от системата. Това намалява шума, миграциите на нишки и проблемите със закъснението, които често възникват, когато всички се конкурират за едни и същи процесори.

На ниво памет, комбинирането на numactl с cgroups (или директно използване на NUMA контролерите на паметта, когато са налични) помага данните да се съхраняват на физическия възел най-близо до ядрата, които го използват. Това е забележимо в приложения, чувствителни към латентност.

Мониторинг и наблюдаемост на c-групи и пространства от имена

Определянето на ограничения на ресурсите е добре, но Ако не прецените какво се случва, можете да се простреляте в крака, без дори да го осъзнаете.Самият cgroup v2 предлага доста полезни показатели в лог файловете *.stat, *.events y *.pressure.

Някои практически примери:

  • cpu.stat Той ви показва колко процесорно време е използвала групата, колко пъти е била ограничавана и т.н.
  • memory.current y memory.max Те показват текущата консумация и конфигурирания лимит.
  • memory.events Той записва OOM-и, достигнати меки лимити и други опасения.
  • io.stat натрупва четения/записи за всяко устройство.

За бърз преглед, systemd-cgtop Много е практично и ако искате нещо по-индустриално, инструменти като cAdvisor Те експортират показатели на Docker/containerd cgroup към Prometheus, което ви позволява да изграждате пълни табла за управление в Grafana без много усилия, идеални за усъвършенстван системен монитор.

При отстраняване на грешки в проблеми с именни пространства, прости скриптове, които преминават през /proc/<pid>/ns/ и сравнете символичните връзки, които помагат за да се знае кои процеси споделят едно и също пространство от именаили за да намерите „изгубено“ мрежово пространство от имена, което е блокирало.

Използване на systemd като мениджър на cgroup

В повечето съвременни дистрибуции, systemd разчита в голяма степен на cgroups за управление на услуги, срезове и обхвати . Когато дефинирате единица с граници на ресурсите, systemd всъщност създава cgroup за тази услуга и конфигурира нейните обработчици.

Услуга, декларирана с директиви като:

CPUQuota=50%
CPUWeight=500
MemoryMax=512M
IOReadBandwidthMax=/dev/sda 10M

Това се изразява в ограничения на cgroup за процесора, паметта и входно-изходните операции за процеса на това устройство. Това позволява синхронизиране на „класическото“ управление на услуги с контейнерния модел, използвайки същата базова подсистема на ядрото. За повече подробности относно systemd и неговите изисквания вижте промените в systemd.

За екипи, които комбинират традиционни услуги с контейнери (много често срещано), разчитането на systemd за задаване на ограничения на критичните демони е елегантен начин да се предотврати унищожаването на ресурси от pod-овете в контейнеризирана среда.

В среди с множество натоварвания, от бази данни до агенти за наблюдение и персонализирани приложения, овладяването на пространствата от имена и c-групите ви позволява да дефинирате силни политики за изолация, да коригирате качеството на обслужване и да гарантирате, че всеки компонент има свое собствено добре контролирано разпределение на процесора и паметта . Разбирането как Docker, Kubernetes и systemd използват тези възможности на ядрото ви дава възможност да проектирате по-сигурни многонаемателни инфраструктури, да отстранявате грешки в сложни проблеми (от OOM до I/O затруднения) и да извлечете максимума от вашия хардуер, без да жертвате стабилността.

systemd 259 поддръжка за musl
Свързана статия:
systemd 259: поддръжка за musl, сигурност и промени в ключовете