Using cgroups with redpak and systemd
redpak has options to setup cgroup restrictions on started rednodes. This behaviour duplicates the behaviour of systemd that already manages cgroup features.
One of the design principle of how systemd manages cgroup is that only one writer can control a cgroup (see Two Key Design Rules).
That single-writer behaviour can not be enforced by the kernel. So designers of systemd took the decision that the full cgroup hierarchy is under the control of systemd except if the opposite is explicitly required.
Using cgroup features of redpak without taking care of what systemd expects is possible but:
-
it violates the single-writer principle because redwrap will write and rearrange features in cgroup when systemd expects to be the only writer.
-
it implies that you run redwrap as root or with some capabilities for writing where systemd writes.
In order to solve this kind of issues, systemd has provision for allowing other writers to manage parts of cgroup that system will not overwrite after setting it up. This behaviour, called delegation, is described in that document.
Delegation in systemd’s user land
The two lines below are from systemd’s service user@.service
Slice=user-%i.slice
Delegate=pids memory
It shows that every user service or application started by
systemd and the children of these services or applications
are in the cgroup slice user.slice/user-UID.slice/.
And that slice is restricted to have only access to the
cgroup’s controllers pids and memory.
So if the rednode only needs to setup pids and memory,
it could be possible in theory, because the controllers
are available. But in fact it will not work because the
files controlling the behaviour of these cgroups are owned by
root and are write protected.
Before discussing on how systemd allows delegation of the control of these features, let’s talk about other cgroup controllers that redpak manages: cpu, cpuset and io.
Because these controllers are not listed in user@.service,
they cannot be delegated to user services. This can be
changed by adding drop-in configurations. For example
for adding the missing controllers to user 1001, it is
needed to create the file
/etc/systemd/system/user@1001.service.d/delegate.conf
(more details here) that contains:
[Service]
Delegate=cpu cpuset io
But this action requires system privileges to be achieved.
Without delegation, the cgroup properties can be controlled by systemd settings and properties.
In order to run redpak in user mode, you need to turn on the delegation. This is done by including the below lines in your service:
[Service]
Delegate=yes
that delegates all available cgroup controllers.
Or by listing the expected cgroup controllers like below:
[Service]
Delegate=memory pids
In this cases, systemd creates a slice for controlling
the service. That slice can be named explicitly using
Slice directive of systemd.
When running redpak from command line in the user environment, if the rednode has cgroup settings, they may be applied or not depending on rights that systemd lets to cgroups files. But in all cases it conflicts with systemd and the single-writer rule.
So the systemd command systemd-run should be used. Here
is an example of use:
systemd-run --user -p Delegate=yes ...
Using the slice is possible because it allows default controllers, so the command below works as well:
systemd-run --user --slice redpak ...
In this case, the user still gets the ability to modify its cgroup restrictions itself. This is intended for implementing a manager but not for running a restricted program. However redpak allows running rednodes unable to change their cgroup restrictions if the cgroup namespace is unshared:
config:
share_cgroup: disabled
Delegation in systemd’s system land
Restriction applied by user@.service are not existing
in system land. So all cgroup controllers are available.
But the use of the directive User, even in system’s services,
makes them user services and then only allows pids and memory
controllers as seen above. To circumvent this
restriction, either follow what is explained above or use
the redpak feature for changing the user.
Since redpak version 2.4.2, it is possible to start
a rednode from root that will run as another user.
It opens the possibility to use all cgroups from
system land, but in user land. In such a case, services
could be changed to not set User=... while still
setting dependency to user@%i.service. That way,
user services are started and all cgroup controllers are
available.
When using this option, items of cgroup hierarchy are owned by root, not by the end user. This is good because it avoids the rednode to change its settings.
Security considerations on using cgroup and delegation
When delegation of cgroup is granted by systemd to a service, the service is allowed to change its cgroup settings. The hierarchical imbrication of the cgroups means that it can not be better than what systemd allocated initially to the main service.
But it means that if the service forks, it has to be cautious of what its children, running with the same rights, can change in the cgroup settings.
This can be avoided by un-sharing the cgroup namespace
in the redpak configuration file (config.share_cgroup: disabled),
this ensures that the settings of rednode configuration
will not be changed.
rednodes, cgroups, and russian dolls
For cgroup management of rednode, the concept of russian dolls applies. The hierarchy of rednodes is applied by fitting children in their parent. This behaviour automatically applies with cumulated cgroup restrictions.
So using a dedicated slice for running rednodes works correctly because redwrap takes care of setting cgroup features with the hierarchy of nodes.
So we recommend to use the slice named redpak for
running the cgroup aware rednode. But note well that
using the default slice user-%i also works.
systemd-run --user -p Delegate=yes --slice redpak ...
or
systemd-run -p Delegate=yes --slice redpak ...