- 使用 Spring Initializr 创建 Spring Boot 应用程序
- 在Spring Boot中配置Cassandra
- 在 Spring Boot 上配置 Tomcat 连接池
- 将Camel消息路由到嵌入WildFly的Artemis上
**摘要:**使用Docker容器,将带UI的程序,直接转换为Web应用。很方便,跟大家分享一下。
本文分享自华为云社区《使用Docker容器,将带UI的程序,直接转为Web应用》,作者:tsjsdbd。
我们可以通过Docker容器,将App的UI界面,投射到任意的网络目的端。
即:
其原理是利用X11协议,把界面投射转化为网络协议,到达目的端显示出来。
但是这种方案,有一个硬性要求:就是目的端必须要安装一个“投屏软件(X11 Server)”,比如:VcXsrv 或者 MobaXterm。
那么用户想要看到App的界面,他就得额外安装一个软件,用户体验并不是最佳的。
Windows的远程桌面,相信大家都用过吧。 VNC就是Linux版的远程桌面。它可以将屏幕,通过网络共享给客户端。
在服务端,安装vncserver。 在客户端,安装vncviewer。
不过,windows是自带了一个 远程桌面客户端。对VNC的话,用户就得安装一个 vnc-viewer客户端。和X11方案差不多,还是不够方便。
好消息是,VNC-Viewer有一个WEB版的客户端,叫做 noVNC。它直接打开网页,就获得VNC-Viewer能力。详见:https://novnc.com/info.html
于是,我们可以将方案拓展为:
毕竟,浏览器基本上每个客户都会有。这就好比,微信大家都有,所以“单独安装一个App”vs“微信小程序” ,肯定是后者在使用更便捷一样的道理。
所以你可以看到各大云厂商,比如华为云的ECS虚机,也都自带了使用noVNC的方式来展示虚机的界面。可见noVNC的产品化可靠性还是OK的。
这里我为了方便,准备将各种Server都安装到一个Docker容器里面,如下:
因为最终我们要通过HTML访问这个容器,所以启动的时候,我们得记得开放端口:
docker run -it -p 80:8080 ubuntu:20.04 /bin/bash
在这个容器里面,启动上图中的各种Server。
首先,安装一个叫做 xvfb 的软件。这是一个“虚拟屏幕”,都在内存中模拟的屏幕。见:https://en.wikipedia.org/wiki/Xvfb
安装:
apt-get install -y xvfb
然后启动“虚拟屏幕”:
Xvfb :0 -screen 0 1920x1080x24 -listen tcp -ac +extension GLX +extension RENDER
其中,1920x1080x24 表示:屏幕大小(分辨率)。 24则是像素深度。
这个屏幕大小,到时候可以根据App的界面效果自己调整。
然后,我们安装 x11服务器(因为安装这个有交互,所以之类设置了 无交互模式)
export DEBIAN_FRONTEND=noninteractive
apt-get install -y x11vnc
然后启动 x11服务器:
x11vnc -forever -shared -noipv6 -passwd tsjsdbd
其中标红的password换成你自己喜欢的密码。
最后,我们通过noVNC服务器,将 VNC翻译为HTML服务,
安装:
apt-get install -y novnc
然后启动:
websockify --web /usr/share/novnc 8080 localhost:5900
apt-get install x11-apps
DISPLAY=:0.0 xclock
这里的DISPLAY变量的作用,是表示把App的界面,投射到咱们的这个“虚拟屏幕”上。
详细请看我之前的那篇文章。
从浏览器,访问我们的容器。地址(因为我们启动容器用来http默认端口80,所以这里URL不用设置端口了。):
http://容器ip/vnc.html
这里填,第3步咱设置的密码。然后可以看到App的界面啦:
这里为了大家方便,直接提供一个Dockerfile
FROM ubuntu:20.04
ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get install -y novnc x11vnc xvfb
EXPOSE 8080
ENTRYPOINT ["/bin/bash"]
然后写个 start-novnc.sh 脚本:
#!/bin/bash
set -e
#虚拟屏幕
Xvfb :0 -screen 0 1920x1080x24 -listen tcp -ac +extension GLX +extension RENDER > /dev/null 2>&1 &
#vnc服务器
x11vnc -forever -shared -noipv6 -passwd tsjsdbd > /dev/null 2>&1 &
#novnc
websockify --web /usr/share/novnc 8080 localhost:5900 > /dev/null 2>&1 &
最后你启动app的时候,记得带上:
DISPLAY==========================================BN
=:0.0 your-ui-app
就可以了。
运行 PostgreSQL(7.4 和 8.x),我认为这是可行的,但现在我遇到了错误。 我可以单独运行查询,它工作得很好,但如果我使用 UNION 或 UNION ALL,它会抛出错误。 这个错误:
我试图为我的应用程序创建一个导航,使用抽屉导航我的 fragment 之一(HomeFragment)有一个 ViewPager,可容纳 3 个 fragment (Bundy Clock、Annou
以我目前正在开发的应用为例: - 它有一个包含多个项目的抽屉导航;现在有两个项目让我感兴趣,我将它们称为 X 和 Y。 X 和 Y 都在单击时显示包含 x 元素或 y 元素列表的 fragment 选
我有一个形状为 (370,275,210) 的 NumPy 数组,我想将其重新整形为 (275,210,370)。我将如何在 Python 中实现这一点? 370是波段数,275是行数,210是图像包
我们如何与被子 UIViewController 阻止的父 UIViewController(具有按钮)交互。显然,触摸事件不会通过子 Nib 。 (启用用户交互) 注意:我正在加载默认和自定义 NI
我是 Jpa 新手,我想执行过程 我的代码如下 private static final String PERSISTENCE_UNIT_NAME = "todos"; private static
与安装了 LAMP 的 GCE 相比,选择与 Google Cloud SQL 链接的 GCE 实例有哪些优势? 我确定 GCE 是可扩展的,但是安装在其上的 mysql 数据库的可扩展性如何? 使用
这个问题在这里已经有了答案: Value receiver vs. pointer receiver (3 个答案) 关闭 3 年前。 我刚接触 golang。只是想了解为 Calc 类型声明的两种
我不小心按了一个快捷键,一个非常漂亮的断线出现在日期上。 有点像 # 23 Jun 2010 -------------------- 有人知道有问题的快捷方式吗?? (我在 mac 上工作!) 在
我正在Scala中编写正则表达式 val regex = "^foo.*$".r 这很好,但是如果我想做 var x = "foo" val regex = s"""^$x.*$""".r 现在我们有
以下 XML 文档在技术上是否相同? James Dean 19 和: James Dean 19 最佳答案 这两个文档在语义上是相同的。在 X
我在对数据帧列表运行稳健的线性回归模型(使用 MASS 库中的 rlm)时遇到问题。 可重现的示例: var1 <- c(1:100) var2 <- var1*var1 df1 <- data.f
好的,我有一个自定义数字键盘,可以在标签(numberField)中将数字显示为 0.00,现在我需要它显示 $0.00。 NSString *digit = sender.currentTitle;
在基于文档的应用程序中,使用 XIB 文件,创建新窗口时其行为是: 根据最后一个事件的位置进行定位和调整大小 window 。 如果最后一个事件窗口仍然可见,则新窗口 窗口应该是级联的,这样它就不会直
我想使用参数进行查询,如下所示: SELECT * FROM MATABLE WHERE MT_ID IN (368134, 181956) 所以我考虑一下 SELECT * FROM MATABLE
我遇到一些性能问题。 我有一个大约有 200 万行的表。 CREATE TABLE [dbo].[M8]( [M8_ID] [int] IDENTITY(1,1) NOT NULL,
我在 jquery 中的按键功能遇到问题。我不知道为什么按键功能不起作用。我已经使用了正确的 key 代码。在我的函数中有 2 个代码,其中包含 2 个事件键,按一个键表示 (+) 代码 107 和(
我想显示音频波形,我得到了此代码,它需要.raw音频输入并显示音频波形,但是当我放入.3gp,.mp3音频时,我得到白噪声,有人可以帮助我如何使其按需与.3gp一起使用使用.3gp音频运行它。 Inp
我无法让 stristr 函数返回真值,我相信这是因为我的搜索中有一个 $ 字符。 当我这样做时: var_dump($nopricecart); 完整的 $nopricecart 值是 $0 ,我得
如果我有这样的循环: for(int i=0;i O(n) 次。所以do some执行了O(n)次。如果做某事是线性时间,那么代码片段的复杂度是O(n^2)。 关于algorithm - 带 If 语
我是一名优秀的程序员,十分优秀!