作者选择了 自由和开源基金作为 写给捐款计划的一部分接受捐款。
介绍
即使在云服务的普及日益增加,仍然需要运行本地应用程序。
使用 noVNC和 TigerVNC可在 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_USERNAME
和APP_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
,使用您之前选择的凭证登录
,然后点击连接
。
您现在应该能够与应用程序进行交互,它应该自动调整尺寸,以适应您的浏览器窗口。
如果你右击黑桌面,你应该看到一个菜单,允许你访问一个终端. 如果你中间点击,你应该看到一个窗口列表。
现在在网页浏览器中打开 http://your_server_ip:8080/files/
. 您应该能够访问您的文件。
此外,您可以尝试在 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,而不是手动启动每个容器。
此后一种选项展示了容器化和远程访问 GUI 应用的巨大潜力. 通过此设置,您现在可以使用具有远大计算能力的服务器,而不是本地运行 Cutter 等资源密集工具。