Deploying JxBrowser Applications With Docker

This tutorial demonstrates how to deploy a JxBrowser application in the headless environment using Docker.

Prerequisites

For this tutorial, you will need the following:

  • Installed and running a Docker Engine.
  • A valid JxBrowser license. It can be either Evaluation or Commercial. For more information on licensing please see the Licensing guide.

Getting the Code

You can find a complete Dockerfile and a sample application in our collection of examples:

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

JxBrowser Application

Creating an Application

Create a new JxBrowser application using Gradle or use one from the examples repository. Next, create a new directory and copy the created project under the project sub-directory.

Adding the License

To move forward, put the license key into the application.

Configuring Chromium for Docker

If there is an issue, and you want to inspect the web browser’s state with DevTools, it is possible to access the developer tools via the remote debugging port. The instructions on how to connect to it are in the troubleshooting section.

// Enable the remote debugging port.
options.remoteDebuggingPort(9222);

Creating a Dockerfile

Selecting a Base Image and Basic Environment Configuration

Create a new Dockerfile in the directory we created in the previous step. We start our Dockerfile by selecting Ubuntu 20.04 (LTS) as our base image. Then we perform basic configuration for our environment and update the package lists.

  1. Select a base image:
    FROM ubuntu:20.04
    
  2. Configure the time zone and set a noninteractive frontend for debconf, so it won’t expect a user interaction and pick default choices:
    ENV DEBIAN_FRONTEND=noninteractive
    ENV TZ=UTC
    
  3. Update the package list:
    RUN apt update
    

Installing OpenJDK and Gradle

We use OpenJDK 8 in this tutorial. But you are free to use any other supported JDK.

RUN apt install -y openjdk-8-jdk

Installing Chromium Dependencies

Install dynamic libraries that Chromium requires.

If you want to use a different Ubuntu version or another Linux distribution as a base image, install dependencies required by Chromium package that comes for that system. You can find the list of Chromium packages for various Linux distributives here. Its dependency list should be about the same for JxBrowser as well.

RUN apt install -y \
    libasound2 \
    libatk-bridge2.0-0 \
    libatk1.0-0 \
    libatspi2.0-0 \
    libc6 \
    libcairo2  \
    libcups2 \
    libdbus-1-3 \
    libdrm2 \
    libexpat1 \
    libfontconfig1 \
    libgbm1 \
    libgcc-s1 \
    libglib2.0-0 \
    libgtk-3-0 \
    libnspr4 \
    libnss3 \
    libpango-1.0-0 \
    libpulse0 \
    libx11-6 \
    libxcb1 \
    libxcomposite1 \
    libxdamage1 \
    libxext6 \
    libxfixes3 \
    libxkbcommon0 \
    libxrandr2 \
    libxshmfence1 \
    libxtst6 \
    xdg-utils

Chromium requires an X11 server to work. We use Xvfb that is a lightweight X11 server implementation.

RUN apt install -y xvfb

Copying and Building the Project

In the final part of our Dockerfile, we have to copy all the required files into the image and build our project.

  1. Copy the start-up script and make it executable. We will review its content shortly.
  2. Copy the Java application and build it with Gradle.
  3. Set the entry point for the image.
COPY startup.sh .
RUN chmod +x startup.sh

COPY project/ project
RUN cd project && ./gradlew build

WORKDIR /
ENTRYPOINT ["sh", "-c", "/startup.sh"]

In the start-up script, we launch the X11 server and start our application with Gradle.

#!/bin/sh
Xvfb :0 -screen 0 1920x1080x24+32 &
cd project
DISPLAY=:0 ./gradlew run

Building and Launching a Docker Container

Build a Docker image and name it jxbrowser:

docker build -t jxbrowser .

Start a container using this image:

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

The --shm-size=1gb extends the amount of shared memory to 1 GB. By default, the shared memory in Docker containers is limited to 64MB, which is not enough for Chromium to work.

You should see the title of the loaded page in the console output. In our sample application, we load Google, and it prints out:

Title: Google

Troubleshooting

Accessing DevTools via the Remote Debugging Port

There is no easy way to connect to Chromium’s DevTools via the Remote Debugging Port because Chromium only allows connections from localhost. To bypass it, we use SSH port forwarding.

We have to start the Docker container with the SSH port exposed to the host system. For this, we pass the -p 2222:22 parameter.

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

Once our container is running, we can access the container’s shell to install an SSH server and launch it.

docker exec -it <container_id> /bin/bash
apt install -y openssh-server
service ssh start

We also have to add a new user that we could use to connect to our container.

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

With it, everything is ready to forward the container’s remote debugging port to our host machine.

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

Now you can access open the http://127.0.0.1:9222/ URL with Chrome or Chromium to access the DevTools.

Kubernetes

It is impossible to pass the required --shm-size=1gb flag to Kubernetes and, instead, you have to create a volume for /dev/shm manually:

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

Summary

In this tutorial, we have demonstrated how you can:

  1. Create a Docker image to run with a JxBrowser application.
  2. Configure your application for the Docker environment.
Go Top