Skip to content

Latest commit

 

History

History
150 lines (127 loc) · 6.21 KB

USERMODE.md

File metadata and controls

150 lines (127 loc) · 6.21 KB

The User Mode

Be warned, the systemctl script's user-mode is not identical with the systemd user-manager behaviour.

Both concepts can be explicitly selected when running "systemctl --user" however. For the systemctl replacement script it enables the user-mode while for systemd it opens the socket to send commands to the user-manager. Such a user-manager exists when you have a graphical desktop running.

In reality, the user-manager feature has been scarcily used. The systemd guys do even think about droppping the 'systemctl --user' level altogether. Even when you are not root, all commands default to "systemctl --system" anyway, assuming a systemd controlled operating system.

Anyway, the distinction of user/system level is the reason that most developers will need to install their new *.service files into a subdirectory of /etc/systemd or /usr/lib/systemd. If you look closer then you will see that there are two subdirectories, and there are actually service files in your /usr/lib/systemd/user/ directory. Did you ever think about why the *.service install directory is named /usr/lib/systemd/system/.? Well, here's why.

Let's get back to systemctl.py. It does behave similar to systemd's systemctl in that it will only search x/systemd/system directories when in system-mode. It ignores any files in x/systemd/user directories. However if in user-mode then x/systemd/user directories are searched - and just like the systemd user-manager it will also find *.service files under the user's home directory at "~/.config/systemd/user" and "~.local/share/systemd/user"

So when running "systemctl --user list-units" you will get a very different list of services. That accounts for both the systemctl script and systemd's systemctl. Give it a try.

User Containers

The existance of a user-level would have been totally irrelevant if it would not have been for a rule from OpenShift in that processes in a container must not try to be run as a virtual root user. In fact, all docker containers are started with an explicit "docker run --user=foo" value. So when the systemctl replacement script is registered as the CMD of the container then it will not have root permissions.

Now that can make for a problem when you consider that services may want to read/write global /var/xyz directories. If systemctl.py is started in a user container then it can not start services that expect to be run with root permissions. It just does not make sense.

Luckily, most modern *.service files do name an explicit "User=target". So in a user container, the systemctl replacement script can start them when the target user is the same as the container has been started under. Effectivly, when systemctl script is running as PID-1 it will filter all *.service files to the current user of the container.

Theoretically you can still start multiple enabled services through the systemctl script in a single container. Practically it does not happen very often as a tomcat.service has "User=tomcat" and a postgresql.service has "User=postgres". There is no way to run them both in a user container at the same time. Unless of course you change those lines while preparing such a docker image to have the same "User=target".

User Mode

The systemctl.py user-mode is automatically selected when it runs as PID-1 and it finds itself to be not root (the re-mapped virtual root of course). As described above, only systemd/system files with the same running user may be started/stopped. The systemctl default-services list of enabled services will only show those.

Adding to that, the systemctl replacment script will also offer to start/stop systemd/user services as they are naturally designed to be started as non-root processes. And that's the basic difference between systemd's user-manager and systemctl.py user-mode - when you select "systemctl --user" then our script will allow operations on all systemd/user services plus all systemd/system services with a matching "User=target". The systemd's systemctl will however only offer systemd/user services.

Having systemd/user services in user-mode allows a developer to explicitly prepare a service to be run under a user-manager. In fact one can find a lot of examples that were meant to be run as user containers where the actually application is deployed to a virtual /home/foo in the container image. When taking advantage of the systemctl replacement script then a developer can just as well add a /home/foo/.config/systemd/user/foo.service file. Such a deployment script will not only allow such an application to be run in a user-container but it will also work in a classic virtual machine with a user-manager.

Other Paths

In the general case, developers do not need to think about that too much. Just deploy a systemd/system service and when there is a "User=target" line in the configuration then the docker image can be started as a user container. You can the use systemctl script just like with classic containers.

When a developer takes advantage of deploying to /home/foo then you need to be aware however that some other directories are searched for these user services. And the special variables like %t in a *.service file may in fact point to a different directory. The freedeskop standard for XDG directories has the details what to think about.

User Images

At the url https://github.com/gdraheim/docker-systemctl-images you find a sister project that has examples where the systemctl replacment script is used to help creating docker images. Not only are there classic images where the systemctl script will run as PID-1 in root mode - there are also docker images which have a user-mode configuration.

In fact, the Dockerfile "USER foo" directive is meant to force an image into be run as a user container by default. So any of those images will have the systemctl script in user-mode.

Naturally, the docker-systemctl-images can show user-mode images for single applications like Apache and MariaDB. But having a full LAMP stack in single container is not possible for user-mode.

Anyway, it just works - you can use the systemctl replacement script even for user containers. No need write special docker-entrypoint scripts, just install the service, enable it, name the "USER target" in the Dockerfile, and then you can run the container.