Как создать пользовательские cgroups с systemd

14

Я использую непривилегированные lxcконтейнеры в Arch Linux. Вот основные сведения о системе:

[chb@conventiont ~]$ uname -a
Linux conventiont 3.17.4-Chb #1 SMP PREEMPT Fri Nov 28 12:39:54 UTC 2014 x86_64 GNU/Linux

Это кастомное / скомпилированное ядро ​​с user namespace enabled:

[chb@conventiont ~]$ lxc-checkconfig 
--- Namespaces ---
Namespaces: enabled
Utsname namespace: enabled
Ipc namespace: enabled
Pid namespace: enabled
User namespace: enabled
Network namespace: enabled
Multiple /dev/pts instances: enabled

--- Control groups ---
Cgroup: enabled
Cgroup clone_children flag: enabled
Cgroup device: enabled
Cgroup sched: enabled
Cgroup cpu account: enabled
Cgroup memory controller: enabled
Cgroup cpuset: enabled

--- Misc ---
Veth pair device: enabled
Macvlan: enabled
Vlan: enabled
File capabilities: enabled

Note : Before booting a new kernel, you can check its configuration
usage : CONFIG=/path/to/config /usr/bin/lxc-checkconfig

[chb@conventiont ~]$ systemctl --version
systemd 217
+PAM -AUDIT -SELINUX -IMA -APPARMOR +SMACK -SYSVINIT +UTMP +LIBCRYPTSETUP +GCRYPT +GNUTLS +ACL +XZ +LZ4 +SECCOMP +BLKID -ELFUTILS +KMOD +IDN 

К сожалению, systemdне очень хорошо в lxcнастоящее время. Особенно cgroupsпохоже, что настройка для пользователя без полномочий root работает не очень хорошо, или я просто слишком незнаком, как это сделать. lxcконтейнер будет запускаться только в непривилегированном режиме, когда он может создать необходимые группы в /sys/fs/cgroup/XXX/*. Это, однако, невозможно, lxcпотому что systemdмонтирует rootиерархию cgroup в /sys/fs/cgroup/*. Обходной путь, кажется, должен сделать следующее:

for d in /sys/fs/cgroup/*; do
        f=$(basename $d)
        echo "looking at $f"
        if [ "$f" = "cpuset" ]; then
                echo 1 | sudo tee -a $d/cgroup.clone_children;
        elif [ "$f" = "memory" ]; then
                echo 1 | sudo tee -a $d/memory.use_hierarchy;
        fi
        sudo mkdir -p $d/$USER
        sudo chown -R $USER $d/$USER
        echo $$ > $d/$USER/tasks
done

Этот код создает соответствующие cgroupкаталоги в cgroupиерархии для непривилегированного пользователя. Однако происходит то, чего я не понимаю. Перед выполнением вышеупомянутого я увижу это:

[chb@conventiont ~]$ cat /proc/self/cgroup 
8:blkio:/
7:net_cls:/
6:freezer:/
5:devices:/
4:memory:/
3:cpu,cpuacct:/
2:cpuset:/
1:name=systemd:/user.slice/user-1000.slice/session-c1.scope

После выполнения вышеупомянутого кода, который я вижу в оболочке, я запустил его:

[chb@conventiont ~]$ cat /proc/self/cgroup 
8:blkio:/chb
7:net_cls:/chb
6:freezer:/chb
5:devices:/chb
4:memory:/chb
3:cpu,cpuacct:/chb
2:cpuset:/chb
1:name=systemd:/chb

Но в любой другой оболочке я все еще вижу:

[chb@conventiont ~]$ cat /proc/self/cgroup 
8:blkio:/
7:net_cls:/
6:freezer:/
5:devices:/
4:memory:/
3:cpu,cpuacct:/
2:cpuset:/
1:name=systemd:/user.slice/user-1000.slice/session-c1.scope

Следовательно, я могу запустить свой непривилегированный lxcконтейнер в оболочке, в которой я выполнил код, упомянутый выше, но ни в каком другом.

  1. Может кто-нибудь объяснить это поведение?

  2. Кто-то нашел лучший способ установить требуемый cgroupsс текущей версией systemd( >= 217)?

lord.garbage
источник

Ответы:

13

Лучшее и более безопасное решение - установить cgmanagerи запустить его systemctl start cgmanagersystemdдистрибутиве на основе). Вы можете сделать так, чтобы ваш rootпользователь, или если у вас есть sudoправа на хосте, создал cgroupsдля вашего непривилегированного пользователя во всех контроллерах:

sudo cgm create all $USER
sudo cgm chown all $USER $(id -u $USER) $(id -g $USER)

После того, как они были созданы для вашего непривилегированного пользователя, она / он может переместить процессы, к которым он имеет доступ, в свой cgroupдля каждого контроллера, используя:

cgm movepid all $USER $PPID

Безопаснее, быстрее, надежнее, чем сценарий оболочки, который я написал.

Ручное решение:

Ответить 1.

for d in /sys/fs/cgroup/*; do
        f=$(basename $d)
        echo "looking at $f"
        if [ "$f" = "cpuset" ]; then
                echo 1 | sudo tee -a $d/cgroup.clone_children;
        elif [ "$f" = "memory" ]; then
                echo 1 | sudo tee -a $d/memory.use_hierarchy;
        fi
        sudo mkdir -p $d/$USER
        sudo chown -R $USER $d/$USER
        echo $$ > $d/$USER/tasks
done

Я не знал о том, что происходит именно тогда , когда я писал этот сценарий , но читает это и экспериментируя немного помог мне понять , что происходит. То, что я в основном делаю в этом сценарии, - это создание нового cgroupсеанса для текущего, о userчем я уже говорил выше. Когда я запускаю эти команды в текущем shellили запускаю их в сценарии и делаю так, чтобы они оценивались в текущем, shellа не в subshell(через . scriptЭто .важно для этого работает!), Я не просто открываю новый сеанс для userно добавьте текущую оболочку как процесс, который выполняется в этой новой группе. Я могу добиться того же эффекта, запустив сценарий в подоболочке, а затем погрузиться в cgroupиерархию chb subcgroupи использоватьecho $$ > tasksдобавить текущую оболочку для каждого члена chb cgroup hierarchy.

Следовательно, когда я запускаю lxcэту текущую оболочку, мой контейнер также становится членом всех элементов, членом chb subcgroupкоторых является текущий shell. То есть мой containerнаследует cgroupстатус моего shell. Это также объясняет, почему он не работает в любой другой оболочке, которая не является частью текущей chb subcgroups.

Я все еще прохожу 2.. Возможно, нам придется подождать либо systemdобновления, либо дальнейших Kernelразработок, чтобы systemdпринять согласованное поведение, но я все равно предпочитаю ручную настройку, поскольку она заставляет вас понимать, что вы делаете.

lord.garbage
источник
Вы не можете просто смонтировать каталог cgroups где-нибудь еще (честный вопрос) ? В прошлом году было много споров по поводу Linux-cgroups и systemd, когда сопровождающий cgroups явно решил предоставить systemd по имени и другим подобным безымянным приложениям полномочия по обработке cgroups в пользовательском пространстве. Я не уверен, как все это получилось, но я знаю, что это было в воздухе, мог ли пользователь сделать это вообще год назад.
mikeserv
Я, вероятно, мог бы сделать это, но я должен был бы препятствовать тому, чтобы systemd сначала монтировал корневой каталог cgroup. Всякий раз, когда я захожу на мой компьютер, systemd монтирует корневую иерархию корневой группы в / sys / fs / cgroup и добавляет пользовательскую группу только в системную часть корневой группы (вы можете увидеть это выше.). Разница между системными дистрибутивами и не системными дистрибутивами до их переключения заключается в том, что, например, управление Ubuntu cgroup не находится в руках демона init.
lord.garbage
Вместо этого он обрабатывается программой, например, cgmanager. Или вы можете сделать это вручную, как предложено в ссылке на kernel.org, которую я разместил выше. В настоящее время у меня нет достаточно глубокого понимания управления systemd cgroup, чтобы заниматься им глубже, чем сейчас. Но, надеюсь, это скоро изменится.
lord.garbage
1
Правда, я помню, как вы указали это в комментарии к ответу, который я давал давным-давно. Я поинтересуюсь ...
Лорд. Грязь,
1
Хитрость в основном это: sudo systemctl start cgmanager && sudo cgm create all $USER && sudo cgm chown all $USER $(id -u) $(id -g) && sudo cgm movepid all $USER $PPID. Последняя команда должна быть запущена в текущей оболочке, чтобы добавить ее в новую группу для $USER.
lord.garbage
0

На самом деле в archlinux это не будет работать, например, с непривилегированным пользователем (рекомендуется при использовании контейнеров unpriv. Lxc). то есть у этого пользователя нет sudo :)

Вместо этого определите группу в /etc/cgconfig.conf, активируйте cgconfig, cgrules (libcgroup в AUR), добавьте также cgrules, сделано .. unpriv. Пользователь также будет иметь такие же права.

В systemd 218 (я не знаю, когда, но, похоже, нужно добавить еще два условия, поскольку они не устанавливаются при создании способом cgconfig):

cat /etc/cgconfig.conf

group lxcadmin {
perm {
    task {
        uid = lxcadmin;
        gid = lxcadmin;
    }
    admin {
        uid = lxcadmin;
        gid = lxcadmin;
    }
}
cpu { }
memory { memory.use_hierarchy = 1; }  
blkio { }
cpuacct { }
cpuset { 
    cgroup.clone_children = 1;
    cpuset.mems = 0;
    cpuset.cpus = 0-3; 
}
devices { }
freezer { }
hugetlb { }
net_cls { }
}

cat /etc/cgrules.conf
lxcadmin        *       lxcadmin/

Предполагая, что пространство имен скомпилировано в ядре.

Это шаблон, процессор может быть в зависимости от того, сколько ядер у вас есть, mem может быть установлена ​​на какое-то фактическое значение и т. Д. И т. Д.

РЕДАКТИРОВАТЬ 2: Наконец, в systemd, если вы хотите использовать автозапуск с таким непривилегированным пользователем, вы можете сделать:

cp /usr/lib/systemd/system/lxc],admin‹\@.service, затем добавьте User = lxcadmin

и включите его для контейнера lxcadmin под названием lolz systemctl enable lxcadmin @ lolz.

Малина салина
источник
Спасибо @Anthon, я никогда не смогу получить правильное форматирование кода на этих сайтах, х
Малина Салина
Спасибо. Извините за задержку с ответом. Ваш первый пункт: «На самом деле в archlinux это не сработает, например, с непривилегированным пользователем (рекомендуется при использовании контейнеров unpriv. Lxc). То есть у пользователя нет sudo :)», не означает, что вам нужен только ваш rootадминистратор. создать и chownвы во всех cgroupконтроллерах. Это прекрасно и безопасно. movepidможет быть сделано без rootправ и, следовательно, неприв. пользователю не нужны никакие sudoправа. (Кстати, libcgroupбольше не предполагается его использовать. RHEL и другие
осудили
@Brauner. Как вы автоматически запускаете при загрузке контейнеры вашего непривилегированного пользователя? На самом деле перечисленные вами решения работали (и подразумевали) пользователя sudo. Мой не сделал. Вы спросили, как это исправить. В любом случае, только что произошло обновление, и cgconfig теперь не запускается, так как user.slices добавляются автоматически, перед настройками cgconfig, как кажется. Им не хватает каких-либо разрешений пользователя (возможно, это ошибка регрессии, сейчас я ее изучаю). Я не говорил, что это лучшее решение. Это было / решение вашего запроса. :) Но мои контейнеры не запускаются при загрузке, гррр.
Малина Салина
Причина, по которой я перечислил systemctl enable lxcadmin @ container, была в том, что root мог принять решение запустить unpriv контейнер при загрузке. Если пользователь сам использует его в --user (land), он загружается только при входе в систему, что не очень полезно для сервера. И примечание к вашему комментарию. Я полагаю, что «засорение» пользователя всеми контроллерами позволяет ему начать перемещать pid в пространство хоста, что представляет собой серьезную угрозу безопасности.
Малина Салина
Хм, похоже, это то, что вы делали с первоначально перечисленным методом, но посмотрите на это, даже если это пакет ubuntu systemd bugs.launchpad.net/ubuntu/+source/systemd/+bug/1413927 Но что-то было обновлено в последние дни меняя логику .. я пытаюсь выследить это.
Малина Салина
0

Поэтому я столкнулся с той же проблемой, когда пытался заставить LXC непривилегированные контейнеры работать на CentOS 7. Я не хотел их использовать, cgmanagerпотому что не люблю вводить какие-либо дополнительные сервисы, если в этом нет необходимости. Вместо этого я в итоге исправил systemd, используя некоторые исправления из пакета ubuntu и одно специальное исправление для расширения списка контроллеров cgroup. У меня есть источники, необходимые для создания RPM в моей учетной записи GitHub по адресу https://github.com/CtrlC-Root/rpmdist . У меня также есть исправленные версии shadow-utils (для subuids и subgids) и pam (для loginuid). После того, как я установлю эти RPM и настрою пользователя на запуск непривилегированных контейнеров (назначение subuids & subgids, выделение пар веток в lxc-usernet, создание .config / lxc / default.conf и т. Д.), Я могу нормально запускать непривилегированные контейнеры LXC.

РЕДАКТИРОВАТЬ: Другая причина, по которой я не хотел использовать cgmanager, заключается в том, что я не хотел, чтобы мои обычные пользователи вообще использовали sudo. Обычные пользователи должны иметь возможность войти в систему, и все должно "просто работать" из коробки.

CtrlC корень
источник