要解决的问题
试图在容器中运行一个需要 X Window 系统的应用并不十分困难,但也不是看起来那么简单。有几种方式可以处理这个问题:
1、通过共享 X11 socket 使用主机的 X Server。这有一篇非常好的文章展示了不同的选项。
2、通过 ssh -X 转发显示。这里的一篇文章描述了使用几种镜像的一种方式。
3、运行一个带有 X server 的 VNC server。这种方案同样存在几种镜像。这里有一个样例。
我寻找的方案应该是完全不依赖主机的,你可以在任何地方部署它。这也意味着我在 X11 server 上看到的输出仅仅只是作为调试需要。
现在我要解决的问题是如何在一个容器中使用 Wine 和 WiX toolset 来构建 MSI 文件(微软 windows 安装文件)。通常它是一个不需要任何用户交互的工作流,因此并不需要在一个 X Window 上显示一些东西。然而,我的一个首要的问题时适当的建立完整的环境。在这个过程中我不得不查看 wine 或它运行的应用的输出。
这基本意味着我必须一直运行 X11 server 来保证 wine 和它的应用不会抱怨缺少 window 系统。但是一旦 wine 不像期望的那样工作,我就不时的需要观察 wine 的输出。最终我希望嵌入 docker 的最佳实践在任何地方运行我的方案(比如避免在一个容器中运行 sshd)。
因此我将采用 VNC,但是保证没有客户端连接到 VNC server 时 X11 server 也一直在运行。
我的第一个方法是把所有的东西(构建 MSI 文件的源码, WiX toolset,Wine, X11 server, VNC server, ...)放入一个单独的 docker 镜像中。结果形成一个非常大和不便的镜像。重新构建完整的镜像或者加入新的包会花费很长的时间,因为大约200个包需要下载并安装。
SRP 来拯救
为什么不应用非常有名的软件开发原则来处理设置 docker 镜像?所以我决定用更多的 docker 镜像并采用单一职能的原则。在我看来这也是 docker 的方式。
所以这个方案由下面 docker 镜像组成:
1、[suchja/x11server] - 这个镜像运行 X11 server 和 VNC server。它提供一个用于 X11 client连接到 server 的 magic cookie 并要求用户设置一个 VNC 连接的密码。另外它可以通过环境变量来配置一些 X11 server 的参数。将来我还将研究更安全的访问镜像。
2、[suchja/x11client] - 使用X11 server 的 magic cookie 来准备一个认证的连接。它可以作为一个需要 X11 访问应用的基础镜像。
3、[suchja/wine] - 我验证 X11 访问是否按期望工作的示例应用。它从 suchja/x11client 派生。另外它还使用一个 entrypoint 脚本来使用当容器启动就一直运行的 wine 命令。
4、[suchja/x11tools] - 即使不是我初始应用所需要的,可能是想获得 X11 server 运行的截图或视屏。因此这个镜像能提供一些额外的工具来访问 X11 server。