目录

使用 Docker 部署 JxBrowser 应用程序

本教程演示了如何使用 Docker 部署 JxBrowser 应用程序。

为什么使用 Docker 

Docker 允许您将 JxBrowser 应用程序与其所需的所有系统依赖项一起打包,并在不同环境中一致地运行, 包括在官方尚未支持的较旧 Linux 发行版上。

在本教程中,Docker 用于:

  • 在无图形界面的 Linux 环境中,通过虚拟 X 服务器运行 JxBrowser。
  • 通过将容器连接到主机的 X 服务器,以桌面应用程序的方式运行 JxBrowser。

前提条件 

获取代码 

您可以在我们的示例仓库中找到完整的 Dockerfile 和示例应用程序:

$ git clone https://github.com/TeamDev-IP/JxBrowser-Examples
$ cd JxBrowser-Examples/tutorials/docker

JxBrowser 应用程序 

创建应用程序 

使用上述仓库中的示例项目,或使用 Gradle 创建您自己的项目。

该示例使用以下目录结构:

tutorials/docker/
├── Dockerfile      # Builds the Docker image with all required system dependencies
├── startup.sh      # Script to start the application
└── project/        # Gradle project containing the application
    └── build.gradle

添加许可证 

将许可证密钥添加到应用程序中。请参见将许可证添加到项目中

创建 Dockerfile 

创建一个 Dockerfile,用于将应用程序与其所需的系统依赖项一起打包。

基本环境配置 

使用 Ubuntu LTS 作为基础镜像:

FROM ubuntu:24.04

Chromium 需要 glibc 才能正常运行。因此,我们不能使用 Alpine 或任何使用 musl 或其他 C 标准库的 Linux 发行版。

配置用于软件包安装的非交互式环境:

ENV DEBIAN_FRONTEND=noninteractive

更新软件包列表:

RUN apt update

安装 Java 和 Chromium 依赖项 

安装 OpenJDK 17。您也可以根据需要使用任何其他受支持的 JDK

RUN apt install -y openjdk-17-jdk

安装 Chromium 所需的本地系统库:

RUN apt install -y \
    ca-certificates \
    fonts-liberation \
    libasound2t64 \
    libatk-bridge2.0-0 \
    libatk1.0-0 \
    libatspi2.0-0 \
    libc6 \
    libcairo2 \
    libcups2 \
    libdbus-1-3 \
    libdrm2 \
    libexpat1 \
    libgbm1 \
    libglib2.0-0 \
    libgtk-3-0 \
    libnspr4 \
    libnss3 \
    libpango-1.0-0 \
    libu2f-udev \
    libvulkan1 \
    libx11-6 \
    libxcb1 \
    libxcomposite1 \
    libxdamage1 \
    libxext6 \
    libxfixes3 \
    libxkbcommon0 \
    libxrandr2

如果您选择使用不同的基础镜像,请按照系统要求 为该发行版安装相应的依赖项。

安装 X11 服务器 

Chromium 需要 X11 服务器才能运行。安装 Xvfb(一个轻量级的虚拟 X 服务器), 以便在没有图形显示的环境中运行:

RUN apt install -y xvfb

复制并构建项目 

在基础镜像和依赖项准备完成后,定义应用程序的启动方式,并将项目复制到镜像中。

  1. 创建用于运行应用程序的 startup.sh 脚本:
#!/bin/sh

if [ -z "${DISPLAY:-}" ]; then
  Xvfb :0 -screen 0 1920x1080x24+32 &
  export DISPLAY=:0
fi

cd project
./gradlew run

该脚本会检查 DISPLAY 环境变量中是否存在可用的 X 服务器:

  • 如果未设置 DISPLAY,则启动虚拟 X 服务器(Xvfb),以无头模式运行。
  • 如果已设置 DISPLAY,则使用指定的 X 服务器,以桌面模式运行应用程序。

为简化示例,此处通过 Gradle 运行应用程序。在生产环境中,通常会构建 JAR 文件并直接运行。

  1. 将启动脚本复制到镜像中并赋予执行权限:
COPY startup.sh .
RUN chmod +x startup.sh
  1. 复制 Gradle 项目并在镜像中构建:
COPY project/ project
RUN cd project && ./gradlew build
  1. 配置容器入口点:
WORKDIR /
ENTRYPOINT ["sh", "-c", "/startup.sh"]

构建并启动 Docker 容器 

构建 Docker 镜像并命名为 jxbrowser

docker build -t jxbrowser .

镜像构建完成后,您可以根据使用场景以不同方式运行应用程序。

本教程演示了两种模式:

  • 无头模式 — 适用于自动化、测试以及不需要 UI 的服务器端执行。
  • 桌面模式 — 适用于将应用程序作为带有可视界面的桌面应用程序分发和运行。

无头模式 

在无头模式下,应用程序通过虚拟 X 服务器(Xvfb)运行。

启动容器:

docker run --shm-size=1gb -t jxbrowser

--shm-size=1gb 将共享内存大小扩展至 1 GB。 Docker 默认仅提供 64 MB,这对于 Chromium 来说是不够的。

在示例应用程序中,我们加载 Google 并打印页面标题。您应该在控制台中看到:

Title: Google

桌面模式 

在桌面模式下,应用程序会连接到主机系统的 X 服务器,从而像本地桌面应用程序一样运行。 此配置仅适用于使用 X11 的 Linux 系统。

在该模式下,应用程序可以在本地窗口中显示浏览器内容。 为此,请在应用程序中添加一个简单的 Swing UI:

SwingUtilities.invokeLater(() -> {
    var view = BrowserView.newInstance(browser);
    var frame = new JFrame("Demo App");
    frame.addWindowListener(new WindowAdapter() {
        @Override
        public void windowClosing(WindowEvent e) {
            engine.close();
        }
    });
    frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
    frame.add(view, BorderLayout.CENTER);
    frame.setSize(800, 500);
    frame.setLocationRelativeTo(null);
    frame.setVisible(true);

    browser.navigation().loadUrl("https://google.com");
});

修改应用程序后,请不要忘记重新构建 Docker 镜像。

在运行容器之前,执行以下命令以允许本地连接到 X 服务器:

xhost +local:root

以访问主机 X 服务器的方式运行容器:

docker run --shm-size=1gb -t \
  -e DISPLAY=$DISPLAY \
  -v /tmp/.X11-unix:/tmp/.X11-unix \
  jxbrowser

该命令会将主机的 DISPLAY 变量传递给容器,并挂载 X11 套接字。

您应该会在主机桌面上看到应用程序窗口: Docker app window

完成调试后,请恢复 X 服务器的访问控制:

xhost -local:root

故障排除 

通过远程调试端口访问 DevTools 

在开发和调试过程中,您可以使用 Chrome DevTools 来检查浏览器。 为此,请在应用程序中启用远程调试端口

var engine = Engine.newInstance(
        EngineOptions.newBuilder(HARDWARE_ACCELERATED)
                .addSwitch("--remote-allow-origins=http://localhost:9222")
                .remoteDebuggingPort(9222)
                .build()
);

在 Docker 中,Chromium 通常只接受来自容器内部 localhost 的 DevTools 连接。 要从主机访问 DevTools,可以使用 SSH 本地端口转发。

在主机上启动容器并暴露 SSH 端口:

docker run -p 2222:22 --shm-size=1gb -t jxbrowser

在运行中的容器内打开一个 shell:

docker exec -it <container_id> /bin/bash

<container_id> 替换为正在运行的容器 ID(可通过 docker ps 查看)。

在容器中安装并启动 SSH 服务器:

apt install -y openssh-server
service ssh start

在容器中创建一个用于 SSH 访问的用户:

useradd --create-home --shell /bin/bash jxbrowser
passwd jxbrowser

在主机上转发远程调试端口:

ssh -L 9222:localhost:9222 -p 2222 jxbrowser@localhost

该命令会将主机上的 localhost:9222 转发到容器内部的 localhost:9222。 在使用 DevTools 时,请保持该 SSH 会话处于打开状态。

在主机上打开 Google Chrome,并访问 chrome://inspect 以使用 DevTools。

Kubernetes 

Kubernetes 不支持像 Docker 那样直接使用 --shm-size 选项, 因此需要手动为 /dev/shm 创建一个基于内存的卷:

spec:
  volumes:
  - name: chromium_shm
    emptyDir:
      sizeLimit: "1Gi"
      medium: Memory
  containers:
  - image: jxbrowser
    volumeMounts:
      - mountPath: /dev/shm
        name: chromium_shm

总结 

在本教程中,您学习了如何:

  • 使用 Docker 构建并运行 JxBrowser 应用程序。
  • 在虚拟 X 服务器中运行应用程序,或使用主机的 X 服务器。
  • 启用远程调试端口,并通过 SSH 端口转发访问 DevTools。