如何在 Debian 10 上使用 Docker 和 Caddy 远程访问图形用户界面应用程序

作者选择了 自由和开源基金作为 写给捐款计划的一部分接受捐款。

介绍

即使在云服务的普及日益增加,仍然需要运行本地应用程序。

使用 noVNCTigerVNC可在 Docker容器内运行本体应用程序,并通过 Web 浏览器远程访问它们。

在本教程中,您将使用 Docker 集装 Mozilla Thunderbird,一个电子邮件客户端,随后,您将使用 Caddy Web 服务器保护它并提供远程访问。

当你完成时,你将能够从任何设备访问Thunderbird,只使用一个网页浏览器. 可选的是,你还可以使用WebDAV(http://www.webdav.org/)本地访问文件。

前提条件

在您开始本指南之前,您将需要以下内容:

  • 一个 Debian 10 服务器,至少有 2 GB 的 RAM 和 4 GB 的磁盘空间。
  • 具有sudo特权的非根用户。
  • Docker 设置在您的服务器上。

步骤 1 — 创建supervisord配置

现在你的服务器正在运行,Docker已安装,你已经准备好开始配置你的应用程序的容器. 因为你的容器由多个组件组成,你需要使用一个流程管理器来启动和监控它们。

首先,为您的容器创建并输入名为thunderbird的目录:

1mkdir ~/thunderbird
2cd ~/thunderbird

现在,使用nano或您喜爱的编辑器创建并打开名为supervisord.conf的文件:

1nano ~/thunderbird/supervisord.conf

现在,将这个第一个代码块添加到‘supervisord.conf’中,这将定义 supervisord 的全球选项:

1[label ~/thunderbird/supervisord.conf]
2[supervisord]
3nodaemon=true
4pidfile=/tmp/supervisord.pid
5logfile=/dev/fd/1
6logfile_maxbytes=0

在这个块中,你正在配置supervisord本身。你需要将nodaemon设置为true,因为它将作为入口点运行在Docker容器内部。因此,你希望它继续在前沿运行。你还将pidfile设置为非根用户可访问的路径(稍后了解更多),并将logfile设置为stdout,以便你可以看到日志。

接下来,将另一个小的代码块添加到supervisord.conf。这个块开始了 TigerVNC,这是一个组合的 VNC/X11 服务器:

1[label ~/thunderbird/supervisord.conf]
2...
3[program:x11]
4priority=0
5command=/usr/bin/Xtigervnc -desktop "Thunderbird" -localhost -rfbport 5900 -SecurityTypes None -AlwaysShared -AcceptKeyEvents -AcceptPointerEvents -AcceptSetDesktopSize -SendCutText -AcceptCutText :0
6autorestart=true
7stdout_logfile=/dev/fd/1
8stdout_logfile_maxbytes=0
9redirect_stderr=true

在这个块中,你正在设置X11服务器。 X11是一个显示服务器协议,这就是允许GUI应用程序运行的原因。

对于此容器,您正在使用 TigerVNC 和其内置的 VNC 服务器。

  • 更快的响应时间,因为GUI绘图是直接到VNC服务器,而不是到中间框架缓存(存储屏幕内容的内存)。
  • 自动屏幕调整,允许远程应用程序自动调整尺寸以适应客户端(在这种情况下,您的Web浏览器窗口)。

如果您愿意,您可以将桌面选项的参数从Thunderbird更改为您选择的其他东西,服务器将显示您的选择,作为访问您的应用程序所使用的网页的标题。

现在,让我们在supervisord.conf中添加第三个代码块,开始easy-novnc:

1[label ~/thunderbird/supervisord.conf]
2...
3[program:easy-novnc]
4priority=0
5command=/usr/local/bin/easy-novnc --addr :8080 --host localhost --port 5900 --no-url-password --novnc-params "resize=remote"
6autorestart=true
7stdout_logfile=/dev/fd/1
8stdout_logfile_maxbytes=0
9redirect_stderr=true

在这个块中,你正在设置 easy-novnc,一个独立的服务器,它提供了围绕 noVNC的包装器。 这个服务器执行两个角色. 首先,它提供了一个简单的连接页面,允许您配置连接的选项,并允许您设置默认选项。 第二,它通过 WebSocket代理VNC,允许通过普通的Web浏览器访问。

通常,在客户端方面进行调整(即图像扩展),但您正在使用resize=remote选项,以充分利用TigerVNC的远程分辨率调整。

<$>[注] **注:**本教程使用easy-novnc。如果你愿意的话,你可以使用websockify和一个单独的Web服务器,而不是easy-novnc。easy-novnc的优点是,内存使用量和启动时间显著较低,而且它是自含的。

现在,将以下块添加到您的配置中,以启动 OpenBox,窗口管理器:

 1[label ~/thunderbird/supervisord.conf]
 2...
 3[program:openbox]
 4priority=1
 5command=/usr/bin/openbox
 6environment=DISPLAY=:0
 7autorestart=true
 8stdout_logfile=/dev/fd/1
 9stdout_logfile_maxbytes=0
10redirect_stderr=true

在此块中,您正在设置 OpenBox,一个轻量级的 X11 窗口管理器. 您可以跳过此步骤,但如果没有它,您将没有标题栏或能够调整窗口大小。

最后,让我们将最后一个块添加到supervisord.conf,它将启动主应用程序:

 1[label ~/thunderbird/supervisord.conf]
 2...
 3[program:app]
 4priority=1
 5environment=DISPLAY=:0
 6command=/usr/bin/thunderbird
 7autorestart=true
 8stdout_logfile=/dev/fd/1
 9stdout_logfile_maxbytes=0
10redirect_stderr=true

在这个最后的区块中,您将优先级设置为1,以确保Thunderbird启动 after TigerVNC,否则它会遇到竞赛条件并随机失败。

以下是完成的supervisord.conf的样子:

 1[label ~/thunderbird/supervisord.conf]
 2[supervisord]
 3nodaemon=true
 4pidfile=/tmp/supervisord.pid
 5logfile=/dev/fd/1
 6logfile_maxbytes=0
 7
 8[program:x11]
 9priority=0
10command=/usr/bin/Xtigervnc -desktop "Thunderbird" -localhost -rfbport 5900 -SecurityTypes None -AlwaysShared -AcceptKeyEvents -AcceptPointerEvents -AcceptSetDesktopSize -SendCutText -AcceptCutText :0
11autorestart=true
12stdout_logfile=/dev/fd/1
13stdout_logfile_maxbytes=0
14redirect_stderr=true
15
16[program:easy-novnc]
17priority=0
18command=/usr/local/bin/easy-novnc --addr :8080 --host localhost --port 5900 --no-url-password --novnc-params "resize=remote"
19autorestart=true
20stdout_logfile=/dev/fd/1
21stdout_logfile_maxbytes=0
22redirect_stderr=true
23
24[program:openbox]
25priority=1
26command=/usr/bin/openbox
27environment=DISPLAY=:0
28autorestart=true
29stdout_logfile=/dev/fd/1
30stdout_logfile_maxbytes=0
31redirect_stderr=true
32
33[program:app]
34priority=1
35environment=DISPLAY=:0
36command=/usr/bin/thunderbird
37autorestart=true
38stdout_logfile=/dev/fd/1
39stdout_logfile_maxbytes=0
40redirect_stderr=true

如果您想集装一个不同的应用程序,请用/usr/bin/thunderbird代替应用程序的可执行路径,否则,您现在已经准备好配置您的GUI的主菜单。

步骤 2 — 设置 OpenBox 菜单

现在你的流程管理器已配置,让我们设置OpenBox菜单. 这个菜单允许我们在容器内启动应用程序. 我们还将包括一个终端和流程监视器进行调试,如有需要。

在应用程序目录中,使用nano或您最喜欢的文本编辑器创建并打开名为menu.xml的新文件:

1nano ~/thunderbird/menu.xml

现在将以下代码添加到「menu.xml」中:

 1[label ~/thunderbird/menu.xml]
 2<?xml version="1.0" encoding="utf-8"?>
 3<openbox_menu xmlns="http://openbox.org/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://openbox.org/ file:///usr/share/openbox/menu.xsd">
 4    <menu id="root-menu" label="Openbox 3">
 5        <item label="Thunderbird">
 6            <action name="Execute">
 7                <execute>/usr/bin/thunderbird</execute>
 8            </action>
 9        </item>
10        <item label="Terminal">
11            <action name="Execute">
12                <execute>/usr/bin/x-terminal-emulator</execute>
13            </action>
14        </item>
15        <item label="Htop">
16            <action name="Execute">
17                <execute>/usr/bin/x-terminal-emulator -e htop</execute>
18            </action>
19        </item>
20    </menu>
21</openbox_menu>

此 XML 文件包含在桌面上右键单击时出现的菜单项目. 每个项目由标签和操作组成。

如果您想容器化另一个应用程序,请用/ usr / bin / thunderbird代替应用程序的可执行路径,并更改该项目的标签

步骤 3 — 创建 Dockerfile

现在OpenBox已配置,您将创建Dockerfile,将所有东西连接在一起。

在您的容器目录中创建 Dockerfile:

1nano ~/thunderbird/Dockerfile

首先,让我们添加一些代码来构建easy-novnc:

1[label ~/thunderbird/Dockerfile]
2FROM golang:1.14-buster AS easy-novnc-build
3WORKDIR /src
4RUN go mod init build && \
5    go get github.com/geek1011/[email protected] && \
6    go build -o /bin/easy-novnc github.com/geek1011/easy-novnc

在第一个阶段,你正在构建easy-novnc。这在一个单独的阶段进行,以便简化和节省空间;你不需要整个Go工具链在最终图像中。在构建命令中记住@v1.1.0。这确保了结果是确定性的,这很重要,因为Docker缓存每个步骤的结果。 如果你没有指定一个明确的版本,Docker会在图像首次构建时引用easy-novnc的最新版本。

现在让我们创建第二个阶段,这将成为最终的图像. 在这里,您将使用 Debian 10 (buster) 作为基本图像. 请注意,因为它在容器中运行,它将无论您在服务器上运行的发行版如何工作。

接下来,将以下块添加到您的Dockerfile:

1[label ~/thunderbird/Dockerfile]
2...
3FROM debian:buster
4RUN apt-get update -y && \
5    apt-get install -y --no-install-recommends openbox tigervnc-standalone-server supervisor gosu && \
6    rm -rf /var/lib/apt/lists && \
7    mkdir -p /usr/share/desktop-directories

在本指示中,您将 Debian 10 作为您的基本图像安装,然后安装在容器中运行 GUI 应用程序所需的最低限度。 请注意,您将apt-get update运行作为同一指示的一部分,以防止 Docker 出现缓存问题。 为了节省空间,您还会删除随后下载的包列表(缓存包本身是 默认移除

再加上一个小小的代码:

1[label ~/thunderbird/Dockerfile]
2...
3RUN apt-get update -y && \
4    apt-get install -y --no-install-recommends lxterminal nano wget openssh-client rsync ca-certificates xdg-utils htop tar xzip gzip bzip2 zip unzip && \
5    rm -rf /var/lib/apt/lists

在本教程中,您正在安装一些有用的通用实用程序和套件. 特别有趣的是xdg-utils (提供 Linux 上桌面应用程序使用的基本命令) 和ca-certificates (安装根证书,使我们能够访问 HTTPS 站点)。

现在,我们可以添加主要应用程序的说明:

1[label ~/thunderbird/Dockerfile]
2...
3RUN apt-get update -y && \
4    apt-get install -y --no-install-recommends thunderbird && \
5    rm -rf /var/lib/apt/lists

如前所述,在这里我们正在安装该应用程序. 如果您正在集装不同的应用程序,您可以用安装特定应用程序所需的命令代替这些命令. 有些应用程序需要更多的工作才能在 Docker 中运行。

接下来,让我们开始添加添加最后几个文件到容器的说明:

1[label ~/thunderbird/Dockerfile]
2...
3COPY --from=easy-novnc-build /bin/easy-novnc /usr/local/bin/
4COPY menu.xml /etc/xdg/openbox/
5COPY supervisord.conf /etc/
6EXPOSE 8080

在这里,您正在将您之前创建的配置文件添加到图像中,并从第一阶段复制easy-novnc二进制。

此下一个代码块会创建数据目录并为您的应用添加一个专用用户,这很重要,因为一些应用拒绝作为 root 运行。

1[label ~/thunderbird/Dockerfile]
2...
3RUN groupadd --gid 1000 app && \
4    useradd --home-dir /data --shell /bin/bash --uid 1000 --gid 1000 app && \
5    mkdir -p /data
6VOLUME /data

为了确保文件的UID/GID一致,您正在明确地将其设置为1000

最后,让我们添加启动一切的说明:

1[label ~/thunderbird/Dockerfile]
2...
3CMD ["sh", "-c", "chown app:app /data /dev/stdout && exec gosu app supervisord"]

通过将默认命令设置为supervisord,管理员将启动运行您的应用程序所需的流程。在这种情况下,您正在使用CMD而不是ENTRYPOINT。在大多数情况下,它不会产生任何差异,但使用CMD更适合这个目的,因为几个原因。 第一,supervisord不采取任何对我们有意义的论点,如果您向容器提供论点,它们将取代CMD并附加到ENTRYPOINT。 第二,使用CMD允许我们在将论点传递到容器时提供完全不同的命令(将由/bin/sh -c执行),这使得调试更容易。

最后,在启动supervisord之前,您需要运行chown作为根,以防止数据量出现权限问题,并允许孩子处理器打开stdout

以下是完成的Dockerfile的样子:

 1[label ~/thunderbird/Dockerfile]
 2FROM golang:1.14-buster AS easy-novnc-build
 3WORKDIR /src
 4RUN go mod init build && \
 5    go get github.com/geek1011/[email protected] && \
 6    go build -o /bin/easy-novnc github.com/geek1011/easy-novnc
 7
 8FROM debian:buster
 9
10RUN apt-get update -y && \
11    apt-get install -y --no-install-recommends openbox tigervnc-standalone-server supervisor gosu && \
12    rm -rf /var/lib/apt/lists && \
13    mkdir -p /usr/share/desktop-directories
14
15RUN apt-get update -y && \
16    apt-get install -y --no-install-recommends lxterminal nano wget openssh-client rsync ca-certificates xdg-utils htop tar xzip gzip bzip2 zip unzip && \
17    rm -rf /var/lib/apt/lists
18
19RUN apt-get update -y && \
20    apt-get install -y --no-install-recommends thunderbird && \
21    rm -rf /var/lib/apt/lists
22
23COPY --from=easy-novnc-build /bin/easy-novnc /usr/local/bin/
24COPY menu.xml /etc/xdg/openbox/
25COPY supervisord.conf /etc/
26EXPOSE 8080
27
28RUN groupadd --gid 1000 app && \
29    useradd --home-dir /data --shell /bin/bash --uid 1000 --gid 1000 app && \
30    mkdir -p /data
31VOLUME /data
32
33CMD ["sh", "-c", "chown app:app /data /dev/stdout && exec gosu app supervisord"]

现在我们已经准备好构建和运行我们的容器,然后访问Thunderbird - 一个GUI应用程序。

步骤 4 — 构建和运行集装箱

下一步是构建您的容器并将其设置为在启动时运行,您还将设置一个卷,以便在重新启动和更新之间保存应用程序数据。

首先构建您的容器. 请确保在 ~/thunderbird 目录中运行这些命令:

1docker build -t thunderbird .

现在创建一个新的网络,该网络将在应用程序的容器之间共享:

1docker network create thunderbird-net

然后创建一个体积来存储应用程序数据:

1docker volume create thunderbird-data

最后,运行它并设置为自动重新启动:

1docker run --detach --restart=always --volume=thunderbird-data:/data --net=thunderbird-net --name=thunderbird-app thunderbird

请注意,如果您想要的话,您可以用不同的名称替换thunderbird-app之后的--name选项。 无论您选择了什么,您的应用程序现在已集装并运行。

步骤 5 — 设置 Caddy

在此步骤中,您将设置 Caddy Web 服务器以提供身份验证,并可选择通过 WebDAV 远程访问文件。

创建一个新目录,然后移动到里面:

1mkdir ~/caddy
2cd ~/caddy

现在使用nano或您喜爱的编辑器创建一个新的Dockerfile:

1nano ~/caddy/Dockerfile

然后添加以下指令:

 1[label ~/caddy/Dockerfile]
 2FROM golang:1.14-buster AS caddy-build
 3WORKDIR /src
 4RUN echo 'module caddy' > go.mod && \
 5    echo 'require github.com/caddyserver/caddy/v2 v2.1.1' >> go.mod && \
 6    echo 'require github.com/mholt/caddy-webdav v0.0.0-20200523051447-bc5d19941ac3' >> go.mod
 7RUN echo 'package main' > caddy.go && \
 8    echo 'import caddycmd "github.com/caddyserver/caddy/v2/cmd"' >> caddy.go && \
 9    echo 'import _ "github.com/caddyserver/caddy/v2/modules/standard"' >> caddy.go && \
10    echo 'import _ "github.com/mholt/caddy-webdav"' >> caddy.go && \
11    echo 'func main() { caddycmd.Main() }' >> caddy.go
12RUN go build -o /bin/caddy .
13
14FROM debian:buster
15
16RUN apt-get update -y && \
17    apt-get install -y --no-install-recommends gosu && \
18    rm -rf /var/lib/apt/lists
19
20COPY --from=caddy-build /bin/caddy /usr/local/bin/
21COPY Caddyfile /etc/
22EXPOSE 8080
23
24RUN groupadd --gid 1000 app && \
25    useradd --home-dir /data --shell /bin/bash --uid 1000 --gid 1000 app && \
26    mkdir -p /data
27VOLUME /data
28
29WORKDIR /data
30CMD ["sh", "-c", "chown app:app /data && exec gosu app /usr/local/bin/caddy run -adapter caddyfile -config /etc/Caddyfile"]

此 Dockerfile 使用 WebDAV 插件启用创建 Caddy,然后在端口 8080 启动它,然后在 /etc/Caddyfile 中的 Caddyfile

接下来,您将配置 Caddy Web 服务器. 在您刚刚创建的目录中创建一个名为 Caddyfile 的文件:

1nano ~/caddy/Caddyfile

现在将以下代码块添加到你的Caddyfile:

 1[label ~/caddy/Caddyfile]
 2{
 3    order webdav last
 4}
 5:8080 {
 6    log
 7    root * /data
 8    reverse_proxy thunderbird-app:8080
 9
10    handle_path /files/* {         
11        file_server browse
12    }
13    redir /files /files/
14
15    handle /webdav/* {
16        webdav {             
17            prefix /webdav         
18        }
19    }
20    redir /webdav /webdav/
21
22    basicauth /* {
23        {env.APP_USERNAME} {env.APP_PASSWORD_HASH}
24    }
25}

这个Caddyfile向你在步骤 4 中创建的thunderbird-app容器的 root 目录代理(Docker 将其解决为正确的 IP)。它还将为在/files上提供一个仅限于阅读的基于 Web 的文件浏览器,并在/webdav上运行 WebDAV 服务器,您可以本地安装以访问您的文件。用户名和密码从环境变量APP_USERNAMEAPP_PASSWORD_HASH中读取。

现在把容器放进去:

1docker build -t thunderbird-caddy .

Caddy v2 要求您对所需密码进行哈希。运行以下命令,并记住用您所选择的强有力的密码代替「mypass」:

1docker run --rm -it thunderbird-caddy caddy hash-password -plaintext 'mypass'

此命令将输出一个字符串. 将此副本复制到您的剪辑板,以准备运行下一个命令。

现在你已经准备好运行容器了,请确保用你所选择的用户名替换myuser,并用你在上一步执行的命令的输出代替mypass-hash

1docker run --detach --restart=always --volume=thunderbird-data:/data --net=thunderbird-net --name=thunderbird-web --env=APP_USERNAME="myuser" --env=APP_PASSWORD_HASH="mypass-hash" --publish=8080:8080 thunderbird-caddy

我们现在已经准备好访问和测试我们的应用程序。

步骤6 —测试和管理应用程序

让我们访问您的应用程序并确保它工作。

首先,在网页浏览器中打开http://your_server_ip:8080,使用您之前选择的凭证登录 ,然后点击连接

NoVNC connect page

您现在应该能够与应用程序进行交互,它应该自动调整尺寸,以适应您的浏览器窗口。

Thunderbird main menu

如果你右击黑桌面,你应该看到一个菜单,允许你访问一个终端. 如果你中间点击,你应该看到一个窗口列表。

NoVNC right click

现在在网页浏览器中打开 http://your_server_ip:8080/files/. 您应该能够访问您的文件。

NoVNC file access webdav

此外,您可以尝试在 WebDAV 客户端中安装 http://your_server_ip:8080/webdav/. 您应该能够直接访问和修改您的文件。 如果您在 Windows 浏览器中使用 Map 网络驱动器 选项,则需要使用反向代理来添加 HTTPS 或将 HKLM\SYSTEM\CurrentControlSet\Services\WebClient\Parameters\BasicAuthLevel 设置为 DWORD:2

在任何情况下,您的本地 GUI 应用程序现在已经准备好远程使用。

结论

现在您已成功为 Thunderbird 设置了 Docker 容器,然后使用 Caddy,您已通过 Web 浏览器配置了访问它. 如果您需要升级您的应用程序,停止容器,运行docker rm thunderbird-app thunderbird-web,重新构建图像,然后从上面的步骤中重新运行docker run命令。

如果您想了解有关基本的Docker命令的更多信息,您可以阅读此教程(https://andsky.com/tech/tutorials/how-to-install-and-use-docker-on-debian-10#step-2-%E2%80%94-executing-the-docker-command-without-sudo-(optional))或此小册子(https://andsky.com/tech/tutorials/how-to-remove-docker-images-containers-and-volumes)。

此外,如果您正在部署多个应用程序,您可能希望使用Docker Compose或Kubernetes,而不是手动启动每个容器。

  • Wine,用于在 Linux 上运行 Windows 应用程序的兼容性层。
  • GIMP,是一个开源图像编辑器。

此后一种选项展示了容器化和远程访问 GUI 应用的巨大潜力. 通过此设置,您现在可以使用具有远大计算能力的服务器,而不是本地运行 Cutter 等资源密集工具。

Published At
Categories with 技术
comments powered by Disqus