From 88ca7e9df40657c537d182377a413071b7e7daba Mon Sep 17 00:00:00 2001 From: moqui-industrial <729502+moqui-industrial@users.noreply.github.com> Date: Fri, 17 Jul 2026 18:01:05 +0200 Subject: [PATCH] Add JEP-enabled industrial Docker deployment profile --- industrial/jep/Dockerfile | 34 ++++++++++ industrial/jep/README.md | 102 ++++++++++++++++++++++++++++ industrial/jep/docker-build.sh | 17 +++++ industrial/jep/docker-entrypoint.sh | 49 +++++++++++++ 4 files changed, 202 insertions(+) create mode 100644 industrial/jep/Dockerfile create mode 100644 industrial/jep/README.md create mode 100755 industrial/jep/docker-build.sh create mode 100755 industrial/jep/docker-entrypoint.sh diff --git a/industrial/jep/Dockerfile b/industrial/jep/Dockerfile new file mode 100644 index 0000000..28c05b2 --- /dev/null +++ b/industrial/jep/Dockerfile @@ -0,0 +1,34 @@ +ARG MOQUI_IMAGE=moqui:latest +FROM ${MOQUI_IMAGE} + +USER root + +# curl and certificates are useful for health checks and outbound HTTPS calls. +RUN apt-get update \ + && apt-get install -y --no-install-recommends \ + curl ca-certificates \ + python3 python3-venv python3-pip python3-dev build-essential \ + && rm -rf /var/lib/apt/lists/* + +ARG JEP_VERSION=4.3.1 +ARG NUMPY_VERSION= + +ENV MOQUI_HOME=/opt/moqui +ENV VENV_DIR=/opt/moqui/runtime/python_venv +ENV PYTHONNOUSERSITE=1 +ENV PYTHONPATH= +ENV REQUIRE_JEP=true + +RUN python3 -m venv "${VENV_DIR}" \ + && "${VENV_DIR}/bin/python" -m pip install --upgrade pip \ + && if [ -n "${NUMPY_VERSION}" ]; then \ + "${VENV_DIR}/bin/pip" install --no-cache-dir "numpy==${NUMPY_VERSION}"; \ + else \ + "${VENV_DIR}/bin/pip" install --no-cache-dir numpy; \ + fi \ + && "${VENV_DIR}/bin/pip" install --no-cache-dir "jep==${JEP_VERSION}" + +COPY docker-entrypoint.sh /usr/local/bin/docker-entrypoint.sh +RUN chmod +x /usr/local/bin/docker-entrypoint.sh + +ENTRYPOINT ["/usr/local/bin/docker-entrypoint.sh"] diff --git a/industrial/jep/README.md b/industrial/jep/README.md new file mode 100644 index 0000000..47776a4 --- /dev/null +++ b/industrial/jep/README.md @@ -0,0 +1,102 @@ +# Industrial JEP Docker Profile + +This profile builds an opinionated Moqui runtime image with embedded Python and +JEP support for industrial deployments that include the `moqui-jep` component. + +It belongs in `moqui-deploy` because it is deployment packaging, not framework +behavior. Application services, Python scripts, and the JEP component itself +remain in `moqui-jep`. + +## Relationship to other repositories + +- `moqui-framework` provides the standard Moqui runtime image layout. +- `moqui-jep` provides the component, Gradle tasks, Python requirements, and + runtime integration points for JEP-based services. +- `moqui-deploy` packages an image profile that adds the Python/JEP runtime on + top of a normal Moqui image. + +## Layout expectations + +Build your base Moqui image so it already contains the runtime, components, and +configuration you want to deploy. If you use `moqui-jep`, make sure the +component is present in the base image build context before creating the JEP +variant. + +## Build + +Build from the profile directory: + +```bash +cd industrial/jep +./docker-build.sh moqui-jep:latest moqui:latest +``` + +Equivalent raw `docker build` command: + +```bash +docker build \ + -t moqui-jep:latest \ + --build-arg MOQUI_IMAGE=moqui:latest \ + --build-arg JEP_VERSION=4.3.1 \ + . +``` + +Optional build arguments: + +- `MOQUI_IMAGE`: base Moqui image to extend +- `JEP_VERSION`: JEP package version, default `4.3.1` +- `NUMPY_VERSION`: optional pinned NumPy version + +## Run + +```bash +docker run --rm -p 8080:80 moqui-jep:latest conf=conf/MoquiProductionConf.xml +``` + +The entrypoint preserves normal Moqui startup and forwards all arguments to +`MoquiStart`. + +## Runtime behavior + +- Creates `/opt/moqui/runtime/python_venv` +- Resolves the installed `libjep.so` from the venv at startup +- Exports `LD_LIBRARY_PATH` +- Starts Java with `-Djep.lib` and `-Djep_site_pkgs` +- Fails fast if `REQUIRE_JEP=true` and the native library cannot be found + +Environment variables: + +- `MOQUI_HOME`: defaults to `/opt/moqui` +- `VENV_DIR`: defaults to `/opt/moqui/runtime/python_venv` +- `PORT`: defaults to `80` +- `REQUIRE_JEP`: defaults to `true` + +## Verification + +Build: + +```bash +docker build -t moqui-jep:latest . +``` + +Inspect the Python/JEP installation: + +```bash +docker run --rm moqui-jep:latest /bin/sh -lc ' + /opt/moqui/runtime/python_venv/bin/python -c "import jep; print(jep.__file__)" && + find /opt/moqui/runtime/python_venv -name "libjep.so" -o -name "libjep.dylib" +' +``` + +Start Moqui: + +```bash +docker run --rm -p 8080:80 moqui-jep:latest conf=conf/MoquiProductionConf.xml +``` + +## Notes + +- This profile assumes Linux/glibc style packaging and is primarily intended + for Debian/Ubuntu based Moqui base images. +- Keep the base image aligned with the standard Moqui image so runtime layout + changes are reflected here when needed. diff --git a/industrial/jep/docker-build.sh b/industrial/jep/docker-build.sh new file mode 100755 index 0000000..81991e9 --- /dev/null +++ b/industrial/jep/docker-build.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env bash +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +IMAGE_TAG="${1:-moqui-jep:latest}" +MOQUI_IMAGE="${2:-moqui:latest}" +JEP_VERSION="${JEP_VERSION:-4.3.1}" +NUMPY_VERSION="${NUMPY_VERSION:-}" + +echo "Building ${IMAGE_TAG} from base image ${MOQUI_IMAGE}" + +docker build \ + -t "${IMAGE_TAG}" \ + --build-arg "MOQUI_IMAGE=${MOQUI_IMAGE}" \ + --build-arg "JEP_VERSION=${JEP_VERSION}" \ + --build-arg "NUMPY_VERSION=${NUMPY_VERSION}" \ + "${SCRIPT_DIR}" diff --git a/industrial/jep/docker-entrypoint.sh b/industrial/jep/docker-entrypoint.sh new file mode 100755 index 0000000..233eda5 --- /dev/null +++ b/industrial/jep/docker-entrypoint.sh @@ -0,0 +1,49 @@ +#!/usr/bin/env sh +set -eu + +MOQUI_HOME="${MOQUI_HOME:-/opt/moqui}" +VENV_DIR="${VENV_DIR:-$MOQUI_HOME/runtime/python_venv}" +PORT="${PORT:-80}" +PYBIN="$VENV_DIR/bin/python" +REQUIRE_JEP="${REQUIRE_JEP:-true}" + +if [ ! -x "$PYBIN" ]; then + if [ "$REQUIRE_JEP" = "true" ]; then + echo "ERROR: Python virtual environment not found at $VENV_DIR" >&2 + exit 1 + fi + exec java -cp . MoquiStart "port=$PORT" "$@" +fi + +unset PYTHONPATH +export PYTHONNOUSERSITE=1 + +JEP_INFO="$("$PYBIN" - <<'PY' +import os +import sysconfig + +site = sysconfig.get_paths().get("purelib") or "" +jep_dir = os.path.join(site, "jep") +candidates = [ + os.path.join(jep_dir, "libjep.so"), + os.path.join(jep_dir, "libjep.dylib"), +] +jep_lib = next((path for path in candidates if os.path.isfile(path)), "") +print(jep_lib) +print(site) +PY +)" + +JEP_LIB=$(printf '%s\n' "$JEP_INFO" | sed -n '1p') +SITE_PKGS=$(printf '%s\n' "$JEP_INFO" | sed -n '2p') + +if [ -z "$JEP_LIB" ] || [ ! -f "$JEP_LIB" ]; then + if [ "$REQUIRE_JEP" = "true" ]; then + echo "ERROR: JEP native library not found in $VENV_DIR" >&2 + exit 1 + fi + exec java -cp . MoquiStart "port=$PORT" "$@" +fi + +export LD_LIBRARY_PATH="$(dirname "$JEP_LIB")${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}" +exec java -Djep.lib="$JEP_LIB" -Djep_site_pkgs="$SITE_PKGS" -cp . MoquiStart "port=$PORT" "$@"