Containers
A container in the application-manager world describes an execution environment for an executable (either an app's binary or its runtime binary) in multi-process mode. This does not have to be something sophisticated like a Docker container, but can be as simple as an Unix process.
Predefined Containers
The application-manager comes with a single type of container built-in: the process
container, which simply spawns a new Unix process to execute the requested binary.
In addition, a very basic integration of Pelagicore's software-containers is provided in examples/softwarecontainers
. This can be used as a blueprint to either create a customer-specific production version of a softwarecontainers plugin, or to integrate another container solution.
Extending with Container Plugins
Custom container solution can easily be added via plugins. These plugins need not to be built as part of the application-manager, but they need to be built against a private Qt module to get the interface definition:
TEMPLATE = lib CONFIG += plugin TARGET = mycontainer-plugin QT += appman_plugininterfaces-private
The only thing you have to then implement are two classes that derive from ContainerInterface
and from ContainerManagerInterface respectively, e.g.:
#include <QtAppManPluginInterfaces/containerinterface.h> class SoftwareContainer : public ContainerInterface { // ... }; class SoftwareContainerManager : public QObject, public ContainerManagerInterface { Q_OBJECT Q_PLUGIN_METADATA(IID AM_ContainerManagerInterface_iid) Q_INTERFACES(ContainerManagerInterface) // .... };
Please be aware that your container plugin has to support a few basic requirements in order to support UI clients in multi-process mode:
- The plugin has to be able to forward Unix local sockets into the container. This is needed for both the Wayland socket as well as for the private peer-to-peer D-Bus connection. If the plugin is not able to map these sockets to the exact same location within the container, it needs to alter the environment variables for the respective locations before passing them into the container. See below for a list of relevant environment variables.
- In order to support hardware OpenGL acceleration, the container needs to have access to the necessary devices: for GPUs following Linux standards (e.g. Intel), you have to make sure to have /c{/dev/dri/*} available within the container.
- If you want to make use of the application-manager's security features, you also have to implement PID mapping in your plugin (this is unnecessary if your container solution shares its PID namespace with the rest of the system). Every connection coming into the application-manager via the Wayland or D-Bus Unix local sockets is queried for the PID of the application requesting the connection. The application-manager will verify these PIDs against the PIDs of all running applications via ContainerInterface::processId(). Connections that will not match a PID will not be accepted. This behavior can be disable though by use of the
--no-security
command line option.
The application-manager will use these environment variables to communicate various settings to the application. A custom container plugin has to make sure to forward these or adjust them accordingly:
Name | Description |
---|---|
WAYLAND_DISPLAY | The path to the Wayland server socket. If your container uses its own filesystem namespace, you need to make sure that this socket gets forwarded accordingly. |
QT_QPA_PLATFORM | Always set to wayland . |
QT_IM_MODULE | Not really set, but explicitly unset by the application-manager. Make sure to not set it, if the automatic Wayland input method implementation should be used. |
DBUS_SESSION_BUS_ADDRESS | The standard D-Bus session bus |
AM_DBUS_PEER_ADDRESS | This variable holds the D-Bus socket identifier for the private peer-to-peer bus between the application-manager and the application. If your container uses its own filesystem namespace, you need to make sure that this socket gets forwarded accordingly. |
AM_DBUS_NOTIFICATION_BUS_ADDRESS | Since the org.freedesktop.Notifications interface could be on a different bus as the rest of the D-Bus interfaces, the application-manager needs to tell the application explicitly where to look for this interface. |
AM_BASE_DIR | The current directory of the application-manager. |
AM_RUNTIME_SYSTEM_PROPERTIES | The public part of the system properties, encoded as an YAML document. |
AM_NO_DLT_LOGGING | Tells the application to not use DLT for logging. |
Configuration
There are three parts to the container configuration:
- Configure which containers are available at all.
- Add specific settings for each available container integration.
- Configure which container solution is selected to run a specific application.
Load Container Plugins
In order to activate an existing container plugin for use in the application-manager, you need to add its full path to the list of plugins to load in the application-manager's config file:
plugins: container: [ "/full/path/to/softwarecontainers.so", "/another/plugin.so" ]
Please note that the application-manager does not load plugins automatically if they are placed in a specific directory, since container plugins control the central security mechanism for separating applications.
Container Integration Configuration
Each container integration has an unique id, which can be used to add settings to the application-manager's config file, e.g.
containers: process: defaultControlGroup: "foo" softwarecontainers: bar: [ 1, 2, 3 ]
The process
container accepts the following configuration settings:
Name | Type | Description |
---|---|---|
controlGroups | object | A two-stage mapping object to allow for more readable code when dealing with cgroups from the System-UI via Container::controlGroup. The top-level keys are readable group names that are used to interface Container::controlGroup, while the values are themselves maps between multiple low-level cgroup sub-system names and the actual cgroup names within those sub-systems, e.g.:controlGroups: foreGround: memory: mem1 cpu: cpu_full backGround: memory: mem2 cpu: cpu_minimal |
defaultControlGroup | string | The default control group for an application when it is first launched. |
For other container plugins, please consult the respective documentation.
Container Selection Configuration
There are multiple ways to control which container integration is used when starting an application from within the application-manager:
- If the config file does not contain the key
containers/selection
, the container integration id will default toprocess
- If the aforementioned key exists, its contents will be parsed as a list of maps, where each map only has a single mapping (this is a bit awkward, but needed to preserve the order of the mappings). Each key is interpreted as a standard Unix wildcard expression that will be matched against the application id. The first match will stop this algorithm and the mapping's value will be used as the container integration id. If no matches are found, the resulting containter integration id will be the empty string.
containers: selection: - com.pelagicore.*: "process" - com.navigation: "special-container" - '*': "softwarecontainers" # a single asterisk needs to be quoted
- Afterwards, if the System-UI did set the ApplicationManager::containerSelectionFunction property to a valid JavaScript function, this function will be called with the first parameter set to the application's id and the second parameter set to the container integration id that resulted from step 1 and 2.
ApplicationManager.containerSelectionFunction = function(appId, containerId) { var app = ApplicationManager.application(appId) if (app.capabilities.indexOf("non-secure") != -1) return "process" else return containerId }
© 2019 Luxoft Sweden AB. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.