From 43e894b645fea5179f213c3331c6243888eede7c Mon Sep 17 00:00:00 2001 From: Ben Francis Date: Thu, 31 Jul 2025 22:00:21 +0100 Subject: [PATCH] Docker image for Balena OS --- .dockerignore | 1 + Dockerfile.template | 43 +++++++++++++++++++++++++++++++++++++++++++ docker-compose.yml | 22 ++++++++++++++++++++++ package.json | 2 +- start.sh | 14 ++++++++++++++ 5 files changed, 81 insertions(+), 1 deletion(-) create mode 100644 .dockerignore create mode 100644 Dockerfile.template create mode 100644 docker-compose.yml create mode 100644 start.sh diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..40b878d --- /dev/null +++ b/.dockerignore @@ -0,0 +1 @@ +node_modules/ \ No newline at end of file diff --git a/Dockerfile.template b/Dockerfile.template new file mode 100644 index 0000000..de630b8 --- /dev/null +++ b/Dockerfile.template @@ -0,0 +1,43 @@ +ARG NODEJS_VERSION="20" + +# If we specify BALENA_MACHINE_NAME, when we do a 'balena push', it will automatically substitute the machine type into our variable, so that you can build it for more than one architecture. +FROM balenalib/%%BALENA_MACHINE_NAME%%-node:${NODEJS_VERSION}-run + +RUN install_packages \ + curl \ + libasound2 \ + libdrm2 \ + libgbm1 \ + libgdk-pixbuf2.0-0 \ + libglib2.0-0 \ + libgtk-3-0 \ + libnss3 \ + libx11-xcb1 \ + libxss1 \ + libxtst6 \ + libgles2-mesa \ + libxshmfence1 \ + mesa-utils \ + mesa-utils-extra + +WORKDIR /opt + +# Copy package files +COPY package.json package-lock.json /opt/ + +# Install node dependencies +RUN JOBS=MAX npm install --unsafe-perm --production && npm cache clean --force && rm -rf /root/.cache/* + +# Now that we are done NPM installing, copy everything else +COPY chrome /opt/chrome +COPY config /opt/config +COPY main.js start.sh /opt/ + +# We are running our entrypoint commands through the start.sh script, because we need to do a couple more things outside of just run electron +CMD ["bash", "/opt/start.sh"] + +ENV NODE_ENV=production \ + # this is specific for balena, to let the startup script know we want to use all udev devices (mouse, keyboard, etc) + UDEV=1 \ + # this is very important, we need to tell our environment that we are going to talk to display 0, which is hosted by the xserver block + DISPLAY=:0 \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..49c101c --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,22 @@ +version: '2.1' +volumes: + # we create a shared volume so that the xserver can mount its socket file, and our application container will be able to use it to display + xserver-volume: +services: + xserver: + image: webthingsio/xserver + restart: always + privileged: true + volumes: + # when we start, a UNIX socket is mounted in this directory, for communication to the X server + - 'xserver-volume:/tmp/.X11-unix' + webthings-shell: + build: . + restart: always + network_mode: host + volumes: + # We will have access to the UNIX socket shared by xserver after it has started up. + - 'xserver-volume:/tmp/.X11-unix' + environment: + # We need to specify which display we want to use for the X server. :0 is the first display that we have plugged in. This because there is no default display specified. + - DISPLAY=:0 \ No newline at end of file diff --git a/package.json b/package.json index c9ed8e0..f424ce5 100644 --- a/package.json +++ b/package.json @@ -15,10 +15,10 @@ "author": "WebThingsIO", "license": "MPL-2.0", "devDependencies": { - "electron": "^35.1.5", "electron-packager": "^17.1.1" }, "dependencies": { + "electron": "^35.1.5", "url-regex": "^5.0.0", "uuid": "^11.1.0" } diff --git a/start.sh b/start.sh new file mode 100644 index 0000000..346364f --- /dev/null +++ b/start.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash + +# We are going to wait for the UNIX socket to be mounted before trying to start the application. This will prevent us from going into a crash loop before xserver is ready. See more info here: https://github.com/balenablocks/xserver#waiting-for-xserver-to-start +while [ ! -e /tmp/.X11-unix/X${DISPLAY#*:} ]; do sleep 0.5; done + +# Run balena base image entrypoint script. We also specified UDEV=1 in the Dockerfile. This will allow udev devices (mouse, etc) to be mounted +/usr/bin/entry.sh echo "Running balena base image entrypoint..." + +# This stops the CPU performance scaling down +echo "Setting CPU Scaling Governor to 'performance'" +echo 'performance' > /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor + +# We are using root to run --no-sandbox for chrome, partially because of this issue: https://github.com/electron/electron/issues/17972 +/opt/node_modules/.bin/electron --no-sandbox /opt/main.js \ No newline at end of file