容器

在应用管理器上下文中,容器描述了一个可执行文件的执行环境:它可能是应用程序的二进制文件或其运行时二进制文件,在多进程模式下。容器不一定需要像 Docker 容器那样复杂,也可以简单地是一个 Unix 进程。

预定义容器

应用管理器自带一种内置容器类型:进程容器,它通过启动一个新的 Unix 进程来执行请请求的二进制文件。

此外,您可以在 examples/applicationmanager/softwarecontainer-plugin 中找到一个对 Pelagicore 的 SoftwareContainer 的基本集成。有关更多信息,请参阅 SoftwareContainer 插件示例。此示例可以用作创建特定于客户的软件容器插件的生产版本或集成其他容器解决方案的蓝图。

通过容器插件进行扩展

可以通过插件添加自定义容器解决方案。这些插件不需要作为应用管理器的一部分来构建,但它们需要针对私有 Qt 模块进行构建以获取接口定义。

TEMPLATE = lib
CONFIG += plugin
TARGET = mycontainer-plugin

QT += appman_plugininterfaces-private

然后,您只需要实现两个类,它们分别从 ContainerInterfaceContainerManagerInterface 派生。

#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)

    // ....
};

请注意,您的容器插件必须支持一些基本要求以支持多进程模式下的 UI 客户端。

  1. 插件必须能够将 Unix 本地套接字转发到容器中。这对于 Wayland 套接字以及私有的点对点 D-Bus 连接都必不可少。如果插件无法将这些套接字映射到容器中的正确位置,则插件需要修改这些位置的相应环境变量,然后再将其传递给容器。下表列出了相关的环境变量。
  2. 为了支持硬件 OpenGL 加速,容器需要访问必要的设备。对于遵循 Linux 标准的 GPU,例如英特尔,确保容器中有 /dev/dri/* 可用。
  3. 您必须在插件中实现 PID 映射;除非您的容器解决方案与整个系统共享 PID 命名空间。如果您想使用应用管理器的安全功能,则这是必要的。通过 Wayland 或 D-Bus Unix 本地套接字进入应用管理器的每个连接都会查询请求连接的应用程序的 PID。应用管理器通过 ContainerInterface::processId() 验证这些 PID 与所有运行中的应用程序的 PID。与 PID 不匹配的连接不接受。但是,您可以通过 --no-security 命令行选项禁用此行为。

应用管理器使用以下环境变量将各种设置传达给应用。自定义容器插件必须转发这些变量或相应地调整它们

名称描述
WAYLAND_DISPLAYWayland 服务器套接字的路径。如果您使用的容器使用自己的文件系统命名空间,请确保相应地转发此套接字。
QT_QPA_PLATFORM始终设置为 wayland
QT_IM_MODULE没有设置,但应用程序管理器会明确定义未设置。确保保持未设置,以使用自动的 Wayland 输入法实现。
QT_SCALE_FACTOR为空(未设置),以防止相对于合成器的 wayland 客户端缩放。否则,在 4K 桌面上缩放运行应用管理器将导致应用管理器中的应用程序缩放两次。
QT_WAYLAND_SHELL_INTEGRATION设置为xdg-shell。这是首选的Wayland Shell集成方法。
DBUS_SESSION_BUS_ADDRESS标准的D-Bus会话总线。
AM_CONFIGamConfig映射的YAML,UTF-8编码字符串版本。
AM_NO_DLT_LOGGING告诉应用程序不要使用DLT进行日志记录。

配置

容器配置有三个部分

  1. 配置在加载容器插件时哪些容器可用
  2. 为可用的每个容器集成添加特定设置
  3. 配置要运行特定应用程序时选择的容器解决方案

加载容器插件

要配置可在应用程序管理器中使用的新容器插件,您需要将其完整路径添加到应用程序管理器配置文件中要加载的插件列表中

plugins:
  container: [ "/full/path/to/softwarecontainers.so", "/another/plugin.so" ]

请注意,如果插件放置在特定目录中,应用程序管理器不会自动加载插件,因为容器插件控制应用程序的核心安全机制。

添加容器集成设置

每个容器集成都有一个唯一的ID,可以用来向应用程序管理器的配置文件中添加设置,例如

containers:
  process:
    defaultControlGroup: "foo"
  softwarecontainers:
    bar: [ 1, 2, 3 ]

process容器接受以下配置设置

设置名称类型描述
controlGroups对象一个双阶段映射对象,以便在处理来自系统UI的cgroups(通过Container::controlGroup)时具有更易读的代码。顶级键是可读的组名,用于与Container::controlGroup接口。这些值本身是在多个低级cgroup子系统名称和这些子系统内实际cgroup名称之间映射的映射,例如
controlGroups:
  foreGround:
    memory: mem1
    cpu: cpu_full
  backGround:
    memory: mem2
    cpu: cpu_minimal
defaultControlGroup字符串当应用程序首次启动时的默认控制组。

有关其他容器插件,请参阅它们的相应文档。

容器选择配置

当您在应用程序管理器中启动应用程序时,有多种方式可以控制使用哪种容器集成

  1. 如果配置文件不包含containers/selection键,容器集成ID默认为process
  2. 如果存在containers/selection键,其内容被解析为一个列表的映射,其中每个映射只有一个映射。虽然这个单映射很尴尬,但这是必要的,以保留映射的顺序。每个键被解释为与应用程序ID匹配的标准Unix通配符表达式。第一次匹配停止算法,并使用映射的值作为容器集成ID。如果没有找到匹配项,则最终容器集成ID为空字符串。
    containers:
      selection:
      - com.pelagicore.*: "process"
      - com.navigation: "special-container"
      - '*': "softwarecontainers"  # a single asterisk needs to be quoted
  3. 之后,如果系统UI已将ApplicationManager::containerSelectionFunction属性设置为一个有效的JavaScript函数,则会调用此函数,将其第一个参数设置为应用程序的ID,并将第二个参数设置为步骤1和2中得到的容器集成ID。
    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。本文件所包括的文档贡献是该相关所有者的版权。提供的文档根据自由软件基金会发布的GNU自由文档许可协议版本1.3的条款进行许可。Qt及其相关标志是芬兰及/或世界其他地区Qt公司有限公司的商标。所有其他商标均为各自所有者的财产。