Как использовать cgroups, чтобы ограничить все процессы, кроме белого списка, одним процессором?

26

Существует руководство для cgroups от Red Hat, которое может быть своего рода полезным (но не отвечает на этот вопрос).

Я знаю, как ограничить конкретный процесс конкретным процессором во время команды запуска этого процесса:

Во-первых, поместив следующее * в /etc/cgconfig.conf:

mount {
  cpuset =  /cgroup/cpuset;
  cpu =     /cgroup/cpu;
  cpuacct = /cgroup/cpuacct;
  memory =  /cgroup/memory;
  devices = /cgroup/devices;
  freezer = /cgroup/freezer;
  net_cls = /cgroup/net_cls;
  blkio =   /cgroup/blkio;
}

group cpu0only {
  cpuset {
    cpuset.cpus = 0;
    cpuset.mems = 0;
  }
}

А затем запустите процесс и назначьте его именно этой группе, используя:

cgexec -g cpuset:cpu0only myprocessname

Я могу ограничить все экземпляры определенного имени процесса автоматически (я думаю, что это правильно), добавив следующее /etc/cgrules.conf:

# user:process  controller  destination
*:myprocessname cpuset      cpu0only

Мой вопрос: как я могу сделать обратное ?

Другими словами, как я могу назначить все процессы, кроме определенного набора процессов из белого списка и их дочерних элементов, в ограниченную группу?


Исходя из того, что я изучал, но не проверял, я считаю, что частичное решение будет:

Добавьте «неограниченную» группу:

group anycpu {
  cpuset {
    cpuset.cpus = 0-31;
    cpuset.mems = 0;  # Not sure about this param but it seems to be required
  }
}

Присвойте мой процесс явным образом группе без ограничений, а все остальное группе с ограниченными правами:

# user:process  controller  destination
*:myprocessname cpuset      anycpu
*               cpuset      cpu0only

Тем не менее, предостережение по этому поводу (из чтения документов, а не из тестирования, так что ни малейшего соли), что потомки myprocessnameбудут переназначены в ограниченную группу cpu0only.

Возможный альтернативный подход - создать пользователя, который будет запускаться myprocessnameи иметь все процессы этого пользователя неограниченными, а все остальное ограничено. Однако в моем реальном случае использования процесс должен запускаться пользователем root, и существуют другие процессы, которые также должны запускаться пользователем root, которые должны быть ограничены.

Как я могу сделать это с помощью cgroups?


Если это невозможно с cgroups (что, как я теперь подозреваю, так), верны ли мои представления о частичных решениях, и будут ли они работать так, как я думаю?

* Отказ от ответственности: это, вероятно, не минимальный пример кода, я не понимаю все части, поэтому я не знаю, какие не нужны.

Wildcard
источник

Ответы:

30

ОБНОВЛЕНИЕ: Обратите внимание, что приведенный ниже ответ относится к RHEL 6. В RHEL 7 большинство cgroups управляется systemd, а libcgroup устарела.


После публикации этого вопроса я изучил все руководство, на которое я ссылался выше, а также большую часть документации cgroups.txt и cpusets.txt . Теперь я знаю больше, чем когда-либо ожидал узнать о cgroups, поэтому я отвечу на свой вопрос здесь.

Есть несколько подходов, которые вы можете использовать. Контакт нашей компании в Red Hat (Технический Архитектор) рекомендовал не ограничивать все процессы, а отдавать предпочтение более декларативному подходу - ограничивать только те процессы, которые мы специально хотели ограничить. Причина этого, согласно его высказываниям на эту тему, заключается в том, что системные вызовы могут зависеть от кода пользовательского пространства (такого как процессы LVM), который в случае ограничения может замедлить работу системы - противоположность предполагаемому эффекту. В итоге я ограничил несколько специально названных процессов и оставил все остальное в покое.

Кроме того, я хочу упомянуть некоторые основные данные cgroup, которые мне не хватало, когда я публиковал свой вопрос.


Группы не зависят от libcgroupустановки. Однако это набор инструментов для автоматической обработки конфигурации cgroup и назначения процессов для cgroups, и он может быть очень полезным.

Я обнаружил, что инструменты libcgroup также могут вводить в заблуждение, поскольку пакет libcgroup построен на собственном наборе абстракций и предположений об использовании cgroups, которые немного отличаются от фактической реализации cgroups на уровне ядра. (Я могу привести примеры, но это займет немного работы; прокомментируйте, если вам интересно.)

Поэтому перед использованием libcgroup инструментов (таких , как /etc/cgconfig.conf, /etc/cgrules.conf, cgexec, cgcreate, cgclassifyи т.д.) , я настоятельно рекомендую получить хорошо знакомы с /cgroupсамой виртуальной файловой системы, а также создание контрольных групп, контрольной группы иерархии (включая иерархии с несколькими подсистемами прикрепленными, которые libcgroup скрытно и leakily аннотаций вручную далеко), переназначение процессов различным группам путем запуска echo $the_pid > /cgroup/some_cgroup_hierarchy/a_cgroup_within_that_hierarchy/tasksи другие, казалось бы, волшебные задачи, libcgroupвыполняемые под капотом.


Другой основной концепцией я пропускал в том , что если /cgroupвиртуальная файловая система установлена в вашей системе на всех (или более точно, если какой - либо из контрольной группы подсистем ака «контроллеры» смонтированы на всех), то каждый процесс по всей системе в а контрольная группа. Нет такой вещи, как «некоторые процессы находятся в cgroup, а некоторые нет».

Для данной иерархии существует то, что называется корневой группой , которая владеет всеми ресурсами системы для подключенных подсистем. Например, иерархия cgroup, к которой подключены подсистемы cpuset и blkio, будет иметь корневую cgroup, которая будет владеть всеми процессорами в системе и всеми blkio в системе, и может совместно использовать некоторые из этих ресурсов с дочерними cgroups. Вы не можете ограничить корневую группу, поскольку она владеет всеми ресурсами вашей системы, поэтому ограничивать ее даже не имеет смысла.


Некоторые другие простые данные, которые мне не хватало в libcgroup:

Если вы используете /etc/cgconfig.conf, вы должны убедиться, что chkconfig --list cgconfigпоказывает, что cgconfigустановлен для запуска при загрузке системы.

Если вы измените /etc/cgconfig.conf, вам нужно запустить, service cgconfig restartчтобы загрузить изменения. (А проблемы с остановкой или запуском службы cgclearочень распространены, когда вы дурачитесь с тестированием. Для отладки я рекомендую, например lsof /cgroup/cpuset, if cpusetэто имя используемой вами иерархии cgroup.)

Если вы хотите использовать /etc/cgrules.conf, вы должны убедиться, что «демон механизма правил cgroup» ( cgrulesengd) работает: service cgred startи chkconfig cgred on. (И вы должны знать о возможном, но маловероятном состоянии гонки в отношении этой службы, как описано в Руководстве по управлению ресурсами Red Hat в разделе 2.8.1 внизу страницы.)

Если вы хотите дурачиться вручную и настраивать свои cgroups, используя виртуальную файловую систему (которую я рекомендую для первого использования), вы можете сделать это, а затем создать cgconfig.confфайл, который будет отражать ваши настройки, используя cgsnapshotего различные параметры.


И, наконец, ключевая информация, которую мне не хватало, когда я писал следующее:

Однако предостережение об этом, похоже, заключается в том, что потомки myprocessname будут переназначены в ограниченную cpu0only cgroup.

Я был прав, но есть вариант, о котором я не знал.

cgexec это команда для запуска процесса / запуска команды и назначения ее группе.

cgclassify это команда для назначения уже запущенного процесса в cgroup.

Оба из них также будут препятствовать cgred( cgrulesengd) переназначению указанного процесса другой cgroup на основе /etc/cgrules.conf.

Оба cgexecи cgclassifyподдерживают --stickyфлаг, который дополнительно предотвращает cgredпереназначение дочерних процессов на основе /etc/cgrules.conf.


Итак, ответ на вопрос в том виде, в котором он был написан мной (хотя это и не та установка, которую я в итоге реализовал из-за рекомендаций нашего Red Hat Technical Architect, упомянутых выше):

Сделайте cpu0onlyи anycpucgroup, как описано в моем вопросе. (Убедитесь, cgconfigчто установлен для запуска при загрузке.)

Сделайте * cpuset cpu0onlyправило, как описано в моем вопросе. (И убедитесь, cgredчто установлен для запуска при загрузке.)

Запустите все процессы , я хочу неограниченные с: cgexec -g cpuset:anycpu --sticky myprocessname.

Эти процессы будут неограниченными, и все их дочерние процессы также будут неограниченными. Все остальное в системе будет ограничено CPU 0 (после перезагрузки, поскольку cgredcgrules не применяется к уже запущенным процессам, если они не меняют свой EUID). Это не совсем рекомендуется, но это было то, что я изначально просил, и это можно сделать с помощью cgroups.

Wildcard
источник
Вау. прохладный. откуда у этого 0 голосов?
mikeserv
@mikeserv, спасибо. :) Ответьте на свой вопрос: проверьте даты; Я только что написал этот ответ вчера.
Wildcard
1
я видел это. но это было 24 часа назад. вероятно, его причина его долго. хорошие вещи иногда можно пропустить так. и в любом случае, ответы с большим количеством голосов действительно очень редко бывают хорошими - информация не может быть настолько полезной, если так много людей уже знают, что это так. Это один из хороших. cgroups чертовски таинственны.
mikeserv